bool IVCONV::smf_read ( FileIO *filein ) /******************************************************************************/ /* Purpose: SMF_READ reads an SMF file. Author: John Burkardt Modified: 03 July 1999 */ { short material_binding,normal_binding,texture_binding; //Prepare structure for reading "per face" UV mapping array<FaceUV> face_uv; long mesh_idx; unsigned long color_idx; unsigned long normal_idx; unsigned long uvmap_idx; long texture_idx; unsigned long material_base; unsigned long vertex_base; unsigned long face_base; int level; int vertex_correction; char *next; int width; char cnr[LINE_MAX_LEN]; char token[LINE_MAX_LEN]; char token2[LINE_MAX_LEN]; material_binding=BND_UNDEFINED; normal_binding=BND_UNDEFINED; texture_binding=BND_UNDEFINED; vertex_correction = 0; material_base = material_num; vertex_base = vertex_num; face_base = face_num; level = 0; color_idx=0; normal_idx=0; uvmap_idx=0; mesh_idx=-1; texture_idx=-1; // Read the next line of the file into INPUT. stats.text_num = 0; char input[LINE_MAX_LEN]; while ( filein->fgets(input,LINE_MAX_LEN) != NULL ) { stats.text_num++; if ( debug ) printf ( "SMF_READ: Reading line %u\n", stats.text_num ); // Advance to the first nonspace character in INPUT. for ( next = input; *next != '\0' && isspace(*next); next++ ) { } // Skip blank lines. if ( *next == '\0' ) { continue; } // Skip comment lines. if ( (*next == '#') || (*next == '$') ) { stats.comment_num++; continue; } // Extract the first word in this line. sscanf ( next, "%s%n", token, &width ); // Set NEXT to point to just after this token. next += width; // BEGIN // Reset the transformation matrix to identity. // Node numbering starts at zero again. (Really, this is level based) // (Really should define a new transformation matrix, and concatenate.) // (Also, might need to keep track of level.) if ( leqi(token,"BEGIN") ) { level++; // Update materials added in last block unsigned int material_idx; for (material_idx=material_base;material_idx<material_num;material_idx++) material[material_idx].texture=texture_idx; material_base = material_num; //Convert material mapping to "per vertex" if (material_binding==BND_PER_FACE) face_to_vertex_material(face_uv,face_base,face_num-face_base); //Convert UV mapping to "per vertex" if (texture_binding==BND_PER_FACE) face_to_vertex_uv(face_uv,face_base,face_num-face_base); // Create new mesh mesh[mesh_num]=Mesh(); mesh_idx=mesh_num; mesh_num++; // Clear the block-dependent variables vertex_base = vertex_num; face_base = face_num; color_idx=0; normal_idx=0; uvmap_idx=0; texture_idx=-1; tmat_init ( transform_matrix ); } else // BIND [c|n|r] [vertex|face] // Specify the binding for RGB color, Normal, or Texture. // Options are "vertex" or "face" if ( leqi( token, "BIND" ) ) { char type[LINE_MAX_LEN]; sscanf ( next, "%s%n", cnr, &width ); next += width; sscanf ( next, "%s%n", type, &width ); next += width; if ( debug ) printf ( "SMF_READ: Bind - CNR=%s, TYPE=%s\n",cnr,type ); if ( leqi(cnr,"C") ) { if ( leqi(type,"VERTEX") ) { material_binding=BND_PER_VERTEX; } else if ( leqi(type,"FACE") ) { material_binding=BND_PER_FACE; } else { stats.bad_num++; printf ( "SMF_READ: Unrecognized material binding in line %u (ignored).\n",stats.text_num ); } } else if ( leqi(cnr,"N") ) { if ( leqi(type,"VERTEX") ) { normal_binding=BND_PER_VERTEX; } else if ( leqi(type,"FACE") ) { normal_binding=BND_PER_FACE; } else { stats.bad_num++; printf ( "SMF_READ: Unrecognized normal binding in line %u (ignored).\n",stats.text_num ); } } else if ( leqi ( cnr, "R" ) ) { if ( leqi(type,"VERTEX") ) { texture_binding=BND_PER_VERTEX; } else if ( leqi(type,"FACE") ) { texture_binding=BND_PER_FACE; } else { stats.bad_num++; printf ( "SMF_READ: Unrecognized texture binding in line %u (ignored).\n",stats.text_num ); } } else { stats.bad_num++; printf ( "SMF_READ: Unrecognized binding in line %u (ignored).\n",stats.text_num ); } } else // C <r> <g> <b> // Specify an RGB color, with R, G, B between 0.0 and 1.0. if ( leqi(token,"C") ) { int count=1; float r,g,b; if (count==1) count = sscanf ( next, "%f%n", &r, &width ); next += width; if (count==1) count = sscanf ( next, "%f%n", &g, &width ); next += width; if (count==1) count = sscanf ( next, "%f%n", &b, &width ); next += width; if (count!=1) { stats.bad_num++; printf ( "SMF_READ: Couldn't read color in line %u (ignored).\n",stats.text_num ); continue; } // Set up a temporary material (R,G,B,1.0). // Add the material to the material database, or find the index of // a matching material already in. // Assign the material of the node or face to this index. unsigned int material_idx; material[material_num]=Material(r,g,b); material_idx = material_num; material_num++; if (material_binding==BND_PER_FACE) { // Make sure we won't initialize the FaceUV twice if (color_idx>=uvmap_idx) face_uv[color_idx]=FaceUV(); face_uv[color_idx].material=material_idx; } else if (material_binding==BND_PER_VERTEX) { if (vertex_base+color_idx < vertex_num) { vertex[vertex_base+color_idx].material=material_idx; } else { stats.bad_num++; printf ( "SMF_READ: More colors than vertices in line %u (ignored).\n",stats.text_num ); } } else { stats.bad_num++; printf ( "SMF_READ: Color error - Material binding undefined in line %u (ignored).\n",stats.text_num ); } color_idx++; } else // END // Drop down a level. if ( leqi(token,"END") ) { level--; if ( level < 0 ) { printf ( "\n" ); printf ( "SMF_READ - Fatal error!\n" ); printf ( " More END statements than BEGINs!\n" ); return false; } // Update materials added in last block unsigned int material_idx; for (material_idx=material_base;material_idx<material_num;material_idx++) material[material_idx].texture=texture_idx; material_base = material_num; //Convert material mapping to "per vertex" if (material_binding==BND_PER_FACE) face_to_vertex_material(face_uv,face_base,face_num-face_base); //Convert UV mapping to "per vertex" if (texture_binding==BND_PER_FACE) face_to_vertex_uv(face_uv,face_base,face_num-face_base); // Back to previous mesh mesh_idx--; color_idx=0; normal_idx=0; uvmap_idx=0; } else // F V1 V2 V3 // Face. // A face is defined by the vertices. // Node indices are 1 based rather than 0 based. // So we have to decrement them before loading them into FACE. // Note that vertex indices start back at 0 each time a BEGIN is entered. // The strategy here won't handle nested BEGIN's, just one at a time. if ( leqi(token,"F") ) { if (face_num>=FACES_MAX) { stats.bad_num++; if (stats.bad_num<16) printf ( "SMF_READ: Faces limit reached in line %u (ignored).\n",stats.text_num ); continue; } unsigned long face_idx; face[face_num] = Face(); face_idx=face_num; face_num++; if (mesh_idx<0) { mesh[mesh_num]=Mesh(); mesh_idx=mesh_num; mesh_num++; } face[face_num].mesh=mesh_idx; // Read each item in the F definition as a token, and then // take it apart. int ivert; for (ivert=0;ivert<ORDER_MAX;ivert++ ) { int count=1; int node; if (count==1) count = sscanf ( next, "%s%n", token2, &width ); next += width; if (count==1) count = sscanf ( token2, "%d%n", &node, &width ); if (count!=1) break; unsigned long vertex_idx=node + vertex_base - 1 + vertex_correction; if (vertex_idx<vertex_num) { face[face_idx].vertices[ivert] = vertex_idx; face[face_idx].order++; } else { printf ( "SMF_READ: Warning - face definition had nonexisting vertex.\n" ); } } if (ivert==ORDER_MAX) printf ( "SMF_READ: Warning - max order reached, face truncated in line %u.\n",stats.text_num ); else if ((debug)&&(face[face_idx].order<3)) printf ( "SMF_READ: Warning - face order smaller than 3 in line %u.\n",stats.text_num ); } else // N <x> <y> <z> // Specify a normal vector. if ( leqi ( token, "N" ) ) { int count=1; float x,y,z; if (count==1) count = sscanf ( next, "%f%n", &x, &width ); next += width; if (count==1) count = sscanf ( next, "%f%n", &y, &width ); next += width; if (count==1) count = sscanf ( next, "%f%n", &z, &width ); next += width; if (count!=1) { stats.bad_num++; printf ( "SMF_READ: Couldn't read normal vector in line %u (ignored).\n",stats.text_num ); continue; } if (normal_binding==BND_PER_FACE) { unsigned long face_idx=face_base+normal_idx; if (face_idx<face_num) { face[face_idx].normal=vec3(x,y,z); } else { stats.bad_num++; printf ( "SMF_READ: Normal vector for nonexisting face in line %u (ignored).\n",stats.text_num ); } } else if (normal_binding==BND_PER_VERTEX) { unsigned long vertex_idx=vertex_base+normal_idx; if (vertex_idx<vertex_num) { vertex[vertex_idx].normal=vec3(x,y,z); } else { stats.bad_num++; printf ( "SMF_READ: Normal vector for nonexisting vertex in line %u (ignored).\n",stats.text_num ); } } else { stats.bad_num++; if (stats.bad_num<16) printf ( "SMF_READ: Normal vector error - binding undefined in line %u (ignored).\n",stats.text_num ); } normal_idx++; } else // R <u> <v> // Specify a texture coordinate. if ( leqi(token,"R") ) { int count=1; float u,v; if (count==1) count = sscanf ( next, "%f%n", &u, &width ); next += width; if (count==1) count = sscanf ( next, "%f%n", &v, &width ); next += width; if (count!=1) { stats.bad_num++; printf ( "SMF_READ: Couldn't read UV mapping in line %u (ignored).\n",stats.text_num ); continue; } if (texture_binding==BND_PER_FACE) { // Make sure we won't initialize the FaceUV twice if (uvmap_idx>=color_idx) face_uv[uvmap_idx]=FaceUV(); face_uv[uvmap_idx].tex_uv[face_uv[uvmap_idx].order]=vec2(u,v); face_uv[uvmap_idx].order++; } else if (texture_binding==BND_PER_VERTEX) { unsigned long vertex_idx=vertex_base+uvmap_idx; if (vertex_idx<vertex_num) { vertex[vertex_idx].tex_uv=vec2(u,v); } else { stats.bad_num++; printf ( "SMF_READ: UV mapping for nonexisting vertex in line %u (ignored).\n",stats.text_num ); } } else { stats.bad_num++; if (stats.bad_num<16) printf ( "SMF_READ: UV mapping error - binding undefined in line %u (ignored).\n",stats.text_num ); } uvmap_idx++; } else // ROT [x|y|z] <theta> if ( leqi(token,"ROT") ) { int count=1; float angle; char axis; if (count==1) sscanf ( next, "%c%n", &axis, &width ); next += width; if (count==1) sscanf ( next, "%f%n", &angle, &width ); next += width; if (count!=1) { stats.bad_num++; printf ( "SMF_READ: Couldn't read rotation in line %u (ignored).\n",stats.text_num ); continue; } tmat_rot_axis ( transform_matrix, transform_matrix, angle, axis ); } else // SCALE <sx> <sy> <sz> if ( leqi(token,"SCALE") ) { int count=1; float x,y,z; if (count==1) count = sscanf ( next, "%f%n", &x, &width ); next += width; if (count==1) count = sscanf ( next, "%f%n", &y, &width ); next += width; if (count==1) count = sscanf ( next, "%f%n", &z, &width ); next += width; if (count!=1) { stats.bad_num++; printf ( "SMF_READ: Couldn't read scale in line %u (ignored).\n",stats.text_num ); continue; } tmat_scale ( transform_matrix, transform_matrix, x, y, z ); } else // SET VERTEX_CORRECTION <i> // Specify increment to add to vertex indices in file. if ( leqi(token,"SET") ) { int count=1; int vcorrct; if (count==1) count = sscanf ( next, "%s%n", cnr, &width ); next += width; if (count==1) count = sscanf ( next, "%d%n", &vcorrct, &width ); next += width; if (count!=1) { stats.bad_num++; printf ( "SMF_READ: Couldn't read vertex correction in line %u (ignored).\n",stats.text_num ); vertex_correction=0; continue; } vertex_correction=vcorrct; } else // T_SCALE <dx> <dy> // Specify a scaling to texture coordinates. if ( leqi(token,"T_SCALE") ) { int count=1; float dx,dy; if (count==1) count = sscanf ( next, "%f%n", &dx, &width ); next += width; if (count==1) count = sscanf ( next, "%f%n", &dy, &width ); next += width; if (count!=1) { stats.bad_num++; printf ( "SMF_READ: Couldn't read texture scale in line %u (ignored).\n",stats.text_num ); continue; } //TODO: store the scaling } else // T_TRANS <dx> <dy> // Specify a translation to texture coordinates. if ( leqi(token,"T_TRANS") ) { int count=1; float dx,dy; if (count==1) count = sscanf ( next, "%f%n", &dx, &width ); next += width; if (count==1) count = sscanf ( next, "%f%n", &dy, &width ); next += width; if (count!=1) { stats.bad_num++; printf ( "SMF_READ: Couldn't read texture translation in line %u (ignored).\n",stats.text_num ); continue; } //TODO: store the value } else // TEX <filename> // Specify a filename containing the texture. if ( leqi(token,"TEX") ) { int count=1; int vcorrct; if (count==1) count = sscanf ( next, "%s%n", cnr, &width ); if (count!=1) { stats.bad_num++; printf ( "SMF_READ: Couldn't read texture name in line %u (ignored).\n",stats.text_num ); continue; } texture[texture_num]=Texture(); texture_num++; texture_idx=texture_num; strncpy(texture[texture_idx].name,cnr,LINE_MAX_LEN); // TODO: set materials to this texture } else // TRANS <dx> <dy> <dz> if ( leqi(token,"TRANS") ) { int count=1; float x,y,z; if (count==1) count = sscanf ( next, "%f%n", &x, &width ); next += width; if (count==1) count = sscanf ( next, "%f%n", &y, &width ); next += width; if (count==1) count = sscanf ( next, "%f%n", &z, &width ); next += width; if (count!=1) { stats.bad_num++; printf ( "SMF_READ: Couldn't read transform vector in line %u (ignored).\n",stats.text_num ); continue; } tmat_trans ( transform_matrix, transform_matrix, x, y, z ); } else // V <X> <Y> <Z> // Geometric vertex. if ( leqi(token,"V") ) { if (vertex_num>=VERTICES_MAX) { stats.bad_num++; if (stats.bad_num<10) printf ( "SMF_READ: Vertex limit reached in line %u (ignored).\n",stats.text_num ); continue; } int count; float xvec[3]; count = sscanf ( next, "%e %e %e",&(xvec[0]),&(xvec[1]),&(xvec[2])); if (count!=3) { stats.bad_num++; printf ( "SMF_READ: Couldn't read vertex coords in line %u (ignored).\n",stats.text_num ); continue; } vertex[vertex_num]=Vertex(); vertex[vertex_num].cor3=vec3(xvec[0],xvec[1],xvec[2]); // Apply current transformation matrix. // Right now, we can only handle one matrix, not a stack of // matrices representing nested BEGIN/END's. tmat_mxp ( transform_matrix, xvec, xvec ); vertex_num++; } else // Unrecognized keyword. { stats.bad_num++; if ( stats.bad_num <= 10 ) { printf ( "SMF_READ: Bad data in line %u (ignored).\n", stats.text_num ); } } } // Update materials added in last block unsigned int material_idx; for (material_idx=material_base;material_idx<material_num;material_idx++) material[material_idx].texture=texture_idx; //Convert material mapping to "per vertex" if (material_binding==BND_PER_FACE) face_to_vertex_material(face_uv,face_base,face_num-face_base); //Convert UV mapping to "per vertex" if (texture_binding==BND_PER_FACE) face_to_vertex_uv(face_uv,face_base,face_num-face_base); if ( debug ) printf ( "SMF_READ: Finished analyzing file lines.\n" ); return true; }
bool IVCONV::stla_read ( FILE *filein ) /******************************************************************************/ /* Purpose: STLA_READ reads an ASCII STL (stereolithography) file. Examples: solid MYSOLID facet normal 0.4 0.4 0.2 outerloop vertex 1.0 2.1 3.2 vertex 2.1 3.7 4.5 vertex 3.1 4.5 6.7 endloop endfacet ... facet normal 0.2 0.2 0.4 outerloop vertex 2.0 2.3 3.4 vertex 3.1 3.2 6.5 vertex 4.1 5.5 9.0 endloop endfacet endsolid MYSOLID Modified: 20 October 1998 Author: John Burkardt */ { int count; int i; int icor3; int ivert; char *next; float r1; float r2; float r3; float r4; float temp[3]; char token[LINE_MAX_LEN]; int width; /* Read the next line of the file into INPUT. */ char input[LINE_MAX_LEN]; while ( fgets ( input, LINE_MAX_LEN, filein ) != NULL ) { ++text_num; /* Advance to the first nonspace character in INPUT. */ for ( next = input; *next != '\0' && isspace(*next); next++ ) { } /* Skip blank lines and comments. */ if ( *next == '\0' || *next == '#' || *next == '!' || *next == '$' ) { continue; } /* Extract the first word in this line. */ sscanf ( next, "%s%n", token, &width ); /* Set NEXT to point to just after this token. */ next = next + width; /* FACET */ if ( leqi ( token, "facet" ) ) { /* Get the XYZ coordinates of the normal vector to the face. */ sscanf ( next, "%*s %e %e %e", &r1, &r2, &r3 ); // if ( face_num < FACE_MAX ) { face_normal[face_num] = vec3(r1,r2,r3); } fgets ( input, LINE_MAX_LEN, filein ); ++text_num; ivert = 0; for ( ;; ) { fgets ( input, LINE_MAX_LEN, filein ); ++text_num; count = sscanf ( input, "%*s %e %e %e", &r1, &r2, &r3 ); if ( count != 3 ) { break; } temp[0] = r1; temp[1] = r2; temp[2] = r3; if ( cor3_num < 1000 ) { icor3 = rcol_find ( cor3, cor3_num, temp ); } else { icor3 = -1; } if ( icor3 == -1 ) { icor3 = cor3_num; // if ( cor3_num < COR3_MAX ) { cor3[cor3_num] = temp; } cor3_num = cor3_num + 1; } else { dup_num = dup_num + 1; } // if ( ivert < ORDER_MAX && face_num < FACE_MAX ) { face[ivert][face_num] = icor3; vertex_material[ivert][face_num] = 0; for ( i = 0; i < 3; ++i ) { vertex_normal[ivert][face_num][i] = face_normal[face_num][i]; } } ivert = ivert + 1; } fgets ( input, LINE_MAX_LEN, filein ); ++text_num; // if ( face_num < FACE_MAX ) { face_order[face_num] = ivert; } ++face_num; } /* COLOR */ else if ( leqi ( token, "color" ) ) { sscanf ( next, "%*s %f %f %f %f", &r1, &r2, &r3, &r4 ); } /* SOLID */ else if ( leqi ( token, "solid" ) ) { object_num = object_num + 1; } /* ENDSOLID */ else if ( leqi ( token, "endsolid" ) ) { } /* Unexpected or unrecognized. */ else { printf ( "\n" ); printf ( "STLA_READ - Fatal error!\n" ); printf ( " Unrecognized first word on line.\n" ); return false; } } return true; }