import sys, re start_comm=re.compile('//|/\*') end_comm=re.compile('\*/|/\*') slc=re.compile('//.*([\n\r]|.$)') whitespace=re.compile('\s*') vecpat=re.compile(r'(<.*?>)') #find the actual vectors mesh2pat=re.compile(r'(mesh2\s*{)') #find the mesh def find_comment(str): """Returns the start and end positions of, single and multi-line, comments. Format is a list of tuples. """ comments=[] start=0 while 1: results=start_comm.search(str, start) try: start=results.start() except: break if results.group() == '/*': end=find_end_comment(str, results.end()) comments.append((start, end)) start=end else: # '//' sl=slc.search(str, start).span() comments.append(sl) start=sl[1] return comments def find_end_comment(str, end): """Finds and returns the end position of a 'multy line /*...*/' comment. Checks for and deals with nested comments.""" end_comment=0 while end_comment == 0: res=end_comm.search(str, end) try: end=res.end() except: sys.exit('no closing comment */ found') if res.group() == '*/': end_comment=1 else: # '/*', deal with nested comments. end=find_end_comment(str, end) return end def remove_section(str, section_list): """Removes sections from a string. The sections are given in a list of tuples, that specify the start and end of each section.""" section_list.sort() section_list.reverse() for section in section_list: str=str[:section[0]]+str[section[1]:] return str def remove_comment(str): """Removes POV-Ray style comments from a string.""" comments=find_comment(str) str=remove_section(str, comments) return str def find_end_block(str,search_pattern,end_pattern,end): search_pat= re.compile(search_pattern) endsearch=0 while endsearch == 0: res=search_pat.search(str,end) try: end=res.end() except: sys.exit('no closing of block found') if res.group() == end_pattern: endsearch=1 else: end=find_end_block(str,search_pattern,end_pattern,end) return end def find_kb(str, re_pattern, pos=0, endpos=-1): if endpos==-1: endpos = len(str) found_pat=re.compile(re_pattern) found=[] while 1: p=found_pat.search(str, pos, endpos) try: bs=p.end() except: break be=find_end_block(str,'({|})','}',bs) found.append((bs, be)) pos=p.end() return found def getvectors(str,pos=0,endpos=-1): """Finds POV-Ray style vectors returns a list of tuples that represent the found vectors""" if endpos==-1: endpos = len(str) veclist=[] while 1: p=vecpat.search(str, pos, endpos) try: v= p.group() v=v.replace(' ','') v=v.replace('<','') v=v.replace('>','') v=tuple(v.split(',')) veclist.append(v) except: break pos=p.end() return veclist def write_obj(FileName,outfile,vsum,isum,vertices,normals,uv_vec,faces): f_out=open(outfile,'w') f_out.write('# File name %s \n' % outfile) f_out.write('# Converted from %s \n\n' % FileName) if vsum==1: #write vertices and faces f_out.write('# Vertices: %s\n' %len(vertices)) for vertex in vertices: f_out.write('v %s %s %s\n' %(vertex)) f_out.write('\n# Faces: %s\n' %len(faces)) for face in faces: a=int(face[0])+1 b=int(face[1])+1 c=int(face[2])+1 f_out.write('f %s %s %s\n' %(a,b,c)) elif vsum==3: #write vertices and normals f_out.write('# Vertices: %s\n' %len(vertices)) for vertex in vertices: f_out.write('v %s %s %s\n' %(vertex)) f_out.write('\n# Normals: %s\n' %len(normals)) for normal in normals: f_out.write('vn %s %s %s\n' %(normal)) if isum==0: f_out.write('\n# Faces: %s\n' %len(faces)) for face in faces: a=int(face[0])+1 b=int(face[1])+1 c=int(face[2])+1 f_out.write('f %s//%s %s//%s %s//%s\n' %(a,a,b,b,c,c)) elif vsum==5: #write vertices and uv_vectors f_out.write('# Vertices: %s\n' %len(vertices)) for vertex in vertices: f_out.write('v %s %s %s\n' %(vertex)) f_out.write('\n# UV_vectors: %s\n' %len(uv_vec)) for uv_vector in uv_vec: f_out.write('vt %s %s\n' %(uv_vector)) if isum==0: f_out.write('\n# Faces: %s\n' %len(faces)) for face in faces: a=int(face[0])+1 b=int(face[1])+1 c=int(face[2])+1 f_out.write('f %s/%s %s/%s %s/%s\n' %(a,a,b,b,c,c)) elif vsum==7: #write vertices, normals and uv_vectors f_out.write('# Vertices: %s\n' %len(vertices)) for vertex in vertices: f_out.write('v %s %s %s\n' %(vertex)) f_out.write('\n# Normals: %s\n' %len(normals)) for normal in normals: f_out.write('vn %s %s %s\n' %(normal)) f_out.write('\n# UV_vectors: %s\n' %len(uv_vec)) for uv_vector in uv_vec: f_out.write('vt %s %s\n' %(uv_vector)) if isum==0: f_out.write('\n# Faces: %s\n' %len(faces)) #flag=0 for face in faces: a=int(face[0])+1 b=int(face[1])+1 c=int(face[2])+1 f_out.write('f %s/%s/%s %s/%s/%s %s/%s/%s\n' %(a,a,a,b,b,b,c,c,c)) f_out.close() def convert (FileName, IgnoreNormals,IgnoreUV): try: f_in=open(FileName,'r') except IOError, (errno, strerror): print 'I/O error(%s): "%s", %s' % (errno, FileName, strerror) else: POVsdl=f_in.read() f_in.close() remove_comment(POVsdl) mesh2list=find_kb(POVsdl,r'(mesh2\s*{)') #shoud find all mesh2's nr_mesh2=len(mesh2list) outfile=FileName.split('.') count=1 for mesh in mesh2list: pos_vertices= find_kb(POVsdl,r'(vertex_vectors\s*{)',mesh[0],mesh[1]) pos_normals= find_kb(POVsdl,r'(normal_vectors\s*{)',mesh[0],mesh[1]) pos_uvvec= find_kb(POVsdl,r'(uv_vectors\s*{)',mesh[0],mesh[1]) pos_faces= find_kb(POVsdl,r'(face_indices\s*{)',mesh[0],mesh[1]) if len(pos_vertices) !=0: vertices= getvectors(POVsdl,pos_vertices[0][0],pos_vertices[0][1]) vsum=1 if len(pos_normals) !=0 and IgnoreNormals==0: normals= getvectors(POVsdl,pos_normals[0][0],pos_normals[0][1]) vsum=vsum+2 else: normals=-1 if len(pos_uvvec) !=0 and IgnoreUV==0: uv_vec= getvectors(POVsdl,pos_uvvec[0][0],pos_uvvec[0][1]) vsum=vsum+4 else: uv_vec=-1 isum=0 if len(pos_faces) !=0: faces= getvectors(POVsdl,pos_faces[0][0],pos_faces[0][1]) if len(pos_vertices)==0 | len(pos_faces)==0: sys.exit('no vertices / faces found in %s' % FileName) if nr_mesh2==1: outfile=outfile[0]+'.obj' else: outfile=outfile[0]+'_'+str(count)+'.obj' count=count+1 write_obj(FileName,outfile,vsum,isum,vertices,normals,uv_vec,faces) def use(): print""" USE: mesh22obj.py [options] filename(s)\n OPTIONS: -h, --help : shows this message and quits mesh22obj.py -n : ignores all normals -u : ignores all uv_data """ def main(): import getopt, glob try: options, remainder=getopt.getopt(sys.argv[1:],"hnu",["help"]) except getopt.GetoptError: sys.stderr.write("\n Unknown option specified") use() sys.exit(2) IgnoreNormals=0 IgnoreUV=0 for (option, val) in options: if option in ("-h","--help"): use() sys.exit(2) if option =='-n': IgnoreNormals=1 if option=='-u': IgnoreUV=1 if len(remainder) == 0: sys.stderr.write("\n No filename specified\n") use() sys.exit(2) for FileNames in remainder: for FileName in glob.glob(FileNames): convert(FileName,IgnoreNormals,IgnoreUV) if __name__ == "__main__": main()