1 /************
2 *
3 *   This file is part of a tool for producing 3D content in the PRC format.
4 *   Copyright (C) 2008  Orest Shardt <shardtor (at) gmail dot com>
5 *   with enhancements contributed by Michail Vidiassov.
6 *
7 *   This program is free software: you can redistribute it and/or modify
8 *   it under the terms of the GNU Lesser General Public License  as published by
9 *   the Free Software Foundation, either version 3 of the License, or
10 *   (at your option) any later version.
11 *
12 *   This program is distributed in the hope that it will be useful,
13 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
14 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 *   GNU Lesser General Public License  for more details.
16 *
17 *   You should have received a copy of the GNU Lesser General Public License
18 *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 *
20 *************/
21 
22 #include "oPRCFile.h"
23 #include <time.h>
24 #include <sstream>
25 #include <iostream>
26 #include <fstream>
27 #include <iomanip>
28 #include <string>
29 #include <zlib.h>
30 #include <string.h>
31 
32 #define WriteUnsignedInteger( value ) out << (uint32_t)(value);
33 #define WriteInteger( value ) out << (int32_t)(value);
34 #define WriteDouble( value ) out << (double)(value);
35 #define WriteString( value ) out << (value);
36 #define WriteUncompressedUnsignedInteger( value ) writeUncompressedUnsignedInteger(out, (uint32_t)(value));
37 #define WriteUncompressedBlock( value, count ) out.write((char *)(value),(count));
38 #define SerializeFileStructureUncompressedUniqueId( value ) (value).serializeFileStructureUncompressedUniqueId(out);
39 #define SerializeCompressedUniqueId( value ) (value).serializeCompressedUniqueId(out);
40 #define SerializeContentPRCBase write(out);
41 #define SerializeRgbColor( value ) (value).serializeRgbColor(out);
42 #define SerializePicture( value ) (value)->serializePicture(out);
43 #define SerializeTextureDefinition( value ) (value)->serializeTextureDefinition(out);
44 #define SerializeMarkup( value ) (value)->serializeMarkup(out);
45 #define SerializeAnnotationEntity( value ) (value)->serializeAnnotationEntity(out);
46 #define SerializeFontKeysSameFont( value ) (value).serializeFontKeysSameFont(out);
47 #define SerializeMaterial( value ) (value)->serializeMaterial(out);
48 
49 #define SerializeUserData UserData(0,0).write(out);
50 #define SerializeEmptyContentPRCBase ContentPRCBase(PRC_TYPE_ROOT_PRCBase).serializeContentPRCBase(out);
51 #define SerializeCategory1LineStyle( value ) (value)->serializeCategory1LineStyle(out);
52 #define SerializeCoordinateSystem( value ) (value)->serializeCoordinateSystem(out);
53 #define SerializeRepresentationItem( value ) (value)->serializeRepresentationItem(out);
54 #define SerializePartDefinition( value ) (value)->serializePartDefinition(out);
55 #define SerializeProductOccurrence( value ) (value)->serializeProductOccurrence(out);
56 #define SerializeContextAndBodies( value ) (value)->serializeContextAndBodies(out);
57 #define SerializeGeometrySummary( value ) (value)->serializeGeometrySummary(out);
58 #define SerializeContextGraphics( value ) (value)->serializeContextGraphics(out);
59 #define SerializeStartHeader serializeStartHeader(out);
60 #define SerializeUncompressedFile( value ) (value)->serializeUncompressedFile(out);
61 #define SerializeUncompressedFiles  serializeUncompressedFiles(out);
62 
63 #define SerializeModelFileData serializeModelFileData(modelFile_out); modelFile_out.compress();
64 #define SerializeUnit( value ) (value).serializeUnit(out);
65 
66 using std::string;
67 using namespace std;
68 
69 // Map [0,1] to [0,255]
toByte(double r)70 inline uint8_t toByte(double r)
71 {
72   if(r < 0.0) r=0.0;
73   else if(r > 1.0) r=1.0;
74   int a=(int)(256.0*r);
75   if(a == 256) a=255;
76   return a;
77 }
78 
serializeFileStructureGlobals(PRCbitStream & out)79 void PRCFileStructure::serializeFileStructureGlobals(PRCbitStream &out)
80 {
81   // even though this is technically not part of this section,
82   // it is handled here for convenience
83   const uint32_t number_of_schema = 0;
84   WriteUnsignedInteger (number_of_schema)
85 
86   WriteUnsignedInteger (PRC_TYPE_ASM_FileStructureGlobals)
87 
88   PRCSingleAttribute sa((int32_t)PRCVersion);
89   PRCAttribute a("__PRC_RESERVED_ATTRIBUTE_PRCInternalVersion");
90   a.addKey(sa);
91   ContentPRCBase cb(PRC_TYPE_ROOT_PRCBase);
92   cb.addAttribute(a);
93   cb.serializeContentPRCBase(out);
94   WriteUnsignedInteger (number_of_referenced_file_structures)
95   // SerializeFileStructureInternalGlobalData
96   WriteDouble (tessellation_chord_height_ratio)
97   WriteDouble (tessellation_angle_degree)
98 
99   // SerializeMarkupSerializationHelper
100   WriteString (default_font_family_name)
101 
102   const uint32_t number_of_fonts = font_keys_of_font.size();
103   WriteUnsignedInteger (number_of_fonts)
104   for (uint32_t i=0;i<number_of_fonts;i++)
105   {
106     SerializeFontKeysSameFont (font_keys_of_font[i])
107   }
108 
109   const uint32_t number_of_colors = colors.size();
110   WriteUnsignedInteger (number_of_colors)
111   for (uint32_t i=0;i<number_of_colors;i++)
112       SerializeRgbColor (colors[i])
113 
114   const uint32_t number_of_pictures = pictures.size();
115   WriteUnsignedInteger (number_of_pictures)
116   for (uint32_t i=0;i<number_of_pictures;i++)
117      SerializePicture (pictures[i])
118 
119   const uint32_t number_of_texture_definitions = texture_definitions.size();
120   WriteUnsignedInteger (number_of_texture_definitions)
121   for (uint32_t i=0;i<number_of_texture_definitions;i++)
122      SerializeTextureDefinition (texture_definitions[i])
123 
124   const uint32_t number_of_materials = materials.size();
125   WriteUnsignedInteger (number_of_materials)
126   for (uint32_t i=0;i<number_of_materials;i++)
127      SerializeMaterial (materials[i])
128 
129   // number of line patterns hard coded for now
130   const uint32_t number_of_line_patterns = 1;
131   WriteUnsignedInteger (number_of_line_patterns)
132   PRCLinePattern().serializeLinePattern(out);
133 
134   const uint32_t number_of_styles = styles.size();
135   WriteUnsignedInteger (number_of_styles)
136   for (uint32_t i=0;i<number_of_styles;i++)
137      SerializeCategory1LineStyle (styles[i])
138 
139   const uint32_t number_of_fill_patterns = 0;
140   WriteUnsignedInteger (number_of_fill_patterns)
141 
142   const uint32_t number_of_reference_coordinate_systems = reference_coordinate_systems.size();
143   WriteUnsignedInteger (number_of_reference_coordinate_systems)
144   for (uint32_t i=0;i<number_of_reference_coordinate_systems;i++)
145      SerializeCoordinateSystem (reference_coordinate_systems[i])
146 
147   SerializeUserData
148 }
149 
serializeFileStructureTree(PRCbitStream & out)150 void PRCFileStructure::serializeFileStructureTree(PRCbitStream &out)
151 {
152   WriteUnsignedInteger (PRC_TYPE_ASM_FileStructureTree)
153 
154   SerializeEmptyContentPRCBase
155 
156   const uint32_t number_of_part_definitions = part_definitions.size();
157   WriteUnsignedInteger (number_of_part_definitions)
158   for (uint32_t i=0;i<number_of_part_definitions;i++)
159     SerializePartDefinition (part_definitions[i])
160 
161   const uint32_t number_of_product_occurrences = product_occurrences.size();
162   WriteUnsignedInteger (number_of_product_occurrences)
163   for (uint32_t i=0;i<number_of_product_occurrences;i++)
164   {
165     product_occurrences[i]->unit_information.unit_from_CAD_file = true;
166     product_occurrences[i]->unit_information.unit = unit;
167     SerializeProductOccurrence (product_occurrences[i])
168   }
169 
170   // SerializeFileStructureInternalData
171   WriteUnsignedInteger (PRC_TYPE_ASM_FileStructure)
172   SerializeEmptyContentPRCBase
173   const uint32_t next_available_index = makePRCID();
174   WriteUnsignedInteger (next_available_index)
175   const uint32_t index_product_occurence = number_of_product_occurrences;  // Asymptote (oPRCFile) specific - we write the root product last
176   WriteUnsignedInteger (index_product_occurence)
177 
178   SerializeUserData
179 }
180 
serializeFileStructureTessellation(PRCbitStream & out)181 void PRCFileStructure::serializeFileStructureTessellation(PRCbitStream &out)
182 {
183   WriteUnsignedInteger (PRC_TYPE_ASM_FileStructureTessellation)
184 
185   SerializeEmptyContentPRCBase
186   const uint32_t number_of_tessellations = tessellations.size();
187   WriteUnsignedInteger (number_of_tessellations)
188   for (uint32_t i=0;i<number_of_tessellations;i++)
189     tessellations[i]->serializeBaseTessData(out);
190 
191   SerializeUserData
192 }
193 
serializeFileStructureGeometry(PRCbitStream & out)194 void PRCFileStructure::serializeFileStructureGeometry(PRCbitStream &out)
195 {
196   WriteUnsignedInteger (PRC_TYPE_ASM_FileStructureGeometry)
197 
198   SerializeEmptyContentPRCBase
199   const uint32_t number_of_contexts = contexts.size();
200   WriteUnsignedInteger (number_of_contexts)
201   for (uint32_t i=0;i<number_of_contexts;i++)
202     SerializeContextAndBodies (contexts[i])
203 
204   SerializeUserData
205 }
206 
serializeFileStructureExtraGeometry(PRCbitStream & out)207 void PRCFileStructure::serializeFileStructureExtraGeometry(PRCbitStream &out)
208 {
209   WriteUnsignedInteger (PRC_TYPE_ASM_FileStructureExtraGeometry)
210 
211   SerializeEmptyContentPRCBase
212   const uint32_t number_of_contexts = contexts.size();
213   WriteUnsignedInteger (number_of_contexts)
214   for (uint32_t i=0;i<number_of_contexts;i++)
215   {
216      SerializeGeometrySummary (contexts[i])
217      SerializeContextGraphics (contexts[i])
218   }
219 
220   SerializeUserData
221 }
222 
serializeModelFileData(PRCbitStream & out)223 void oPRCFile::serializeModelFileData(PRCbitStream &out)
224 {
225   // even though this is technically not part of this section,
226   // it is handled here for convenience
227   const uint32_t number_of_schema = 0;
228   WriteUnsignedInteger (number_of_schema)
229   WriteUnsignedInteger (PRC_TYPE_ASM_ModelFile)
230 
231   PRCSingleAttribute sa((int32_t)PRCVersion);
232   PRCAttribute a("__PRC_RESERVED_ATTRIBUTE_PRCInternalVersion");
233   a.addKey(sa);
234   ContentPRCBase cb(PRC_TYPE_ROOT_PRCBase,"PRC file");
235   cb.addAttribute(a);
236   cb.serializeContentPRCBase(out);
237 
238   SerializeUnit (unit)
239 
240   out << (uint32_t)1; // 1 product occurrence
241   //UUID
242   SerializeCompressedUniqueId( fileStructures[0]->file_structure_uuid )
243   // index+1
244   out << (uint32_t)fileStructures[0]->product_occurrences.size();
245   // active
246   out << true;
247   out << (uint32_t)0; // index in model file
248 
249   SerializeUserData
250 }
251 
makeFileUUID(PRCUniqueId & UUID)252 void makeFileUUID(PRCUniqueId& UUID)
253 {
254   // make a UUID
255   static uint32_t count = 0;
256   ++count;
257   // the minimum requirement on UUIDs is that all must be unique in the file
258   UUID.id0 = 0x33595341; // some constant
259   UUID.id1 = (uint32_t)time(NULL); // the time
260   UUID.id2 = count;
261   UUID.id3 = 0xa5a55a5a; // Something random, not seeded by the time, would be nice. But for now, a constant
262   // maybe add something else to make it more unique
263   // so multiple files can be combined
264   // a hash of some data perhaps?
265 }
266 
makeAppUUID(PRCUniqueId & UUID)267 void makeAppUUID(PRCUniqueId& UUID)
268 {
269   UUID.id0 = UUID.id1 = UUID.id2 = UUID.id3 = 0;
270 }
271 
serializeStartHeader(ostream & out) const272 void PRCStartHeader::serializeStartHeader(ostream &out) const
273 {
274   WriteUncompressedBlock ("PRC",3)
275   WriteUncompressedUnsignedInteger (minimal_version_for_read)
276   WriteUncompressedUnsignedInteger (authoring_version)
277   SerializeFileStructureUncompressedUniqueId( file_structure_uuid );
278   SerializeFileStructureUncompressedUniqueId( application_uuid );
279 }
280 
serializeUncompressedFiles(ostream & out) const281 void PRCStartHeader::serializeUncompressedFiles(ostream &out) const
282 {
283   const uint32_t number_of_uncompressed_files = uncompressed_files.size();
284   WriteUncompressedUnsignedInteger (number_of_uncompressed_files)
285   for (uint32_t i=0; i<number_of_uncompressed_files; i++)
286     SerializeUncompressedFile (uncompressed_files[i])
287 }
288 
getStartHeaderSize() const289 uint32_t PRCStartHeader::getStartHeaderSize() const
290 {
291   return 3+(2+2*4)*sizeof(uint32_t);
292 }
293 
getUncompressedFilesSize() const294 uint32_t PRCStartHeader::getUncompressedFilesSize() const
295 {
296   uint32_t size = 0;
297   for(PRCUncompressedFileList::const_iterator it = uncompressed_files.begin(); it != uncompressed_files.end(); it++)
298     size += (*it)->getSize();
299   return size;
300 }
301 
write(ostream & out)302 void PRCFileStructure::write(ostream &out)
303 {
304   // SerializeFileStructureHeader
305   SerializeStartHeader
306   SerializeUncompressedFiles
307   globals_out.write(out);
308   tree_out.write(out);
309   tessellations_out.write(out);
310   geometry_out.write(out);
311   extraGeometry_out.write(out);
312 }
313 
314 #define SerializeFileStructureGlobals serializeFileStructureGlobals(globals_out); globals_out.compress(); sizes[1]=globals_out.getSize();
315 #define SerializeFileStructureTree serializeFileStructureTree(tree_out); tree_out.compress(); sizes[2]=tree_out.getSize();
316 #define SerializeFileStructureTessellation serializeFileStructureTessellation(tessellations_out); tessellations_out.compress(); sizes[3]=tessellations_out.getSize();
317 #define SerializeFileStructureGeometry serializeFileStructureGeometry(geometry_out); geometry_out.compress(); sizes[4]=geometry_out.getSize();
318 #define SerializeFileStructureExtraGeometry serializeFileStructureExtraGeometry(extraGeometry_out); extraGeometry_out.compress(); sizes[5]=extraGeometry_out.getSize();
319 #define FlushSerialization resetGraphicsAndName();
prepare()320 void PRCFileStructure::prepare()
321 {
322   uint32_t size = 0;
323   size += getStartHeaderSize();
324   size += sizeof(uint32_t);
325   size += getUncompressedFilesSize();
326   sizes[0]=size;
327 
328   SerializeFileStructureGlobals
329   FlushSerialization
330 
331   SerializeFileStructureTree
332   FlushSerialization
333 
334   SerializeFileStructureTessellation
335   FlushSerialization
336 
337   SerializeFileStructureGeometry
338   FlushSerialization
339 
340   SerializeFileStructureExtraGeometry
341   FlushSerialization
342 }
343 
getSize()344 uint32_t PRCFileStructure::getSize()
345 {
346   uint32_t size = 0;
347   for(size_t i=0; i<6; i++)
348     size += sizes[i];
349   return size;
350 }
351 
352 
write(ostream & out)353 void PRCFileStructureInformation::write(ostream &out)
354 {
355   SerializeFileStructureUncompressedUniqueId( UUID );
356 
357   WriteUncompressedUnsignedInteger (reserved)
358   WriteUncompressedUnsignedInteger (number_of_offsets)
359   for(uint32_t i = 0; i < number_of_offsets; ++i)
360   {
361     WriteUncompressedUnsignedInteger (offsets[i])
362   }
363 }
364 
getSize()365 uint32_t PRCFileStructureInformation::getSize()
366 {
367   return (4+2+number_of_offsets)*sizeof(uint32_t);
368 }
369 
write(ostream & out)370 void PRCHeader::write(ostream &out)
371 {
372   SerializeStartHeader
373   WriteUncompressedUnsignedInteger (number_of_file_structures)
374   for(uint32_t i = 0; i < number_of_file_structures; ++i)
375   {
376     fileStructureInformation[i].write(out);
377   }
378   WriteUncompressedUnsignedInteger (model_file_offset)
379   WriteUncompressedUnsignedInteger (file_size)
380   SerializeUncompressedFiles
381 }
382 
getSize()383 uint32_t PRCHeader::getSize()
384 {
385   uint32_t size = getStartHeaderSize() + sizeof(uint32_t);
386   for(uint32_t i = 0; i < number_of_file_structures; ++i)
387     size += fileStructureInformation[i].getSize();
388   size += 3*sizeof(uint32_t);
389   size += getUncompressedFilesSize();
390   return size;
391 }
392 
doGroup(PRCgroup & group)393 void oPRCFile::doGroup(PRCgroup& group)
394 {
395     const string& name = group.name;
396 
397     PRCProductOccurrence*& product_occurrence        = group.product_occurrence;
398     PRCProductOccurrence*& parent_product_occurrence = group.parent_product_occurrence;
399     PRCPartDefinition*& part_definition              = group.part_definition;
400     PRCPartDefinition*& parent_part_definition       = group.parent_part_definition;
401 
402     if(group.options.tess)
403     {
404       if(!group.lines.empty())
405       {
406         for(PRCtesslineMap::const_iterator wit=group.lines.begin(); wit!=group.lines.end(); wit++)
407         {
408           bool same_color = true;
409           const PRCtesslineList& lines = wit->second;
410           const PRCRgbColor &color = lines.front().color;
411           for(PRCtesslineList::const_iterator lit=lines.begin(); lit!=lines.end(); lit++)
412             if(color!=lit->color)
413             {
414               same_color = false;
415               break;
416             }
417           map<PRCVector3d,uint32_t> points;
418           PRC3DWireTess *tess = new PRC3DWireTess();
419           if(!same_color)
420           {
421             tess->is_segment_color = true;
422             tess->is_rgba = false;
423           }
424           for(PRCtesslineList::const_iterator lit=lines.begin(); lit!=lines.end(); lit++)
425           {
426             tess->wire_indexes.push_back(lit->point.size());
427             for(uint32_t i=0; i<lit->point.size(); i++)
428             {
429               map<PRCVector3d,uint32_t>::iterator pPoint = points.find(lit->point[i]);
430               if(pPoint!=points.end())
431                 tess->wire_indexes.push_back(pPoint->second);
432               else
433               {
434                 const uint32_t point_index = tess->coordinates.size();
435                 points.insert(make_pair(lit->point[i],point_index));
436                 tess->wire_indexes.push_back(point_index);
437                 tess->coordinates.push_back(lit->point[i].x);
438                 tess->coordinates.push_back(lit->point[i].y);
439                 tess->coordinates.push_back(lit->point[i].z);
440               }
441               if(!same_color && i>0)
442               {
443                 tess->rgba_vertices.push_back(toByte(lit->color.red));
444                 tess->rgba_vertices.push_back(toByte(lit->color.green));
445                 tess->rgba_vertices.push_back(toByte(lit->color.blue));
446               }
447             }
448           }
449           const uint32_t tess_index = add3DWireTess(tess);
450           PRCPolyWire *polyWire = new PRCPolyWire();
451           polyWire->index_tessellation = tess_index;
452           if(same_color)
453             polyWire->index_of_line_style = addColourWidth(RGBAColour(color.red,color.green,color.blue),wit->first);
454           else
455             polyWire->index_of_line_style = addColourWidth(RGBAColour(1,1,1),wit->first);
456           part_definition->addPolyWire(polyWire);
457         }
458       }
459 //    make rectangles pairs of triangles in a tesselation
460       if(!group.rectangles.empty())
461       {
462         bool same_color = true;
463         const uint32_t &style = group.rectangles.front().style;
464         for(PRCtessrectangleList::const_iterator rit=group.rectangles.begin(); rit!=group.rectangles.end(); rit++)
465           if(style!=rit->style)
466           {
467             same_color = false;
468             break;
469           }
470         map<PRCVector3d,uint32_t> points;
471         PRC3DTess *tess = new PRC3DTess();
472         tess->crease_angle = group.options.crease_angle;
473         PRCTessFace *tessFace = new PRCTessFace();
474         tessFace->used_entities_flag=PRC_FACETESSDATA_Triangle;
475         uint32_t triangles = 0;
476         for(PRCtessrectangleList::const_iterator rit=group.rectangles.begin(); rit!=group.rectangles.end(); rit++)
477         {
478           const bool degenerate = (rit->vertices[0]==rit->vertices[1]);
479           uint32_t vertex_indices[4];
480           for(size_t i = (degenerate?1:0); i < 4; ++i)
481           {
482             map<PRCVector3d,uint32_t>::const_iterator pPoint = points.find(rit->vertices[i]);
483             if(pPoint!=points.end())
484               vertex_indices[i] =  pPoint->second;
485             else
486             {
487               points.insert(make_pair(rit->vertices[i],(vertex_indices[i] = tess->coordinates.size())));
488               tess->coordinates.push_back(rit->vertices[i].x);
489               tess->coordinates.push_back(rit->vertices[i].y);
490               tess->coordinates.push_back(rit->vertices[i].z);
491             }
492           }
493           if(degenerate)
494           {
495             tess->triangulated_index.push_back(vertex_indices[1]);
496             tess->triangulated_index.push_back(vertex_indices[2]);
497             tess->triangulated_index.push_back(vertex_indices[3]);
498             triangles++;
499             if(!same_color)
500               tessFace->line_attributes.push_back(rit->style);
501           }
502           else
503           {
504             tess->triangulated_index.push_back(vertex_indices[0]);
505             tess->triangulated_index.push_back(vertex_indices[2]);
506             tess->triangulated_index.push_back(vertex_indices[3]);
507             triangles++;
508             if(!same_color)
509               tessFace->line_attributes.push_back(rit->style);
510             tess->triangulated_index.push_back(vertex_indices[3]);
511             tess->triangulated_index.push_back(vertex_indices[1]);
512             tess->triangulated_index.push_back(vertex_indices[0]);
513             triangles++;
514             if(!same_color)
515               tessFace->line_attributes.push_back(rit->style);
516           }
517         }
518         tessFace->sizes_triangulated.push_back(triangles);
519         tess->addTessFace(tessFace);
520         const uint32_t tess_index = add3DTess(tess);
521         PRCPolyBrepModel *polyBrepModel = new PRCPolyBrepModel();
522         polyBrepModel->index_tessellation = tess_index;
523         polyBrepModel->is_closed = group.options.closed;
524         if(same_color)
525           polyBrepModel->index_of_line_style = style;
526         part_definition->addPolyBrepModel(polyBrepModel);
527       }
528     }
529 
530     if(!group.quads.empty())
531     {
532       map<PRCVector3d,uint32_t> points;
533       PRC3DTess *tess = new PRC3DTess();
534       tess->crease_angle = group.options.crease_angle;
535       PRCTessFace *tessFace = new PRCTessFace();
536       tessFace->used_entities_flag=PRC_FACETESSDATA_Triangle;
537       uint32_t triangles = 0;
538 
539       tessFace->is_rgba = false;
540       for(PRCtessquadList::const_iterator qit=group.quads.begin(); qit!=group.quads.end(); qit++)
541       {
542         const RGBAColour* C = qit->colours;
543         if(C[0].A != 1.0 || C[1].A != 1.0 || C[2].A != 1.0 || C[3].A != 1.0)
544         {
545           tessFace->is_rgba = true;
546           break;
547         }
548       }
549       bool same_colour = true;
550       const RGBAColour& colour = group.quads.front().colours[0];
551       for(PRCtessquadList::const_iterator qit=group.quads.begin(); qit!=group.quads.end(); qit++)
552       {
553         const RGBAColour* C = qit->colours;
554         if(colour!=C[0] || colour!=C[1] || colour!=C[2] || colour!=C[3])
555         {
556           same_colour = false;
557           break;
558         }
559       }
560 
561       for(PRCtessquadList::const_iterator qit=group.quads.begin(); qit!=group.quads.end(); qit++)
562       {
563         const RGBAColour* C = qit->colours;
564         const bool degenerate = (qit->vertices[0]==qit->vertices[1]);
565         uint32_t vertex_indices[4];
566         for(size_t i = (degenerate?1:0); i < 4; ++i)
567         {
568           map<PRCVector3d,uint32_t>::const_iterator pPoint = points.find(qit->vertices[i]);
569           if(pPoint!=points.end())
570             vertex_indices[i] =  pPoint->second;
571           else
572           {
573             points.insert(make_pair(qit->vertices[i],(vertex_indices[i] = tess->coordinates.size())));
574             tess->coordinates.push_back(qit->vertices[i].x);
575             tess->coordinates.push_back(qit->vertices[i].y);
576             tess->coordinates.push_back(qit->vertices[i].z);
577           }
578         }
579         if(degenerate)
580         {
581           tess->triangulated_index.push_back(vertex_indices[1]);
582           tess->triangulated_index.push_back(vertex_indices[2]);
583           tess->triangulated_index.push_back(vertex_indices[3]);
584           triangles++;
585           if(!same_colour)
586           {
587             tessFace->rgba_vertices.push_back(toByte(C[1].R));
588             tessFace->rgba_vertices.push_back(toByte(C[1].G));
589             tessFace->rgba_vertices.push_back(toByte(C[1].B));
590             if(tessFace->is_rgba)
591               tessFace->rgba_vertices.push_back(toByte(C[1].A));
592 
593             tessFace->rgba_vertices.push_back(toByte(C[2].R));
594             tessFace->rgba_vertices.push_back(toByte(C[2].G));
595             tessFace->rgba_vertices.push_back(toByte(C[2].B));
596             if(tessFace->is_rgba)
597               tessFace->rgba_vertices.push_back(toByte(C[2].A));
598 
599             tessFace->rgba_vertices.push_back(toByte(C[3].R));
600             tessFace->rgba_vertices.push_back(toByte(C[3].G));
601             tessFace->rgba_vertices.push_back(toByte(C[3].B));
602             if(tessFace->is_rgba)
603               tessFace->rgba_vertices.push_back(toByte(C[3].A));
604           }
605         }
606         else
607         {
608           tess->triangulated_index.push_back(vertex_indices[0]);
609           tess->triangulated_index.push_back(vertex_indices[2]);
610           tess->triangulated_index.push_back(vertex_indices[3]);
611           triangles++;
612           if(!same_colour)
613           {
614             tessFace->rgba_vertices.push_back(toByte(C[0].R));
615             tessFace->rgba_vertices.push_back(toByte(C[0].G));
616             tessFace->rgba_vertices.push_back(toByte(C[0].B));
617             if(tessFace->is_rgba)
618               tessFace->rgba_vertices.push_back(toByte(C[0].A));
619 
620             tessFace->rgba_vertices.push_back(toByte(C[2].R));
621             tessFace->rgba_vertices.push_back(toByte(C[2].G));
622             tessFace->rgba_vertices.push_back(toByte(C[2].B));
623             if(tessFace->is_rgba)
624               tessFace->rgba_vertices.push_back(toByte(C[2].A));
625 
626             tessFace->rgba_vertices.push_back(toByte(C[3].R));
627             tessFace->rgba_vertices.push_back(toByte(C[3].G));
628             tessFace->rgba_vertices.push_back(toByte(C[3].B));
629             if(tessFace->is_rgba)
630               tessFace->rgba_vertices.push_back(toByte(C[3].A));
631           }
632           tess->triangulated_index.push_back(vertex_indices[3]);
633           tess->triangulated_index.push_back(vertex_indices[1]);
634           tess->triangulated_index.push_back(vertex_indices[0]);
635           triangles++;
636           if(!same_colour)
637           {
638             tessFace->rgba_vertices.push_back(toByte(C[3].R));
639             tessFace->rgba_vertices.push_back(toByte(C[3].G));
640             tessFace->rgba_vertices.push_back(toByte(C[3].B));
641             if(tessFace->is_rgba)
642               tessFace->rgba_vertices.push_back(toByte(C[3].A));
643 
644             tessFace->rgba_vertices.push_back(toByte(C[1].R));
645             tessFace->rgba_vertices.push_back(toByte(C[1].G));
646             tessFace->rgba_vertices.push_back(toByte(C[1].B));
647             if(tessFace->is_rgba)
648               tessFace->rgba_vertices.push_back(toByte(C[1].A));
649 
650             tessFace->rgba_vertices.push_back(toByte(C[0].R));
651             tessFace->rgba_vertices.push_back(toByte(C[0].G));
652             tessFace->rgba_vertices.push_back(toByte(C[0].B));
653             if(tessFace->is_rgba)
654               tessFace->rgba_vertices.push_back(toByte(C[0].A));
655           }
656         }
657       }
658       tessFace->sizes_triangulated.push_back(triangles);
659       tess->addTessFace(tessFace);
660       const uint32_t tess_index = add3DTess(tess);
661       PRCPolyBrepModel *polyBrepModel = new PRCPolyBrepModel();
662       polyBrepModel->index_tessellation = tess_index;
663       polyBrepModel->is_closed = group.options.closed;
664       if(same_colour)
665         polyBrepModel->index_of_line_style = addColour(colour);
666       part_definition->addPolyBrepModel(polyBrepModel);
667     }
668 
669     if(!group.points.empty())
670     {
671       for(PRCpointsetMap::const_iterator pit=group.points.begin(); pit!=group.points.end(); pit++)
672       {
673         PRCPointSet *pointset = new PRCPointSet();
674         pointset->index_of_line_style = pit->first;
675         pointset->point = pit->second;
676         part_definition->addPointSet(pointset);
677       }
678     }
679 
680     if(!group.pointsets.empty())
681     {
682       for(std::vector<PRCPointSet*>::iterator pit=group.pointsets.begin(); pit!=group.pointsets.end(); pit++)
683       {
684         part_definition->addPointSet(*pit);
685       }
686     }
687 
688     if(!group.polymodels.empty())
689     {
690       for(std::vector<PRCPolyBrepModel*>::iterator pit=group.polymodels.begin(); pit!=group.polymodels.end(); pit++)
691       {
692         (*pit)->is_closed = group.options.closed;
693         part_definition->addPolyBrepModel(*pit);
694       }
695     }
696 
697     if(!group.polywires.empty())
698     {
699       for(std::vector<PRCPolyWire*>::iterator pit=group.polywires.begin(); pit!=group.polywires.end(); pit++)
700       {
701         part_definition->addPolyWire(*pit);
702       }
703     }
704 
705     if(!group.wires.empty())
706     {
707       PRCTopoContext *wireContext = NULL;
708       const uint32_t context_index = getTopoContext(wireContext);
709       for(PRCwireList::iterator wit=group.wires.begin(); wit!=group.wires.end(); wit++)
710       {
711         PRCWireEdge *wireEdge = new PRCWireEdge;
712         wireEdge->curve_3d = wit->curve;
713         PRCSingleWireBody *wireBody = new PRCSingleWireBody;
714         wireBody->setWireEdge(wireEdge);
715         const uint32_t wire_body_index = wireContext->addSingleWireBody(wireBody);
716         PRCWire *wire = new PRCWire();
717         wire->index_of_line_style = wit->style;
718         wire->context_id = context_index;
719         wire->body_id = wire_body_index;
720         if(wit->transform)
721             wire->index_local_coordinate_system = addTransform(wit->transform);
722         part_definition->addWire(wire);
723       }
724     }
725 
726     PRCfaceList &faces = group.faces;
727     if(!faces.empty())
728     {
729       bool same_color = true;
730       const uint32_t style = faces.front().style;
731       for(PRCfaceList::const_iterator fit=faces.begin(); fit!=faces.end(); fit++)
732         if(style!=fit->style)
733         {
734           same_color = false;
735           break;
736         }
737       PRCTopoContext *context = NULL;
738       const uint32_t context_index = getTopoContext(context);
739       context->granularity = group.options.granularity;
740    // Acrobat 9 also does the following:
741    // context->tolerance = group.options.granularity;
742    // context->have_smallest_face_thickness = true;
743    // context->smallest_thickness = group.options.granularity;
744       PRCShell *shell = new PRCShell;
745 
746       for(PRCfaceList::iterator fit=faces.begin(); fit!=faces.end(); fit++)
747       {
748         if(fit->transform || group.options.do_break ||
749            (fit->transparent && !group.options.no_break))
750         {
751           PRCShell *shell = new PRCShell;
752           shell->addFace(fit->face);
753           PRCConnex *connex = new PRCConnex;
754           connex->addShell(shell);
755           PRCBrepData *body = new PRCBrepData;
756           body->addConnex(connex);
757           const uint32_t body_index = context->addBrepData(body);
758 
759           PRCBrepModel *brepmodel = new PRCBrepModel();
760           brepmodel->index_of_line_style = fit->style;
761           brepmodel->context_id = context_index;
762           brepmodel->body_id = body_index;
763           brepmodel->is_closed = group.options.closed;
764 
765           brepmodel->index_local_coordinate_system = addTransform(fit->transform);
766 
767           part_definition->addBrepModel(brepmodel);
768         }
769         else
770         {
771           if(!same_color)
772             fit->face->index_of_line_style = fit->style;
773           shell->addFace(fit->face);
774         }
775       }
776       if(shell->face.empty())
777       {
778         delete shell;
779       }
780       else
781       {
782         PRCConnex *connex = new PRCConnex;
783         connex->addShell(shell);
784         PRCBrepData *body = new PRCBrepData;
785         body->addConnex(connex);
786         const uint32_t body_index = context->addBrepData(body);
787         PRCBrepModel *brepmodel = new PRCBrepModel();
788         if(same_color)
789           brepmodel->index_of_line_style = style;
790         brepmodel->context_id = context_index;
791         brepmodel->body_id = body_index;
792         brepmodel->is_closed = group.options.closed;
793         part_definition->addBrepModel(brepmodel);
794       }
795     }
796 
797     PRCcompfaceList &compfaces = group.compfaces;
798     if(!compfaces.empty())
799     {
800       bool same_color = true;
801       const uint32_t style = compfaces.front().style;
802       for(PRCcompfaceList::const_iterator fit=compfaces.begin(); fit!=compfaces.end(); fit++)
803         if(style!=fit->style)
804         {
805           same_color = false;
806           break;
807         }
808       PRCTopoContext *context = NULL;
809       const uint32_t context_index = getTopoContext(context);
810       PRCCompressedBrepData *body = new PRCCompressedBrepData;
811 
812       body->serial_tolerance=group.options.compression;
813       body->brep_data_compressed_tolerance=0.1*group.options.compression;
814 
815       for(PRCcompfaceList::const_iterator fit=compfaces.begin(); fit!=compfaces.end(); fit++)
816       {
817         if(group.options.do_break ||
818            (fit->transparent && !group.options.no_break))
819         {
820           PRCCompressedBrepData *body = new PRCCompressedBrepData;
821           body->face.push_back(fit->face);
822 
823           body->serial_tolerance=group.options.compression;
824           body->brep_data_compressed_tolerance=2.8346456*
825             group.options.compression;
826           const uint32_t body_index = context->addCompressedBrepData(body);
827 
828           PRCBrepModel *brepmodel = new PRCBrepModel();
829           brepmodel->index_of_line_style = fit->style;
830           brepmodel->context_id = context_index;
831           brepmodel->body_id = body_index;
832           brepmodel->is_closed = group.options.closed;
833 
834           part_definition->addBrepModel(brepmodel);
835         }
836         else
837         {
838           if(!same_color)
839             fit->face->index_of_line_style = fit->style;
840           body->face.push_back(fit->face);
841         }
842       }
843       if(body->face.empty())
844       {
845         delete body;
846       }
847       else
848       {
849         const uint32_t body_index = context->addCompressedBrepData(body);
850         PRCBrepModel *brepmodel = new PRCBrepModel();
851         if(same_color)
852           brepmodel->index_of_line_style = style;
853         brepmodel->context_id = context_index;
854         brepmodel->body_id = body_index;
855         brepmodel->is_closed = group.options.closed;
856         part_definition->addBrepModel(brepmodel);
857       }
858     }
859 
860     // Simplify and reduce to as simple entities as possible
861     // products with named representation items can not be reduced to sets, since
862     // outside references are already set
863     bool nonamedparts = true;
864     for(PRCRepresentationItemList::const_iterator it=part_definition->representation_item.begin(); it!=part_definition->representation_item.end(); it++)
865     {
866       if (!(*it)->name.empty())
867       {
868         nonamedparts = false;
869         break;
870       }
871     }
872     lastgroupname.clear();
873     lastgroupnames.clear();
874     // First option - reduce to one element in parent
875     if (parent_part_definition && product_occurrence->index_son_occurrence.empty() &&
876         part_definition->representation_item.size() == 1 &&
877         ( name.empty() || part_definition->representation_item.front()->name.empty() ) &&
878         ( !group.transform  || part_definition->representation_item.front()->index_local_coordinate_system==m1) )
879     {
880       if(part_definition->representation_item.front()->name.empty() )
881         part_definition->representation_item.front()->name = name;
882       if(part_definition->representation_item.front()->index_local_coordinate_system==m1)
883         part_definition->representation_item.front()->index_local_coordinate_system = addTransform(group.transform);
884       lastgroupname = calculate_unique_name(part_definition->representation_item.front(), parent_product_occurrence);
885       parent_part_definition->addRepresentationItem(part_definition->representation_item.front());
886       part_definition->representation_item.clear();
887       delete product_occurrence; product_occurrence = NULL;
888       delete part_definition; part_definition = NULL;
889     }
890     // Second option - reduce to a set
891     else if (parent_part_definition && product_occurrence->index_son_occurrence.empty() &&
892       !part_definition->representation_item.empty() &&
893       !group.options.do_break && nonamedparts)
894     {
895       PRCSet *set = new PRCSet(name);
896       set->index_local_coordinate_system = addTransform(group.transform);
897       lastgroupname = calculate_unique_name(set, parent_product_occurrence);
898       for(PRCRepresentationItemList::iterator it=part_definition->representation_item.begin(); it!=part_definition->representation_item.end(); it++)
899       {
900         lastgroupnames.push_back(calculate_unique_name(*it, parent_product_occurrence));
901         set->addRepresentationItem(*it);
902       }
903       part_definition->representation_item.clear();
904       parent_part_definition->addSet(set);
905       delete product_occurrence; product_occurrence = NULL;
906       delete part_definition; part_definition = NULL;
907     }
908     // Third option - create product
909     else if ( !product_occurrence->index_son_occurrence.empty() || !part_definition->representation_item.empty())
910     {
911       // if everything is enclosed in one group - drop the root group
912       if (parent_product_occurrence == NULL && group.transform == NULL &&
913           part_definition->representation_item.empty() && product_occurrence->index_son_occurrence.size()==1) {
914         delete part_definition; part_definition = NULL;
915         delete product_occurrence; product_occurrence = NULL;
916       }
917       else
918       {
919         lastgroupname = calculate_unique_name(product_occurrence, NULL);
920         if (part_definition->representation_item.empty()) {
921           delete part_definition; part_definition = NULL;
922         }
923         else
924         {
925           for(PRCRepresentationItemList::const_iterator it=part_definition->representation_item.begin(); it!=part_definition->representation_item.end(); it++)
926             if ((*it)->name.empty())
927               lastgroupnames.push_back(calculate_unique_name(*it, product_occurrence));
928           product_occurrence->index_part = addPartDefinition(part_definition);
929         }
930         if (group.transform) {
931           product_occurrence->location = group.transform;
932           group.transform = NULL;
933         }
934         if (parent_product_occurrence) {
935           parent_product_occurrence->index_son_occurrence.push_back(addProductOccurrence(product_occurrence));
936         }
937         else {
938           addProductOccurrence(product_occurrence);
939         }
940       }
941     }
942     // Last case - absolutely nothing to do
943     else
944     {
945       delete product_occurrence; product_occurrence = NULL;
946       delete part_definition; part_definition = NULL;
947     }
948 
949 }
950 
calculate_unique_name(const ContentPRCBase * prc_entity,const ContentPRCBase * prc_occurence)951 std::string oPRCFile::calculate_unique_name(const ContentPRCBase *prc_entity,const ContentPRCBase *prc_occurence)
952 {
953   std::stringstream ss (std::stringstream::in | std::stringstream::out);
954   uint8_t *serialization_buffer = NULL;
955   PRCbitStream serialization(serialization_buffer,0u);
956   const PRCFileStructure *pfile_structure = fileStructures[0];
957   const PRCUniqueId& uuid = pfile_structure->file_structure_uuid;
958 // ConvertUniqueIdentifierToString (prc_entity)
959 // SerializeCompressedUniqueId (file_structure)
960   serialization << uuid.id0 << uuid.id1 << uuid.id2 << uuid.id3;
961 // WriteUnsignedInteger (type)
962   serialization << prc_entity->getType();
963 // WriteUnsignedInteger (unique_identifier)
964   serialization << prc_entity->getPRCID();
965   if (prc_occurence)
966   {
967 // serialization_buffer = Flush serialization (serialization)
968   {
969     const uint32_t size_serialization = serialization.getSize();
970     while(size_serialization == serialization.getSize())
971       serialization << false;
972   }
973 // ConvertUniqueIdentifierToString (prc_occurrence_unique_id)
974 // SerializeCompressedUniqueId (file_structure)
975     serialization << uuid.id0 << uuid.id1 << uuid.id2 << uuid.id3;
976 // WriteUnsignedInteger (type)
977     serialization << (uint32_t)PRC_TYPE_ASM_ProductOccurence;
978 // WriteUnsignedInteger (unique_identifier)
979     serialization << prc_occurence->getPRCID();
980   }
981   ss << (prc_entity->name.empty()?"node":prc_entity->name.c_str()) << '.';
982   const uint32_t size_serialization = serialization.getSize();
983   for(size_t j=0; j<size_serialization; j++)
984     ss << hex << setfill('0') << setw(2) << (uint32_t)(serialization_buffer[j]);
985   free(serialization_buffer);
986 
987   return ss.str();
988 }
989 
finish()990 bool oPRCFile::finish()
991 {
992   if(groups.size()!=1) {
993     fputs("begingroup without matching endgroup",stderr);
994     exit(1);
995   }
996   doGroup(groups.top());
997 
998   // write each section's bit data
999   fileStructures[0]->prepare();
1000   SerializeModelFileData
1001 
1002   // create the header
1003 
1004   // fill out enough info so that sizes can be computed correctly
1005   header.number_of_file_structures = number_of_file_structures;
1006   header.fileStructureInformation = new PRCFileStructureInformation[number_of_file_structures];
1007   for(uint32_t i = 0; i < number_of_file_structures; ++i)
1008   {
1009     header.fileStructureInformation[i].UUID = fileStructures[i]->file_structure_uuid;
1010     header.fileStructureInformation[i].reserved = 0;
1011     header.fileStructureInformation[i].number_of_offsets = 6;
1012     header.fileStructureInformation[i].offsets = new uint32_t[6];
1013   }
1014 
1015   header.minimal_version_for_read = PRCVersion;
1016   header.authoring_version = PRCVersion;
1017   makeFileUUID(header.file_structure_uuid);
1018   makeAppUUID(header.application_uuid);
1019 
1020   header.file_size = getSize();
1021   header.model_file_offset = header.file_size - modelFile_out.getSize();
1022 
1023   uint32_t currentOffset = header.getSize();
1024 
1025   for(uint32_t i = 0; i < number_of_file_structures; ++i)
1026   {
1027     for(size_t j=0; j<6; j++)
1028     {
1029       header.fileStructureInformation[i].offsets[j] = currentOffset;
1030       currentOffset += fileStructures[i]->sizes[j];
1031     }
1032   }
1033 
1034   // write the data
1035   header.write(output);
1036 
1037   for(uint32_t i = 0; i < number_of_file_structures; ++i)
1038   {
1039     fileStructures[i]->write(output);
1040   }
1041 
1042   modelFile_out.write(output);
1043   output.flush();
1044 
1045   for(uint32_t i = 0; i < number_of_file_structures; ++i)
1046     delete[] header.fileStructureInformation[i].offsets;
1047   delete[] header.fileStructureInformation;
1048 
1049   return true;
1050 }
1051 
getSize()1052 uint32_t oPRCFile::getSize()
1053 {
1054   uint32_t size = header.getSize();
1055 
1056   for(uint32_t i = 0; i < number_of_file_structures; ++i)
1057   {
1058     size += fileStructures[i]->getSize();
1059   }
1060 
1061   size += modelFile_out.getSize();
1062   return size;
1063 }
1064 
addPicture(EPRCPictureDataFormat format,uint32_t size,const uint8_t * p,uint32_t width,uint32_t height,string name)1065 uint32_t PRCFileStructure::addPicture(EPRCPictureDataFormat format, uint32_t size, const uint8_t *p, uint32_t width, uint32_t height, string name)
1066 {
1067   uint8_t *data = NULL;
1068   if(size==0 || p==NULL)
1069   { cerr << "image not set" << endl; return m1; }
1070   if(format==KEPRCPicture_PNG || format==KEPRCPicture_JPG)
1071   {
1072     width = 0; // width and height are ignored for JPG and PNG pictures - but let us keep things clean
1073     height = 0;
1074     data = new uint8_t[size];
1075     memcpy(data, p, size);
1076   }
1077   else
1078   {
1079     uint32_t components=0;
1080     switch(format)
1081     {
1082       case KEPRCPicture_BITMAP_RGB_BYTE:
1083         components = 3; break;
1084       case KEPRCPicture_BITMAP_RGBA_BYTE:
1085         components = 4; break;
1086       case KEPRCPicture_BITMAP_GREY_BYTE:
1087         components = 1; break;
1088       case KEPRCPicture_BITMAP_GREYA_BYTE:
1089         components = 2; break;
1090       default:
1091       { cerr << "unknown picture format" << endl; return m1; }
1092     }
1093     if(width==0 || height==0)
1094     { cerr << "width or height parameter not set" << endl; return m1; }
1095     if (size < width*height*components)
1096     { cerr << "image too small" << endl; return m1; }
1097     {
1098       uint32_t compressedDataSize = 0;
1099       const int CHUNK= 1024; // is this reasonable?
1100 
1101       z_stream strm;
1102       strm.zalloc = Z_NULL;
1103       strm.zfree = Z_NULL;
1104       strm.opaque = Z_NULL;
1105       if(deflateInit(&strm,Z_DEFAULT_COMPRESSION) != Z_OK)
1106       { cerr << "Compression initialization failed" << endl; return m1; }
1107       unsigned int sizeAvailable = deflateBound(&strm,size);
1108       uint8_t *compressedData = (uint8_t*) malloc(sizeAvailable);
1109       strm.avail_in = size;
1110       strm.next_in = (unsigned char*)p;
1111       strm.next_out = (unsigned char*)compressedData;
1112       strm.avail_out = sizeAvailable;
1113 
1114       int code;
1115       unsigned int chunks = 0;
1116       while((code = deflate(&strm,Z_FINISH)) == Z_OK)
1117       {
1118         ++chunks;
1119         // strm.avail_out should be 0 if we got Z_OK
1120         compressedDataSize = sizeAvailable - strm.avail_out;
1121         compressedData = (uint8_t*) realloc(compressedData,CHUNK*chunks);
1122         strm.next_out = (Bytef*)(compressedData + compressedDataSize);
1123         strm.avail_out += CHUNK;
1124         sizeAvailable += CHUNK;
1125       }
1126       compressedDataSize = sizeAvailable-strm.avail_out;
1127 
1128       if(code != Z_STREAM_END)
1129       {
1130         deflateEnd(&strm);
1131         free(compressedData);
1132         { cerr << "Compression error" << endl; return m1; }
1133       }
1134 
1135       deflateEnd(&strm);
1136       size = compressedDataSize;
1137       data = new uint8_t[compressedDataSize];
1138       memcpy(data, compressedData, compressedDataSize);
1139       free(compressedData);
1140     }
1141   }
1142 
1143   uint32_t uncompressed_file_index = m1;
1144   {
1145     PRCUncompressedFile* uncompressed_file = new PRCUncompressedFile(size, data);
1146     uncompressed_file_index = addUncompressedFileUnique(uncompressed_file);
1147     delete[] data;
1148   }
1149   uint32_t picture_index = m1;
1150   {
1151     PRCPicture* picture = new PRCPicture(name);
1152     picture->format = format;
1153     picture->uncompressed_file_index = uncompressed_file_index;
1154     picture->pixel_width = width;
1155     picture->pixel_height = height;
1156     picture_index = addPictureUnique(picture);
1157   }
1158   return picture_index;
1159 }
1160 
addColour(const RGBAColour & colour)1161 uint32_t oPRCFile::addColour(const RGBAColour &colour)
1162 {
1163   PRCcolourMap::const_iterator pColour = colourMap.find(colour);
1164   if(pColour!=colourMap.end())
1165     return pColour->second;
1166   const uint32_t color_index = addRgbColorUnique(colour.R, colour.G, colour.B);
1167   PRCStyle *style = new PRCStyle();
1168   style->line_width = 1.0;
1169   style->is_vpicture = false;
1170   style->line_pattern_vpicture_index = 0;
1171   style->is_material = false;
1172   style->color_material_index = color_index;
1173   style->is_transparency_defined = (colour.A < 1.0);
1174   style->transparency = (uint8_t)(colour.A * 256);
1175   style->additional = 0;
1176   const uint32_t style_index = addStyle(style);
1177   colourMap.insert(make_pair(colour,style_index));
1178   return style_index;
1179 }
1180 
addColourWidth(const RGBAColour & colour,double width)1181 uint32_t oPRCFile::addColourWidth(const RGBAColour &colour, double width)
1182 {
1183   const RGBAColourWidth colourwidth(colour.R, colour.G, colour.B, colour.A, width);
1184   PRCcolourwidthMap::const_iterator pColour = colourwidthMap.find(colourwidth);
1185   if(pColour!=colourwidthMap.end())
1186     return pColour->second;
1187   const uint32_t color_index = addRgbColorUnique(colour.R, colour.G, colour.B);
1188   PRCStyle *style = new PRCStyle();
1189   style->line_width = width;
1190   style->is_vpicture = false;
1191   style->line_pattern_vpicture_index = 0;
1192   style->is_material = false;
1193   style->color_material_index = color_index;
1194   style->is_transparency_defined = (colour.A < 1.0);
1195   style->transparency = (uint8_t)(colour.A * 256);
1196   style->additional = 0;
1197   const uint32_t style_index = addStyle(style);
1198   colourwidthMap.insert(make_pair(colourwidth,style_index));
1199   return style_index;
1200 }
1201 
addTransform(PRCGeneralTransformation3d * & transform)1202 uint32_t oPRCFile::addTransform(PRCGeneralTransformation3d*& transform)
1203 {
1204   if(!transform)
1205     return m1;
1206   PRCtransformMap::const_iterator pTransform = transformMap.find(*transform);
1207   if(pTransform!=transformMap.end())
1208     return pTransform->second;
1209   PRCCoordinateSystem *coordinateSystem = new PRCCoordinateSystem();
1210   bool transform_replaced = false;
1211   if(                            transform->M(0,1)==0 && transform->M(0,2)==0 &&
1212       transform->M(1,0)==0 &&                            transform->M(1,2)==0 &&
1213       transform->M(2,0)==0 && transform->M(2,1)==0 &&
1214       transform->M(3,0)==0 && transform->M(3,1)==0 && transform->M(3,2)==0 && transform->M(3,3)==1 )
1215   {
1216     transform_replaced = true;
1217     PRCCartesianTransformation3d *carttransform = new PRCCartesianTransformation3d;
1218 //  if(transform->M(0,3)==0 && transform->M(1,3)==0 && transform->M(1,3)==0 &&
1219 //     transform->M(0,0)==1 && transform->M(1,1)==1 && transform->M(2,2)==1 )
1220 //    carttransform->behaviour = PRC_TRANSFORMATION_Identity;
1221     if(transform->M(0,3)!=0 || transform->M(1,3)!=0 || transform->M(2,3)!=0)
1222     {
1223       carttransform->behaviour |= PRC_TRANSFORMATION_Translate;
1224       carttransform->origin.Set(transform->M(0,3),transform->M(1,3),transform->M(2,3));
1225     }
1226     if(transform->M(0,0)!=transform->M(1,1) || transform->M(0,0)!=transform->M(2,2))
1227     {
1228       carttransform->behaviour |= PRC_TRANSFORMATION_NonUniformScale;
1229       carttransform->scale.Set(transform->M(0,0),transform->M(1,1),transform->M(2,2));
1230     }
1231     else
1232       if(transform->M(0,0)!=1)
1233       {
1234         carttransform->behaviour |= PRC_TRANSFORMATION_Scale;
1235         carttransform->uniform_scale=transform->M(0,0);
1236       }
1237     coordinateSystem->axis_set = carttransform;
1238   }
1239   else
1240     coordinateSystem->axis_set = transform;
1241 
1242   const uint32_t coordinate_system_index = fileStructures[0]->addCoordinateSystem(coordinateSystem);
1243   transformMap.insert(make_pair(*transform,coordinate_system_index));
1244   if(transform_replaced)
1245     delete transform;
1246   transform = NULL;
1247   return coordinate_system_index;
1248 }
1249 
addTransform(const double * t)1250 uint32_t oPRCFile::addTransform(const double* t)
1251 {
1252   if(!t)
1253     return m1;
1254   PRCGeneralTransformation3d* transform = new PRCGeneralTransformation3d(t);
1255   return addTransform(transform);
1256 }
1257 
addTransform(const double origin[3],const double x_axis[3],const double y_axis[3],double scale)1258 uint32_t oPRCFile::addTransform(const double origin[3], const double x_axis[3], const double y_axis[3], double scale)
1259 {
1260   PRCCartesianTransformation3d* transform = new PRCCartesianTransformation3d(origin, x_axis, y_axis, scale);
1261   if(transform->behaviour==PRC_TRANSFORMATION_Identity)
1262   { delete transform;  return m1; }
1263   PRCCoordinateSystem *coordinateSystem = new PRCCoordinateSystem();
1264   coordinateSystem->axis_set = transform;
1265   const uint32_t coordinate_system_index = fileStructures[0]->addCoordinateSystem(coordinateSystem);
1266   return coordinate_system_index;
1267 }
1268 
addMaterial(const PRCmaterial & m)1269 uint32_t oPRCFile::addMaterial(const PRCmaterial& m)
1270 {
1271   PRCmaterialMap::const_iterator pMaterial = materialMap.find(m);
1272   if(pMaterial!=materialMap.end())
1273     return pMaterial->second;
1274 
1275   uint32_t material_index = m1;
1276   {
1277     PRCMaterialGeneric *materialGeneric = new PRCMaterialGeneric;
1278     materialGeneric->ambient  = addRgbColorUnique(m.ambient.R,  m.ambient.G,  m.ambient.B);
1279     materialGeneric->diffuse  = addRgbColorUnique(m.diffuse.R,  m.diffuse.G,  m.diffuse.B);
1280     materialGeneric->emissive = addRgbColorUnique(m.emissive.R, m.emissive.G, m.emissive.B);
1281     materialGeneric->specular = addRgbColorUnique(m.specular.R, m.specular.G, m.specular.B);
1282     materialGeneric->shininess = m.shininess;
1283     materialGeneric->ambient_alpha  = m.ambient.A;
1284     materialGeneric->diffuse_alpha  = m.diffuse.A;
1285     materialGeneric->emissive_alpha = m.emissive.A;
1286     materialGeneric->specular_alpha = m.specular.A;
1287     material_index = addMaterialGenericUnique(materialGeneric);
1288   }
1289 
1290   uint32_t style_index = m1;
1291   {
1292     PRCStyle *style = new PRCStyle;
1293     style->line_width = m.width;
1294     style->is_vpicture = false;
1295     style->line_pattern_vpicture_index = 0;
1296     style->is_material = true;
1297     style->is_transparency_defined = (m.alpha < 1.0);
1298     style->transparency = (uint8_t)(m.alpha * 256);
1299     style->additional = 0;
1300     style->color_material_index = material_index;
1301     style_index = addStyleUnique(style);
1302   }
1303   materialMap.insert(make_pair(m,style_index));
1304   return style_index;
1305 }
1306 
addTexturedMaterial(const PRCmaterial & m,uint32_t n,const PRCtexture * const tt[])1307 uint32_t oPRCFile::addTexturedMaterial(const PRCmaterial& m, uint32_t n, const PRCtexture* const tt[])
1308 {
1309   uint32_t material_generic_index = m1;
1310   {
1311     PRCMaterialGeneric *materialGeneric = new PRCMaterialGeneric;
1312     materialGeneric->ambient  = addRgbColorUnique(m.ambient.R,  m.ambient.G,  m.ambient.B);
1313     materialGeneric->diffuse  = addRgbColorUnique(m.diffuse.R,  m.diffuse.G,  m.diffuse.B);
1314     materialGeneric->emissive = addRgbColorUnique(m.emissive.R, m.emissive.G, m.emissive.B);
1315     materialGeneric->specular = addRgbColorUnique(m.specular.R, m.specular.G, m.specular.B);
1316     materialGeneric->shininess = m.shininess;
1317     materialGeneric->ambient_alpha  = m.ambient.A;
1318     materialGeneric->diffuse_alpha  = m.diffuse.A;
1319     materialGeneric->emissive_alpha = m.emissive.A;
1320     materialGeneric->specular_alpha = m.specular.A;
1321     material_generic_index = addMaterialGenericUnique(materialGeneric);
1322   }
1323 
1324   uint32_t color_material_index = material_generic_index;
1325 
1326   uint32_t texture_application_index = m1;
1327   for (uint32_t i=n; i>0; i--) {
1328     const PRCtexture* t = tt[i-1];
1329     if (t == NULL) {
1330       continue;
1331     }
1332     const uint32_t picture_index = addPicture(t->format, t->size, t->data, t->height, t->width);
1333 
1334     uint32_t texture_definition_index = m1;
1335     {
1336       PRCTextureDefinition *textureDefinition = new PRCTextureDefinition;
1337       textureDefinition->picture_index = picture_index;
1338       textureDefinition->texture_mapping_attribute = t->mapping;
1339       textureDefinition->texture_mapping_attribute_components = t->components;
1340       textureDefinition->texture_function = t->function;
1341       textureDefinition->texture_wrapping_mode_S = t->wrapping_mode_S;
1342       textureDefinition->texture_wrapping_mode_T = t->wrapping_mode_T;
1343       texture_definition_index = addTextureDefinitionUnique(textureDefinition);
1344     }
1345     {
1346       PRCTextureApplication *textureApplication = new PRCTextureApplication;
1347       textureApplication->material_generic_index=material_generic_index;
1348       textureApplication->texture_definition_index=texture_definition_index;
1349       textureApplication->next_texture_index = texture_application_index;
1350       texture_application_index = addTextureApplicationUnique(textureApplication);
1351     }
1352     color_material_index = texture_application_index;
1353   }
1354 
1355   uint32_t style_index = m1;
1356   {
1357     PRCStyle *style = new PRCStyle;
1358     style->line_width = 0.0;
1359     style->is_vpicture = false;
1360     style->line_pattern_vpicture_index = 0;
1361     style->is_material = true;
1362     style->is_transparency_defined = (m.alpha < 1.0);
1363     style->transparency = (uint8_t)(m.alpha * 256);
1364     style->additional = 0;
1365     style->color_material_index = color_material_index;
1366     style_index = addStyleUnique(style);
1367   }
1368   return style_index;
1369 }
1370 
isid(const double * t)1371 bool isid(const double* t)
1372 {
1373   return(
1374          t[0]==1 && t[4]==0 && t[ 8]==0 && t[12]==0 &&
1375          t[1]==0 && t[5]==1 && t[ 9]==0 && t[13]==0 &&
1376          t[2]==0 && t[6]==0 && t[10]==1 && t[14]==0 &&
1377          t[3]==0 && t[7]==0 && t[11]==0 && t[15]==1 );
1378 }
1379 
1380 
begingroup(const char * name,const PRCoptions * options,const double * t)1381 void oPRCFile::begingroup(const char *name, const PRCoptions *options,
1382                           const double* t)
1383 {
1384   const PRCgroup &parent_group = groups.top();
1385   groups.push(PRCgroup());
1386   PRCgroup &group = groups.top();
1387   group.name=name;
1388   if(options) group.options=*options;
1389   if(t&&!isid(t))
1390     group.transform = new PRCGeneralTransformation3d(t);
1391   group.product_occurrence = new PRCProductOccurrence(name);
1392   group.parent_product_occurrence = parent_group.product_occurrence;
1393   group.part_definition = new PRCPartDefinition;
1394   group.parent_part_definition = parent_group.part_definition;
1395 }
1396 
endgroup()1397 void oPRCFile::endgroup()
1398 {
1399   if(groups.size()<2) {
1400     fputs("begingroup without matching endgroup",stderr);
1401     exit(1);
1402   }
1403 
1404   doGroup(groups.top());
1405   groups.pop();
1406 
1407 // std::cout << lastgroupname << std::endl;
1408 // for(std::vector<std::string>::const_iterator it=lastgroupnames.begin(); it!=lastgroupnames.end(); it++)
1409 //   std::cout << " " << *it << std::endl;
1410 
1411 }
1412 
findGroup()1413 PRCgroup& oPRCFile::findGroup()
1414 {
1415   return groups.top();
1416 }
1417 
1418 #define ADDWIRE(curvtype)                                 \
1419   PRCgroup &group = findGroup();                          \
1420   group.wires.push_back(PRCwire());                       \
1421   PRCwire &wire = group.wires.back();                     \
1422   curvtype *curve = new curvtype;                         \
1423   wire.curve = curve;                                     \
1424   wire.style = addColour(c);
1425 
1426 #define ADDFACE(surftype)                                 \
1427   PRCgroup &group = findGroup();                          \
1428   group.faces.push_back(PRCface());                       \
1429   PRCface& face = group.faces.back();                     \
1430   surftype *surface = new surftype;                       \
1431   face.face = new PRCFace;                                \
1432   face.face->base_surface = surface;                      \
1433   face.transparent = m.alpha < 1.0;                       \
1434   face.style = addMaterial(m);
1435 
1436 #define ADDCOMPFACE                                       \
1437   PRCgroup &group = findGroup();                          \
1438   group.compfaces.push_back(PRCcompface());               \
1439   PRCcompface& face = group.compfaces.back();             \
1440   PRCCompressedFace *compface = new PRCCompressedFace;    \
1441   face.face = compface;                                   \
1442   face.transparent = m.alpha < 1.0;                       \
1443   face.style = addMaterial(m);
1444 
addPoint(const double P[3],const RGBAColour & c,double w)1445 void oPRCFile::addPoint(const double P[3], const RGBAColour &c, double w)
1446 {
1447   PRCgroup &group = findGroup();
1448   group.points[addColourWidth(c,w)].push_back(PRCVector3d(P[0],P[1],P[2]));
1449 }
1450 
addPoint(double x,double y,double z,const RGBAColour & c,double w)1451 void oPRCFile::addPoint(double x, double y, double z, const RGBAColour &c, double w)
1452 {
1453   PRCgroup &group = findGroup();
1454   group.points[addColourWidth(c,w)].push_back(PRCVector3d(x,y,z));
1455 }
1456 
1457 
addPoints(uint32_t n,const double P[][3],const RGBAColour & c,double w)1458 void oPRCFile::addPoints(uint32_t n, const double P[][3], const RGBAColour &c, double w)
1459 {
1460   if(n==0 || P==NULL)
1461      return;
1462   PRCgroup &group = findGroup();
1463   PRCPointSet *pointset = new PRCPointSet();
1464   group.pointsets.push_back(pointset);
1465   pointset->index_of_line_style = addColourWidth(c,w);
1466   pointset->point.reserve(n);
1467   for(uint32_t i=0; i<n; i++)
1468     pointset->point.push_back(PRCVector3d(P[i][0],P[i][1],P[i][2]));
1469 }
1470 
addPoints(uint32_t n,const double P[][3],uint32_t style_index)1471 void oPRCFile::addPoints(uint32_t n, const double P[][3], uint32_t style_index)
1472 {
1473   if(n==0 || P==NULL)
1474     return;
1475   PRCgroup &group = findGroup();
1476   PRCPointSet *pointset = new PRCPointSet();
1477   group.pointsets.push_back(pointset);
1478   pointset->index_of_line_style = style_index;
1479   pointset->point.reserve(n);
1480   for(uint32_t i=0; i<n; i++)
1481     pointset->point.push_back(PRCVector3d(P[i][0],P[i][1],P[i][2]));
1482 }
1483 
useMesh(uint32_t tess_index,uint32_t style_index,const double origin[3],const double x_axis[3],const double y_axis[3],double scale)1484 void oPRCFile::useMesh(uint32_t tess_index, uint32_t style_index, const double origin[3], const double x_axis[3], const double y_axis[3], double scale)
1485 {
1486   PRCgroup &group = findGroup();
1487   PRCPolyBrepModel *polyBrepModel = new PRCPolyBrepModel();
1488   polyBrepModel->index_local_coordinate_system = addTransform(origin, x_axis, y_axis, scale);
1489   polyBrepModel->index_tessellation = tess_index;
1490   polyBrepModel->is_closed = group.options.closed;
1491   polyBrepModel->index_of_line_style = style_index;
1492   group.polymodels.push_back(polyBrepModel);
1493 }
1494 
useMesh(uint32_t tess_index,uint32_t style_index,const double * t)1495 void oPRCFile::useMesh(uint32_t tess_index, uint32_t style_index, const double* t)
1496 {
1497   PRCgroup &group = findGroup();
1498   PRCPolyBrepModel *polyBrepModel = new PRCPolyBrepModel();
1499   polyBrepModel->index_local_coordinate_system = addTransform(t);
1500   polyBrepModel->index_tessellation = tess_index;
1501   polyBrepModel->is_closed = group.options.closed;
1502   polyBrepModel->index_of_line_style = style_index;
1503   group.polymodels.push_back(polyBrepModel);
1504 }
1505 
useLines(uint32_t tess_index,uint32_t style_index,const double origin[3],const double x_axis[3],const double y_axis[3],double scale)1506 void oPRCFile::useLines(uint32_t tess_index, uint32_t style_index, const double origin[3], const double x_axis[3], const double y_axis[3], double scale)
1507 {
1508   PRCgroup &group = findGroup();
1509   PRCPolyWire *polyWire = new PRCPolyWire();
1510   polyWire->index_local_coordinate_system = addTransform(origin, x_axis, y_axis, scale);
1511   polyWire->index_tessellation = tess_index;
1512   polyWire->index_of_line_style = style_index;
1513   group.polywires.push_back(polyWire);
1514 }
1515 
useLines(uint32_t tess_index,uint32_t style_index,const double * t)1516 void oPRCFile::useLines(uint32_t tess_index, uint32_t style_index, const double* t)
1517 {
1518   PRCgroup &group = findGroup();
1519   PRCPolyWire *polyWire = new PRCPolyWire();
1520   polyWire->index_local_coordinate_system = addTransform(t);
1521   polyWire->index_tessellation = tess_index;
1522   polyWire->index_of_line_style = style_index;
1523   group.polywires.push_back(polyWire);
1524 }
1525 
addTriangles(uint32_t nP,const double P[][3],uint32_t nI,const uint32_t PI[][3],const PRCmaterial & m,uint32_t nN,const double N[][3],const uint32_t NI[][3],uint32_t nT,const double T[][2],const uint32_t TI[][3],uint32_t nC,const RGBAColour C[],const uint32_t CI[][3],uint32_t nM,const PRCmaterial M[],const uint32_t MI[],double ca)1526 void oPRCFile::addTriangles(uint32_t nP, const double P[][3], uint32_t nI, const uint32_t PI[][3], const PRCmaterial& m,
1527  uint32_t nN, const double N[][3],   const uint32_t NI[][3],
1528  uint32_t nT, const double T[][2],   const uint32_t TI[][3],
1529  uint32_t nC, const RGBAColour C[],  const uint32_t CI[][3],
1530  uint32_t nM, const PRCmaterial M[], const uint32_t MI[], double ca)
1531 {
1532   if(nP==0 || P==NULL || nI==0 || PI==NULL)
1533      return;
1534   const uint32_t tess_index = createTriangleMesh(nP, P, nI, PI, m, nN, N, NI, nT, T, TI, nC, C, CI, nM, M, MI, ca);
1535   useMesh(tess_index,m1);
1536 }
1537 
createTriangleMesh(uint32_t nP,const double P[][3],uint32_t nI,const uint32_t PI[][3],const uint32_t style_index,uint32_t nN,const double N[][3],const uint32_t NI[][3],uint32_t nT,const double T[][2],const uint32_t TI[][3],uint32_t nC,const RGBAColour C[],const uint32_t CI[][3],uint32_t nS,const uint32_t S[],const uint32_t SI[],double ca)1538 uint32_t oPRCFile::createTriangleMesh(uint32_t nP, const double P[][3], uint32_t nI, const uint32_t PI[][3], const uint32_t style_index,
1539  uint32_t nN, const double N[][3],  const uint32_t NI[][3],
1540  uint32_t nT, const double T[][2],  const uint32_t TI[][3],
1541  uint32_t nC, const RGBAColour C[], const uint32_t CI[][3],
1542  uint32_t nS, const uint32_t S[],   const uint32_t SI[], double ca)
1543 {
1544   if(nP==0 || P==NULL || nI==0 || PI==NULL)
1545      return m1;
1546 
1547   const bool triangle_color = (nS != 0 && S != NULL && SI != NULL);
1548   const bool vertex_color   = (nC != 0 && C != NULL && CI != NULL);
1549   const bool has_normals    = (nN != 0 && N != NULL && NI != NULL);
1550   const bool textured       = (nT != 0 && T != NULL && TI != NULL);
1551 
1552   PRC3DTess *tess = new PRC3DTess();
1553   PRCTessFace *tessFace = new PRCTessFace();
1554   tessFace->used_entities_flag = textured ? PRC_FACETESSDATA_TriangleTextured : PRC_FACETESSDATA_Triangle;
1555   tessFace->number_of_texture_coordinate_indexes = textured ? 1 : 0;
1556   tess->coordinates.reserve(3*nP);
1557   for(uint32_t i=0; i<nP; i++)
1558   {
1559     tess->coordinates.push_back(P[i][0]);
1560     tess->coordinates.push_back(P[i][1]);
1561     tess->coordinates.push_back(P[i][2]);
1562   }
1563   if(has_normals)
1564   {
1565     tess->normal_coordinate.reserve(3*nN);
1566   for(uint32_t i=0; i<nN; i++)
1567   {
1568     tess->normal_coordinate.push_back(N[i][0]);
1569     tess->normal_coordinate.push_back(N[i][1]);
1570     tess->normal_coordinate.push_back(N[i][2]);
1571   }
1572   }
1573   else
1574     tess->crease_angle = ca;
1575   if(textured)
1576   {
1577     tess->texture_coordinate.reserve(2*nT);
1578   for(uint32_t i=0; i<nT; i++)
1579   {
1580     tess->texture_coordinate.push_back(T[i][0]);
1581     tess->texture_coordinate.push_back(T[i][1]);
1582   }
1583   }
1584   tess->triangulated_index.reserve(3*nI+(has_normals?3:0)*nI+(textured?3:0)*nI);
1585   for(uint32_t i=0; i<nI; i++)
1586   {
1587     if(has_normals)
1588     tess->triangulated_index.push_back(3*NI[i][0]);
1589     if(textured)
1590     tess->triangulated_index.push_back(2*TI[i][0]);
1591     tess->triangulated_index.push_back(3*PI[i][0]);
1592     if(has_normals)
1593     tess->triangulated_index.push_back(3*NI[i][1]);
1594     if(textured)
1595     tess->triangulated_index.push_back(2*TI[i][1]);
1596     tess->triangulated_index.push_back(3*PI[i][1]);
1597     if(has_normals)
1598     tess->triangulated_index.push_back(3*NI[i][2]);
1599     if(textured)
1600     tess->triangulated_index.push_back(2*TI[i][2]);
1601     tess->triangulated_index.push_back(3*PI[i][2]);
1602   }
1603   tessFace->sizes_triangulated.push_back(nI);
1604   if(triangle_color)
1605   {
1606     tessFace->line_attributes.reserve(nI);
1607     for(uint32_t i=0; i<nI; i++)
1608        tessFace->line_attributes.push_back(SI[i]);
1609   }
1610   else if (style_index != m1 )
1611   {
1612       tessFace->line_attributes.push_back(style_index);
1613   }
1614   if(vertex_color)
1615   {
1616     tessFace->is_rgba=false;
1617     for(uint32_t i=0; i<nI; i++)
1618       if(1.0 != C[CI[i][0]].A || 1.0 != C[CI[i][1]].A || 1.0 != C[CI[i][2]].A)
1619       {
1620          tessFace->is_rgba=true;
1621          break;
1622       }
1623 
1624     tessFace->rgba_vertices.reserve((tessFace->is_rgba?4:3)*3*nI);
1625     for(uint32_t i=0; i<nI; i++)
1626     {
1627        tessFace->rgba_vertices.push_back(toByte(C[CI[i][0]].R));
1628        tessFace->rgba_vertices.push_back(toByte(C[CI[i][0]].G));
1629        tessFace->rgba_vertices.push_back(toByte(C[CI[i][0]].B));
1630        if(tessFace->is_rgba)
1631        tessFace->rgba_vertices.push_back(toByte(C[CI[i][0]].A));
1632        tessFace->rgba_vertices.push_back(toByte(C[CI[i][1]].R));
1633        tessFace->rgba_vertices.push_back(toByte(C[CI[i][1]].G));
1634        tessFace->rgba_vertices.push_back(toByte(C[CI[i][1]].B));
1635        if(tessFace->is_rgba)
1636        tessFace->rgba_vertices.push_back(toByte(C[CI[i][1]].A));
1637        tessFace->rgba_vertices.push_back(toByte(C[CI[i][2]].R));
1638        tessFace->rgba_vertices.push_back(toByte(C[CI[i][2]].G));
1639        tessFace->rgba_vertices.push_back(toByte(C[CI[i][2]].B));
1640        if(tessFace->is_rgba)
1641        tessFace->rgba_vertices.push_back(toByte(C[CI[i][2]].A));
1642     }
1643   }
1644   tess->addTessFace(tessFace);
1645   const uint32_t tess_index = add3DTess(tess);
1646   return tess_index;
1647 }
1648 
addQuads(uint32_t nP,const double P[][3],uint32_t nI,const uint32_t PI[][4],const PRCmaterial & m,uint32_t nN,const double N[][3],const uint32_t NI[][4],uint32_t nT,const double T[][2],const uint32_t TI[][4],uint32_t nC,const RGBAColour C[],const uint32_t CI[][4],uint32_t nM,const PRCmaterial M[],const uint32_t MI[],double ca)1649 void oPRCFile::addQuads(uint32_t nP, const double P[][3], uint32_t nI, const uint32_t PI[][4], const PRCmaterial& m,
1650  uint32_t nN, const double N[][3],   const uint32_t NI[][4],
1651  uint32_t nT, const double T[][2],   const uint32_t TI[][4],
1652  uint32_t nC, const RGBAColour C[],  const uint32_t CI[][4],
1653  uint32_t nM, const PRCmaterial M[], const uint32_t MI[], double ca)
1654 {
1655   if(nP==0 || P==NULL || nI==0 || PI==NULL)
1656      return;
1657   const uint32_t tess_index = createQuadMesh(nP, P, nI, PI, m, nN, N, NI, nT, T, TI, nC, C, CI, nM, M, MI, ca);
1658   useMesh(tess_index,m1);
1659 }
1660 
createQuadMesh(uint32_t nP,const double P[][3],uint32_t nI,const uint32_t PI[][4],uint32_t style_index,uint32_t nN,const double N[][3],const uint32_t NI[][4],uint32_t nT,const double T[][2],const uint32_t TI[][4],uint32_t nC,const RGBAColour C[],const uint32_t CI[][4],uint32_t nS,const uint32_t S[],const uint32_t SI[],double ca)1661 uint32_t oPRCFile::createQuadMesh(uint32_t nP, const double P[][3], uint32_t nI, const uint32_t PI[][4], uint32_t style_index,
1662  uint32_t nN, const double N[][3],   const uint32_t NI[][4],
1663  uint32_t nT, const double T[][2],   const uint32_t TI[][4],
1664  uint32_t nC, const RGBAColour C[],  const uint32_t CI[][4],
1665  uint32_t nS, const uint32_t S[],    const uint32_t SI[], double ca)
1666 {
1667   if(nP==0 || P==NULL || nI==0 || PI==NULL)
1668      return m1;
1669 
1670   const bool triangle_color = (nS != 0 && S != NULL && SI != NULL);
1671   const bool vertex_color   = (nC != 0 && C != NULL && CI != NULL);
1672   const bool has_normals    = (nN != 0 && N != NULL && NI != NULL);
1673   const bool textured       = (nT != 0 && T != NULL && TI != NULL);
1674 
1675   PRC3DTess *tess = new PRC3DTess();
1676   PRCTessFace *tessFace = new PRCTessFace();
1677   tessFace->used_entities_flag = textured ? PRC_FACETESSDATA_TriangleTextured : PRC_FACETESSDATA_Triangle;
1678   tessFace->number_of_texture_coordinate_indexes = textured ? 1 : 0;
1679   tess->coordinates.reserve(3*nP);
1680   for(uint32_t i=0; i<nP; i++)
1681   {
1682     tess->coordinates.push_back(P[i][0]);
1683     tess->coordinates.push_back(P[i][1]);
1684     tess->coordinates.push_back(P[i][2]);
1685   }
1686   if(has_normals)
1687   {
1688     tess->normal_coordinate.reserve(3*nN);
1689   for(uint32_t i=0; i<nN; i++)
1690   {
1691     tess->normal_coordinate.push_back(N[i][0]);
1692     tess->normal_coordinate.push_back(N[i][1]);
1693     tess->normal_coordinate.push_back(N[i][2]);
1694   }
1695   }
1696   else
1697     tess->crease_angle = ca;
1698   if(textured)
1699   {
1700     tess->texture_coordinate.reserve(2*nT);
1701   for(uint32_t i=0; i<nT; i++)
1702   {
1703     tess->texture_coordinate.push_back(T[i][0]);
1704     tess->texture_coordinate.push_back(T[i][1]);
1705   }
1706   }
1707   tess->triangulated_index.reserve(2*(3*nI+(has_normals?3:0)*nI+(textured?3:0)*nI));
1708   for(uint32_t i=0; i<nI; i++)
1709   {
1710     // first triangle
1711     if(has_normals)
1712     tess->triangulated_index.push_back(3*NI[i][0]);
1713     if(textured)
1714     tess->triangulated_index.push_back(2*TI[i][0]);
1715     tess->triangulated_index.push_back(3*PI[i][0]);
1716     if(has_normals)
1717     tess->triangulated_index.push_back(3*NI[i][1]);
1718     if(textured)
1719     tess->triangulated_index.push_back(2*TI[i][1]);
1720     tess->triangulated_index.push_back(3*PI[i][1]);
1721     if(has_normals)
1722     tess->triangulated_index.push_back(3*NI[i][3]);
1723     if(textured)
1724     tess->triangulated_index.push_back(2*TI[i][3]);
1725     tess->triangulated_index.push_back(3*PI[i][3]);
1726     // second triangle
1727     if(has_normals)
1728     tess->triangulated_index.push_back(3*NI[i][1]);
1729     if(textured)
1730     tess->triangulated_index.push_back(2*TI[i][1]);
1731     tess->triangulated_index.push_back(3*PI[i][1]);
1732     if(has_normals)
1733     tess->triangulated_index.push_back(3*NI[i][2]);
1734     if(textured)
1735     tess->triangulated_index.push_back(2*TI[i][2]);
1736     tess->triangulated_index.push_back(3*PI[i][2]);
1737     if(has_normals)
1738     tess->triangulated_index.push_back(3*NI[i][3]);
1739     if(textured)
1740     tess->triangulated_index.push_back(2*TI[i][3]);
1741     tess->triangulated_index.push_back(3*PI[i][3]);
1742   }
1743   tessFace->sizes_triangulated.push_back(2*nI);
1744   if(triangle_color)
1745   {
1746     tessFace->line_attributes.reserve(2*nI);
1747     for(uint32_t i=0; i<nI; i++)
1748     {
1749        tessFace->line_attributes.push_back(SI[i]);
1750        tessFace->line_attributes.push_back(SI[i]);
1751     }
1752   }
1753   else
1754   {
1755       tessFace->line_attributes.push_back(style_index);
1756   }
1757   if(vertex_color)
1758   {
1759     tessFace->is_rgba=false;
1760     for(uint32_t i=0; i<nI; i++)
1761       if(1.0 != C[CI[i][0]].A || 1.0 != C[CI[i][1]].A || 1.0 != C[CI[i][2]].A)
1762       {
1763          tessFace->is_rgba=true;
1764          break;
1765       }
1766 
1767     tessFace->rgba_vertices.reserve(2*(tessFace->is_rgba?4:3)*3*nI);
1768     for(uint32_t i=0; i<nI; i++)
1769     {
1770        // first triangle
1771        tessFace->rgba_vertices.push_back(toByte(C[CI[i][0]].R));
1772        tessFace->rgba_vertices.push_back(toByte(C[CI[i][0]].G));
1773        tessFace->rgba_vertices.push_back(toByte(C[CI[i][0]].B));
1774        if(tessFace->is_rgba)
1775        tessFace->rgba_vertices.push_back(toByte(C[CI[i][0]].A));
1776        tessFace->rgba_vertices.push_back(toByte(C[CI[i][1]].R));
1777        tessFace->rgba_vertices.push_back(toByte(C[CI[i][1]].G));
1778        tessFace->rgba_vertices.push_back(toByte(C[CI[i][1]].B));
1779        if(tessFace->is_rgba)
1780        tessFace->rgba_vertices.push_back(toByte(C[CI[i][1]].A));
1781        tessFace->rgba_vertices.push_back(toByte(C[CI[i][3]].R));
1782        tessFace->rgba_vertices.push_back(toByte(C[CI[i][3]].G));
1783        tessFace->rgba_vertices.push_back(toByte(C[CI[i][3]].B));
1784        if(tessFace->is_rgba)
1785        tessFace->rgba_vertices.push_back(toByte(C[CI[i][3]].A));
1786        // second triangle
1787        tessFace->rgba_vertices.push_back(toByte(C[CI[i][1]].R));
1788        tessFace->rgba_vertices.push_back(toByte(C[CI[i][1]].G));
1789        tessFace->rgba_vertices.push_back(toByte(C[CI[i][1]].B));
1790        if(tessFace->is_rgba)
1791        tessFace->rgba_vertices.push_back(toByte(C[CI[i][1]].A));
1792        tessFace->rgba_vertices.push_back(toByte(C[CI[i][2]].R));
1793        tessFace->rgba_vertices.push_back(toByte(C[CI[i][2]].G));
1794        tessFace->rgba_vertices.push_back(toByte(C[CI[i][2]].B));
1795        if(tessFace->is_rgba)
1796        tessFace->rgba_vertices.push_back(toByte(C[CI[i][2]].A));
1797        tessFace->rgba_vertices.push_back(toByte(C[CI[i][3]].R));
1798        tessFace->rgba_vertices.push_back(toByte(C[CI[i][3]].G));
1799        tessFace->rgba_vertices.push_back(toByte(C[CI[i][3]].B));
1800        if(tessFace->is_rgba)
1801        tessFace->rgba_vertices.push_back(toByte(C[CI[i][3]].A));
1802     }
1803   }
1804   tess->addTessFace(tessFace);
1805   const uint32_t tess_index = add3DTess(tess);
1806   return tess_index;
1807 }
1808 
addQuad(const double P[][3],const RGBAColour C[])1809 void oPRCFile::addQuad(const double P[][3], const RGBAColour C[])
1810 {
1811   PRCgroup &group = findGroup();
1812 
1813   group.quads.push_back(PRCtessquad());
1814   PRCtessquad &quad = group.quads.back();
1815   for(size_t i = 0; i < 4; i++)
1816   {
1817     quad.vertices[i].x = P[i][0];
1818     quad.vertices[i].y = P[i][1];
1819     quad.vertices[i].z = P[i][2];
1820     quad.colours[i] = C[i];
1821   }
1822 }
1823 /*
1824 void oPRCFile::addTriangle(const double P[][3], const double T[][2], uint32_t style_index)
1825 {
1826   PRCgroup &group = findGroup();
1827 
1828   group.triangles.push_back(PRCtesstriangle());
1829   PRCtesstriangle &triangle = group.triangles.back();
1830   for(size_t i = 0; i < 3; i++)
1831   {
1832     triangle.vertices[i].x = P[i][0];
1833     triangle.vertices[i].y = P[i][1];
1834     triangle.vertices[i].z = P[i][2];
1835     triangle.texcoords[i].x = T[i][0];
1836     triangle.texcoords[i].y = T[i][1];
1837   }
1838   triangle.style = style_index;
1839 }
1840 */
1841 
addLines(uint32_t nP,const double P[][3],uint32_t nI,const uint32_t PI[],const RGBAColour & c,double w,bool segment_color,uint32_t nC,const RGBAColour C[],uint32_t nCI,const uint32_t CI[])1842 void oPRCFile::addLines(uint32_t nP, const double P[][3], uint32_t nI, const uint32_t PI[],
1843  const RGBAColour& c, double w,
1844  bool segment_color, uint32_t nC, const RGBAColour C[], uint32_t nCI, const uint32_t CI[])
1845 {
1846   if(nP==0 || P==NULL || nI==0 || PI==NULL)
1847     return;
1848   const uint32_t tess_index = createLines(nP, P, nI, PI, segment_color, nC, C, nCI, CI);
1849   useLines(tess_index, c, w);
1850 }
1851 
createLines(uint32_t nP,const double P[][3],uint32_t nI,const uint32_t PI[],bool segment_color,uint32_t nC,const RGBAColour C[],uint32_t nCI,const uint32_t CI[])1852 uint32_t oPRCFile::createLines(uint32_t nP, const double P[][3], uint32_t nI, const uint32_t PI[],
1853  bool segment_color, uint32_t nC, const RGBAColour C[], uint32_t nCI, const uint32_t CI[])
1854 {
1855   if(nP==0 || P==NULL || nI==0 || PI==NULL)
1856     return m1;
1857 
1858   const bool vertex_color  = (nC != 0 && C != NULL && CI != NULL);
1859 
1860   PRC3DWireTess *tess = new PRC3DWireTess();
1861   tess->coordinates.reserve(3*nP);
1862   for(uint32_t i=0; i<nP; i++)
1863   {
1864     tess->coordinates.push_back(P[i][0]);
1865     tess->coordinates.push_back(P[i][1]);
1866     tess->coordinates.push_back(P[i][2]);
1867   }
1868   tess->wire_indexes.reserve(nI);
1869   for(uint32_t i=0; i<nI;)
1870   {
1871     tess->wire_indexes.push_back(PI[i]);
1872     const uint32_t ni = i+PI[i]+1;
1873     for(i++; i<ni; i++)
1874       tess->wire_indexes.push_back(3*PI[i]);
1875   }
1876   if(vertex_color)
1877   {
1878     tess->is_segment_color = segment_color;
1879     tess->is_rgba=false;
1880     for(uint32_t i=0; i<nCI; i++)
1881       if(1.0 != C[CI[i]].A)
1882       {
1883          tess->is_rgba=true;
1884          break;
1885       }
1886     tess->rgba_vertices.reserve((tess->is_rgba?4:3)*nCI);
1887     for(uint32_t i=0; i<nCI; i++)
1888     {
1889        tess->rgba_vertices.push_back(toByte(C[CI[i]].R));
1890        tess->rgba_vertices.push_back(toByte(C[CI[i]].G));
1891        tess->rgba_vertices.push_back(toByte(C[CI[i]].B));
1892        if(tess->is_rgba)
1893        tess->rgba_vertices.push_back(toByte(C[CI[i]].A));
1894     }
1895   }
1896   const uint32_t tess_index = add3DWireTess(tess);
1897   return tess_index;
1898 }
1899 
createSegments(uint32_t nP,const double P[][3],uint32_t nI,const uint32_t PI[][2],bool segment_color,uint32_t nC,const RGBAColour C[],const uint32_t CI[][2])1900 uint32_t oPRCFile::createSegments(uint32_t nP, const double P[][3], uint32_t nI, const uint32_t PI[][2],
1901                                bool segment_color, uint32_t nC, const RGBAColour C[], const uint32_t CI[][2])
1902 {
1903   if(nP==0 || P==NULL || nI==0 || PI==NULL)
1904     return m1;
1905 
1906   const bool vertex_color  = (nC != 0 && C != NULL && CI != NULL);
1907 
1908   PRC3DWireTess *tess = new PRC3DWireTess();
1909   tess->coordinates.reserve(3*nP);
1910   for(uint32_t i=0; i<nP; i++)
1911   {
1912     tess->coordinates.push_back(P[i][0]);
1913     tess->coordinates.push_back(P[i][1]);
1914     tess->coordinates.push_back(P[i][2]);
1915   }
1916   tess->wire_indexes.reserve(3*nI);
1917   for(uint32_t i=0; i<nI; i++)
1918   {
1919     tess->wire_indexes.push_back(2);
1920     tess->wire_indexes.push_back(3*PI[i][0]);
1921     tess->wire_indexes.push_back(3*PI[i][1]);
1922   }
1923   if(vertex_color)
1924   {
1925     tess->is_segment_color = segment_color;
1926     tess->is_rgba=false;
1927     for(uint32_t i=0; i<nI; i++)
1928       if(1.0 != C[CI[i][0]].A || 1.0 != C[CI[i][1]].A)
1929       {
1930         tess->is_rgba=true;
1931         break;
1932       }
1933     tess->rgba_vertices.reserve((tess->is_rgba?4:3)*(segment_color?1:2)*nI);
1934     for(uint32_t i=0; i<nI; i++)
1935     {
1936       if (segment_color) {
1937         tess->rgba_vertices.push_back(toByte(0.5*C[CI[i][0]].R+0.5*C[CI[i][1]].R));
1938         tess->rgba_vertices.push_back(toByte(0.5*C[CI[i][0]].G+0.5*C[CI[i][1]].G));
1939         tess->rgba_vertices.push_back(toByte(0.5*C[CI[i][0]].B+0.5*C[CI[i][1]].B));
1940         if(tess->is_rgba)
1941           tess->rgba_vertices.push_back(toByte(0.5*C[CI[i][0]].A+0.5*C[CI[i][1]].A));
1942       } else {
1943         tess->rgba_vertices.push_back(toByte(C[CI[i][0]].R));
1944         tess->rgba_vertices.push_back(toByte(C[CI[i][0]].G));
1945         tess->rgba_vertices.push_back(toByte(C[CI[i][0]].B));
1946         if(tess->is_rgba)
1947           tess->rgba_vertices.push_back(toByte(C[CI[i][0]].A));
1948         tess->rgba_vertices.push_back(toByte(C[CI[i][1]].R));
1949         tess->rgba_vertices.push_back(toByte(C[CI[i][1]].G));
1950         tess->rgba_vertices.push_back(toByte(C[CI[i][1]].B));
1951         if(tess->is_rgba)
1952           tess->rgba_vertices.push_back(toByte(C[CI[i][1]].A));
1953       }
1954     }
1955   }
1956   const uint32_t tess_index = add3DWireTess(tess);
1957   return tess_index;
1958 }
1959 
addLine(uint32_t n,const double P[][3],const RGBAColour & c,double w)1960 void oPRCFile::addLine(uint32_t n, const double P[][3], const RGBAColour &c, double w)
1961 {
1962   PRCgroup &group = findGroup();
1963   if(group.options.tess)
1964   {
1965     group.lines[w].push_back(PRCtessline());
1966     PRCtessline& line = group.lines[w].back();
1967     line.color.red   = c.R;
1968     line.color.green = c.G;
1969     line.color.blue  = c.B;
1970     for(uint32_t i=0; i<n; i++)
1971       line.point.push_back(PRCVector3d(P[i][0],P[i][1],P[i][2]));
1972   }
1973   else
1974   {
1975     ADDWIRE(PRCPolyLine)
1976     curve->point.resize(n);
1977     for(uint32_t i=0; i<n; i++)
1978      curve->point[i].Set(P[i][0],P[i][1],P[i][2]);
1979     curve->interval.min = 0;
1980     curve->interval.max = curve->point.size()-1;
1981   }
1982 }
1983 
addSegment(const double P1[3],const double P2[3],const RGBAColour & c,double w)1984 void oPRCFile::addSegment(const double P1[3], const double P2[3], const RGBAColour &c, double w)
1985 {
1986   PRCgroup &group = findGroup();
1987   if(group.options.tess)
1988   {
1989     group.lines[w].push_back(PRCtessline());
1990     PRCtessline& line = group.lines[w].back();
1991     line.color.red   = c.R;
1992     line.color.green = c.G;
1993     line.color.blue  = c.B;
1994     line.point.push_back(PRCVector3d(P1[0],P1[1],P1[2]));
1995     line.point.push_back(PRCVector3d(P2[0],P2[1],P2[2]));
1996   }
1997   else
1998   {
1999     ADDWIRE(PRCPolyLine)
2000     curve->point.resize(2);
2001     curve->point[0].Set(P1[0],P1[1],P1[2]);
2002     curve->point[1].Set(P2[0],P2[1],P2[2]);
2003     curve->interval.min = 0;
2004     curve->interval.max = curve->point.size()-1;
2005   }
2006 }
2007 
addBezierCurve(uint32_t n,const double cP[][3],const RGBAColour & c)2008 void oPRCFile::addBezierCurve(uint32_t n, const double cP[][3],
2009                               const RGBAColour &c)
2010 {
2011   ADDWIRE(PRCNURBSCurve)
2012   curve->is_rational = false;
2013   curve->degree = 3;
2014   const size_t NUMBER_OF_POINTS = n;
2015   curve->control_point.resize(NUMBER_OF_POINTS);
2016   for(size_t i = 0; i < NUMBER_OF_POINTS; ++i)
2017     curve->control_point[i].Set(cP[i][0],cP[i][1],cP[i][2]);
2018   curve->knot.resize(3+NUMBER_OF_POINTS+1);
2019   curve->knot[0] = 1;
2020   for(size_t i = 1; i < 3+NUMBER_OF_POINTS; ++i)
2021     curve->knot[i] = (i+2)/3; // integer division is intentional
2022   curve->knot[3+NUMBER_OF_POINTS] = (3+NUMBER_OF_POINTS+1)/3;
2023 }
2024 
addCurve(uint32_t d,uint32_t n,const double cP[][3],const double * k,const RGBAColour & c,const double w[])2025 void oPRCFile::addCurve(uint32_t d, uint32_t n, const double cP[][3], const double *k, const RGBAColour &c, const double w[])
2026 {
2027   ADDWIRE(PRCNURBSCurve)
2028   curve->is_rational = (w!=NULL);
2029   curve->degree = d;
2030   curve->control_point.resize(n);
2031   for(uint32_t i = 0; i < n; i++)
2032     if(w)
2033       curve->control_point[i].Set(cP[i][0]*w[i],cP[i][1]*w[i],cP[i][2]*w[i],w[i]);
2034     else
2035       curve->control_point[i].Set(cP[i][0],cP[i][1],cP[i][2]);
2036   curve->knot.resize(d+n+1);
2037   for(uint32_t i = 0; i < d+n+1; i++)
2038     curve->knot[i] = k[i];
2039 }
2040 
addRectangle(const double P[][3],const PRCmaterial & m)2041 void oPRCFile::addRectangle(const double P[][3], const PRCmaterial &m)
2042 {
2043   PRCgroup &group = findGroup();
2044   if(group.options.tess)
2045   {
2046     group.rectangles.push_back(PRCtessrectangle());
2047     PRCtessrectangle &rectangle = group.rectangles.back();
2048     rectangle.style = addMaterial(m);
2049     for(size_t i = 0; i < 4; i++)
2050     {
2051        rectangle.vertices[i].x = P[i][0];
2052        rectangle.vertices[i].y = P[i][1];
2053        rectangle.vertices[i].z = P[i][2];
2054     }
2055   }
2056   else if(group.options.compression == 0.0)
2057   {
2058     ADDFACE(PRCNURBSSurface)
2059 
2060     surface->is_rational = false;
2061     surface->degree_in_u = 1;
2062     surface->degree_in_v = 1;
2063     surface->control_point.resize(4);
2064     for(size_t i = 0; i < 4; ++i)
2065     {
2066         surface->control_point[i].x = P[i][0];
2067         surface->control_point[i].y = P[i][1];
2068         surface->control_point[i].z = P[i][2];
2069     }
2070     surface->knot_u.resize(4);
2071     surface->knot_v.resize(4);
2072     surface->knot_v[0] = surface->knot_u[0] = 1;
2073     surface->knot_v[1] = surface->knot_u[1] = 3;
2074     surface->knot_v[2] = surface->knot_u[2] = 4;
2075     surface->knot_v[3] = surface->knot_u[3] = 4;
2076   }
2077   else
2078   {
2079     ADDCOMPFACE
2080 
2081     compface->degree = 1;
2082     compface->control_point.resize(4);
2083     for(size_t i = 0; i < 4; ++i)
2084     {
2085         compface->control_point[i].x = P[i][0];
2086         compface->control_point[i].y = P[i][1];
2087         compface->control_point[i].z = P[i][2];
2088     }
2089   }
2090 }
2091 
addPatch(const double cP[][3],const PRCmaterial & m)2092 void oPRCFile::addPatch(const double cP[][3], const PRCmaterial &m)
2093 {
2094   PRCgroup &group = findGroup();
2095   if(group.options.compression == 0.0)
2096   {
2097     ADDFACE(PRCNURBSSurface)
2098 
2099     surface->is_rational = false;
2100     surface->degree_in_u = 3;
2101     surface->degree_in_v = 3;
2102     surface->control_point.resize(16);
2103     for(size_t i = 0; i < 16; ++i)
2104     {
2105         surface->control_point[i].x = cP[i][0];
2106         surface->control_point[i].y = cP[i][1];
2107         surface->control_point[i].z = cP[i][2];
2108     }
2109     surface->knot_u.resize(8);
2110     surface->knot_v.resize(8);
2111     surface->knot_v[0] = surface->knot_u[0] = 1;
2112     surface->knot_v[1] = surface->knot_u[1] = 1;
2113     surface->knot_v[2] = surface->knot_u[2] = 1;
2114     surface->knot_v[3] = surface->knot_u[3] = 1;
2115     surface->knot_v[4] = surface->knot_u[4] = 2;
2116     surface->knot_v[5] = surface->knot_u[5] = 2;
2117     surface->knot_v[6] = surface->knot_u[6] = 2;
2118     surface->knot_v[7] = surface->knot_u[7] = 2;
2119   }
2120   else
2121   {
2122     ADDCOMPFACE
2123 
2124     compface->degree = 3;
2125     compface->control_point.resize(16);
2126     for(size_t i = 0; i < 16; ++i)
2127     {
2128         compface->control_point[i].x = cP[i][0];
2129         compface->control_point[i].y = cP[i][1];
2130         compface->control_point[i].z = cP[i][2];
2131     }
2132   }
2133 }
2134 
addSurface(uint32_t dU,uint32_t dV,uint32_t nU,uint32_t nV,const double cP[][3],const double * kU,const double * kV,const PRCmaterial & m,const double w[])2135 void oPRCFile::addSurface(uint32_t dU, uint32_t dV, uint32_t nU, uint32_t nV,
2136                           const double cP[][3], const double *kU,
2137                           const double *kV, const PRCmaterial &m,
2138                           const double w[])
2139 {
2140   ADDFACE(PRCNURBSSurface)
2141 
2142   surface->is_rational = (w!=NULL);
2143   surface->degree_in_u = dU;
2144   surface->degree_in_v = dV;
2145   surface->control_point.resize(nU*nV);
2146   for(size_t i = 0; i < nU*nV; i++)
2147     if(w)
2148       surface->control_point[i]=PRCControlPoint(cP[i][0]*w[i],cP[i][1]*w[i],cP[i][2]*w[i],w[i]);
2149     else
2150       surface->control_point[i]=PRCControlPoint(cP[i][0],cP[i][1],cP[i][2]);
2151   surface->knot_u.insert(surface->knot_u.end(), kU, kU+(dU+nU+1));
2152   surface->knot_v.insert(surface->knot_v.end(), kV, kV+(dV+nV+1));
2153 }
2154 
2155 #define SETTRANSF \
2156   if(t&&!isid(t))                                                             \
2157     face.transform = new PRCGeneralTransformation3d(t);                       \
2158   if(origin) surface->origin.Set(origin[0],origin[1],origin[2]);              \
2159   if(x_axis) surface->x_axis.Set(x_axis[0],x_axis[1],x_axis[2]);              \
2160   if(y_axis) surface->y_axis.Set(y_axis[0],y_axis[1],y_axis[2]);              \
2161   surface->scale = scale;                                                     \
2162   surface->geometry_is_2D = false;                                            \
2163   if(surface->origin!=PRCVector3d(0.0,0.0,0.0))                                     \
2164     surface->behaviour = surface->behaviour | PRC_TRANSFORMATION_Translate;   \
2165   if(surface->x_axis!=PRCVector3d(1.0,0.0,0.0)||surface->y_axis!=PRCVector3d(0.0,1.0,0.0)) \
2166     surface->behaviour = surface->behaviour | PRC_TRANSFORMATION_Rotate;      \
2167   if(surface->scale!=1)                                                       \
2168     surface->behaviour = surface->behaviour | PRC_TRANSFORMATION_Scale;       \
2169   surface->has_transformation = (surface->behaviour != PRC_TRANSFORMATION_Identity);
2170 
2171 #define PRCFACETRANSFORM const double origin[3], const double x_axis[3], const double y_axis[3], double scale, const double* t
2172 
addTube(uint32_t n,const double cP[][3],const double oP[][3],bool straight,const PRCmaterial & m,PRCFACETRANSFORM)2173 void oPRCFile::addTube(uint32_t n, const double cP[][3], const double oP[][3], bool straight, const PRCmaterial &m, PRCFACETRANSFORM)
2174 {
2175   ADDFACE(PRCBlend01)
2176   SETTRANSF
2177   if(straight)
2178   {
2179     PRCPolyLine *center_curve = new PRCPolyLine;
2180     center_curve->point.resize(n);
2181     for(uint32_t i=0; i<n; i++)
2182       center_curve->point[i].Set(cP[i][0],cP[i][1],cP[i][2]);
2183     center_curve->interval.min = 0;
2184     center_curve->interval.max = center_curve->point.size()-1;
2185     surface->center_curve = center_curve;
2186 
2187     PRCPolyLine *origin_curve = new PRCPolyLine;
2188     origin_curve->point.resize(n);
2189     for(uint32_t i=0; i<n; i++)
2190       origin_curve->point[i].Set(oP[i][0],oP[i][1],oP[i][2]);
2191     origin_curve->interval.min = 0;
2192     origin_curve->interval.max = origin_curve->point.size()-1;
2193     surface->origin_curve = origin_curve;
2194 
2195     surface->uv_domain.min.x = 0;
2196     surface->uv_domain.max.x = 2*pi;
2197     surface->uv_domain.min.y = 0;
2198     surface->uv_domain.max.y = n-1;
2199   }
2200   else
2201   {
2202     PRCNURBSCurve *center_curve = new PRCNURBSCurve;
2203     center_curve->is_rational = false;
2204     center_curve->degree = 3;
2205     const uint32_t CENTER_NUMBER_OF_POINTS = n;
2206     center_curve->control_point.resize(CENTER_NUMBER_OF_POINTS);
2207     for(uint32_t i = 0; i < CENTER_NUMBER_OF_POINTS; ++i)
2208       center_curve->control_point[i].Set(cP[i][0],cP[i][1],cP[i][2]);
2209     center_curve->knot.resize(3+CENTER_NUMBER_OF_POINTS+1);
2210     center_curve->knot[0] = 1;
2211     for(uint32_t i = 1; i < 3+CENTER_NUMBER_OF_POINTS; ++i)
2212       center_curve->knot[i] = (i+2)/3; // integer division is intentional
2213     center_curve->knot[3+CENTER_NUMBER_OF_POINTS] = (3+CENTER_NUMBER_OF_POINTS+1)/3;
2214     surface->center_curve = center_curve;
2215 
2216     PRCNURBSCurve *origin_curve = new PRCNURBSCurve;
2217     origin_curve->is_rational = false;
2218     origin_curve->degree = 3;
2219     const uint32_t ORIGIN_NUMBER_OF_POINTS = n;
2220     origin_curve->control_point.resize(ORIGIN_NUMBER_OF_POINTS);
2221     for(uint32_t i = 0; i < ORIGIN_NUMBER_OF_POINTS; ++i)
2222       origin_curve->control_point[i].Set(oP[i][0],oP[i][1],oP[i][2]);
2223     origin_curve->knot.resize(3+ORIGIN_NUMBER_OF_POINTS+1);
2224     origin_curve->knot[0] = 1;
2225     for(size_t i = 1; i < 3+ORIGIN_NUMBER_OF_POINTS; ++i)
2226       origin_curve->knot[i] = (i+2)/3; // integer division is intentional
2227     origin_curve->knot[3+ORIGIN_NUMBER_OF_POINTS] = (3+ORIGIN_NUMBER_OF_POINTS+1)/3;
2228     surface->origin_curve = origin_curve;
2229 
2230     surface->uv_domain.min.x = 0;
2231     surface->uv_domain.max.x = 2*pi;
2232     surface->uv_domain.min.y = 1; // first knot
2233     surface->uv_domain.max.y = (3+CENTER_NUMBER_OF_POINTS+1)/3; // last knot
2234   }
2235 }
2236 
addHemisphere(double radius,const PRCmaterial & m,PRCFACETRANSFORM)2237 void oPRCFile::addHemisphere(double radius, const PRCmaterial &m, PRCFACETRANSFORM)
2238 {
2239   ADDFACE(PRCSphere)
2240   SETTRANSF
2241   surface->uv_domain.min.x = 0;
2242   surface->uv_domain.max.x = 2*pi;
2243   surface->uv_domain.min.y = 0;
2244   surface->uv_domain.max.y = 0.5*pi;
2245   surface->radius = radius;
2246 }
2247 
addSphere(double radius,const PRCmaterial & m,PRCFACETRANSFORM)2248 void oPRCFile::addSphere(double radius, const PRCmaterial &m, PRCFACETRANSFORM)
2249 {
2250   ADDFACE(PRCSphere)
2251   SETTRANSF
2252   surface->uv_domain.min.x = 0;
2253   surface->uv_domain.max.x = 2*pi;
2254   surface->uv_domain.min.y =-0.5*pi;
2255   surface->uv_domain.max.y = 0.5*pi;
2256   surface->radius = radius;
2257 }
2258 
addDisk(double radius,const PRCmaterial & m,PRCFACETRANSFORM)2259 void oPRCFile::addDisk(double radius, const PRCmaterial &m, PRCFACETRANSFORM)
2260 {
2261   ADDFACE(PRCRuled)
2262   SETTRANSF
2263   PRCCircle *first_curve = new PRCCircle;
2264   first_curve->radius = radius;
2265   surface->first_curve = first_curve;
2266   PRCCircle *second_curve = new PRCCircle;
2267   second_curve->radius = 0;
2268   surface->second_curve = second_curve;
2269 
2270   surface->uv_domain.min.x = 0;
2271   surface->uv_domain.max.x = 1;
2272   surface->uv_domain.min.y = 0;
2273   surface->uv_domain.max.y = 2*pi;
2274   surface->parameterization_on_v_coeff_a = -1;
2275   surface->parameterization_on_v_coeff_b = 2*pi;
2276 }
2277 
addCylinder(double radius,double height,const PRCmaterial & m,PRCFACETRANSFORM)2278 void oPRCFile::addCylinder(double radius, double height, const PRCmaterial &m, PRCFACETRANSFORM)
2279 {
2280   ADDFACE(PRCCylinder)
2281   SETTRANSF
2282   surface->uv_domain.min.x = 0;
2283   surface->uv_domain.max.x = 2*pi;
2284   surface->uv_domain.min.y = (height>0)?0:height;
2285   surface->uv_domain.max.y = (height>0)?height:0;
2286   surface->radius = radius;
2287 }
2288 
addCone(double radius,double height,const PRCmaterial & m,PRCFACETRANSFORM)2289 void oPRCFile::addCone(double radius, double height, const PRCmaterial &m, PRCFACETRANSFORM)
2290 {
2291   ADDFACE(PRCCone)
2292   SETTRANSF
2293   surface->uv_domain.min.x = 0;
2294   surface->uv_domain.max.x = 2*pi;
2295   surface->uv_domain.min.y = (height>0)?0:height;
2296   surface->uv_domain.max.y = (height>0)?height:0;
2297   surface->bottom_radius = radius;
2298   surface->semi_angle = -atan(radius/height);;
2299 }
2300 
addTorus(double major_radius,double minor_radius,double angle1,double angle2,const PRCmaterial & m,PRCFACETRANSFORM)2301 void oPRCFile::addTorus(double major_radius, double minor_radius, double angle1, double angle2, const PRCmaterial &m, PRCFACETRANSFORM)
2302 {
2303   ADDFACE(PRCTorus)
2304   SETTRANSF
2305   surface->uv_domain.min.x = (angle1/180)*pi;
2306   surface->uv_domain.max.x = (angle2/180)*pi;
2307   surface->uv_domain.min.y = 0;
2308   surface->uv_domain.max.y = 2*pi;
2309   surface->major_radius = major_radius;
2310   surface->minor_radius = minor_radius;
2311 }
2312 
2313 #undef PRCFACETRANSFORM
2314 #undef ADDFACE
2315 #undef ADDWIRE
2316 #undef SETTRANSF
2317 
addRgbColor(double r,double g,double b)2318 uint32_t PRCFileStructure::addRgbColor(double r, double g, double b)
2319 {
2320   const PRCRgbColor color(r, g, b);
2321   colors.push_back(color);
2322   return 3*(colors.size()-1);
2323 }
2324 
addRgbColorUnique(double r,double g,double b)2325 uint32_t PRCFileStructure::addRgbColorUnique(double r, double g, double b)
2326 {
2327   const PRCRgbColor color(r, g, b);
2328   uint32_t color_index = m1;
2329   PRCRgbColorMap::const_iterator iRgbColor = colorMap.find(color);
2330   if(iRgbColor!=colorMap.end())
2331   {
2332     color_index = iRgbColor->second;
2333   }
2334   else
2335   {
2336     color_index = 3*colors.size();
2337     colors.push_back(color);
2338     colorMap.insert(make_pair(color,color_index));
2339   }
2340   return color_index;
2341 }
2342 
2343 #define ADD_ADDUNIQ( prctype, prcmap, prclist) \
2344 uint32_t PRCFileStructure::add##prctype(PRC##prctype *& p##prctype)   \
2345 { \
2346   prclist.push_back(p##prctype); \
2347   p##prctype = NULL; \
2348   return prclist.size()-1; \
2349 } \
2350  \
2351 uint32_t PRCFileStructure::add##prctype##Unique(PRC##prctype*& p##prctype) \
2352 { \
2353   uint32_t prc_index = m1; \
2354   PRC##prctype##Map::const_iterator i##prctype = prcmap.find(p##prctype); \
2355   if(i##prctype!=prcmap.end()) \
2356   { \
2357     delete p##prctype; \
2358     prc_index = i##prctype->second; \
2359   } \
2360   else \
2361   { \
2362     prc_index = prclist.size(); \
2363     prclist.push_back(p##prctype); \
2364     prcmap.insert(make_pair(p##prctype,prc_index)); \
2365   } \
2366   p##prctype = NULL; \
2367   return prc_index; \
2368 }
2369 
ADD_ADDUNIQ(UncompressedFile,uncompressedfileMap,uncompressed_files)2370 ADD_ADDUNIQ(UncompressedFile,   uncompressedfileMap,   uncompressed_files  )
2371 ADD_ADDUNIQ(Picture,            pictureMap,            pictures            )
2372 ADD_ADDUNIQ(TextureDefinition,  texturedefinitionMap,  texture_definitions )
2373 ADD_ADDUNIQ(MaterialGeneric,    materialgenericMap,    materials           )
2374 ADD_ADDUNIQ(TextureApplication, textureapplicationMap, materials           )
2375 ADD_ADDUNIQ(Style,              styleMap,              styles              )
2376 
2377 #undef ADD_ADDUNIQ
2378 
2379 uint32_t PRCFileStructure::addPartDefinition(PRCPartDefinition*& pPartDefinition)
2380 {
2381   part_definitions.push_back(pPartDefinition);
2382   pPartDefinition = NULL;
2383   return part_definitions.size()-1;
2384 }
2385 
addProductOccurrence(PRCProductOccurrence * & pProductOccurrence)2386 uint32_t PRCFileStructure::addProductOccurrence(PRCProductOccurrence*& pProductOccurrence)
2387 {
2388   product_occurrences.push_back(pProductOccurrence);
2389   pProductOccurrence = NULL;
2390   return product_occurrences.size()-1;
2391 }
2392 
addTopoContext(PRCTopoContext * & pTopoContext)2393 uint32_t PRCFileStructure::addTopoContext(PRCTopoContext*& pTopoContext)
2394 {
2395   contexts.push_back(pTopoContext);
2396   pTopoContext = NULL;
2397   return contexts.size()-1;
2398 }
2399 
getTopoContext(PRCTopoContext * & pTopoContext)2400 uint32_t PRCFileStructure::getTopoContext(PRCTopoContext*& pTopoContext)
2401 {
2402   pTopoContext = new PRCTopoContext;
2403   contexts.push_back(pTopoContext);
2404   return contexts.size()-1;
2405 }
2406 
add3DTess(PRC3DTess * & p3DTess)2407 uint32_t PRCFileStructure::add3DTess(PRC3DTess*& p3DTess)
2408 {
2409   tessellations.push_back(p3DTess);
2410   p3DTess = NULL;
2411   return tessellations.size()-1;
2412 }
2413 
add3DWireTess(PRC3DWireTess * & p3DWireTess)2414 uint32_t PRCFileStructure::add3DWireTess(PRC3DWireTess*& p3DWireTess)
2415 {
2416   tessellations.push_back(p3DWireTess);
2417   p3DWireTess = NULL;
2418   return tessellations.size()-1;
2419 }
2420 /*
2421 uint32_t PRCFileStructure::addMarkupTess(PRCMarkupTess*& pMarkupTess)
2422 {
2423   tessellations.push_back(pMarkupTess);
2424   pMarkupTess = NULL;
2425   return tessellations.size()-1;
2426 }
2427 
2428 uint32_t PRCFileStructure::addMarkup(PRCMarkup*& pMarkup)
2429 {
2430   markups.push_back(pMarkup);
2431   pMarkup = NULL;
2432   return markups.size()-1;
2433 }
2434 
2435 uint32_t PRCFileStructure::addAnnotationItem(PRCAnnotationItem*& pAnnotationItem)
2436 {
2437   annotation_entities.push_back(pAnnotationItem);
2438   pAnnotationItem = NULL;
2439   return annotation_entities.size()-1;
2440 }
2441 */
addCoordinateSystem(PRCCoordinateSystem * & pCoordinateSystem)2442 uint32_t PRCFileStructure::addCoordinateSystem(PRCCoordinateSystem*& pCoordinateSystem)
2443 {
2444   reference_coordinate_systems.push_back(pCoordinateSystem);
2445   pCoordinateSystem = NULL;
2446   return reference_coordinate_systems.size()-1;
2447 }
2448 
addCoordinateSystemUnique(PRCCoordinateSystem * & pCoordinateSystem)2449 uint32_t PRCFileStructure::addCoordinateSystemUnique(PRCCoordinateSystem*& pCoordinateSystem)
2450 {
2451   for(uint32_t i = 0; i < reference_coordinate_systems.size(); ++i)
2452   {
2453     if(*(reference_coordinate_systems[i])==*pCoordinateSystem) {
2454       pCoordinateSystem = NULL;
2455       return i;
2456     }
2457   }
2458   reference_coordinate_systems.push_back(pCoordinateSystem);
2459   pCoordinateSystem = NULL;
2460   return reference_coordinate_systems.size()-1;
2461 }
2462