/*========================================================================= Program: Visualization Toolkit Module: vtk3DSImporter.cxx Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen All rights reserved. See Copyright.txt or http://www.kitware.com/Copyright.htm for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notice for more information. =========================================================================*/ #include "vtk3DSImporter.h" #include "vtkActor.h" #include "vtkByteSwap.h" #include "vtkCamera.h" #include "vtkCellArray.h" #include "vtkLight.h" #include "vtkObjectFactory.h" #include "vtkPolyData.h" #include "vtkPolyDataMapper.h" #include "vtkPolyDataNormals.h" #include "vtkProperty.h" #include "vtkRenderer.h" #include "vtkStripper.h" #include "vtksys/SystemTools.hxx" #include vtkStandardNewMacro(vtk3DSImporter); // Silence warning like // "dereferencing type-punned pointer will break strict-aliasing rules" // This file just has too many of them. // This is due to the use of (vtk3DSList **)&root in VTK_LIST_* macros // defined in vtk3DS.h #if defined(__GNUC__) #pragma GCC diagnostic ignored "-Wstrict-aliasing" #endif // Wrap these globals in a namespace to prevent identifier collisions with // inline code on MSVC2015: namespace vtk3DS { static vtk3DSColour black = { 0.0f, 0.0f, 0.0f }; static char objName[80] = ""; static vtk3DSColour fogColour = { 0.0f, 0.0f, 0.0f }; static vtk3DSColour col = { 0.0f, 0.0f, 0.0f }; static vtk3DSColour globalAmb = { 0.1f, 0.1f, 0.1f }; static vtk3DSVector pos = { 0.0, 0.0, 0.0 }; static vtk3DSVector target = { 0.0, 0.0, 0.0 }; static float hotspot = -1; static float falloff = -1; /* Default material property */ static vtk3DSMatProp defaultMaterial = { "Default", nullptr, { 1.0, 1.0, 1.0 }, { 1.0, 1.0, 1.0 }, { 1.0, 1.0, 1.0 }, 70.0, // shininess 0.0, // transparency 0.0, // reflection 0, // self illumination "", // tex_map 0.0, // tex_strength "", // bump_map 0.0, // bump_strength nullptr }; // vtkProperty } // end namespace vtk3DS static void cleanup_name(char*); static void list_insert(vtk3DSList** root, vtk3DSList* new_node); static void* list_find(vtk3DSList** root, const char* name); static void list_kill(vtk3DSList** root); static vtk3DSMatProp* create_mprop(); static vtk3DSMesh* create_mesh(char* name, int vertices, int faces); static int parse_3ds_file(vtk3DSImporter* importer); static void parse_3ds(vtk3DSImporter* importer, vtk3DSChunk* mainchunk); static void parse_mdata(vtk3DSImporter* importer, vtk3DSChunk* mainchunk); static void parse_fog(vtk3DSImporter* importer, vtk3DSChunk* mainchunk); static void parse_fog_bgnd(vtk3DSImporter* importer); static void parse_mat_entry(vtk3DSImporter* importer, vtk3DSChunk* mainchunk); static char* parse_mapname(vtk3DSImporter* importer, vtk3DSChunk* mainchunk); static void parse_named_object(vtk3DSImporter* importer, vtk3DSChunk* mainchunk); static void parse_n_tri_object(vtk3DSImporter* importer, vtk3DSChunk* mainchunk); static void parse_point_array(vtk3DSImporter* importer, vtk3DSMesh* mesh); static void parse_face_array(vtk3DSImporter* importer, vtk3DSMesh* mesh, vtk3DSChunk* mainchunk); static void parse_msh_mat_group(vtk3DSImporter* importer, vtk3DSMesh* mesh); static void parse_smooth_group(vtk3DSImporter* importer); static void parse_mesh_matrix(vtk3DSImporter* importer, vtk3DSMesh* mesh); static void parse_n_direct_light(vtk3DSImporter* importer, vtk3DSChunk* mainchunk); static void parse_dl_spotlight(vtk3DSImporter* importer); static void parse_n_camera(vtk3DSImporter* importer); static void parse_colour(vtk3DSImporter* importer, vtk3DSColour* colour); static void parse_colour_f(vtk3DSImporter* importer, vtk3DSColour* colour); static void parse_colour_24(vtk3DSImporter* importer, vtk3DSColour_24* colour); static float parse_percentage(vtk3DSImporter* importer); static short parse_int_percentage(vtk3DSImporter* importer); static float parse_float_percentage(vtk3DSImporter* importer); static vtk3DSMaterial* update_materials( vtk3DSImporter* importer, const char* new_material, int ext); static void start_chunk(vtk3DSImporter* importer, vtk3DSChunk* chunk); static void end_chunk(vtk3DSImporter* importer, vtk3DSChunk* chunk); static byte read_byte(vtk3DSImporter* importer); static word read_word(vtk3DSImporter* importer); static word peek_word(vtk3DSImporter* importer); static dword peek_dword(vtk3DSImporter* importer); static float read_float(vtk3DSImporter* importer); static void read_point(vtk3DSImporter* importer, vtk3DSVector v); static char* read_string(vtk3DSImporter* importer); vtk3DSImporter::vtk3DSImporter() { this->OmniList = nullptr; this->SpotLightList = nullptr; this->CameraList = nullptr; this->MeshList = nullptr; this->MaterialList = nullptr; this->MatPropList = nullptr; this->FileName = nullptr; this->FileFD = nullptr; this->ComputeNormals = 0; } int vtk3DSImporter::ImportBegin() { vtkDebugMacro(<< "Opening import file as binary"); this->FileFD = vtksys::SystemTools::Fopen(this->FileName, "rb"); if (this->FileFD == nullptr) { vtkErrorMacro(<< "Unable to open file: " << this->FileName); return 0; } return this->Read3DS(); } void vtk3DSImporter::ImportEnd() { vtkDebugMacro(<< "Closing import file"); if (this->FileFD != nullptr) { fclose(this->FileFD); } this->FileFD = nullptr; } //------------------------------------------------------------------------------ std::string vtk3DSImporter::GetOutputsDescription() { std::stringstream ss; size_t idx = 0; for (auto mesh = this->MeshList; mesh != (vtk3DSMesh*)nullptr; mesh = (vtk3DSMesh*)mesh->next, idx++) { if (mesh->aPolyData) { ss << "Mesh " << idx << " polydata:\n"; ss << vtkImporter::GetDataSetDescription(mesh->aPolyData, vtkIndent(1)); } } return ss.str(); } int vtk3DSImporter::Read3DS() { vtk3DSMatProp* aMaterial; if (parse_3ds_file(this) == 0) { vtkErrorMacro(<< "Error readings .3ds file: " << this->FileName << "\n"); return 0; } // create a vtk3DSMatProp and fill if in with default aMaterial = (vtk3DSMatProp*)malloc(sizeof(vtk3DSMatProp)); *aMaterial = vtk3DS::defaultMaterial; aMaterial->aProperty = vtkProperty::New(); VTK_LIST_INSERT(this->MatPropList, aMaterial); return 1; } void vtk3DSImporter::ImportActors(vtkRenderer* renderer) { vtk3DSMatProp* material; vtk3DSMesh* mesh; vtkStripper* polyStripper; vtkPolyDataNormals* polyNormals; vtkPolyDataMapper* polyMapper; vtkPolyData* polyData; vtkActor* actor; // walk the list of meshes, creating actors for (mesh = this->MeshList; mesh != (vtk3DSMesh*)nullptr; mesh = (vtk3DSMesh*)mesh->next) { if (mesh->faces == 0) { vtkWarningMacro(<< "part " << mesh->name << " has zero faces... skipping\n"); continue; } polyData = this->GeneratePolyData(mesh); mesh->aMapper = polyMapper = vtkPolyDataMapper::New(); mesh->aStripper = polyStripper = vtkStripper::New(); // if ComputeNormals is on, insert a vtkPolyDataNormals filter if (this->ComputeNormals) { mesh->aNormals = polyNormals = vtkPolyDataNormals::New(); polyNormals->SetInputData(polyData); polyStripper->SetInputConnection(polyNormals->GetOutputPort()); } else { polyStripper->SetInputData(polyData); } polyMapper->SetInputConnection(polyStripper->GetOutputPort()); vtkDebugMacro(<< "Importing Actor: " << mesh->name); mesh->anActor = actor = vtkActor::New(); actor->SetMapper(polyMapper); material = (vtk3DSMatProp*)VTK_LIST_FIND(this->MatPropList, mesh->mtl[0]->name); actor->SetProperty(material->aProperty); renderer->AddActor(actor); } } vtkPolyData* vtk3DSImporter::GeneratePolyData(vtk3DSMesh* mesh) { int i; vtk3DSFace* face; vtkCellArray* triangles; vtkPoints* vertices; vtkPolyData* polyData; face = mesh->face; mesh->aCellArray = triangles = vtkCellArray::New(); triangles->AllocateEstimate(mesh->faces, 3); for (i = 0; i < mesh->faces; i++, face++) { triangles->InsertNextCell(3); triangles->InsertCellPoint(face->a); triangles->InsertCellPoint(face->b); triangles->InsertCellPoint(face->c); } mesh->aPoints = vertices = vtkPoints::New(); vertices->Allocate(mesh->vertices); for (i = 0; i < mesh->vertices; i++) { vertices->InsertPoint(i, (float*)mesh->vertex[i]); } mesh->aPolyData = polyData = vtkPolyData::New(); polyData->SetPolys(triangles); polyData->SetPoints(vertices); return polyData; } void vtk3DSImporter::ImportCameras(vtkRenderer* renderer) { vtkCamera* aCamera; vtk3DSCamera* camera; // walk the list of cameras and create vtk cameras for (camera = this->CameraList; camera != (vtk3DSCamera*)nullptr; camera = (vtk3DSCamera*)camera->next) { camera->aCamera = aCamera = vtkCamera::New(); aCamera->SetPosition(camera->pos[0], camera->pos[1], camera->pos[2]); aCamera->SetFocalPoint(camera->target[0], camera->target[1], camera->target[2]); aCamera->SetViewUp(0, 0, 1); aCamera->SetClippingRange(.1, 10000); aCamera->Roll(camera->bank); renderer->SetActiveCamera(aCamera); vtkDebugMacro(<< "Importing Camera: " << camera->name); } } void vtk3DSImporter::ImportLights(vtkRenderer* renderer) { vtk3DSOmniLight* omniLight; vtk3DSSpotLight* spotLight; vtkLight* aLight; // just walk the list of omni lights, creating vtk lights for (omniLight = this->OmniList; omniLight != (vtk3DSOmniLight*)nullptr; omniLight = (vtk3DSOmniLight*)omniLight->next) { omniLight->aLight = aLight = vtkLight::New(); aLight->SetPosition(omniLight->pos[0], omniLight->pos[1], omniLight->pos[2]); aLight->SetFocalPoint(0, 0, 0); aLight->SetColor(omniLight->col.red, omniLight->col.green, omniLight->col.blue); renderer->AddLight(aLight); vtkDebugMacro(<< "Importing Omni Light: " << omniLight->name); } // now walk the list of spot lights, creating vtk lights for (spotLight = this->SpotLightList; spotLight != (vtk3DSSpotLight*)nullptr; spotLight = (vtk3DSSpotLight*)spotLight->next) { spotLight->aLight = aLight = vtkLight::New(); aLight->PositionalOn(); aLight->SetPosition(spotLight->pos[0], spotLight->pos[1], spotLight->pos[2]); aLight->SetFocalPoint(spotLight->target[0], spotLight->target[1], spotLight->target[2]); aLight->SetColor(spotLight->col.red, spotLight->col.green, spotLight->col.blue); aLight->SetConeAngle(spotLight->falloff); renderer->AddLight(aLight); vtkDebugMacro(<< "Importing Spot Light: " << spotLight->name); } } void vtk3DSImporter::ImportProperties(vtkRenderer* vtkNotUsed(renderer)) { float amb = 0.1, dif = 0.9; float dist_white, dist_diff, phong, phong_size; vtkProperty* property; vtk3DSMatProp* m; // just walk the list of material properties, creating vtk properties for (m = this->MatPropList; m != (vtk3DSMatProp*)nullptr; m = (vtk3DSMatProp*)m->next) { if (m->self_illum) { amb = 0.9; dif = 0.1; } dist_white = fabs(1.0 - m->specular.red) + fabs(1.0 - m->specular.green) + fabs(1.0 - m->specular.blue); dist_diff = fabs(m->diffuse.red - m->specular.red) + fabs(m->diffuse.green - m->specular.green) + fabs(m->diffuse.blue - m->specular.blue); if (dist_diff < dist_white) { dif = .1; amb = .8; } phong_size = 0.7 * m->shininess; if (phong_size < 1.0) { phong_size = 1.0; } if (phong_size > 30.0) { phong = 1.0; } else { phong = phong_size / 30.0; } property = m->aProperty; property->SetAmbientColor(m->ambient.red, m->ambient.green, m->ambient.blue); property->SetAmbient(amb); property->SetDiffuseColor(m->diffuse.red, m->diffuse.green, m->diffuse.blue); property->SetDiffuse(dif); property->SetSpecularColor(m->specular.red, m->specular.green, m->specular.blue); property->SetSpecular(phong); property->SetSpecularPower(phong_size); property->SetOpacity(1.0 - m->transparency); vtkDebugMacro(<< "Importing Property: " << m->name); m->aProperty = property; } } /* Insert a new node into the list */ static void list_insert(vtk3DSList** root, vtk3DSList* new_node) { new_node->next = *root; *root = new_node; } /* Find the node with the specified name */ static void* list_find(vtk3DSList** root, const char* name) { vtk3DSList* p; for (p = *root; p != (vtk3DSList*)nullptr; p = (vtk3DSList*)p->next) { if (strcmp(p->name, name) == 0) { break; } } return (void*)p; } /* Delete the entire list */ static void list_kill(vtk3DSList** root) { vtk3DSList* temp; while (*root != (vtk3DSList*)nullptr) { temp = *root; *root = (vtk3DSList*)(*root)->next; free(temp); } } /* Add a new material to the material list */ static vtk3DSMaterial* update_materials(vtk3DSImporter* importer, const char* new_material, int ext) { vtk3DSMaterial* p; p = (vtk3DSMaterial*)VTK_LIST_FIND(importer->MaterialList, new_material); if (p == nullptr) { p = (vtk3DSMaterial*)malloc(sizeof(*p)); strcpy(p->name, new_material); p->external = ext; VTK_LIST_INSERT(importer->MaterialList, p); } return p; } static vtk3DSMatProp* create_mprop() { vtk3DSMatProp* new_mprop; new_mprop = (vtk3DSMatProp*)malloc(sizeof(*new_mprop)); strcpy(new_mprop->name, ""); new_mprop->ambient = vtk3DS::black; new_mprop->diffuse = vtk3DS::black; new_mprop->specular = vtk3DS::black; new_mprop->shininess = 0.0; new_mprop->transparency = 0.0; new_mprop->reflection = 0.0; new_mprop->self_illum = 0; strcpy(new_mprop->tex_map, ""); new_mprop->tex_strength = 0.0; strcpy(new_mprop->bump_map, ""); new_mprop->bump_strength = 0.0; new_mprop->aProperty = vtkProperty::New(); return new_mprop; } /* Create a new mesh */ static vtk3DSMesh* create_mesh(char* name, int vertices, int faces) { vtk3DSMesh* new_mesh; new_mesh = (vtk3DSMesh*)malloc(sizeof(*new_mesh)); strcpy(new_mesh->name, name); new_mesh->vertices = vertices; if (vertices <= 0) { new_mesh->vertex = nullptr; } else { new_mesh->vertex = (vtk3DSVector*)malloc(vertices * sizeof(*new_mesh->vertex)); } new_mesh->faces = faces; if (faces <= 0) { new_mesh->face = nullptr; new_mesh->mtl = nullptr; } else { new_mesh->face = (vtk3DSFace*)malloc(faces * sizeof(*new_mesh->face)); // NOLINTNEXTLINE(bugprone-sizeof-expression) new_mesh->mtl = (vtk3DSMaterial**)malloc(faces * sizeof(*new_mesh->mtl)); } new_mesh->hidden = 0; new_mesh->shadow = 1; new_mesh->anActor = nullptr; new_mesh->aMapper = nullptr; new_mesh->aNormals = nullptr; new_mesh->aStripper = nullptr; new_mesh->aPoints = nullptr; new_mesh->aCellArray = nullptr; new_mesh->aPolyData = nullptr; return new_mesh; } static int parse_3ds_file(vtk3DSImporter* importer) { vtk3DSChunk chunk; start_chunk(importer, &chunk); if (chunk.tag == 0x4D4D) { parse_3ds(importer, &chunk); } else { vtkGenericWarningMacro(<< "Error: Input file is not .3DS format\n"); return 0; } end_chunk(importer, &chunk); return 1; } static void parse_3ds(vtk3DSImporter* importer, vtk3DSChunk* mainchunk) { vtk3DSChunk chunk; do { start_chunk(importer, &chunk); if (chunk.end <= mainchunk->end) { switch (chunk.tag) { case 0x3D3D: parse_mdata(importer, &chunk); break; } } end_chunk(importer, &chunk); } while (chunk.end <= mainchunk->end); } static void parse_mdata(vtk3DSImporter* importer, vtk3DSChunk* mainchunk) { vtk3DSChunk chunk; vtk3DSColour bgnd_colour; do { start_chunk(importer, &chunk); if (chunk.end <= mainchunk->end) { switch (chunk.tag) { case 0x2100: parse_colour(importer, &vtk3DS::globalAmb); break; case 0x1200: parse_colour(importer, &bgnd_colour); break; case 0x2200: parse_fog(importer, &chunk); break; case 0x2210: parse_fog_bgnd(importer); break; case 0xAFFF: parse_mat_entry(importer, &chunk); break; case 0x4000: parse_named_object(importer, &chunk); break; } } end_chunk(importer, &chunk); } while (chunk.end <= mainchunk->end); } static void parse_fog(vtk3DSImporter* importer, vtk3DSChunk* mainchunk) { vtk3DSChunk chunk; (void)read_float(importer); (void)read_float(importer); (void)read_float(importer); (void)read_float(importer); parse_colour(importer, &vtk3DS::fogColour); do { start_chunk(importer, &chunk); if (chunk.end <= mainchunk->end) { switch (chunk.tag) { case 0x2210: parse_fog_bgnd(importer); break; } } end_chunk(importer, &chunk); } while (chunk.end <= mainchunk->end); } static void parse_fog_bgnd(vtk3DSImporter* vtkNotUsed(importer)) {} static void parse_mat_entry(vtk3DSImporter* importer, vtk3DSChunk* mainchunk) { vtk3DSChunk chunk; vtk3DSMatProp* mprop; mprop = create_mprop(); do { start_chunk(importer, &chunk); if (chunk.end <= mainchunk->end) { switch (chunk.tag) { case 0xA000: strcpy(mprop->name, read_string(importer)); cleanup_name(mprop->name); break; case 0xA010: parse_colour(importer, &mprop->ambient); break; case 0xA020: parse_colour(importer, &mprop->diffuse); break; case 0xA030: parse_colour(importer, &mprop->specular); break; case 0xA040: mprop->shininess = 100.0 * parse_percentage(importer); break; case 0xA050: mprop->transparency = parse_percentage(importer); break; case 0xA080: mprop->self_illum = 1; break; case 0xA220: mprop->reflection = parse_percentage(importer); (void)parse_mapname(importer, &chunk); break; case 0xA310: if (mprop->reflection == 0.0) { mprop->reflection = 1.0; } break; case 0xA200: mprop->tex_strength = parse_percentage(importer); strcpy(mprop->tex_map, parse_mapname(importer, &chunk)); break; case 0xA230: mprop->bump_strength = parse_percentage(importer); strcpy(mprop->bump_map, parse_mapname(importer, &chunk)); break; } } end_chunk(importer, &chunk); } while (chunk.end <= mainchunk->end); VTK_LIST_INSERT(importer->MatPropList, mprop); } static char* parse_mapname(vtk3DSImporter* importer, vtk3DSChunk* mainchunk) { static char name[80] = ""; vtk3DSChunk chunk; do { start_chunk(importer, &chunk); if (chunk.end <= mainchunk->end) { switch (chunk.tag) { case 0xA300: strcpy(name, read_string(importer)); break; } } end_chunk(importer, &chunk); } while (chunk.end <= mainchunk->end); return name; } static void parse_named_object(vtk3DSImporter* importer, vtk3DSChunk* mainchunk) { vtk3DSMesh* mesh; vtk3DSChunk chunk; strcpy(vtk3DS::objName, read_string(importer)); cleanup_name(vtk3DS::objName); mesh = nullptr; do { start_chunk(importer, &chunk); if (chunk.end <= mainchunk->end) { switch (chunk.tag) { case 0x4100: parse_n_tri_object(importer, &chunk); break; case 0x4600: parse_n_direct_light(importer, &chunk); break; case 0x4700: parse_n_camera(importer); break; case 0x4010: if (mesh != nullptr) { mesh->hidden = 1; } break; case 0x4012: if (mesh != nullptr) { mesh->shadow = 0; } break; } } end_chunk(importer, &chunk); } while (chunk.end <= mainchunk->end); } static void parse_n_tri_object(vtk3DSImporter* importer, vtk3DSChunk* mainchunk) { vtk3DSMesh* mesh; vtk3DSChunk chunk; mesh = create_mesh(vtk3DS::objName, 0, 0); do { start_chunk(importer, &chunk); if (chunk.end <= mainchunk->end) { switch (chunk.tag) { case 0x4110: parse_point_array(importer, mesh); break; case 0x4120: parse_face_array(importer, mesh, &chunk); break; case 0x4160: parse_mesh_matrix(importer, mesh); break; } } end_chunk(importer, &chunk); } while (chunk.end <= mainchunk->end); VTK_LIST_INSERT(importer->MeshList, mesh); } static void parse_point_array(vtk3DSImporter* importer, vtk3DSMesh* mesh) { int i; mesh->vertices = read_word(importer); mesh->vertex = (vtk3DSVector*)malloc(mesh->vertices * sizeof(*(mesh->vertex))); for (i = 0; i < mesh->vertices; i++) { read_point(importer, mesh->vertex[i]); } } static void parse_face_array(vtk3DSImporter* importer, vtk3DSMesh* mesh, vtk3DSChunk* mainchunk) { vtk3DSChunk chunk; int i; mesh->faces = read_word(importer); mesh->face = (vtk3DSFace*)malloc(mesh->faces * sizeof(*(mesh->face))); // NOLINTNEXTLINE(bugprone-sizeof-expression) mesh->mtl = (vtk3DSMaterial**)malloc(mesh->faces * sizeof(*mesh->mtl)); for (i = 0; i < mesh->faces; i++) { mesh->face[i].a = read_word(importer); mesh->face[i].b = read_word(importer); mesh->face[i].c = read_word(importer); (void)read_word(importer); mesh->mtl[i] = nullptr; } do { start_chunk(importer, &chunk); if (chunk.end <= mainchunk->end) { switch (chunk.tag) { case 0x4130: parse_msh_mat_group(importer, mesh); break; case 0x4150: parse_smooth_group(importer); break; } } end_chunk(importer, &chunk); } while (chunk.end <= mainchunk->end); for (i = 0; i < mesh->faces; i++) { if (mesh->mtl[i] == (vtk3DSMaterial*)nullptr) { mesh->mtl[i] = update_materials(importer, "Default", 0); } } } static void parse_msh_mat_group(vtk3DSImporter* importer, vtk3DSMesh* mesh) { vtk3DSMaterial* new_mtl; char mtlname[80]; int mtlcnt; int i, face; strcpy(mtlname, read_string(importer)); cleanup_name(mtlname); new_mtl = update_materials(importer, mtlname, 0); mtlcnt = read_word(importer); for (i = 0; i < mtlcnt; i++) { face = read_word(importer); mesh->mtl[face] = new_mtl; } } static void parse_smooth_group(vtk3DSImporter* vtkNotUsed(importer)) {} static void parse_mesh_matrix(vtk3DSImporter* vtkNotUsed(importer), vtk3DSMesh* vtkNotUsed(mesh)) { // vtkGenericWarningMacro(<< "mesh matrix detected but not used\n"); } static void parse_n_direct_light(vtk3DSImporter* importer, vtk3DSChunk* mainchunk) { vtk3DSChunk chunk; vtk3DSSpotLight* s; vtk3DSOmniLight* o; int spot_flag = 0; read_point(importer, vtk3DS::pos); parse_colour(importer, &vtk3DS::col); do { start_chunk(importer, &chunk); if (chunk.end <= mainchunk->end) { switch (chunk.tag) { case 0x4620: break; case 0x4610: parse_dl_spotlight(importer); spot_flag = 1; break; } } end_chunk(importer, &chunk); } while (chunk.end <= mainchunk->end); if (!spot_flag) { o = (vtk3DSOmniLight*)VTK_LIST_FIND(importer->OmniList, vtk3DS::objName); if (o != nullptr) { vtk3DS::pos[0] = o->pos[0]; vtk3DS::pos[1] = o->pos[1]; vtk3DS::pos[2] = o->pos[2]; vtk3DS::col = o->col; } else { o = (vtk3DSOmniLight*)malloc(sizeof(*o)); o->pos[0] = vtk3DS::pos[0]; o->pos[1] = vtk3DS::pos[1]; o->pos[2] = vtk3DS::pos[2]; o->col = vtk3DS::col; strcpy(o->name, vtk3DS::objName); VTK_LIST_INSERT(importer->OmniList, o); } } else { s = (vtk3DSSpotLight*)VTK_LIST_FIND(importer->SpotLightList, vtk3DS::objName); if (s != nullptr) { vtk3DS::pos[0] = s->pos[0]; vtk3DS::pos[1] = s->pos[1]; vtk3DS::pos[2] = s->pos[2]; vtk3DS::target[0] = s->target[0]; vtk3DS::target[1] = s->target[1]; vtk3DS::target[2] = s->target[2]; vtk3DS::col = s->col; vtk3DS::hotspot = s->hotspot; vtk3DS::falloff = s->falloff; } else { if (vtk3DS::falloff <= 0.0) { vtk3DS::falloff = 180.0; } if (vtk3DS::hotspot <= 0.0) { vtk3DS::hotspot = 0.7 * vtk3DS::falloff; } s = (vtk3DSSpotLight*)malloc(sizeof(*s)); s->pos[0] = vtk3DS::pos[0]; s->pos[1] = vtk3DS::pos[1]; s->pos[2] = vtk3DS::pos[2]; s->target[0] = vtk3DS::target[0]; s->target[1] = vtk3DS::target[1]; s->target[2] = vtk3DS::target[2]; s->col = vtk3DS::col; s->hotspot = vtk3DS::hotspot; s->falloff = vtk3DS::falloff; strcpy(s->name, vtk3DS::objName); VTK_LIST_INSERT(importer->SpotLightList, s); } } } static void parse_dl_spotlight(vtk3DSImporter* importer) { read_point(importer, vtk3DS::target); vtk3DS::hotspot = read_float(importer); vtk3DS::falloff = read_float(importer); } static void parse_n_camera(vtk3DSImporter* importer) { float bank; float lens; vtk3DSCamera* c = (vtk3DSCamera*)malloc(sizeof(vtk3DSCamera)); read_point(importer, vtk3DS::pos); read_point(importer, vtk3DS::target); bank = read_float(importer); lens = read_float(importer); strcpy(c->name, vtk3DS::objName); c->pos[0] = vtk3DS::pos[0]; c->pos[1] = vtk3DS::pos[1]; c->pos[2] = vtk3DS::pos[2]; c->target[0] = vtk3DS::target[0]; c->target[1] = vtk3DS::target[1]; c->target[2] = vtk3DS::target[2]; c->lens = lens; c->bank = bank; VTK_LIST_INSERT(importer->CameraList, c); } static void parse_colour(vtk3DSImporter* importer, vtk3DSColour* colour) { vtk3DSChunk chunk; vtk3DSColour_24 colour_24; start_chunk(importer, &chunk); switch (chunk.tag) { case 0x0010: parse_colour_f(importer, colour); break; case 0x0011: parse_colour_24(importer, &colour_24); colour->red = colour_24.red / 255.0; colour->green = colour_24.green / 255.0; colour->blue = colour_24.blue / 255.0; break; default: vtkGenericWarningMacro(<< "Error parsing colour"); } end_chunk(importer, &chunk); } static void parse_colour_f(vtk3DSImporter* importer, vtk3DSColour* colour) { colour->red = read_float(importer); colour->green = read_float(importer); colour->blue = read_float(importer); } static void parse_colour_24(vtk3DSImporter* importer, vtk3DSColour_24* colour) { colour->red = read_byte(importer); colour->green = read_byte(importer); colour->blue = read_byte(importer); } static float parse_percentage(vtk3DSImporter* importer) { vtk3DSChunk chunk; float percent = 0.0; start_chunk(importer, &chunk); switch (chunk.tag) { case 0x0030: percent = parse_int_percentage(importer) / 100.0; break; case 0x0031: percent = parse_float_percentage(importer); break; default: vtkGenericWarningMacro(<< "Error parsing percentage\n"); } end_chunk(importer, &chunk); return percent; } static short parse_int_percentage(vtk3DSImporter* importer) { word percent = read_word(importer); return percent; } static float parse_float_percentage(vtk3DSImporter* importer) { float percent = read_float(importer); return percent; } static void start_chunk(vtk3DSImporter* importer, vtk3DSChunk* chunk) { chunk->start = ftell(importer->GetFileFD()); chunk->tag = peek_word(importer); chunk->length = peek_dword(importer); if (chunk->length == 0) { chunk->length = 1; } chunk->end = chunk->start + chunk->length; } static void end_chunk(vtk3DSImporter* importer, vtk3DSChunk* chunk) { fseek(importer->GetFileFD(), chunk->end, 0); } static byte read_byte(vtk3DSImporter* importer) { byte data; data = fgetc(importer->GetFileFD()); return data; } static word read_word(vtk3DSImporter* importer) { word data; if (fread(&data, 2, 1, importer->GetFileFD()) != 1) { vtkErrorWithObjectMacro(importer, "Pre-mature end of file in read_word\n"); data = 0; } vtkByteSwap::Swap2LE((short*)&data); return data; } static word peek_word(vtk3DSImporter* importer) { word data; if (fread(&data, 2, 1, importer->GetFileFD()) != 1) { data = 0; } vtkByteSwap::Swap2LE((short*)&data); return data; } static dword peek_dword(vtk3DSImporter* importer) { dword data; if (fread(&data, 4, 1, importer->GetFileFD()) != 1) { data = 0; } vtkByteSwap::Swap4LE((char*)&data); return data; } static float read_float(vtk3DSImporter* importer) { float data; if (fread(&data, 4, 1, importer->GetFileFD()) != 1) { vtkErrorWithObjectMacro(importer, "Pre-mature end of file in read_float\n"); data = 0; } vtkByteSwap::Swap4LE((char*)&data); return data; } static void read_point(vtk3DSImporter* importer, vtk3DSVector v) { v[0] = read_float(importer); v[1] = read_float(importer); v[2] = read_float(importer); } static char* read_string(vtk3DSImporter* importer) { static char string[80]; int i; for (i = 0; i < 80; i++) { string[i] = read_byte(importer); if (string[i] == '\0') { break; } } return string; } static void cleanup_name(char* name) { char* tmp = (char*)malloc(strlen(name) + 2); int i; /* Remove any leading blanks or quotes */ i = 0; while ((name[i] == ' ' || name[i] == '"') && name[i] != '\0') { i++; } strcpy(tmp, &name[i]); /* Remove any trailing blanks or quotes */ for (i = static_cast(strlen(tmp)) - 1; i >= 0; i--) { if (isprint(tmp[i]) && !isspace(tmp[i]) && tmp[i] != '"') { break; } else { tmp[i] = '\0'; } } strcpy(name, tmp); /* Prefix the letter 'N' to materials that begin with a digit */ if (!isdigit(name[0])) { strcpy(tmp, name); } else { tmp[0] = 'N'; strcpy(&tmp[1], name); } /* Replace all illegal characters in name with underscores */ for (i = 0; tmp[i] != '\0'; i++) { if (!isalnum(tmp[i])) { tmp[i] = '_'; } } strcpy(name, tmp); free(tmp); } vtk3DSImporter::~vtk3DSImporter() { vtk3DSOmniLight* omniLight; vtk3DSSpotLight* spotLight; // walk the light list and delete vtk objects for (omniLight = this->OmniList; omniLight != (vtk3DSOmniLight*)nullptr; omniLight = (vtk3DSOmniLight*)omniLight->next) { omniLight->aLight->Delete(); } VTK_LIST_KILL(this->OmniList); // walk the spot light list and delete vtk objects for (spotLight = this->SpotLightList; spotLight != (vtk3DSSpotLight*)nullptr; spotLight = (vtk3DSSpotLight*)spotLight->next) { spotLight->aLight->Delete(); } VTK_LIST_KILL(this->SpotLightList); vtk3DSCamera* camera; // walk the camera list and delete vtk objects for (camera = this->CameraList; camera != (vtk3DSCamera*)nullptr; camera = (vtk3DSCamera*)camera->next) { camera->aCamera->Delete(); } VTK_LIST_KILL(this->CameraList); // walk the mesh list and delete malloced datra and vtk objects vtk3DSMesh* mesh; for (mesh = this->MeshList; mesh != (vtk3DSMesh*)nullptr; mesh = (vtk3DSMesh*)mesh->next) { if (mesh->anActor != nullptr) { mesh->anActor->Delete(); } if (mesh->aMapper != nullptr) { mesh->aMapper->Delete(); } if (mesh->aNormals != nullptr) { mesh->aNormals->Delete(); } if (mesh->aStripper != nullptr) { mesh->aStripper->Delete(); } if (mesh->aPoints != nullptr) { mesh->aPoints->Delete(); } if (mesh->aCellArray != nullptr) { mesh->aCellArray->Delete(); } if (mesh->aPolyData != nullptr) { mesh->aPolyData->Delete(); } if (mesh->vertex) { free(mesh->vertex); } if (mesh->face) { free(mesh->face); } if (mesh->mtl) { free(mesh->mtl); } } // then delete the list structure VTK_LIST_KILL(this->MeshList); VTK_LIST_KILL(this->MaterialList); // objects allocated in Material Property List vtk3DSMatProp* m; // just walk the list of material properties, deleting vtk properties for (m = this->MatPropList; m != (vtk3DSMatProp*)nullptr; m = (vtk3DSMatProp*)m->next) { m->aProperty->Delete(); } // then delete the list structure VTK_LIST_KILL(this->MatPropList); delete[] this->FileName; } void vtk3DSImporter::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os, indent); os << indent << "File Name: " << (this->FileName ? this->FileName : "(none)") << "\n"; os << indent << "Compute Normals: " << (this->ComputeNormals ? "On\n" : "Off\n"); }