#! /usr/bin/python from canvas2d import * import sys import lex import yacc import Camera from transform import * tokens = ('NUMBER', 'LBRACE', 'RBRACE', 'LBRAC', 'RBRAC', 'TRANSLAT','ROT','SFACTOR','FDIST','NDIST','ORIENT', 'COORDINDEX','TOP','LEFT','RIGHT','BOTTOM','SEPARATOR', 'COORD3','PCAMERA','TRANSFORM','POS','IFS','COMMA', 'POINT') #Tokens t_LBRACE = r'\{' t_RBRACE = r'\}' t_LBRAC = r'\[' t_RBRAC = r'\]' t_TRANSLAT = r'translation' t_ROT = r'rotation' t_SFACTOR = r'scaleFactor' t_FDIST = r'farDistance' t_NDIST = r'nearDistance' t_LEFT = r'left' t_RIGHT = r'right' t_TOP = r'top' t_BOTTOM = r'bottom' t_SEPARATOR = r'Separator' t_COORDINDEX= r'coordIndex' t_COORD3 = r'Coordinate3' t_PCAMERA = r'PerspectiveCamera' t_TRANSFORM = r'Transform' t_POS = r'position' t_IFS = r'IndexedFaceSet' t_ORIENT = r'orientation' t_COMMA = r',' t_POINT = r'point' #All numbers will be interpreted as floating point numbers def t_NUMBER(t): r'[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?' try: t.value = float(t.value) except ValueError: print "Unable to convert to float",t.value sys.exit() return t def t_COMMENT(t): r'\#.*' pass t_ignore = " \t" #ignore whitespace #line counter def t_newline(t): r'[\n\r]' t.lineno += 1 #error handler def t_error(t): print "Illegal character '%s' on line %d" % (t.value[0], t.lineno) sys.exit() lex.lex() #build the lexer ## Data structures mycamera = Camera.camera() mytransforms = [trans((0,0,0))] myifs = [[]] mycoords = [[]] #Parsing def p_blocks(p): '''blocks : block | block blocks''' pass def p_block(p): '''block : camerablock | sepblock''' pass def p_camerablock(p): 'camerablock : PCAMERA LBRACE cameralines RBRACE' for i in range(0,len(p[3])): if p[3][i][0] == 'position': mycamera.position = p[3][i][1] elif p[3][i][0] == 'orientation': mycamera.orientation = p[3][i][1] elif p[3][i][0] == 'nearDistance': mycamera.nearDistance = p[3][i][1] elif p[3][i][0] == 'farDistance': mycamera.farDistance = p[3][i][1] elif p[3][i][0] == 'left': mycamera.left = p[3][i][1] elif p[3][i][0] == 'right': mycamera.right = p[3][i][1] elif p[3][i][0] == 'top': mycamera.top = p[3][i][1] elif p[3][i][0] == 'bottom': mycamera.bottom = p[3][i][1] def p_cameralines(p): '''cameralines : cameraline | cameraline cameralines''' p[0] = [ p[1] ] if len(p) == 3: p[0].extend(p[2]) def p_cameraline(p): '''cameraline : POS triple | ORIENT quad | NDIST NUMBER | FDIST NUMBER | LEFT NUMBER | RIGHT NUMBER | TOP NUMBER | BOTTOM NUMBER''' p[0] = (p[1] , p[2] ) #Camera lines will be put into the camera structure in the #camerablock rule def p_sepblock(p): 'sepblock : SEPARATOR LBRACE sepitems RBRACE' mytransforms.append(trans((0,0,0))) #append identity matrix myifs.append([]) mycoords.append([]) def p_sepitems(p): '''sepitems : sepitem | sepitem sepitems''' pass def p_sepitem(p): '''sepitem : TRANSFORM LBRACE translines RBRACE | COORD3 LBRACE POINT LBRAC triples RBRAC RBRACE | IFS LBRACE ifsline RBRACE''' if p[1] == "Transform": mytransforms[-1] = matrixmultiply(mytransforms[-1],p[3]) elif p[1] == "IndexedFaceSet": myifs[-1].append(p[3]) else: mycoords[-1].append(p[5]) def p_translines(p): '''translines : transline | transline translines''' p[0] = p[1] if len(p) == 3: p[0] = matrixmultiply(p[1],p[2]) def p_transline(p): '''transline : TRANSLAT triple | SFACTOR triple | ROT quad''' if p[1] == 'translation': p[0] = trans(p[2]) elif p[1] == 'rotation': p[0] = rot(p[2]) elif p[1] == 'scaleFactor': p[0] = scale(p[2]) def p_ifsline(p): 'ifsline : COORDINDEX LBRAC singles RBRAC' p[0] = p[3] def p_quad (p): 'quad : NUMBER NUMBER NUMBER NUMBER' p[0] = (p[1],p[2],p[3],p[4]) def p_triple(p): 'triple : NUMBER NUMBER NUMBER' p[0] = (p[1],p[2],p[3]) def p_triples(p): '''triples : triple | triple COMMA triples ''' p[0] = [ p[1] ] if len(p) == 4: p[0].extend( p[3] ) def p_singles(p): '''singles : single | single COMMA singles''' p[0] = [ p[1] ] if len(p) == 4: p[0].extend(p[3]) def p_single(p): 'single : NUMBER' p[0] = p[1] def p_error(t): print "Syntax error at '%s'" % t.value #build parser yacc.yacc() def main(): # check input arguments if len(sys.argv) != 3: sys.stderr.write("Incorrect command line options\n") sys.exit(-1) #std to lexer, then parse lex.input(sys.stdin.read()) yacc.parse(sys.stdin.read()) #Ensure data sanity at a basic level if len(mytransforms) != len(mycoords): if len(mycoords) != len(myifs): print "Error in Open IV file formatting. Layout is not correct." numblocks = len(mytransforms) - 1 #Done with lexing and parsing T_world_cam = inverse(matrixmultiply(trans(mycamera.position), rot(mycamera.orientation))) T_perspective = perspective((mycamera.top,mycamera.bottom, mycamera.left,mycamera.right, mycamera.nearDistance,mycamera.farDistance)) #mycanvas = canvas2d(mycamera.left,mycamera.right,mycamera.top, # mycamera.bottom, int(sys.argv[1]),int(sys.argv[2])) mycanvas = canvas2d(-1.0,1.0,1.0,-1.0,int(sys.argv[1]),int(sys.argv[2])) for i in range(numblocks): #for each block for k in range(len(myifs[i])): #for each index set faces = [[]] for n in range(len(myifs[i][k])): #iterate over indecies if myifs[i][k][n] == -1: faces.append([]) else: point = mycoords[i][0][int(myifs[i][k][n])] point = (point[0],point[1],point[2],1.0) point = matrixmultiply(mytransforms[i],point) point = matrixmultiply(T_world_cam,point) point = matrixmultiply(T_perspective,point) point = (point[0] / point[3], point[1] / point[3], point[2] / point[3],1.0) faces[-1].append(list(point)) #Faces is now full of polys for this block, transform, and IFS, # so we'll start drawing! for m in range(len(faces)-1): mycanvas.line(faces[m][-1][0],faces[m][-1][1], faces[m][0][0],faces[m][0][1]) for w in range(len(faces[m])-1): mycanvas.line(faces[m][w][0],faces[m][w][1], faces[m][w+1][0],faces[m][w+1][1]) mycanvas.toPPM() if __name__ == '__main__': main()