1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtk3DSImporter.cxx
5 
6   Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7   All rights reserved.
8   See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
9 
10      This software is distributed WITHOUT ANY WARRANTY; without even
11      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12      PURPOSE.  See the above copyright notice for more information.
13 
14 =========================================================================*/
15 #include "vtk3DSImporter.h"
16 
17 #include "vtkActor.h"
18 #include "vtkByteSwap.h"
19 #include "vtkCamera.h"
20 #include "vtkCellArray.h"
21 #include "vtkLight.h"
22 #include "vtkObjectFactory.h"
23 #include "vtkPolyData.h"
24 #include "vtkPolyDataMapper.h"
25 #include "vtkPolyDataNormals.h"
26 #include "vtkProperty.h"
27 #include "vtkRenderer.h"
28 #include "vtkStripper.h"
29 
30 vtkStandardNewMacro(vtk3DSImporter);
31 
32 // Silence warning like
33 // "dereferencing type-punned pointer will break strict-aliasing rules"
34 // This file just has too many of them.
35 // This is due to the use of (vtk3DSList **)&root in VTK_LIST_* macros
36 // defined in vtk3DS.h
37 // pragma GCC diagnostic is available since gcc>=4.2
38 #if defined(__GNUC__) && (__GNUC__>4) || (__GNUC__==4 && __GNUC_MINOR__>=2)
39 #pragma GCC diagnostic ignored "-Wstrict-aliasing"
40 #endif
41 
42 static vtk3DSColour Black = {0.0, 0.0, 0.0};
43 static char   obj_name[80] = "";
44 static vtk3DSColour fog_colour = {0.0, 0.0, 0.0};
45 static vtk3DSColour col        = {0.0, 0.0, 0.0};
46 static vtk3DSColour global_amb = {0.1, 0.1, 0.1};
47 static vtk3DSVector pos        = {0.0, 0.0, 0.0};
48 static vtk3DSVector target     = {0.0, 0.0, 0.0};
49 static float  hotspot = -1;
50 static float  falloff = -1;
51 /* Default material property */
52 static vtk3DSMatProp DefaultMaterial =
53   { "Default", NULL,
54     {1.0, 1.0, 1.0}, {1.0, 1.0, 1.0}, {1.0, 1.0, 1.0},
55     70.0, // shininess
56     0.0,  // transparency
57     0.0,  // reflection
58     0,// self illumination
59     "",   // tex_map
60     0.0,  // tex_strength
61     "",   // bump_map
62     0.0,  // bump_strength
63     NULL};// vtkProperty
64 
65 static void cleanup_name (char *);
66 static void list_insert (vtk3DSList **root, vtk3DSList *new_node);
67 static void *list_find (vtk3DSList **root, const char *name);
68 static void list_kill (vtk3DSList **root);
69 static vtk3DSMatProp *create_mprop (void);
70 static vtk3DSMesh *create_mesh (char *name, int vertices, int faces);
71 static int parse_3ds_file (vtk3DSImporter *importer);
72 static void parse_3ds (vtk3DSImporter *importer, vtk3DSChunk *mainchunk);
73 static void parse_mdata (vtk3DSImporter *importer, vtk3DSChunk *mainchunk);
74 static void parse_fog (vtk3DSImporter *importer, vtk3DSChunk *mainchunk);
75 static void parse_fog_bgnd (vtk3DSImporter *importer);
76 static void parse_mat_entry (vtk3DSImporter *importer, vtk3DSChunk *mainchunk);
77 static char *parse_mapname (vtk3DSImporter *importer, vtk3DSChunk *mainchunk);
78 static void parse_named_object (vtk3DSImporter *importer, vtk3DSChunk *mainchunk);
79 static void parse_n_tri_object (vtk3DSImporter *importer, vtk3DSChunk *mainchunk);
80 static void parse_point_array (vtk3DSImporter *importer, vtk3DSMesh *mesh);
81 static void parse_face_array (vtk3DSImporter *importer, vtk3DSMesh *mesh, vtk3DSChunk *mainchunk);
82 static void parse_msh_mat_group (vtk3DSImporter *importer, vtk3DSMesh *mesh);
83 static void parse_smooth_group (vtk3DSImporter *importer);
84 static void parse_mesh_matrix (vtk3DSImporter *importer, vtk3DSMesh *mesh);
85 static void parse_n_direct_light (vtk3DSImporter *importer, vtk3DSChunk *mainchunk);
86 static void parse_dl_spotlight (vtk3DSImporter *importer);
87 static void parse_n_camera (vtk3DSImporter *importer);
88 static void parse_colour (vtk3DSImporter *importer, vtk3DSColour *colour);
89 static void parse_colour_f (vtk3DSImporter *importer, vtk3DSColour *colour);
90 static void parse_colour_24 (vtk3DSImporter *importer, vtk3DSColour_24 *colour);
91 static float parse_percentage (vtk3DSImporter *importer);
92 static short parse_int_percentage (vtk3DSImporter *importer);
93 static float parse_float_percentage (vtk3DSImporter *importer);
94 static vtk3DSMaterial *update_materials (vtk3DSImporter *importer, const char *new_material, int ext);
95 static void start_chunk (vtk3DSImporter *importer, vtk3DSChunk *chunk);
96 static void end_chunk (vtk3DSImporter *importer, vtk3DSChunk *chunk);
97 static byte read_byte (vtk3DSImporter *importer);
98 static word read_word (vtk3DSImporter *importer);
99 static word peek_word (vtk3DSImporter *importer);
100 static dword peek_dword (vtk3DSImporter *importer);
101 static float read_float (vtk3DSImporter *importer);
102 static void read_point (vtk3DSImporter *importer, vtk3DSVector v);
103 static char *read_string (vtk3DSImporter *importer);
104 
vtk3DSImporter()105 vtk3DSImporter::vtk3DSImporter ()
106 {
107   this->OmniList = NULL;
108   this->SpotLightList = NULL;
109   this->CameraList = NULL;
110   this->MeshList = NULL;
111   this->MaterialList = NULL;
112   this->MatPropList = NULL;
113   this->FileName = NULL;
114   this->FileFD = NULL;
115   this->ComputeNormals = 0;
116 }
117 
ImportBegin()118 int vtk3DSImporter::ImportBegin ()
119 {
120   vtkDebugMacro(<< "Opening import file as binary");
121   this->FileFD = fopen (this->FileName, "rb");
122   if (this->FileFD == NULL)
123     {
124     vtkErrorMacro(<< "Unable to open file: "<< this->FileName);
125     return 0;
126     }
127   return this->Read3DS ();
128 }
129 
ImportEnd()130 void vtk3DSImporter::ImportEnd ()
131 {
132   vtkDebugMacro(<<"Closing import file");
133   if ( this->FileFD != NULL )
134     {
135     fclose (this->FileFD);
136     }
137   this->FileFD = NULL;
138 }
139 
Read3DS()140 int vtk3DSImporter::Read3DS ()
141 {
142   vtk3DSMatProp *aMaterial;
143 
144   if (parse_3ds_file (this) == 0)
145     {
146     vtkErrorMacro (<<  "Error readings .3ds file: " << this->FileName << "\n");
147     return 0;
148     }
149 
150 
151   // create a vtk3DSMatProp and fill if in with default
152   aMaterial = (vtk3DSMatProp *) malloc (sizeof (vtk3DSMatProp));
153   *aMaterial = DefaultMaterial;
154   aMaterial->aProperty = vtkProperty::New ();
155   VTK_LIST_INSERT (this->MatPropList, aMaterial);
156   return 1;
157 }
158 
ImportActors(vtkRenderer * renderer)159 void vtk3DSImporter::ImportActors (vtkRenderer *renderer)
160 {
161   vtk3DSMatProp *material;
162   vtk3DSMesh *mesh;
163   vtkStripper *polyStripper;
164   vtkPolyDataNormals *polyNormals;
165   vtkPolyDataMapper *polyMapper;
166   vtkPolyData *polyData;
167   vtkActor *actor;
168 
169   // walk the list of meshes, creating actors
170   for (mesh = this->MeshList; mesh != (vtk3DSMesh *) NULL;
171        mesh = (vtk3DSMesh *) mesh->next)
172     {
173     if (mesh->faces == 0)
174       {
175       vtkWarningMacro (<< "part " << mesh->name << " has zero faces... skipping\n");
176       continue;
177       }
178 
179     polyData = this->GeneratePolyData (mesh);
180     mesh->aMapper = polyMapper = vtkPolyDataMapper::New ();
181     mesh->aStripper = polyStripper = vtkStripper::New ();
182 
183     // if ComputeNormals is on, insert a vtkPolyDataNormals filter
184     if (this->ComputeNormals)
185       {
186       mesh->aNormals = polyNormals = vtkPolyDataNormals::New ();
187       polyNormals->SetInputData (polyData);
188       polyStripper->SetInputConnection(polyNormals->GetOutputPort());
189       }
190     else
191       {
192       polyStripper->SetInputData(polyData);
193       }
194 
195     polyMapper->SetInputConnection(polyStripper->GetOutputPort());
196     vtkDebugMacro (<< "Importing Actor: " << mesh->name);
197     mesh->anActor = actor = vtkActor::New ();
198     actor->SetMapper (polyMapper);
199     material = (vtk3DSMatProp *)VTK_LIST_FIND(this->MatPropList, mesh->mtl[0]->name);
200     actor->SetProperty (material->aProperty);
201     renderer->AddActor (actor);
202   }
203 }
204 
GeneratePolyData(vtk3DSMesh * mesh)205 vtkPolyData *vtk3DSImporter::GeneratePolyData (vtk3DSMesh *mesh)
206 {
207   int i;
208   vtk3DSFace  *face;
209   vtkCellArray *triangles;
210   vtkPoints *vertices;
211   vtkPolyData *polyData;
212 
213   face = mesh->face;
214   mesh->aCellArray = triangles = vtkCellArray::New ();
215   triangles->Allocate(mesh->faces * 3);
216   for (i = 0; i < mesh->faces; i++, face++)
217     {
218     triangles->InsertNextCell (3);
219     triangles->InsertCellPoint (face->a);
220     triangles->InsertCellPoint (face->b);
221     triangles->InsertCellPoint (face->c);
222     }
223 
224   mesh->aPoints = vertices = vtkPoints::New ();
225   vertices->Allocate(mesh->vertices);
226   for (i = 0; i < mesh->vertices; i++)
227     {
228     vertices->InsertPoint (i, (float *) mesh->vertex[i]);
229     }
230   mesh->aPolyData = polyData = vtkPolyData::New ();
231   polyData->SetPolys (triangles);
232   polyData->SetPoints (vertices);
233 
234   return polyData;
235 }
236 
ImportCameras(vtkRenderer * renderer)237 void vtk3DSImporter::ImportCameras (vtkRenderer *renderer)
238 {
239   vtkCamera *aCamera;
240   vtk3DSCamera *camera;
241 
242   // walk the list of cameras and create vtk cameras
243   for (camera = this->CameraList; camera != (vtk3DSCamera *) NULL; camera = (vtk3DSCamera *) camera->next)
244     {
245     camera->aCamera = aCamera = vtkCamera::New ();
246     aCamera->SetPosition (camera->pos[0], camera->pos[1], camera->pos[2]);
247     aCamera->SetFocalPoint (camera->target[0], camera->target[1], camera->target[2]);
248     aCamera->SetViewUp (0, 0, 1);
249     aCamera->SetClippingRange (.1,10000);
250     aCamera->Roll (camera->bank);
251     renderer->SetActiveCamera (aCamera);
252     vtkDebugMacro (<< "Importing Camera: " << camera->name);
253   }
254 }
255 
ImportLights(vtkRenderer * renderer)256 void vtk3DSImporter::ImportLights (vtkRenderer *renderer)
257 {
258   vtk3DSOmniLight *omniLight;
259   vtk3DSSpotLight *spotLight;
260   vtkLight *aLight;
261 
262   // just walk the list of omni lights, creating vtk lights
263   for (omniLight = this->OmniList; omniLight != (vtk3DSOmniLight *) NULL;
264        omniLight = (vtk3DSOmniLight *) omniLight->next)
265   {
266   omniLight->aLight = aLight = vtkLight::New ();
267   aLight->SetPosition (omniLight->pos[0],
268                        omniLight->pos[1],
269                        omniLight->pos[2]);
270   aLight->SetFocalPoint (0, 0, 0);
271   aLight->SetColor (omniLight->col.red,
272                     omniLight->col.green,
273                     omniLight->col.blue);
274   renderer->AddLight (aLight);
275   vtkDebugMacro (<< "Importing Omni Light: " << omniLight->name);
276   }
277 
278   // now walk the list of spot lights, creating vtk lights
279   for (spotLight = this->SpotLightList; spotLight != (vtk3DSSpotLight *) NULL;
280        spotLight = (vtk3DSSpotLight *) spotLight->next)
281   {
282   spotLight->aLight = aLight = vtkLight::New ();
283   aLight->PositionalOn ();
284   aLight->SetPosition (spotLight->pos[0],
285                        spotLight->pos[1],
286                        spotLight->pos[2]);
287   aLight->SetFocalPoint (spotLight->target[0],
288                          spotLight->target[1],
289                          spotLight->target[2]);
290   aLight->SetColor (spotLight->col.red,
291                     spotLight->col.green,
292                     spotLight->col.blue);
293   aLight->SetConeAngle (spotLight->falloff);
294   renderer->AddLight (aLight);
295   vtkDebugMacro (<< "Importing Spot Light: " << spotLight->name);
296   }
297 }
298 
ImportProperties(vtkRenderer * vtkNotUsed (renderer))299 void vtk3DSImporter::ImportProperties (vtkRenderer *vtkNotUsed(renderer))
300 {
301   float amb = 0.1, dif = 0.9;
302   float dist_white, dist_diff, phong, phong_size;
303   vtkProperty *property;
304   vtk3DSMatProp *m;
305 
306   // just walk the list of material properties, creating vtk properties
307   for (m = this->MatPropList; m != (vtk3DSMatProp *) NULL; m = (vtk3DSMatProp *) m->next)
308     {
309     if (m->self_illum)
310       {
311       amb = 0.9;
312       dif = 0.1;
313       }
314 
315     dist_white = fabs(1.0 - m->specular.red) +
316          fabs(1.0 - m->specular.green) +
317          fabs(1.0 - m->specular.blue);
318 
319     dist_diff  = fabs(m->diffuse.red   - m->specular.red) +
320          fabs(m->diffuse.green - m->specular.green) +
321          fabs(m->diffuse.blue  - m->specular.blue);
322 
323     if (dist_diff < dist_white)
324       {
325       dif = .1; amb = .8;
326       }
327 
328     phong_size = 0.7*m->shininess;
329     if (phong_size < 1.0)
330       {
331       phong_size = 1.0;
332       }
333     if (phong_size > 30.0)
334       {
335       phong = 1.0;
336       }
337     else
338       {
339       phong = phong_size/30.0;
340       }
341   property = m->aProperty;
342   property->SetAmbientColor(m->ambient.red, m->ambient.green, m->ambient.blue);
343   property->SetAmbient (amb);
344   property->SetDiffuseColor(m->diffuse.red, m->diffuse.green, m->diffuse.blue);
345   property->SetDiffuse (dif);
346   property->SetSpecularColor(m->specular.red, m->specular.green, m->specular.blue);
347   property->SetSpecular (phong);
348   property->SetSpecularPower(phong_size);
349   property->SetOpacity(1.0 - m->transparency);
350   vtkDebugMacro(<< "Importing Property: " << m->name);
351 
352   m->aProperty = property;
353   }
354 }
355 
356 /* Insert a new node into the list */
list_insert(vtk3DSList ** root,vtk3DSList * new_node)357 static void list_insert (vtk3DSList **root, vtk3DSList *new_node)
358 {
359   new_node->next = *root;
360   *root = new_node;
361 }
362 
363 
364 /* Find the node with the specified name */
list_find(vtk3DSList ** root,const char * name)365 static void *list_find (vtk3DSList **root, const char *name)
366 {
367   vtk3DSList *p;
368   for (p = *root; p != (vtk3DSList *) NULL; p = (vtk3DSList *) p->next)
369     {
370     if (strcmp (p->name, name) == 0)
371       {
372       break;
373       }
374     }
375   return (void *)p;
376 }
377 
378 /* Delete the entire list */
list_kill(vtk3DSList ** root)379 static void list_kill (vtk3DSList **root)
380 {
381   vtk3DSList *temp;
382 
383   while (*root != (vtk3DSList *) NULL)
384     {
385     temp = *root;
386     *root = (vtk3DSList *) (*root)->next;
387     free (temp);
388     }
389 }
390 
391 /* Add a new material to the material list */
update_materials(vtk3DSImporter * importer,const char * new_material,int ext)392 static vtk3DSMaterial *update_materials (vtk3DSImporter *importer, const char *new_material, int ext)
393 {
394   vtk3DSMaterial *p;
395 
396   p = (vtk3DSMaterial *) VTK_LIST_FIND (importer->MaterialList, new_material);
397 
398   if (p == NULL)
399     {
400     p = (vtk3DSMaterial *) malloc (sizeof (*p));
401     strcpy (p->name, new_material);
402     p->external = ext;
403     VTK_LIST_INSERT (importer->MaterialList, p);
404     }
405   return p;
406 }
407 
408 
create_mprop()409 static vtk3DSMatProp *create_mprop()
410 {
411   vtk3DSMatProp *new_mprop;
412 
413   new_mprop = (vtk3DSMatProp *) malloc (sizeof(*new_mprop));
414   strcpy (new_mprop->name, "");
415   new_mprop->ambient = Black;
416   new_mprop->diffuse = Black;
417   new_mprop->specular = Black;
418   new_mprop->shininess = 0.0;
419   new_mprop->transparency = 0.0;
420   new_mprop->reflection = 0.0;
421   new_mprop->self_illum = 0;
422 
423   strcpy (new_mprop->tex_map, "");
424   new_mprop->tex_strength = 0.0;
425 
426   strcpy (new_mprop->bump_map, "");
427   new_mprop->bump_strength = 0.0;
428 
429   new_mprop->aProperty = vtkProperty::New ();
430   return new_mprop;
431 }
432 
433 
434 /* Create a new mesh */
create_mesh(char * name,int vertices,int faces)435 static vtk3DSMesh *create_mesh (char *name, int vertices, int faces)
436 {
437   vtk3DSMesh *new_mesh;
438 
439   new_mesh = (vtk3DSMesh *) malloc (sizeof(*new_mesh));
440   strcpy (new_mesh->name, name);
441 
442   new_mesh->vertices = vertices;
443 
444   if (vertices <= 0)
445     {
446     new_mesh->vertex = NULL;
447     }
448   else
449     {
450     new_mesh->vertex = (vtk3DSVector *) malloc(vertices * sizeof(*new_mesh->vertex));
451     }
452 
453   new_mesh->faces = faces;
454 
455   if (faces <= 0)
456     {
457     new_mesh->face = NULL;
458     new_mesh->mtl = NULL;
459     }
460   else
461     {
462     new_mesh->face = (vtk3DSFace *) malloc (faces * sizeof(*new_mesh->face));
463     new_mesh->mtl = (vtk3DSMaterial **) malloc (faces * sizeof(*new_mesh->mtl));
464     }
465 
466   new_mesh->hidden = 0;
467   new_mesh->shadow = 1;
468 
469   new_mesh->anActor = NULL;
470   new_mesh->aMapper = NULL;
471   new_mesh->aNormals = NULL;
472   new_mesh->aStripper = NULL;
473   new_mesh->aPoints = NULL;
474   new_mesh->aCellArray = NULL;
475   new_mesh->aPolyData = NULL;
476   return new_mesh;
477 }
478 
479 
parse_3ds_file(vtk3DSImporter * importer)480 static int parse_3ds_file(vtk3DSImporter *importer)
481 {
482   vtk3DSChunk chunk;
483 
484   start_chunk(importer, &chunk);
485 
486   if (chunk.tag == 0x4D4D)
487     {
488     parse_3ds (importer, &chunk);
489     }
490   else
491     {
492     vtkGenericWarningMacro(<< "Error: Input file is not .3DS format\n");
493     return 0;
494     }
495 
496   end_chunk (importer, &chunk);
497   return 1;
498 }
499 
parse_3ds(vtk3DSImporter * importer,vtk3DSChunk * mainchunk)500 static void parse_3ds (vtk3DSImporter *importer, vtk3DSChunk *mainchunk)
501 {
502   vtk3DSChunk chunk;
503 
504   do
505     {
506     start_chunk (importer, &chunk);
507 
508     if (chunk.end <= mainchunk->end)
509       {
510       switch (chunk.tag)
511         {
512         case 0x3D3D: parse_mdata (importer, &chunk);
513           break;
514         }
515       }
516     end_chunk (importer, &chunk);
517     } while (chunk.end <= mainchunk->end);
518 }
519 
520 
parse_mdata(vtk3DSImporter * importer,vtk3DSChunk * mainchunk)521 static void parse_mdata (vtk3DSImporter *importer, vtk3DSChunk *mainchunk)
522 {
523   vtk3DSChunk chunk;
524   vtk3DSColour bgnd_colour;
525 
526   do
527     {
528     start_chunk (importer, &chunk);
529 
530     if (chunk.end <= mainchunk->end)
531       {
532       switch (chunk.tag)
533         {
534         case 0x2100: parse_colour (importer, &global_amb);
535           break;
536         case 0x1200: parse_colour (importer, &bgnd_colour);
537           break;
538         case 0x2200: parse_fog (importer, &chunk);
539           break;
540         case 0x2210: parse_fog_bgnd(importer);
541           break;
542         case 0xAFFF: parse_mat_entry (importer, &chunk);
543           break;
544         case 0x4000: parse_named_object (importer, &chunk);
545           break;
546         }
547       }
548 
549     end_chunk (importer, &chunk);
550     } while (chunk.end <= mainchunk->end);
551 }
552 
553 
parse_fog(vtk3DSImporter * importer,vtk3DSChunk * mainchunk)554 static void parse_fog (vtk3DSImporter *importer, vtk3DSChunk *mainchunk)
555 {
556   vtk3DSChunk chunk;
557 
558   (void)read_float(importer);
559   (void)read_float(importer);
560   (void) read_float(importer);
561   (void)read_float(importer);
562 
563   parse_colour (importer, &fog_colour);
564 
565   do
566     {
567     start_chunk (importer, &chunk);
568 
569     if (chunk.end <= mainchunk->end)
570       {
571       switch (chunk.tag)
572         {
573         case 0x2210: parse_fog_bgnd(importer);
574           break;
575         }
576       }
577 
578     end_chunk (importer, &chunk);
579     } while (chunk.end <= mainchunk->end);
580 }
581 
582 
parse_fog_bgnd(vtk3DSImporter * vtkNotUsed (importer))583 static void parse_fog_bgnd(vtk3DSImporter *vtkNotUsed(importer))
584 {
585 }
586 
587 
parse_mat_entry(vtk3DSImporter * importer,vtk3DSChunk * mainchunk)588 static void parse_mat_entry (vtk3DSImporter *importer, vtk3DSChunk *mainchunk)
589 {
590   vtk3DSChunk chunk;
591   vtk3DSMatProp *mprop;
592 
593   mprop = create_mprop();
594 
595   do
596     {
597     start_chunk (importer, &chunk);
598     if (chunk.end <= mainchunk->end)
599       {
600       switch (chunk.tag)
601         {
602         case 0xA000: strcpy (mprop->name, read_string(importer));
603           cleanup_name (mprop->name);
604           break;
605 
606         case 0xA010: parse_colour (importer, &mprop->ambient);
607           break;
608 
609         case 0xA020: parse_colour (importer, &mprop->diffuse);
610           break;
611 
612         case 0xA030: parse_colour (importer, &mprop->specular);
613           break;
614 
615         case 0xA040: mprop->shininess = 100.0*parse_percentage(importer);
616           break;
617 
618         case 0xA050: mprop->transparency = parse_percentage(importer);
619           break;
620 
621         case 0xA080: mprop->self_illum = 1;
622           break;
623 
624         case 0xA220: mprop->reflection = parse_percentage(importer);
625           (void)parse_mapname (importer, &chunk);
626           break;
627 
628         case 0xA310: if (mprop->reflection == 0.0)
629           {
630           mprop->reflection = 1.0;
631           }
632         break;
633 
634         case 0xA200: mprop->tex_strength = parse_percentage(importer);
635           strcpy (mprop->tex_map, parse_mapname (importer, &chunk));
636           break;
637 
638         case 0xA230: mprop->bump_strength = parse_percentage(importer);
639           strcpy (mprop->bump_map, parse_mapname (importer, &chunk));
640           break;
641         }
642       }
643 
644     end_chunk (importer, &chunk);
645     } while (chunk.end <= mainchunk->end);
646 
647     VTK_LIST_INSERT (importer->MatPropList, mprop);
648 }
649 
650 
parse_mapname(vtk3DSImporter * importer,vtk3DSChunk * mainchunk)651 static char *parse_mapname (vtk3DSImporter *importer, vtk3DSChunk *mainchunk)
652 {
653   static char name[80] = "";
654   vtk3DSChunk chunk;
655 
656   do
657     {
658     start_chunk (importer, &chunk);
659 
660     if (chunk.end <= mainchunk->end)
661       {
662       switch (chunk.tag)
663         {
664         case 0xA300: strcpy (name, read_string(importer));
665           break;
666         }
667       }
668 
669     end_chunk (importer, &chunk);
670     } while (chunk.end <= mainchunk->end);
671 
672     return name;
673 }
674 
675 
parse_named_object(vtk3DSImporter * importer,vtk3DSChunk * mainchunk)676 static void parse_named_object (vtk3DSImporter *importer, vtk3DSChunk *mainchunk)
677 {
678   vtk3DSMesh *mesh;
679   vtk3DSChunk chunk;
680 
681   strcpy (obj_name, read_string(importer));
682   cleanup_name (obj_name);
683 
684   mesh = NULL;
685 
686   do
687     {
688     start_chunk (importer, &chunk);
689     if (chunk.end <= mainchunk->end)
690       {
691       switch (chunk.tag)
692         {
693         case 0x4100: parse_n_tri_object (importer, &chunk);
694           break;
695         case 0x4600: parse_n_direct_light (importer, &chunk);
696           break;
697         case 0x4700: parse_n_camera(importer);
698           break;
699         case 0x4010: if (mesh != NULL)
700           {
701           mesh->hidden = 1;
702           }
703         break;
704         case 0x4012: if (mesh != NULL)
705           {
706           mesh->shadow = 0;
707           }
708         break;
709         }
710       }
711 
712     end_chunk (importer, &chunk);
713     } while (chunk.end <= mainchunk->end);
714 
715 }
716 
parse_n_tri_object(vtk3DSImporter * importer,vtk3DSChunk * mainchunk)717 static void parse_n_tri_object (vtk3DSImporter *importer, vtk3DSChunk *mainchunk)
718 {
719   vtk3DSMesh *mesh;
720   vtk3DSChunk chunk;
721 
722   mesh = create_mesh (obj_name, 0, 0);
723 
724   do
725     {
726     start_chunk (importer, &chunk);
727 
728     if (chunk.end <= mainchunk->end)
729       {
730       switch (chunk.tag)
731         {
732         case 0x4110: parse_point_array(importer, mesh);
733           break;
734         case 0x4120: parse_face_array (importer, mesh, &chunk);
735           break;
736         case 0x4160: parse_mesh_matrix(importer, mesh);
737           break;
738         }
739       }
740 
741     end_chunk (importer, &chunk);
742     } while (chunk.end <= mainchunk->end);
743 
744   VTK_LIST_INSERT (importer->MeshList, mesh);
745 }
746 
747 
parse_point_array(vtk3DSImporter * importer,vtk3DSMesh * mesh)748 static void parse_point_array(vtk3DSImporter *importer, vtk3DSMesh *mesh)
749 {
750   int i;
751 
752   mesh->vertices = read_word(importer);
753   mesh->vertex = (vtk3DSVector *) malloc (mesh->vertices * sizeof(*(mesh->vertex)));
754   for (i = 0; i < mesh->vertices; i++)
755     {
756     read_point (importer, mesh->vertex[i]);
757     }
758 }
759 
parse_face_array(vtk3DSImporter * importer,vtk3DSMesh * mesh,vtk3DSChunk * mainchunk)760 static void parse_face_array (vtk3DSImporter *importer, vtk3DSMesh *mesh, vtk3DSChunk *mainchunk)
761 {
762   vtk3DSChunk chunk;
763   int i;
764 
765   mesh->faces = read_word(importer);
766   mesh->face = (vtk3DSFace *) malloc (mesh->faces * sizeof(*(mesh->face)));
767   mesh->mtl = (vtk3DSMaterial **) malloc (mesh->faces * sizeof(*(mesh->mtl)));
768 
769   for (i = 0; i < mesh->faces; i++)
770     {
771     mesh->face[i].a = read_word(importer);
772     mesh->face[i].b = read_word(importer);
773     mesh->face[i].c = read_word(importer);
774     (void)read_word(importer);
775 
776     mesh->mtl[i] = NULL;
777     }
778 
779   do
780     {
781     start_chunk (importer, &chunk);
782     if (chunk.end <= mainchunk->end)
783       {
784       switch (chunk.tag)
785         {
786         case 0x4130: parse_msh_mat_group(importer, mesh);
787           break;
788         case 0x4150: parse_smooth_group(importer);
789           break;
790         }
791       }
792 
793     end_chunk (importer, &chunk);
794     } while (chunk.end <= mainchunk->end);
795 
796   for (i = 0; i < mesh->faces; i++)
797     {
798     if (mesh->mtl[i] == (vtk3DSMaterial *) NULL)
799       {
800       mesh->mtl[i] = update_materials (importer, "Default", 0);
801       }
802     }
803 }
804 
805 
parse_msh_mat_group(vtk3DSImporter * importer,vtk3DSMesh * mesh)806 static void parse_msh_mat_group(vtk3DSImporter *importer, vtk3DSMesh *mesh)
807 {
808   vtk3DSMaterial *new_mtl;
809   char mtlname[80];
810   int  mtlcnt;
811   int  i, face;
812 
813   strcpy (mtlname, read_string(importer));
814   cleanup_name (mtlname);
815 
816   new_mtl = update_materials (importer, mtlname, 0);
817 
818   mtlcnt = read_word(importer);
819 
820   for (i = 0; i < mtlcnt; i++)
821     {
822     face = read_word(importer);
823     mesh->mtl[face] = new_mtl;
824     }
825 }
826 
parse_smooth_group(vtk3DSImporter * vtkNotUsed (importer))827 static void parse_smooth_group(vtk3DSImporter *vtkNotUsed(importer))
828 {
829 }
830 
parse_mesh_matrix(vtk3DSImporter * vtkNotUsed (importer),vtk3DSMesh * vtkNotUsed (mesh))831 static void parse_mesh_matrix(vtk3DSImporter *vtkNotUsed(importer), vtk3DSMesh *vtkNotUsed(mesh))
832 {
833   //  vtkGenericWarningMacro(<< "mesh matrix detected but not used\n");
834 }
835 
836 
parse_n_direct_light(vtk3DSImporter * importer,vtk3DSChunk * mainchunk)837 static void parse_n_direct_light (vtk3DSImporter *importer, vtk3DSChunk *mainchunk)
838 {
839   vtk3DSChunk chunk;
840   vtk3DSSpotLight *s;
841   vtk3DSOmniLight *o;
842   int spot_flag = 0;
843 
844   read_point (importer, pos);
845   parse_colour (importer, &col);
846 
847   do
848     {
849     start_chunk (importer, &chunk);
850 
851     if (chunk.end <= mainchunk->end)
852       {
853       switch (chunk.tag)
854         {
855         case 0x4620: break;
856         case 0x4610: parse_dl_spotlight(importer);
857           spot_flag = 1;
858           break;
859         }
860       }
861 
862     end_chunk (importer, &chunk);
863     } while (chunk.end <= mainchunk->end);
864 
865   if (!spot_flag)
866     {
867     o = (vtk3DSOmniLight *) VTK_LIST_FIND (importer->OmniList, obj_name);
868 
869     if (o != NULL)
870       {
871       pos[0] = o->pos[0];
872       pos[1] = o->pos[1];
873       pos[2] = o->pos[2];
874       col    = o->col;
875       }
876     else
877       {
878       o = (vtk3DSOmniLight *) malloc (sizeof (*o));
879       o->pos[0] = pos[0];
880       o->pos[1] = pos[1];
881       o->pos[2] = pos[2];
882       o->col = col   ;
883       strcpy (o->name, obj_name);
884       VTK_LIST_INSERT (importer->OmniList, o);
885       }
886     }
887   else
888     {
889     s = (vtk3DSSpotLight *) VTK_LIST_FIND (importer->SpotLightList, obj_name);
890 
891     if (s != NULL)
892       {
893       pos[0]    = s->pos[0];
894       pos[1]    = s->pos[1];
895       pos[2]    = s->pos[2];
896       target[0] = s->target[0];
897       target[1] = s->target[1];
898       target[2] = s->target[2];
899       col       = s->col;
900       hotspot   = s->hotspot;
901       falloff   = s->falloff;
902       }
903     else
904       {
905       if (falloff <= 0.0)
906         {
907         falloff = 180.0;
908         }
909       if (hotspot <= 0.0)
910         {
911         hotspot = 0.7*falloff;
912         }
913       s = (vtk3DSSpotLight *) malloc (sizeof (*s));
914       s->pos[0] = pos[0];
915       s->pos[1] = pos[1];
916       s->pos[2] = pos[2];
917       s->target[0] = target[0];
918       s->target[1] = target[1];
919       s->target[2] = target[2];
920       s->col = col   ;
921       s->hotspot = hotspot;
922       s->falloff = falloff;
923       strcpy (s->name, obj_name);
924       VTK_LIST_INSERT (importer->SpotLightList, s);
925       }
926     }
927 }
928 
929 
parse_dl_spotlight(vtk3DSImporter * importer)930 static void parse_dl_spotlight(vtk3DSImporter *importer)
931 {
932   read_point (importer, target);
933 
934   hotspot = read_float(importer);
935   falloff = read_float(importer);
936 }
937 
938 
parse_n_camera(vtk3DSImporter * importer)939 static void parse_n_camera(vtk3DSImporter *importer)
940 {
941   float  bank;
942   float  lens;
943   vtk3DSCamera *c = (vtk3DSCamera *) malloc (sizeof (vtk3DSCamera));
944 
945   read_point (importer, pos);
946   read_point (importer, target);
947   bank = read_float(importer);
948   lens = read_float(importer);
949 
950   strcpy (c->name, obj_name);
951   c->pos[0] = pos[0];
952   c->pos[1] = pos[1];
953   c->pos[2] = pos[2];
954   c->target[0] = target[0];
955   c->target[1] = target[1];
956   c->target[2] = target[2];
957   c->lens = lens;
958   c->bank = bank;
959 
960   VTK_LIST_INSERT (importer->CameraList, c);
961 }
962 
parse_colour(vtk3DSImporter * importer,vtk3DSColour * colour)963 static void parse_colour (vtk3DSImporter *importer, vtk3DSColour *colour)
964 {
965   vtk3DSChunk chunk;
966   vtk3DSColour_24 colour_24;
967 
968   start_chunk (importer, &chunk);
969 
970   switch (chunk.tag)
971     {
972     case 0x0010: parse_colour_f (importer, colour);
973       break;
974 
975     case 0x0011: parse_colour_24 (importer, &colour_24);
976       colour->red   = colour_24.red/255.0;
977       colour->green = colour_24.green/255.0;
978       colour->blue  = colour_24.blue/255.0;
979       break;
980 
981     default: vtkGenericWarningMacro(<< "Error parsing colour");
982     }
983 
984   end_chunk (importer, &chunk);
985 }
986 
987 
parse_colour_f(vtk3DSImporter * importer,vtk3DSColour * colour)988 static void parse_colour_f (vtk3DSImporter *importer, vtk3DSColour *colour)
989 {
990   colour->red   = read_float(importer);
991   colour->green = read_float(importer);
992   colour->blue  = read_float(importer);
993 }
994 
995 
parse_colour_24(vtk3DSImporter * importer,vtk3DSColour_24 * colour)996 static void parse_colour_24 (vtk3DSImporter *importer, vtk3DSColour_24 *colour)
997 {
998   colour->red   = read_byte(importer);
999   colour->green = read_byte(importer);
1000   colour->blue  = read_byte(importer);
1001 }
1002 
1003 
parse_percentage(vtk3DSImporter * importer)1004 static float parse_percentage(vtk3DSImporter *importer)
1005 {
1006   vtk3DSChunk chunk;
1007   float percent = 0.0;
1008 
1009   start_chunk (importer, &chunk);
1010 
1011   switch (chunk.tag)
1012     {
1013     case 0x0030: percent = parse_int_percentage(importer)/100.0;
1014       break;
1015 
1016     case 0x0031: percent = parse_float_percentage(importer);
1017       break;
1018 
1019     default:     vtkGenericWarningMacro( << "Error parsing percentage\n");
1020     }
1021 
1022   end_chunk (importer, &chunk);
1023 
1024   return percent;
1025 }
1026 
1027 
parse_int_percentage(vtk3DSImporter * importer)1028 static short parse_int_percentage(vtk3DSImporter *importer)
1029 {
1030   word percent = read_word(importer);
1031 
1032   return percent;
1033 }
1034 
1035 
parse_float_percentage(vtk3DSImporter * importer)1036 static float parse_float_percentage(vtk3DSImporter *importer)
1037 {
1038   float percent = read_float(importer);
1039 
1040   return percent;
1041 }
1042 
1043 
start_chunk(vtk3DSImporter * importer,vtk3DSChunk * chunk)1044 static void start_chunk (vtk3DSImporter *importer, vtk3DSChunk *chunk)
1045 {
1046   chunk->start  = ftell(importer->GetFileFD());
1047   chunk->tag    = peek_word(importer);
1048   chunk->length = peek_dword(importer);
1049   if (chunk->length == 0)
1050     {
1051     chunk->length = 1;
1052     }
1053   chunk->end    = chunk->start + chunk->length;
1054 }
1055 
1056 
end_chunk(vtk3DSImporter * importer,vtk3DSChunk * chunk)1057 static void end_chunk (vtk3DSImporter *importer, vtk3DSChunk *chunk)
1058 {
1059   fseek (importer->GetFileFD(), chunk->end, 0);
1060 }
1061 
1062 
read_byte(vtk3DSImporter * importer)1063 static byte read_byte(vtk3DSImporter *importer)
1064 {
1065   byte data;
1066 
1067   data = fgetc (importer->GetFileFD());
1068 
1069   return data;
1070 }
1071 
1072 
read_word(vtk3DSImporter * importer)1073 static word read_word(vtk3DSImporter *importer)
1074 {
1075   word data;
1076 
1077   if (fread (&data, 2, 1, importer->GetFileFD()) != 1)
1078     {
1079     vtkErrorWithObjectMacro(
1080       importer, "Pre-mature end of file in read_word\n");
1081     data = 0;
1082     }
1083   vtkByteSwap::Swap2LE ((short *) &data);
1084   return data;
1085 }
1086 
peek_word(vtk3DSImporter * importer)1087 static word peek_word(vtk3DSImporter *importer)
1088 {
1089   word data;
1090 
1091   if (fread (&data, 2, 1, importer->GetFileFD()) != 1)
1092     {
1093     data = 0;
1094     }
1095   vtkByteSwap::Swap2LE ((short *) &data);
1096   return data;
1097 }
1098 
peek_dword(vtk3DSImporter * importer)1099 static dword peek_dword(vtk3DSImporter *importer)
1100 {
1101   dword data;
1102 
1103   if (fread (&data, 4, 1, importer->GetFileFD()) != 1)
1104     {
1105     data = 0;
1106     }
1107 
1108   vtkByteSwap::Swap4LE ((char *) &data);
1109   return data;
1110 }
1111 
read_float(vtk3DSImporter * importer)1112 static float read_float(vtk3DSImporter *importer)
1113 {
1114   float data;
1115 
1116   if (fread (&data, 4, 1, importer->GetFileFD()) != 1)
1117     {
1118     vtkErrorWithObjectMacro(
1119       importer, "Pre-mature end of file in read_float\n");
1120     data = 0;
1121     }
1122 
1123   vtkByteSwap::Swap4LE ((char *) &data);
1124   return data;
1125 }
1126 
1127 
read_point(vtk3DSImporter * importer,vtk3DSVector v)1128 static void read_point (vtk3DSImporter *importer, vtk3DSVector v)
1129 {
1130   v[0] = read_float(importer);
1131   v[1] = read_float(importer);
1132   v[2] = read_float(importer);
1133 }
1134 
1135 
read_string(vtk3DSImporter * importer)1136 static char *read_string(vtk3DSImporter *importer)
1137 {
1138   static char string[80];
1139   int i;
1140 
1141   for (i = 0; i < 80; i++)
1142     {
1143     string[i] = read_byte(importer);
1144 
1145     if (string[i] == '\0')
1146       {
1147       break;
1148       }
1149     }
1150 
1151     return string;
1152 }
1153 
1154 
1155 
cleanup_name(char * name)1156 static void cleanup_name (char *name)
1157 {
1158   char *tmp = (char *) malloc (strlen(name)+2);
1159   int  i;
1160 
1161     /* Remove any leading blanks or quotes */
1162   i = 0;
1163   while ((name[i] == ' ' || name[i] == '"') && name[i] != '\0')
1164     {
1165     i++;
1166     }
1167   strcpy (tmp, &name[i]);
1168 
1169     /* Remove any trailing blanks or quotes */
1170   for (i = static_cast<int>(strlen(tmp))-1; i >= 0; i--)
1171     {
1172     if (isprint(tmp[i]) && !isspace(tmp[i]) && tmp[i] != '"')
1173       {
1174       break;
1175       }
1176     else
1177       {
1178       tmp[i] = '\0';
1179       }
1180     }
1181 
1182     strcpy (name, tmp);
1183 
1184     /* Prefix the letter 'N' to materials that begin with a digit */
1185     if (!isdigit (name[0]))
1186       {
1187       strcpy (tmp, name);
1188       }
1189     else
1190       {
1191       tmp[0] = 'N';
1192       strcpy (&tmp[1], name);
1193       }
1194 
1195     /* Replace all illegal charaters in name with underscores */
1196     for (i = 0; tmp[i] != '\0'; i++)
1197       {
1198       if (!isalnum(tmp[i]))
1199         {
1200         tmp[i] = '_';
1201         }
1202       }
1203 
1204     strcpy (name, tmp);
1205 
1206     free (tmp);
1207 }
1208 
~vtk3DSImporter()1209 vtk3DSImporter::~vtk3DSImporter()
1210 {
1211   vtk3DSOmniLight *omniLight;
1212   vtk3DSSpotLight *spotLight;
1213 
1214   // walk the light list and delete vtk objects
1215   for (omniLight = this->OmniList; omniLight != (vtk3DSOmniLight *) NULL; omniLight = (vtk3DSOmniLight *) omniLight->next)
1216     {
1217     omniLight->aLight->Delete();
1218     }
1219   VTK_LIST_KILL (this->OmniList);
1220 
1221   // walk the spot light list and delete vtk objects
1222   for (spotLight = this->SpotLightList; spotLight != (vtk3DSSpotLight *) NULL;
1223        spotLight = (vtk3DSSpotLight *) spotLight->next)
1224     {
1225     spotLight->aLight->Delete();
1226     }
1227   VTK_LIST_KILL (this->SpotLightList);
1228 
1229   vtk3DSCamera *camera;
1230   // walk the camera list and delete vtk objects
1231   for (camera = this->CameraList; camera != (vtk3DSCamera *) NULL;
1232        camera = (vtk3DSCamera *) camera->next)
1233     {
1234     camera->aCamera->Delete ();
1235     }
1236   VTK_LIST_KILL (this->CameraList);
1237 
1238   // walk the mesh list and delete malloced datra and vtk objects
1239   vtk3DSMesh *mesh;
1240   for (mesh = this->MeshList; mesh != (vtk3DSMesh *) NULL;
1241        mesh = (vtk3DSMesh *) mesh->next)
1242     {
1243     if (mesh->anActor != NULL)
1244       {
1245       mesh->anActor->Delete ();
1246       }
1247     if (mesh->aMapper != NULL)
1248       {
1249       mesh->aMapper->Delete ();
1250       }
1251     if (mesh->aNormals != NULL)
1252       {
1253       mesh->aNormals->Delete ();
1254       }
1255     if (mesh->aStripper != NULL)
1256       {
1257       mesh->aStripper->Delete ();
1258       }
1259     if (mesh->aPoints != NULL)
1260       {
1261       mesh->aPoints->Delete ();
1262       }
1263     if (mesh->aCellArray != NULL)
1264       {
1265       mesh->aCellArray->Delete ();
1266       }
1267     if (mesh->aPolyData != NULL)
1268       {
1269       mesh->aPolyData->Delete ();
1270       }
1271     if (mesh->vertex)
1272       {
1273       free (mesh->vertex);
1274       }
1275     if (mesh->face)
1276       {
1277       free (mesh->face);
1278       }
1279     if (mesh->mtl)
1280       {
1281       free (mesh->mtl);
1282       }
1283     }
1284 
1285   // then delete the list structure
1286 
1287   VTK_LIST_KILL (this->MeshList);
1288   VTK_LIST_KILL (this->MaterialList);
1289 
1290   // objects allocated in Material Property List
1291   vtk3DSMatProp *m;
1292   // just walk the list of material properties, deleting vtk properties
1293   for (m = this->MatPropList; m != (vtk3DSMatProp *) NULL; m = (vtk3DSMatProp *) m->next)
1294     {
1295     m->aProperty->Delete();
1296     }
1297 
1298   // then delete the list structure
1299   VTK_LIST_KILL (this->MatPropList);
1300 
1301   delete [] this->FileName;
1302 }
1303 
PrintSelf(ostream & os,vtkIndent indent)1304 void vtk3DSImporter::PrintSelf(ostream& os, vtkIndent indent)
1305 {
1306   this->Superclass::PrintSelf(os,indent);
1307   os << indent << "File Name: "
1308      << (this->FileName ? this->FileName : "(none)") << "\n";
1309 
1310   os << indent << "Compute Normals: "
1311      << (this->ComputeNormals ? "On\n" : "Off\n");
1312 }
1313 
1314 
1315 
1316 
1317 
1318 
1319