def scale_st(self, x, y, debug): x_slop = math.fabs(self.x1 - self.x2) * 0.05 y_slop = math.fabs(self.y1 - self.y2) * 0.05 if self.x1 < self.x2: if x < (self.x1 - x_slop) or x > (self.x2 + x_slop): raise ExportError( "ERROR: UV coordinates %f,%f are out of bounds (%s) - X normal case!" % (x, y, debug)) else: if x < (self.x2 - x_slop) or x > (self.x1 + x_slop): raise ExportError( "ERROR: UV coordinates %f,%f are out of bounds (%s) - X flip case!" % (x, y, debug)) if self.y1 < self.y2: if y < (self.y1 - y_slop) or y > (self.y2 + y_slop): raise ExportError( "ERROR: UV coordinates %f,%f are out of bounds (%s) - Y normal case!" % (x, y, debug)) else: if y < (self.y2 - y_slop) or y > (self.y1 + y_slop): raise ExportError( "ERROR: UV coordinates %f,%f are out of bounds (%s) - Y flip case!" % (x, y, debug)) return (interp(self.x1, self.s1, self.x2, self.s2, x), interp(self.y1, self.t1, self.y2, self.t2, y))
def locate_root(path): hierarchy = path.split('/') for known_folder in [['Custom Scenery',1], ['Global Scenery',1], ['default scenery',2]]: if known_folder[0] in hierarchy: idx = hierarchy.index(known_folder[0]) return ('/'.join(hierarchy[:(idx+1-known_folder[1])]),'/'.join(hierarchy[:(idx+2)])) raise ExportError("X-Plane folder not found. Your blender file must be INSIDE a scenery package!")
def export_any_bone(file, name, x, y, z, dx, dy, dz): if has_prefix(name, 'EL'): cmd="BONE_INTERSECTION_EDGE_LEFT" metrics=strip_prefix(name,'EL') elif has_prefix(name, 'ER'): cmd="BONE_INTERSECTION_EDGE_RIGHT" metrics=strip_prefix(name,'ER') elif has_prefix(name, 'AL'): cmd="BONE_APPROACH_LEFT" metrics=strip_prefix(name,'AL') elif has_prefix(name, 'AR'): cmd="BONE_APPROACH_RIGHT" metrics=strip_prefix(name,'AR') else: raise ExportError("Bone %s - I cannot parse this prefix" % name) metrics = metrics.replace(",",".",3) nums = metrics.split() if len(nums) != 3: raise ExportError("Bone %s - I cannot parse these numbers: %s" % (name, metrics)) file.write("%s %d %f %f %f %f %f %f %f %f\n" % (cmd, int(nums[0]),float(nums[1]),float(nums[2]), x,z,-y, dx,dz,-dy))
def child_obj_name(wrapper, all): choices = getChildren(wrapper, all) for c in choices: nm = strip_suffix(c.name) # For Alex - skip LD1 if nm[-3:] != 'LD1': if c.getType() == 'Mesh': return c.name if c.getType() == 'Empty': return c.name raise ExportError("ERROR: could not find real physical name for obj %s." % wrapper.name) return wrapper.name[3:]
def add_face(self, f, owner): mm = owner.getMatrix('localspace') np = Prim(f) for v, uv in map(None, f.verts, f.uv): if f.smooth: vt = VT(xform_fixed(v, mm), xform_no(v, mm), uv, []) else: vt = VT(xform_fixed(v, mm), xform_no(f, mm), uv, []) vts = str(vt) if vts in self.idx: np.idx.append(self.idx[vts]) else: self.idx[vts] = len(self.vlist) np.idx.append(len(self.vlist)) self.vlist.append(vt) if len(f.verts) != 3 and len(f.verts) != 4: raise ExportError("Mesh %s has a face that isn't a tri or quad." % owner.name) if not (f.mode & Mesh.FaceModes.INVISIBLE): if len(f.verts) == 3: self.idx_count += 3 else: self.idx_count += 6 self.faces.append(np)
def get_fgon(mesh): vert_list = [] for e in mesh.edges: if (e.flag & Mesh.EdgeFlags.FGON) == 0: v_term = e.v1.index v_now = e.v2.index v_prev = v_term #print "start with %d " % v_term vert_list.append(v_term) while v_term != v_now: #print v_now vert_list.append(v_now) v_next = next_fgon_edge(mesh, v_prev, v_now) if v_next == -1: print "ERROR: bad fgon %s" % o.name break v_prev = v_now v_now = v_next break else: raise ExportError("ERROR: mesh %s apparently has no non-FGON edges?" % o.name) return vert_list
def out_obj(obj,file,oname, mode, xyz,xr,yr,zr,spans,span_length,ctr): oname = get_prop(obj,'external', oname) graded = has_prop(obj,'graded') cmd="OBJECT_DRAPED" if graded: cmd="OBJECT_GRADED" if mode == "DIST": repeat_len=(spans-1) * span_length if repeat_len <= 0.0 or span_length <= 0.0: raise ExportError("Object has repeat interval that is not positive: %s/%s" % (obj.parent.name,obj.name)) start_offset=xyz[1] end_offset = min(start_offset,span_length-start_offset) while end_offset > span_length: end_offset = end_offset - span_length if end_offset < 1.0: end_offset = span_length else: repeat_len=span_length start_offset=xyz[1] end_offset=xyz[1] # note: this used to use the road modeled length as period. But this sucks for Alex because he would have to model only ONE unit of road to get the right # pylon wavelength. Then his end cap and pylon would overlap which would be visually undesireable. file.write("%s %s %s\t%f %f %f %f %f %f %f/%f %f/%f" % (cmd,mode,oname, xyz[0]-ctr,xyz[0]-ctr, round(zr * 180 / 3.14159265), round(zr * 180 / 3.14159265), repeat_len,repeat_len, start_offset,end_offset, start_offset,end_offset)) if has_prop(obj,'obj_show_level'): file.write(" %s" % get_prop(obj,'obj_show_level','')) file.write("\n") obj_keys = ['OBJECT_FREQ', 'OBJECT_ALT' ]; emit_properties(file, obj, obj_keys) return graded
def parse_spelling_info(lines, info): cur_floor = '' for (line_no, line) in enumerate(lines): lclean = line.split('#')[0].strip() token = lclean.split() if len(token) == 0: continue if len(token) >= 2 and token[0].upper() == 'FLOOR': floor_id = token[1] if floor_id in info: raise ExportError("Duplicate floor cmd on line %d: %s" % (line_no, line)) info[floor_id] = [] cur_floor = floor_id elif len(token) >= 6 and token[0].upper() == 'WALL': if not cur_floor in info: raise ExportError( "Wall token found but no floor defined, line %d: %s" % (line_no, line)) info[cur_floor].append( [token[5], [token[1], token[2], token[3], token[4]]]) elif len(token) >= 5 and token[0].upper() == 'WALL_RULE': if not cur_floor in info: raise ExportError( "Wall token found but no floor defined, line %d: %s" % (line_no, line)) info[cur_floor][-1][1].append( [token[1], token[2], token[3], token[4]]) elif len(token) >= 2 and token[0].upper() == 'SPELLING': if not cur_floor in info: raise ExportError( "Spelling token found but no floor defined, line %d: %s" % (line_no, line)) if len(info[cur_floor]) == 0: raise ExportError( "Spelling token found but floor has no walls so far, line %d: %s" % (line_no, line)) info[cur_floor][-1].append(token[1:]) else: raise ExportError("Unknown text file contents: %s at line %d." % (line, line_no))
def lib_fac_name(obj, theme): if has_prop(obj, 'external'): return get_prop(obj, 'external', obj.name) else: raise ExportError("ERROR: The facade %s has no external property." % obj.name)
def export_edge_bone(file, degree, finger, x, y, z, meta_rect): l=meta_rect[0] b=meta_rect[1] r=meta_rect[2] t=meta_rect[3] cx = (l+r)*0.5 cy = (b+t)*0.5 if degree == 3: if y > cy: corner = 0 else: corner = 2 else: if x < cx: if y < cy: corner=0 else: corner=1 else: if y < cy: corner=3 else: corner=2 if degree == 2: if corner == 3: corner = 0 elif corner == 2: corner = 1 corner_next = (corner + 1) % degree if finger == corner: is_right = 0 elif finger == corner_next: is_right = 1 else: raise ExportError("Junction references a finger that is not appropriate for its corner. finger = %d, corner = %d, degree = %d" % (finger, corner, degree)) if degree == 3: if corner == 0: off_1 = t-y off_2 = l-x elif corner == 2: off_1 = x-l off_2 = b-y if finger == 0: dx = -1 dz = 0 elif finger == 1: dx = 0 dz = -1 elif finger == 2: dx = 0 dz = 1 else: if corner == 0: off_1 = x-l off_2 = b-y elif corner == 1: off_1 = t-y off_2 = l-x elif corner == 2: off_1 = r-x off_2 = y-t elif corner == 3: off_1 = y-b off_2 = x-r if finger == 0: dx = 0 dz = 1 elif finger == 1: dx = -1 dz = 0 elif finger == 2: dx = 0 dz = -1 elif finger == 3: dx = 1 dz = 0 off_1 = round(off_1,5) off_2 = round(off_2,2) x = round(x,5) y = round(y,5) z = round(z,5) if is_right: file.write("BONE_INTERSECTION_EDGE_RIGHT %d %f %f %f %f %f %f %f %f\n" %( corner, off_1, off_2, x, z, -y, dx, 0, dz)) else: file.write("BONE_INTERSECTION_EDGE_LEFT %d %f %f %f %f %f %f %f %f\n" %( corner, off_1, off_2, x, z, -y, dx, 0, dz))
def export_hier(parent, all, root, depth): total = 0 kids = getChildren(parent, all) objs = filter_objects(kids, 'Empty', 'OBJ') objs += filter_objects(kids, 'Empty', 'VRT') objs += filter_objects(kids, 'Empty', 'END') objs += filter_objects(kids, 'Empty', 'BGN') grps = filter_objects(kids, 'Empty', 'GRP') for g in grps: total = total + export_hier(g, all, root, depth + 1) # Alex does NOT want the outer-most OBJs to be exported. His projects # apparently contain lots of random objects floating around. # This if statement could be nuked to restore the old behavior. # The current impl lets free objects out if there simply are no groups. #if depth > 0: #This would STRICTLY skip free objs. if depth > 0 or len( grps) == 0: #This takes free objs if there are no groups. for o in objs: n = strip_suffix(o.name)[3:] n = get_prop(o, 'rname', n) n += '.obj' partial = get_prop(o, 'path', '.') export_path = os.path.join(partial, n) export_path = os.path.join(root, export_path) if not os.path.exists(os.path.dirname(export_path)): os.makedirs(os.path.dirname(export_path)) try: (sim, pack) = locate_root(export_path) except ExportError, e: pack = None exporter = OBJexport8(export_path) exporter.additive_lod = 1 my_parts = getGrandChildren(o, all) #if self.debug: # for p in my_parts: # print " object export %s will export DB %s" % (oname, p.name) prefix = '' parts = partial.count('/') + 1 if partial == '.': parts = 0 for n in range(parts): prefix += '../' exporter.openFile(my_parts, o, prefix) exporter.writeHeader() if has_prop(o, 'vname'): if pack == None: raise ExportError( "Illegal vname directive on %s - blender file is not in a scenery pack." % o.name) exporter.file.write( "EXPORT %s.obj %s\n" % (strip_suffix(get_prop(o, 'vname', o.name)), os.path.normpath(export_path[len(pack) + 1:]))) if has_prop(o, 'vname1'): exporter.file.write( "EXPORT %s.obj %s\n" % (strip_suffix(get_prop(o, 'vname1', o.name)), os.path.normpath(export_path[len(pack) + 1:]))) if has_prop(o, 'vname2'): exporter.file.write( "EXPORT %s.obj %s\n" % (strip_suffix(get_prop(o, 'vname2', o.name)), os.path.normpath(export_path[len(pack) + 1:]))) exporter.writeObjects(my_parts) total = total + 1
def export_ag_tile(self, obj, ann_list, all, lib_root, valid_ids): if self.debug: print "Exporting ag tile based on empty obj %s." % obj.name name = obj.name if valid_ids != None: if not name.isdigit(): raise ExportError( "ERROR: tile %s has a name that is not a vaild numeric tile ID." % name) self.file.write("\nTILE_ID %s\n" % name) valid_ids.append(name) else: self.file.write("\n# Tile: %s\n" % name) # Pass 1. Work up an OBJ master list for indexing, and find the tile boundaries. has_tile = 0 objs = filter_objects(ann_list, 'Empty', 'OBJ') facs = filter_objects(ann_list, 'Mesh', 'FAC') tiles = filter_objects(ann_list, 'Mesh', 'TILE') trees = filter_objects(ann_list, 'Mesh', 'TREE') trlns = filter_objects(ann_list, 'Mesh', 'TRLN') pins = filter_objects(ann_list, 'Lamp', 'PIN') metas = filter_objects(ann_list, 'Mesh', 'META') if self.debug: print " %d annotations, %d objs, %d faces, %d tiles, %d trees, %d tree lines, %d pins" % ( len(ann_list), len(objs), len(facs), len(tiles), len(trees), len(trlns), len(pins)) if len(tiles) != 1: raise ExportError("ERROR: tile %s has %d tile objects." % (obj.name, len(tiles))) return tt = TILE(tiles[0]) tt.write_tile_header(self.file) # # ATTACHED OBJECTS # for o in objs: #Ben says: this used to have an anti-dupe logic using a layer check...but...that should NOT be necessary! #One OBJ for each export. oname = lib_obj_name(o, self.theme, lib_root) #xr=tt.scale_s(o.LocX) #yr=tt.scale_t(o.LocY) loc = o.getMatrix('localspace').translationPart() (xr, yr) = tt.scale_st(loc[0], loc[1], o.name) if has_prop(o, "STEP"): agl_span = 0 step = get_prop(o, "step", 1.0) delta_agl = o.getMatrix('localspace').translationPart()[2] scraper_parts = getGrandChildren(o, all) for s in scraper_parts: mm = s.getMatrix('localspace') if s.getType() == 'Mesh': mesh = s.getData(mesh=True) for v in mesh.verts: vt = xform(v, mm) agl_span = max(vt[2], agl_span) self.file.write("OBJ_SCRAPER %f %f %f %d %f %f %s" % (xr, yr, make_degs(-o.RotZ), self.obj_name_list.index(oname), agl_span, agl_span + delta_agl, step)) elif has_prop(o, "DELTA"): self.file.write( "OBJ_DELTA %f %f %f %s %d" % (xr, yr, make_degs(-o.RotZ), get_prop( o, "DELTA", 0.0), self.obj_name_list.index(oname))) elif has_prop(o, "GRADED"): self.file.write("OBJ_GRADED %f %f %f %d" % (xr, yr, make_degs(-o.RotZ), self.obj_name_list.index(oname))) else: self.file.write("OBJ_DRAPED %f %f %f %d" % (xr, yr, make_degs(-o.RotZ), self.obj_name_list.index(oname))) if has_prop(o, 'show_level'): self.file.write(" %s" % get_prop(o, 'show_level', '')) self.file.write("\n") # # TREE LINES # for o in trlns: mesh = o.getData(mesh=True) mm = o.getMatrix('localspace') if len(mesh.faces) != 1: raise ExportError("ERROR: mesh %s has %d faces." % (o.name, len(mesh.faces))) continue f = mesh.faces[0] if len(f.v) != 4: raise ExportError("ERROR: mesh %s has %d vertices." % (o.name, len(f.v))) v0 = xform(f.v[0], mm) v1 = xform(f.v[1], mm) v2 = xform(f.v[2], mm) v3 = xform(f.v[3], mm) exp_layer_name = strip_prefix(o.name, 'TRLN') if near_zero(v0[2]) and near_zero(v1[2]): out_trln(self.file, v0, v1, tt, exp_layer_name) elif near_zero(v1[2]) and near_zero(v2[2]): out_trln(self.file, v1, v2, tt, exp_layer_name) elif near_zero(v2[2]) and near_zero(v3[2]): out_trln(self.file, v2, v3, tt, exp_layer_name) elif near_zero(v3[2]) and near_zero(v0[2]): out_trln(self.file, v3, v0, tt, exp_layer_name) else: raise ExportError( "ERROR: Tree line seems to have no zero intersect" % o.name) # # INDIVIDUAL TREES # for o in trees: mesh = o.getData(mesh=True) loc = o.getMatrix('localspace').translationPart() (xr, yr) = tt.scale_st(loc[0], loc[1], o.name) hi = 0 lo = 0 mm = o.getMatrix('localspace') for f in mesh.faces: if len(f.v) != 4: raise ExportError( "ERROR: the tree %s has a face that is not four-sided." % o.name) v0 = xform(f.v[0], mm) v1 = xform(f.v[1], mm) v2 = xform(f.v[2], mm) v3 = xform(f.v[3], mm) if near_zero(v0[2]) and near_zero(v1[2]): out_tree(self.file, xr, yr, v0, v1, make_degs(-o.RotZ), strip_prefix(o.name, 'TREE')) break elif near_zero(v1[2]) and near_zero(v2[2]): out_tree(self.file, xr, yr, v1, v2, make_degs(-o.RotZ), strip_prefix(o.name, 'TREE')) break elif near_zero(v2[2]) and near_zero(v3[2]): out_tree(self.file, xr, yr, v2, v3, make_degs(-o.RotZ), strip_prefix(o.name, 'TREE')) break elif near_zero(v3[2]) and near_zero(v0[2]): out_tree(self.file, xr, yr, v3, v0, make_degs(-o.RotZ), strip_prefix(o.name, 'TREE')) break else: print v0, v1, v2, v3 raise ExportError( "ERROR: Tree %s seems to have non zero intersect" % o.name) # # FACADES # for o in facs: mesh = o.getData(mesh=True) idx = self.fac_name_list.index(lib_fac_name(o, self.theme)) # We are going to find one non-fgon edge (that is, an edge not internal to the triangulation of the fgon) and # then loop around edge connectivity to find the perimeter. There MIGHT be a blender way to do this with indexing, # but for the small number of edges we have, screw it...next_fgon_edge is O(N) if not is_really_fgon(mesh): if len(mesh.faces) != 1 or len(mesh.faces[0].verts) != 4: raise ExportError("Mesh %s is not an fgon." % mesh.name) vert_list = get_fgon(mesh) if fgon_cw(vert_list, mesh): vert_list.reverse() if len(vert_list) < 2: raise ExportError("ERROR: mesh %s has too few vertices." % o.name) continue mm = o.getMatrix('localspace') v = mesh.verts[0] vt = xform(v, mm) h = vt[2] # Rotate the vertex list to have all but one zero interception first. This ensures that all non-zero # are continuous; for fence-style facades, this means we won't have the end, then circulate to the beginning. n = 0 found_any_near_zero = 0 for ii, i in enumerate(vert_list): if near_zero(xform(mesh.verts[i], mm)[2]): n = ii found_any_near_zero = 1 if n != 0: vert_list[:] = vert_list[n:] + vert_list[:n] # What the hell is THIS? Well, if we have a FENCE style facade, the fgon-cw test above is going to produce CRAP because # the facade isn't co-planar. So: take the first face and compare its normal in the order we traverse it (e.g. grabbing its 4 # verts as they pass by in the stream) to the real face normal. If the user flipped the face, flip the stream. if found_any_near_zero: v_our_order = [] f = mesh.faces[0] for i in vert_list: if face_has_vert_index(f, i): v_our_order.append(i) n = TriangleNormal(mesh.verts[v_our_order[0]].co, mesh.verts[v_our_order[1]].co, mesh.verts[v_our_order[2]].co) if f.no.dot(n) < 0: vert_list.reverse() # Nuke zero intercepts so that fences are now 'just the fence'. vert_list[:] = [ v for v in vert_list if not near_zero(xform(mesh.verts[v], mm)[2]) ] wlist = [] for i in xrange(1, len(vert_list)): v1 = vert_list[i - 1] v2 = vert_list[i] for f in mesh.faces: if face_has_vert_index(f, v1) and face_has_vert_index( f, v2): if f.mode & Mesh.FaceModes.TILES: wlist.append(1) else: wlist.append(0) break else: raise ExportError("Internal error: we never found a face.") wlist.append(0) if sum(wlist) > 0: self.file.write("FAC_WALLS %d %f" % (idx, h)) for x, i in enumerate(vert_list): v = mesh.verts[i] vt = xform(v, mm) #print vt (xr, yr) = tt.scale_st(vt[0], vt[1], o.name) self.file.write(" %f %f %d" % (xr, yr, wlist[x])) self.file.write("\n") else: self.file.write("FAC %d %f" % (idx, h)) for i in vert_list: v = mesh.verts[i] vt = xform(v, mm) #print vt (xr, yr) = tt.scale_st(vt[0], vt[1], o.name) self.file.write(" %f %f" % (xr, yr)) self.file.write("\n") # # PINS # for o in pins: loc = o.getMatrix('localspace').translationPart() (xr, yr) = tt.scale_st(loc[0], loc[1], o.name) self.file.write("%s %f %f\n" % (strip_prefix(o.name, 'PIN'), xr, yr)) # # Meta-rects # for o in metas: mesh = o.getData(mesh=True) if len(mesh.faces) != 1: raise ExportError( "ERROR: meta object %s does not have one face." % o.name) break f = mesh.faces[0] if len(f.verts) != 4: raise ExportError( "ERROR: face for meta object %s does not have four sides." % o.name) break mm = o.getMatrix('localspace') v0 = xform(f.v[0], mm) v1 = xform(f.v[1], mm) v2 = xform(f.v[2], mm) v3 = xform(f.v[3], mm) WWS = 4.25 if strip_prefix(o.name, 'META').lower() == 'block_edge': self.file.write("EDGE_MAX %f %f %f %f\n" % (tt.scale_stst( min(v0[0], v1[0], v2[0], v3[0]) - WWS, min(v0[1], v1[1], v2[1], v3[1]) - WWS, max(v0[0], v1[0], v2[0], v3[0]) + WWS, max(v0[1], v1[1], v2[1], v3[1]) + WWS, o.name))) else: self.file.write("%s " % strip_prefix(o.name, 'META')) self.file.write( "%f %f %f %f\n" % tt.scale_stst(min(v0[0], v1[0], v2[0], v3[0]), min(v0[1], v1[1], v2[1], v3[1]), max(v0[0], v1[0], v2[0], v3[0]), max(v0[1], v1[1], v2[1], v3[1]), o.name))
def export_chain(self, obj, scene): if self.debug: print "Exporting chain based on empty obj %s." % obj.name # First pass: pull out all segments. Hels us find real lenght max_len=0 name=strip_suffix(obj.name[3:]) annotations = getChildren(obj,scene) segs = filter_objects(annotations,'Mesh', '') objs = filter_objects(annotations,'Empty','OBJ') obj2 = filter_objects(annotations,'Mesh','OBJ') ends = filter_objects(annotations,'Empty','END') end2 = filter_objects(annotations,'Mesh','END') bgns = filter_objects(annotations,'Empty','BGN') bgn2 = filter_objects(annotations,'Mesh','BGN') vrts = filter_objects(annotations,'Empty','VRT') vrt2 = filter_objects(annotations,'Mesh','VRT') cars = filter_objects(annotations,'Empty','CAR') car2 = filter_objects(annotations,'Mesh','CAR') objs.extend(obj2) ends.extend(end2) bgns.extend(bgn2) vrts.extend(vrt2) cars.extend(car2) bounds = [] for s in segs: if 1 in s.layers or 2 in s.layers or 3 in s.layers: if not s in objs and not s in ends and not s in bgns and not s in cars and not s in vrts: mesh=s.getData(mesh=True) mm=s.getMatrix('localspace') for v in mesh.verts: vc=xform(v,mm) if len(bounds) == 0: bounds.extend(vc) bounds.extend(vc) else: for n in [0,1,2]: bounds[n ] = min(bounds[n ],vc[n]) bounds[n+3] = max(bounds[n+3],vc[n]) rwidth = abs(round(bounds[3] - bounds[0],4)) rlength = abs(round(bounds[4] - bounds[1],4)) rwidth = float(get_prop(obj,'width',str(rwidth))) rgb = get_prop(obj, 'RGB', "1 1 1") num_lengths=1 if has_prop(obj,'spans'): num_lengths=float(get_prop(obj,'spans','1')) else: num_lengths = guess_spans(rlength, bgns, ends, objs) rlength /= num_lengths self.file.write("\n#%s (%d spans)\n" % (get_prop(obj,'NAME',obj.name[3:]), num_lengths)) self.file.write("ROAD_TYPE %s %.4f %.4f 0 %s\n" % (name.split('.')[0], rwidth, rlength, rgb)) if has_prop(obj,'ROAD_CENTER'): bounds[0] = -float(get_prop(obj,'ROAD_CENTER',str(rwidth*0.5))) elif has_prop(obj,'width'): bounds[0] = -(rwidth*0.5) self.file.write("ROAD_CENTER %f\n" % -bounds[0]) road_keys = ['REQUIRE_EVEN', 'SHOW_LEVEL' ]; emit_properties(self.file, obj, road_keys) self.last_scale = 0 general_mode='DRAPED' for s in segs: if 1 in s.layers or 2 in s.layers or 3 in s.layers: if not s in objs and not s in ends and not s in bgns and not s in cars and not s in vrts: surf=get_prop(s,'surface','asphalt') mesh=s.getData(mesh=True) mm=s.getMatrix('localspace') for f in mesh.faces: if f.mode & Mesh.FaceModes.TWOSIDE: n=len(f.v) if n != 4: raise ExportError(" found degenerate wires with %d verts in mesh %s." % (n, s.name)) else: v=f.verts uv=f.uv for idx in range(0,4): max_len = max(max_len,round(v[idx].co[1])) v0=xform(f.v[0],mm) v1=xform(f.v[1],mm) v2=xform(f.v[2],mm) v3=xform(f.v[3],mm) y_min = min(v1[2],v2[2],v3[2],v0[2]) y_max = max(v1[2],v2[2],v3[2],v0[2]) x = v1[0] self.file.write("WIRE 0 20000\t%f %f %f\n" % ((x - bounds[0]) / rwidth, y_max, 1.0 - y_min / y_max)) else: #if f.image.filename[:2] != '//': # raise ExportError("The image %s is not using a relative path. It is needed by obj %s." % (f.image.name, obj.name)) #if not f.image.has_data: # f.image.reload() #if not f.image.has_data: # raise ExportError("The image %s is not loaded - perhaps the texture is misisng; it is needed by obj %s." % (f.image.name, obj.name)) #(width,height)=f.image.getSize() mat=mesh.materials[f.mat] im = mat.textures[0].tex.image if not im.has_data: raise ExportError("The image %s is not loaded - perhaps the texture is misisng; it is needed by obj %s." % (im.name, obj.name)) (width,height)=im.getSize() #graded = has_prop(obj,'graded') graded = 1 if f.mode & Mesh.FaceModes.TILES: graded = 0 poly_os = 1 if graded: general_mode='GRADED' poly_os = 0 shader_idx=self.shaders.shader_idx(mesh,f) hard_face = f.mode & Mesh.FaceModes.DYNAMIC n=len(f.v) if n != 4: raise ExportError(" found degenerate face with %d verts in mesh %s." % (n, s.name)) else: if width != self.last_scale: self.last_scale = width self.file.write("SCALE %d\n" % width) v=f.verts uv=f.uv for idx in range(0,4): max_len = max(max_len,round(v[idx].co[1])) v0=xform(f.v[0],mm) v1=xform(f.v[1],mm) v2=xform(f.v[2],mm) v3=xform(f.v[3],mm) if near_zero(v0[1]) and near_zero(v1[1]): out_seg(self.file, name, s.layers, shader_idx,width,hard_face,surf,graded,v0,v1, v2, uv[0],uv[1],uv[2],bounds[0],rlength) elif near_zero(v1[1]) and near_zero(v2[1]): out_seg(self.file, name, s.layers, shader_idx,width,hard_face,surf,graded,v1,v2, v3, uv[1],uv[2],uv[3],bounds[0],rlength) elif near_zero(v2[1]) and near_zero(v3[1]): out_seg(self.file, name, s.layers, shader_idx,width,hard_face,surf,graded,v2,v3, v0, uv[2],uv[3],uv[0],bounds[0],rlength) elif near_zero(v3[1]) and near_zero(v0[1]): out_seg(self.file, name, s.layers, shader_idx,width,hard_face,surf,graded,v3,v0, v1, uv[3],uv[0],uv[1],bounds[0],rlength) else: # Map merges xyz vert obj and uv tuples into one big mess of pairs, which for with pair # iterator then pulls apart. Python does not do for a,b in x, y: apparently. for v, uv in map(None, f.verts, f.uv): print v0 print v1 print v2 print v3 print uv[0], uv[1] raise ExportError( "I was not able to pull apart this face (in mesh %s)." % s.name) seg_keys = ['SEGMENT_NORMALS'] emit_properties(self.file, s, seg_keys) for o in objs: if 1 in o.layers or 2 in o.layers or 3 in o.layers: oname = self.lib_lookup(strip_prefix(o.name,'OBJ')) if num_lengths < 2: raise ExportError( "%s: This distance-baesd object can't be used on a one-span segment: %s." % (obj.name, o.name)) if out_obj(o, self.file,oname, "DIST", o.getMatrix('localspace').translationPart(), o.RotX, o.RotY, o.RotZ, num_lengths,rlength,bounds[0]): general_mode='GRADED' for o in bgns: if 1 in o.layers or 2 in o.layers or 3 in o.layers: oname = self.lib_lookup(strip_prefix(o.name,'BGN')) if out_obj(o, self.file,oname, "BEGIN", o.getMatrix('localspace').translationPart(), o.RotX, o.RotY, o.RotZ, num_lengths,rlength,bounds[0]): general_mode='GRADED' for o in ends: if 1 in o.layers or 2 in o.layers or 3 in o.layers: oname = self.lib_lookup(strip_prefix(o.name,'END')) if out_obj(o, self.file,oname, "END", o.getMatrix('localspace').translationPart(), o.RotX, o.RotY, o.RotZ, num_lengths,rlength,bounds[0]): general_mode='GRADED' for o in vrts: if 1 in o.layers or 2 in o.layers or 3 in o.layers: oname = self.lib_lookup(strip_prefix(o.name,'VRT')) if out_obj(o, self.file,oname, "VERT", o.getMatrix('localspace').translationPart(), o.RotX, o.RotY, o.RotZ, num_lengths,rlength,bounds[0]): general_mode='GRADED' for o in cars: if 1 in o.layers or 2 in o.layers or 3 in o.layers: oname = self.lib_lookup(strip_prefix(o.name,'CAR')) out_car(o, self.file,oname, o.getMatrix('localspace').translationPart(), o.RotX, o.RotY, o.RotZ) o = obj while o != None: do_macros(self.file,o,0,-bounds[0],rwidth,general_mode) o = o.parent
def export_fac(fac, all, dir): print "Exporting %s " % fac.name text = text_for_obj(fac.name) info = {} if len(text) != 0: parse_spelling_info(text, info) fname = strip_prefix(fac.name, 'FAC') + '.fac' partial = get_prop(fac, 'path', '.') prefix = '' parts = partial.count('/') + 1 if partial == '.': parts = 0 for n in range(parts): prefix += '../' export_path = os.path.join(partial, fname) export_path = os.path.join(path, export_path) if not os.path.exists(os.path.dirname(export_path)): os.makedirs(os.path.dirname(export_path)) print export_path fi = open(export_path, 'w') if len(text) > 0: fi.write("A\n1000\nFACADE\n\n") else: fi.write("A\n800\nFACADE\n\n") fac_props = [] is_graded = 0 fac_keys = [ 'RING', 'HARD_WALL', 'HARD_ROOF', 'DOUBLED', 'FLOORS_MIN', 'FLOORS_MAX', 'LAYER_GROUP', 'LAYER_GROUP_DRAPED' ] accum_properties(fac, fac_keys, fac_props) for p in fac_props: fi.write("%s\n" % p) if has_prop(fac, 'GRADED'): # avoid using prop data in file fi.write("GRADED\n") is_graded = 1 if has_prop(fac, 'vname'): (sim, pack) = locate_root(export_path) fi.write("EXPORT %s.fac %s\n" % (strip_suffix(get_prop(fac, 'vname', fac.name)), os.path.normpath(export_path[len(pack) + 1:]))) zoning_types = [ 'ind_high_solid', 'ind_low_solid', 'urban_med_solid', 'urban_com_solid' ] tall_zoning_types = ['urban_high_solid'] block_widths = [7.5, 15, 22.5, 30, 45, 60, 75, 90] arch_heights = [24, 32, 999] height_max_for_arch = {24: 24, 32: 40, 999: 999} block_heights = [[8, 10], [10, 16], [16, 24], [24, 32], [32, 40], [40, 80], [80, 120], [120, 999]] legal_block_heights = [8, 10, 16, 24, 32, 40, 80, 120, 999] block_depths = [30, 60, 90] num_fac_spelling_props = 0 for p in [ 'WIDTH_MIN', 'WIDTH_MAX', 'HEIGHT_MIN', 'HEIGHT_MAX', 'DEPTH', 'BLOCK_HEIGHT', 'BLOCK_VARIANT' ]: if has_prop(fac, p): num_fac_spelling_props = num_fac_spelling_props + 1 if num_fac_spelling_props != 0 and num_fac_spelling_props != 7: raise ExportError("You only have some facade tags placed. Typo? %s" % fac.name) if num_fac_spelling_props == 7: (sim, pack) = locate_root(export_path) width_min = float(get_prop(fac, 'WIDTH_MIN', 0)) width_max = float(get_prop(fac, 'WIDTH_MAX', 0)) height_min = float(get_prop(fac, 'HEIGHT_MIN', 0)) height_max = float(get_prop(fac, 'HEIGHT_MAX', 0)) depth = get_prop(fac, 'DEPTH', '') arch_height = get_prop(fac, 'BLOCK_HEIGHT', '') # Alex hack alert: I've made it accept either commas or whitespace as separators, by the only method I could find - I apologise for the mess. if ',' in depth: depth_list = map(float, depth.split(',')) else: depth_list = map(float, depth.split()) if ',' in arch_height: arch_list = map(float, arch_height.split(',')) else: arch_list = map(float, arch_height.split()) if ',' in get_prop(fac, 'BLOCK_VARIANT', ''): var_list = map(toupper, get_prop(fac, 'BLOCK_VARIANT', '').split(',')) else: var_list = map(toupper, get_prop(fac, 'BLOCK_VARIANT', '').split()) zone_filter = get_prop(fac, 'ZONE', '') if zone_filter == '': zone_filter = [] else: if ',' in zone_filter: zone_filter = zone_filter.split(',') else: zone_filter = zone_filter.split() fallback = get_prop(fac, 'FALLBACK', '') if fallback == '1': fallback = '_FALLBACK' else: fallback = '_PRIMARY' density = get_prop(fac, 'DENSITY', '1.0') my_exp = os.path.normpath(export_path[len(pack) + 1:]) num_exp = 0 for d in block_depths: if float(d) in depth_list: for w in block_widths: if w >= width_min and w <= width_max: for z in zoning_types: if zone_filter_match(z, zone_filter): # ALEX - comment this back in to raise an error if a facade is too tall for the low zoning types but # is hitting one of their buckets anyway. When you put FLOORS_MIN in place this check shuts up, because # you have FORCED the building to be tall enough to be non-silly even though the DSF says "10 meters, really!" #if height_min > 10.0 and not has_prop(fac,'FLOORS_MIN'): # raise ExportError("The facade %s matches the non-tall zoning type %s.\nIt has no minimum floor directive but needs to be taller than 10m." % (fac.name, z)) if 'A' in var_list: fi.write( "EXPORT%s %s lib/g10/autogen/%s_%dx%da.fac\t\t%s\n" % (fallback, density, z, w, d, my_exp)) num_exp = num_exp + 1 if 'B' in var_list: fi.write( "EXPORT%s %s lib/g10/autogen/%s_%dx%db.fac\t\t%s\n" % (fallback, density, z, w, d, my_exp)) num_exp = num_exp + 1 for z in tall_zoning_types: if zone_filter_match(z, zone_filter): for bh in block_heights: if bh[0] >= height_min and bh[ 1] <= height_max: for ah in arch_heights: if float(ah) in arch_list and bh[ 1] <= height_max_for_arch[ float(ah)]: #ALEX - comment these lines back in to fail export if the min/max height don't fall on bucket # boundaries. #if not height_min in legal_block_heights: # raise ExportError("The facade %s has an illegal height min %f." % (fac.name, height_min)) #if not height_max in legal_block_heights: # raise ExportError("The facade %s has an illegal height max %f." % (fac.name, height_max)) if 'A' in var_list: fi.write( "EXPORT%s %s lib/g10/autogen/%s_%d_%dx%dx%da.fac\t\t%s\n" % (fallback, density, z, ah, w, bh[1], d, my_exp)) num_exp = num_exp + 1 if 'B' in var_list: fi.write( "EXPORT%s %s lib/g10/autogen/%s_%d_%dx%dx%db.fac\t\t%s\n" % (fallback, density, z, ah, w, bh[1], d, my_exp)) num_exp = num_exp + 1 # This checks that we put at least ONE generated export directive in. If we have none, that's probably a typo. if num_exp == 0: raise ExportError( "The facade %s has export bucketing tags but failed to fit in ANY bucket. This is probably a tagging mistake." % fac.name) roof_images = [] wall_images = [] roof_meshes = [] wall_meshes = [] objs = [] find_objs_recursive(fac, all, objs) find_images_recursive(fac, all, roof_images, wall_images, roof_meshes, wall_meshes) if len(roof_images) > 1: raise ExportError("We found %d roof images." % len(roof_images)) if len(wall_images) > 1: raise ExportError("We found %d wall images." % len(wall_images)) # Ben says: disable this for now - we do want a roof with draped walls for fence around a draped parking lot (roof height = 0) #if len(roof_images) > 0 and not is_graded: raise ExportError("You cannot use a roof in a draped facade!") shader_keys = [ 'TWO_SIDED', 'NO_BLEND', 'SPECULAR', 'BUMP_LEVEL', 'NO_SHADOW', 'DECAL', 'DECAL_RGBA', 'DECAL_KEYED', 'DECAL_PARAMS', 'DECAL_PARAMS_PROJ', 'TEXTURE_DETAIL', 'NO_ALPHA', 'DITHERED_ALPHA', 'DECAL_LIB' ] if len(wall_images) > 0: wt = blender_relative_path(wall_images[0].getFilename()) fi.write("SHADER_WALL\n") fi.write("TEXTURE %s\n" % (prefix + wt)) core = get_core_texture(wt) if tex_exists(core + "_NML.png"): fi.write("TEXTURE_NORMAL 1.0 %s_NML.png\n" % (prefix + core)) elif tex_exists(core + "_NML.dds"): fi.write("TEXTURE_NORMAL 1.0 %s_NML.dds\n" % (prefix + core)) if tex_exists(core + "_LIT.png"): fi.write("TEXTURE_LIT %s_LIT.png\n" % (prefix + core)) elif tex_exists(core + "_LITL.dds"): fi.write("TEXTURE_LIT %s_LIT.dds\n" % (prefix + core)) shader_props = [] accum_properties(fac, shader_keys, shader_props) for p in shader_props: fi.write("%s\n" % p) if len(roof_images) > 0: fi.write("SHADER_ROOF\n") rt = blender_relative_path(roof_images[0].getFilename()) fi.write("TEXTURE %s\n" % (prefix + rt)) core = get_core_texture(rt) if tex_exists(core + "_NML.png"): fi.write("TEXTURE_NORMAL 1.0 %s_NML.png\n" % (prefix + core)) elif tex_exists(core + "_NML.dds"): fi.write("TEXTURE_NORMAL 1.0 %s_NML.dds\n" % (prefix + core)) if tex_exists(core + "_LIT.png"): fi.write("TEXTURE_LIT %s_LIT.png\n" % (prefix + core)) elif tex_exists(core + "_LIT.dds"): fi.write("TEXTURE_LIT %s_LIT.dds\n" % (prefix + core)) roof_empty = fac for o in all: if o.parent == fac and toupper(strip_suffix( o.name)) == 'ROOF_PROPS': roof_empty = o shader_props = [] accum_properties(roof_empty, shader_keys, shader_props) for p in shader_props: fi.write("%s\n" % p) if len(text) > 0 and len(roof_images): if len(roof_meshes) == 0: raise ExportError( "Internal error - we found a roof image but no roof mesh!") x_min = y_min = s_min = t_min = 9999 x_max = y_max = s_max = t_max = -9999 mm = roof_meshes[0][1].getMatrix('localspace') for f in roof_meshes[0][0].faces: for v in f.verts: vv = xform_fixed(v, mm) x_min = min(x_min, vv[0]) x_max = max(x_max, vv[0]) y_min = min(y_min, vv[1]) y_max = max(y_max, vv[1]) for v in f.uv: s_min = min(s_min, v[0]) s_max = max(s_max, v[0]) t_min = min(s_min, v[1]) t_max = max(s_max, v[1]) fi.write("ROOF_SCALE %f %f\n\n" % ((x_max - x_min) / (s_max - s_min), (y_max - y_min) / (t_max - t_min))) obj_idx = {} for o in objs: if not has_prop(o, 'external'): raise ExportError("Object %s has no external property." % o.name) k = get_prop(o, 'external', o.name) if not k in obj_idx: il = len(obj_idx) fi.write("OBJ %s\n" % k) obj_idx[k] = il floors = getChildren(fac, all) floors.sort(lambda x, y: cmp(x.name.lower(), y.name.lower())) for f in floors: if has_prefix(f.name, 'LOD'): export_lod(f, all, fi) elif has_prefix(f.name, 'SCR'): export_scraper(f, all, fi, os.path.join(dir, partial), prefix) elif not toupper(strip_suffix(f.name)) == 'ROOF_PROPS': if not strip_suffix(f.name) in info: raise ExportError("Floor %s is not defined in the text file." % f.name) export_floor(f, all, fi, info[strip_suffix(f.name)], obj_idx, objs) fi.close()
def __init__(self, obj): mesh = obj.getData(mesh=True) self.s1 = 9999 self.s2 = -9999 self.t1 = 9999 self.t2 = -9999 self.x1 = 9999 self.x2 = -9999 self.y1 = 9999 self.y2 = -9999 self.s_cuts = [] self.t_cuts = [] self.s_slop = [] self.t_slop = [] self.tile_count = len(mesh.faces) self.crop = [] self.normal_scale = get_prop(obj, 'TEXTURE_NORMAL', '1.0') self.detail_scale = get_prop(obj, 'TEXTURE_DETAIL', '1.0') self.terrain_scale = get_prop(obj, 'TEXTURE_TERRAIN', '1.0') self.hide_tile = has_prop(obj, 'HIDE_TILE') self.share_y = has_prop(obj, 'SHARE_Y') self.more_props = [] tile_keys = ['DECAL_LIB', 'DITHER_ALPHA'] for t in tile_keys: if has_prop(obj, t): self.more_props.append("%s %s" % (t, get_prop(obj, t, ''))) x1f = 9999 x2f = -9999 y1f = 9999 y2f = -9999 mm = obj.getMatrix('localspace') scaling = mm.scalePart() if scaling[0] < 0.9 or scaling[1] < 0.9 or scaling[2] < 0.9: raise ExportError("ERROR: object %s has scaling!" % obj.name) for f in mesh.faces: (self.tex_width, self.tex_height) = f.image.getSize() for v, uv in map(None, f.v, f.uv): vt = xform(v, mm) self.x1 = min(self.x1, vt[0]) self.x2 = max(self.x2, vt[0]) self.y1 = min(self.y1, vt[1]) self.y2 = max(self.y2, vt[1]) if (uv[0] < self.s1): self.s1 = uv[0] x1f = vt[0] if (uv[0] > self.s2): self.s2 = uv[0] x2f = vt[0] if (uv[1] < self.t1): self.t1 = uv[1] y1f = vt[1] if (uv[1] > self.t2): self.t2 = uv[1] y2f = vt[1] if not round(uv[0] * self.tex_width, 1) in self.s_cuts: self.s_cuts.append(round(uv[0] * self.tex_width, 1)) if not round(uv[1] * self.tex_height, 1) in self.t_cuts: self.t_cuts.append(round(uv[1] * self.tex_height, 1)) # This is a big nasty mess. Basically we have to guess whether the author is # trying to make a trivial tile (tri or quad), a grid (for AG blocks) or an FGON # (for cropped blocks). # So: the fgon case happens when we have multiple faces AND at least one interior (fgon flagged) edge. # The trivial case happens when we have one face of degree 3 or 4. is_fgon = len(mesh.faces) > 1 and is_really_fgon(mesh) is_trivial = len(mesh.faces) == 1 and (len(f.v) == 3 or len(f.v) == 4) if is_trivial or is_fgon: # CROP LOGIC. Get the fgon, write out the crop boundry. crop_raw = get_fgon(mesh) if fgon_cw(crop_raw, mesh): crop_raw.reverse() #print "raw on %s got %d edges" % ( obj.name, len(crop_raw)) self.crop = [] for i in crop_raw: v = mesh.verts[i] vt = xform(v, mm) self.crop.append(vt) else: #$ AG Block logic. Look for two-sided tiles, use to mark slop! if (f.mode & Mesh.FaceModes.TWOSIDE) == 0: smin = min(f.uv[0][0], f.uv[1][0], f.uv[2][0], f.uv[3][0]) tmin = min(f.uv[0][1], f.uv[1][1], f.uv[2][1], f.uv[3][1]) if not round(smin * self.tex_width, 1) in self.s_slop: self.s_slop.append(round(smin * self.tex_width, 1)) if not round(tmin * self.tex_height, 1) in self.t_slop: self.t_slop.append(round(tmin * self.tex_height, 1)) if x1f > x2f: (self.x1, self.x2) = (self.x2, self.x1) if y1f > y2f: (self.y1, self.y2) = (self.y2, self.y1) f = mesh.faces[0] self.tex_name = blender_relative_path(f.image.getFilename()) self.tex_scale = (self.x2 - self.x1) / (self.s2 - self.s1) self.s1 *= self.tex_width self.s2 *= self.tex_width self.t1 *= self.tex_height self.t2 *= self.tex_height self.s_cuts.sort() self.t_cuts.sort() self.s_slop.append(self.s_cuts[-1]) self.t_slop.append(self.t_cuts[-1]) self.rotation = get_prop(obj, "ROTATION", 0) aspect = ((self.s2 - self.s1) * (self.y2 - self.y1)) / ((self.t2 - self.t1) * (self.x2 - self.x1)) if aspect < 0.8 or aspect > 1.2: if aspect < -1.2 or aspect > -0.8: raise ExportError( "WARNING: aspect ratio of tile %s is not 1:1." % obj.name)
def export_scraper(obj, all, fi, dir, prefix): if not has_prop(obj, 'STEP'): raise ExportError("Object %s does not have a step property." % obj.name) if not has_prop(obj, 'FLOORS'): raise ExportError("Object %s does not have a floors property." % obj.name) pairs = getChildren(obj, all) pairs.sort(lambda x, y: cmp(x.name.lower(), y.name.lower())) model_pairs = [] delta_agl = 0 agl_span = 0 for p in pairs: kids = getChildren(p, all) base = None tower = None pad = None pins = [] for k in kids: if has_prefix(k.name, 'BASE'): if base != None: raise ExportError( "There are two bases in this scraper: %s and %s." % (k.name, base.name)) base = k elif has_prefix(k.name, 'TWR'): if tower != None: raise ExportError( "There are two towers in this scraper: %s and %s." % (k.name, tower.name)) tower = k elif has_prefix(k.name, 'PAD'): if pad != None: raise ExportError( "There are two pads in this scraper: %s and %s." % (k.name, pad.name)) pad = k elif has_prefix(k.name, 'PIN'): ploc = k.getMatrix('localspace').translationPart() pins.append(ploc[0]) pins.append(ploc[1]) if base == None: raise ExportError("There is no base in the scaper %s." % obj.name) if tower == None and pad != None: raise ExportError("You cannot use a pad without a tower in %s." % obj.name) #if tower == None: raise ExportError("There is no tower in the scaper %s." % obj.name) delta_agl = 0 delta_pad = 0 base_x = 0 base_z = 0 base_r = 0 tower_x = 0 tower_z = 0 tower_r = 0 pad_x = 0 pad_z = 0 pad_r = 0 # basen = name of obj, basep = fully qualified path to export, basek = all real children of obj, basel = library path or None if non-lib. basen = get_prop(base, 'rname', strip_prefix(base.name, 'BASE')) + '.obj' basep = dir + '/' + basen basek = getGrandChildren(base, all) basel = None bases = get_prop(base, 'show_level', '1 1') if has_prop(base, 'external'): basel = get_prop(base, 'external', None) if tower != None: towern = get_prop(tower, 'rname', strip_prefix(tower.name, 'TWR')) + '.obj' towerp = dir + '/' + towern towerk = getGrandChildren(tower, all) towerl = None if has_prop(tower, 'external'): towerl = get_prop(tower, 'external', None) towers = get_prop(tower, 'show_level', '1 1') else: towern = "" towerp = "" towerk = [] towerl = None towers = '1 1' if pad != None: padn = get_prop(pad, 'rname', strip_prefix(pad.name, 'PAD')) + '.obj' padp = dir + '/' + padn padk = getGrandChildren(pad, all) padl = None if has_prop(pad, 'external'): padl = get_prop(pad, 'external', None) pads = get_prop(pad, 'show_level', '1 1') else: padn = "" padp = "" padk = [] padl = None pads = '1 1' base_x = base.getMatrix('localspace').translationPart()[0] base_z = -base.getMatrix('localspace').translationPart()[1] base_r = make_degs(-base.RotZ) #print basen, towern #print basep, towerp #print basek, towerk if basel == None: exp_base = OBJexport8(basep) exp_base.additive_lod = 1 exp_base.us_mat = 0 exp_base.openFile(basek, base, prefix) exp_base.writeHeader() exp_base.writeObjects(basek) if tower != None: delta_agl = tower.getMatrix('localspace').translationPart()[2] tower_x = tower.getMatrix('localspace').translationPart()[0] tower_z = -tower.getMatrix('localspace').translationPart()[1] tower_r = make_degs(-tower.RotZ) if towerl == None: exp_tower = OBJexport8(towerp) exp_tower.additive_lod = 1 exp_tower.us_mat = 0 exp_tower.openFile(towerk, tower, prefix) exp_tower.writeHeader() exp_tower.writeObjects(towerk) if pad != None: delta_pad = pad.getMatrix('localspace').translationPart( )[2] - tower.getMatrix('localspace').translationPart()[2] pad_x = pad.getMatrix('localspace').translationPart()[0] pad_z = -pad.getMatrix('localspace').translationPart()[1] pad_r = make_degs(-pad.RotZ) if padl == None: exp_pad = OBJexport8(padp) exp_pad.additive_lod = 1 exp_pad.us_mat = 0 exp_pad.openFile(padk, pad, prefix) exp_pad.writeHeader() exp_pad.writeObjects(padk) agl_span = 0 for o in towerk: mm = o.getMatrix('localspace') if o.getType() == 'Mesh': mesh = o.getData(mesh=True) for v in mesh.verts: vt = xform_fixed(v, mm) agl_span = max(vt[2], agl_span) if len(towerk) == 0: # fallback case - no tower, take HEIGHT_MIN/MAX TAGS height_min = float(get_prop(obj, 'HEIGHT_MIN', 0)) height_max = float(get_prop(obj, 'HEIGHT_MAX', 0)) agl_span = height_min delta_agl = height_max - height_min if basel != None: basen = basel if padl != None: padn = padl if towerl != None: towern = towerl model_pairs.append([[basen, base_x, base_z, base_r, bases], [towern, tower_x, tower_z, tower_r, towers], [padn, pad_x, delta_pad, pad_z, pad_r, pads], pins]) fi.write("FACADE_SCRAPER %f %f %s %s\n" % (agl_span, agl_span + delta_agl, get_prop( obj, 'STEP', '4'), get_prop(obj, 'FLOORS', '2'))) for m in model_pairs: print m fi.write("FACADE_SCRAPER_MODEL_OFFSET %f %f %f %s %s" % (m[0][1], m[0][2], m[0][3], m[0][0], m[0][4])) if m[1][0] == "": fi.write(" 0 0 0 - 1 1 ") else: fi.write(" %f %f %f %s %s " % (m[1][1], m[1][2], m[1][3], m[1][0], m[1][4])) for p in m[3]: fi.write(" %f" % -p) fi.write("\n") if m[2][0] != "": fi.write("FACADE_SCRAPER_PAD %f %f %f %f %s %s\n" % (m[2][1], m[2][2], m[2][3], m[2][4], m[2][0], m[2][5]))
def export_lod(lod, all, fi): fi.write("LOD %s\n" % get_prop(lod, 'LOD', strip_prefix(lod.name, 'LOD'))) kids = getChildren(lod, all) kids.sort(lambda x, y: cmp(x.name.lower(), y.name.lower())) for k in kids: mi = mesh_cut_info(k) has_lrbt = 0 if has_prop(k, 'lrbt'): has_lrbt = 1 lrbt_string = get_prop(k, 'lrbt', '') if ',' in lrbt_string: lrbt_strings = lrbt_string.split(',') else: lrbt_strings = lrbt_string.split() if len(lrbt_strings) != 4: raise ExportError( "LOD object %s has mal-formed lrbt property %s" % (k.name, lrbt_string)) lrbt = [ float(lrbt_strings[0]), float(lrbt_strings[1]), float(lrbt_strings[2]), float(lrbt_strings[3]) ] total_h = len(mi[3]) - 1 total_v = len(mi[4]) - 1 if (lrbt[0] + lrbt[1]) > total_h: raise ExportError( "Facade %s has %d left, %d right, but only %d total h panels." % (k.name, lrbt[0], lrbt[1], total_h)) if (lrbt[2] + lrbt[3]) > total_v: raise ExportError( "Facade %s has %d bottom, %d top, but only %d total v panels." % (k.name, lrbt[2], lrbt[3], total_v)) if has_prop(k, 'ROOF_SLOPE') and lrbt[3] < 1: raise ExportError( "Facade %s has roof slope but no top layers. Check lrbt property!" % k.name) #print "bounds: %f,%f,%f tex: %f,%f uv bounds: %f,%f depth %f" % (mi[0],mi[1],mi[2],mi[7],mi[8],mi[9],mi[10], mi[11]) fi.write("TEX_SIZE %f %f\n" % (mi[7], mi[8])) if has_prefix(k.name, 'WALL'): fi.write("WALL %s\n" % get_prop(k, 'WALL', strip_prefix(k.name, 'WALL'))) if has_prop(k, 'WALL_RULE'): fi.write("WALL_RULE %s\n" % get_prop(k, 'WALL_RULE', '')) if has_prop(k, 'ROOF_SLOPE'): if has_prop(k, 'SLANT') and get_prop(k, 'SLANT', '1') == '0': fi.write("ROOF_SLOPE %s\n" % get_prop(k, 'ROOF_SLOPE', '0')) else: fi.write("ROOF_SLOPE %s SLANT\n" % get_prop(k, 'ROOF_SLOPE', '0')) s_range = mi[9] t_range = mi[10] fi.write("SCALE %f %f\n" % (mi[0] / s_range, mi[2] / t_range)) if mi[11] < 0.0: fi.write("BASEMENT_DEPTH %f\n" % (-mi[11] * mi[8] * mi[10] / mi[2])) cuts = ['LEFT', 'CENTER', 'RIGHT'] idx = 0 if sum(mi[5]) == 1: idx = 1 for n in xrange(1, len(mi[3])): nn = n - 1 if has_lrbt: idx = 1 if nn < lrbt[0]: idx = 0 if nn >= (total_h - lrbt[1]): idx = 2 fi.write("%s %f %f\n" % (cuts[idx], mi[3][nn], mi[3][n])) if mi[5][n] != mi[5][nn]: idx = idx + 1 cuts = ['BOTTOM', 'MIDDLE', 'TOP'] idx = 0 for n in xrange(1, len(mi[4])): nn = n - 1 if has_prop(k, 'ROOF_SLOPE'): if n == (len(mi[4]) - 1): idx = 2 if has_lrbt: idx = 1 if nn < lrbt[2]: idx = 0 if nn >= (total_v - lrbt[3]): idx = 2 fi.write("%s %f %f\n" % (cuts[idx], mi[4][nn], mi[4][n])) if mi[6][n] != mi[6][nn]: idx = idx + 1 else: if len(mi[3]) != 3 or len(mi[4]) != 3: raise ExportError("Roof is not cut into four quads.") fi.write("ROOF_SCALE %f %f %f %f %f %f %f %f\n" % (mi[3][0], mi[4][0], mi[3][1], mi[4][1], mi[3][2], mi[4][2], mi[0], mi[1]))
def export_floor(obj, all, fi, info, obj_idx, objs): fi.write("\nFLOOR %s\n" % obj.name) kids = getChildren(obj, all) roofs = filter_objects(kids, 'Mesh', 'ROOF') segs = filter_objects(kids, 'Empty', 'SEG') crvs = filter_objects(kids, 'Empty', 'CRV') #------- EXTRACT ROOF HEIGHTS FROM ALL ROOF OBJECTS ------- all_roofs = [] for r in roofs: max_height = 0 mm = r.getMatrix('localspace') mesh = r.getData(mesh=True) two_sided = 0 x_min = 9999 y_min = 9999 for f in mesh.faces: for i in [0, 1, 2]: vv = xform_fixed(f.v[i], mm) max_height = max(vv[2], max_height) x_min = min(x_min, f.v[i].co[0]) y_min = min(y_min, f.v[i].co[1]) if f.mode & Mesh.FaceModes.TWOSIDE: two_sided = 1 all_roofs.append([r, max_height, two_sided, x_min, y_min]) all_roofs.sort(lambda x, y: cmp(x[1], y[1])) for rr in all_roofs: r = rr[0] roof_h = [] mm = r.getMatrix('localspace') mesh = r.getData(mesh=True) for f in mesh.faces: vv = xform_fixed(f.v[0], mm) if not vv[2] in roof_h: roof_h.append(vv[2]) if len(roof_h) > 0: roof_h.sort() fi.write("ROOF_HEIGHT") for h in roof_h: fi.write(" %f" % round(h, 3)) fi.write("\n") if rr[2] and rr[1] != 0.0: fi.write("TWO_SIDED_ROOF\n") for o in objs: if o.parent == r: oi = obj_idx[get_prop(o, 'external', o.name)] loc = o.getMatrix('localspace').translationPart() fi.write("ROOF_OBJ_HEADING %d %f %f %f" % (oi, loc[0] - rr[3], loc[1] - rr[4], make_degs(-o.RotZ))) if has_prop(o, 'show_level'): fi.write(" %s" % get_prop(o, 'show_level', '')) fi.write("\n") seg_map = {} crv_map = {} for s in segs: i = int(strip_prefix(s.name, 'SEG')) if i in seg_map: raise ExportError( "The segment %s re-uses a segment index number." % s.name) seg_map[i] = s for s in crvs: i = int(strip_prefix(s.name, 'CRV')) if i in crv_map: raise ExportError( "The curved segment %s re-uses a segment index number." % s.name) crv_map[i] = s for i in xrange(len(segs)): if not i in seg_map: raise ExportError( "The floor %s is missing a segment, index number %d." % (obj.name, i)) export_wall2(seg_map[i], all, fi, obj_idx) for i in xrange(len(crvs)): if not i in crv_map: raise ExportError( "The floor %s is missing a curved segment, index number %d." % (obj.name, i)) export_wall2(crv_map[i], all, fi, obj_idx) if len(info) == 0: raise ExportError("There are no walls defined for floor %s" % (obj.name)) if len(seg_map) != len(crv_map): raise ExportError( "There are a different number of curved and flat segments. %d curved, %d flat." % (len(crv_map), len(seg_map))) for w in info: fi.write("WALL %s %s %s %s %s\n" % (w[1][0], w[1][1], w[1][2], w[1][3], w[0])) if len(w) == 2: raise ExportError( "There are no spellings defined for a wall in %s." % (obj.name)) for r in w[1][4:]: fi.write("WALL_RULE %s %s %s %s\n" % (r[0], r[1], r[2], r[3])) for s in w[2:]: fi.write("SPELLING") for ss in s: idx = int(ss) if idx < 0 or idx >= len(segs): raise ExportError( "Wall %s %s %s has a spelling with index %d that is out of range." % (w[0], w[1], w[2], idx)) fi.write(" %s" % ss) fi.write("\n")
def export_plug(self, obj, scene): if self.debug: print "Exporting plug based on armature obj %s." % obj.name plug_keys = ['JUNCTION_DRAPED', 'JUNCTION_GRADED', 'JUNCTION_EMBANKED', 'JUNCTION_BRIDGE', 'JUNCTION_COMPOSITE_CORNER', 'JUNCTION_COMPOSITE_APPROACH', 'JUNCTION_COMPOSITE_CENTER', 'BEZIER_OFFSET', 'JUNCTION_MINIMA', 'MAX_SHEAR', 'CUTBACK' ]; self.file.write("# Junction %s.\n" % obj.name) emit_properties(self.file, obj, plug_keys) degree = 0 for label in ['JUNCTION_DRAPED', 'JUNCTION_GRADED', 'JUNCTION_EMBANKED', 'JUNCTION_BRIDGE']: if has_prop(obj,label): degree = int(get_prop(obj,label,'0')) if has_prop(obj,'JUNCTION_COMPOSITE_CORNER'): degree = 2 if has_prop(obj,'JUNCTION_COMPOSITE_APPROACH'): degree = 4 if has_prop(obj,'JUNCTION_COMPOSITE_CENTER'): degree = 1 for p in obj.getAllProperties(): if strip_suffix(p.name.upper()) == 'MATCH': mn = get_road_match(p.data) if mn == None: mn = str(p.data) mn_cut = mn.split() for i in range(0,len(mn_cut),2): if not mn_cut[i] in ['io', 'in', 'out']: raise ExportError( "%s: This matching directive is illegal: %s" % (obj.name, mn)) self.file.write("MATCH %s\n" % mn) annotations = getChildren(obj,scene) meshes = filter_objects(annotations,'Mesh', '') meta_rect = [ 0, 0, 10, 10 ]; for m in meshes: if has_prefix(m.name,'META'): mesh=m.getData(mesh=True) meta_rect[0] = meta_rect[2] = mesh.verts[0].co[0] meta_rect[1] = meta_rect[3] = mesh.verts[0].co[1] for v in mesh.verts: meta_rect[0] = min(meta_rect[0],v.co[0]) meta_rect[2] = max(meta_rect[2],v.co[0]) meta_rect[1] = min(meta_rect[1],v.co[1]) meta_rect[3] = max(meta_rect[3],v.co[1]) if degree < 1: raise ExportError( "%s: this junctions degree could not be determined." % obj.name) arm=obj.getData() bone_ct=0 bone_idx=dict() annotations = getChildren(obj,scene) objs = filter_objects(annotations,'Empty','OBJ') for bn, bone in arm.bones.items(): bh = bone.head['ARMATURESPACE'] bt = bone.tail['ARMATURESPACE'] if has_prefix(bn,'BEZ'): bone_len = bone_length_to_me(bone) self.file.write("BONE_BEZIER %s %f %f %f %f %f %f %f\n" % (strip_prefix(bn,'BEZ'), bone_len, bh[0], bh[2], -bh[1], bt[0]-bh[0],bt[2]-bh[2],bh[1]-bt[1])) elif has_prefix(bn,'EDG'): finger = int(strip_prefix(bn,'EDG')) export_edge_bone(self.file,degree, finger, bh[0],bh[1],bh[2], meta_rect) elif has_prefix(bn,'APP'): if not has_prop(obj,'JUNCTION_COMPOSITE_APPROACH') and not has_prop(obj,'JUNCTION_COMPOSITE_CENTER'): raise ExportError( "%s: You cnanot use approach bones except on a composite app or center piece: %s", (obj.name % bn)) export_app_bone(self.file,bh[0],bh[1],bh[2], meta_rect) else: export_any_bone(self.file,bn,bh[0],bh[1],bh[2],bt[0]-bh[0],bt[1]-bh[1],bt[2]-bh[2]) bone_idx[bn]=bone_ct bone_ct+=1 vert_list=[] shader_idx=-1 lod_now=-1 surf_now=None up_verts=[] vti = [] for o in meshes: if not has_prefix(o.name,'META'): mesh=o.getData(mesh=True) for f in mesh.faces: while len(vti) < len(mesh.verts): vti.append([]) for v, uv in reversed(map(None, f.verts, f.uv)): weight_list = mesh.getVertexInfluences(v.index) if len(weight_list) == 0: raise ExportError( "ERROR: plug/byt %s OB %s mesh %s is missing its vertex weighting." % (obj.name, o.name, mesh.name)) weight_list.sort(key=lambda w: w[1], reverse=True) for w in weight_list: w[0] = bone_idx[w[0]] want_up=False if not v in up_verts: for e in mesh.edges: if (e.flag & Mesh.EdgeFlags.SEAM): for vv in e: if vv == v: want_up = True up_verts.append(v) vt=VT(v.co,v.no,uv,weight_list, want_up) #print "checking vert %d against: " % v.index #print vti[v.index] for j in vti[v.index]: if vt.equals(vert_list[j]): #print "found it at %d" % j break else: vti[v.index].append(len(vert_list)) #print "Adding - new list is." #print vti[v.index] vert_list.append(vt) for v in vert_list: self.file.write(str(v)) for o in meshes: if not has_prefix(o.name,'META'): mesh=o.getData(mesh=True) for f in mesh.faces: if len(f.verts) != 3 and len(f.verts) != 4: raise ExportError( "ERROR: %d verts in face.\n" % len(f.verts)) else: this_idx = self.shaders.shader_idx(mesh, f) this_lod = far_lod_from_layers(o.layers) this_surf = "none" if not (f.mode & Mesh.FaceModes.DYNAMIC): this_surf = get_prop(o,'surface','asphalt') if this_idx != shader_idx or this_lod != lod_now or this_surf != surf_now: self.file.write("JUNC_SHADER %d %d %s\n" % (this_idx, int(this_lod), this_surf )) shader_idx = this_idx lod_now = this_lod surf_now = this_surf if len(f.verts) == 3: self.file.write("TRI ") else: self.file.write("QUAD ") for v, uv in reversed(map(None, f.verts, f.uv)): weight_list = mesh.getVertexInfluences(v.index) weight_list.sort(key=lambda w: w[1], reverse=True) for w in weight_list: w[0] = bone_idx[w[0]] vt=VT(v.co,v.no,uv,weight_list, v in up_verts) #print "Try to match v %d (%s) against. " % (v.index, str(vt)) #print vti[v.index] for j in vti[v.index]: #print " trying %d (%s)." % (j, str(vert_list[j])) if vt.equals(vert_list[j]): self.file.write(" %d" % j) break else: raise ExportError("ERROR: mesh indexing failed for BYT.") self.file.write("\n") for o in objs: bn = o.parentbonename bidx = bone_idx[bn] oname = strip_prefix(o.name,'OBJ') oname = get_prop(o,'external', oname) draped = not has_prop(o,'graded') if oname[-4:] != '.obj': oname += '.obj' #print oname #print "Obj is at: %f, %f, %f" % (o.LocX, o.LocY, o.LocZ) #print "Transform:" xyz=o.getMatrix('localspace').translationPart() self.file.write("JUNC_OBJECT %f %f %f %f %d %d 1.0 0 0 0 0 0 0 %s" % (xyz[0], xyz[2], -xyz[1], round(-o.RotZ * 180 / 3.14159265), draped, bidx, oname)) if has_prop(o,'obj_show_level'): self.file.write(" %s" % get_prop(o,'obj_show_level','')) self.file.write("\n") obj_keys = ['OBJECT_ALT', 'OBJECT_FREQ' ] emit_properties(self.file, o, obj_keys) for p in o.getAllProperties(): if strip_suffix(p.name.upper()) == 'MACRO': self.file.write("%s" % get_macro(p.data)) do_macros(self.file,obj,0,0,0,'DRAPED')
def export_ag_file(self, obj, scene): if self.debug: print "Starting export of %s" % obj.name want_groups = 0 self.obj_name_list = [] self.fac_name_list = [] real_name = strip_suffix(obj.name[3:]) suffix = '.' + obj.name[0:3].lower() export_name = os.path.join(self.path, real_name + suffix) print 'Starting AG export to ' + export_name is_ags = False if not checkFile(export_name): return if has_prefix(obj.name, 'agb'): self.file = open(export_name, 'w') self.file.write("A\n1000\nAG_BLOCK\n\n") elif has_prefix(obj.name, 'ags'): self.file = open(export_name, 'w') self.file.write("A\n1000\nAG_STRING\n\n") is_ags = True elif has_prefix(obj.name, 'agp'): self.file = open(export_name, 'w') self.file.write("A\n1000\nAG_POINT\n\n") else: if not obj.name[0:3].upper() in ['OBJ', 'BGN', 'END', 'VRT']: print "ERROR: object %s is of unknown type." % obj.name return vname = get_prop(obj, 'vname', real_name) vname1 = get_prop(obj, 'vname1', real_name) vname2 = get_prop(obj, 'vname2', real_name) want_tile_ids = has_prop(obj, 'tile_ids') lib_root = get_prop(obj, 'lib_root', def_lib_root) self.file.write("EXPORT %s/%s/%s %s/%s\n\n" % (lib_root, self.theme, vname + suffix, self.theme, real_name + suffix)) if vname != vname1: self.file.write("EXPORT %s/%s/%s %s/%s\n\n" % (lib_root, self.theme, vname1 + suffix, self.theme, real_name + suffix)) if vname != vname2 and vname1 != vname2: self.file.write("EXPORT %s/%s/%s %s/%s\n\n" % (lib_root, self.theme, vname2 + suffix, self.theme, real_name + suffix)) top_level_objects = getChildren(obj, scene.objects) top_level_objects.sort(key=sort_obj_by_name) # we also grab any 'surplus' objects floating around at the 'tile/variant' level. # these will NOT be used as annotations but for OBJs we still run the export. This gets # Alex (1) more files out on disk and (2) the EXPORT name in the .agp for copying to # library.txt with a shell script. # we have to recurse to get only OUR annotations per file - otherwise we get cross-talk between tiles, which is bad. variants = getChildren(obj, scene.objects) annotations = [] for v in variants: annotations += getChildren(v, scene.objects) annotations_real = getAllDepth(2, scene.objects) objs = filter_objects(annotations, 'Empty', 'OBJ') facs = filter_objects(annotations, 'Mesh', 'FAC') tiles = filter_objects(annotations, 'Mesh', 'TILE') objs += filter_objects(variants, 'Empty', 'OBJ') # objs += filter_objects(extras,'Empty','OBJ') print "For AG %s" % obj.name for v in variants: print "Foudn variant %s" % v.name for a in annotations: print "Found annotation %s" % a.name for r in annotations_real: print "Real annotation: %s" % r.name for o in objs: print "found obj container %s" % o.name if len(tiles) == 0: raise ExportError( "ERROR: no tiles were found in the AG export file %s." % obj.name) return tt = TILE(tiles[0]) ag_keys = [ 'HIDE_TILES', 'TILE_LOD', 'LAYER_GROUP', 'CROP', 'MINIMUM_OVERLAP', 'VEGETATION', 'CREASE_ANGLE', 'CAPS', 'FILL_LAYER', 'SLOPE_LIMIT', 'OVERLAP_H', 'OVERLAP_V', 'SPELLING_S', 'SPELLING_T', 'CORNER', 'SPELLING' ] global_props = [] accum_properties(obj, ag_keys, global_props) text_props = text_for_obj(obj.name) for o in facs: fname = lib_fac_name(o, self.theme) if not fname in self.fac_name_list: self.fac_name_list.append(fname) # Ben says: facades are ALWAYS external, do NOT run facade exporter here. #self.file.write("EXPORT %s/%s/%s.fac %s/objects/%s.fac\n" % (lib_root, self.theme, fname, self.theme,fname)) # # OBJ GENERATION # # Now is a good time to export OBJs for any attached OBJS...why not? # obj_exp_list = [] # List of real files for export. obj_lib_list = [ ] # List of virtual->real path pairs for export lib entries. for o in objs: lname = lib_obj_name(o, self.theme, lib_root) if not lname in self.obj_name_list: self.obj_name_list.append(lname) # if an OBJ is tagged external, don't go writing the OBJ; that means we're using something that already exists. if not has_prop(o, 'external'): l = o.name.rfind('.') export_name = strip_suffix(child_obj_name( o, scene.objects)) + '.obj' export_path = os.path.join(self.objdir, export_name) if not export_name in obj_exp_list: exporter = OBJexport8(export_path) exporter.additive_lod = 1 exporter.use_mat = 0 my_parts = getGrandChildren(o, scene.objects) exporter.openFile(my_parts, o, '../') exporter.writeHeader() exporter.writeObjects(my_parts) # don't double-accume obj-name list because it is used to build the obj index table!! obj_exp_list.append(export_name) else: if self.debug: print "Skipping second export of OBJ %s (%s)" % ( lname, export_name) if not [lname, export_name] in obj_lib_list: if o.name[0:7] != 'OBJcom_': self.file.write("EXPORT %s %s/objects/%s\n" % (lname, self.theme, export_name)) obj_lib_list.append([lname, export_name]) else: if self.debug: print "Skipping second lib entry of OBJ %s (%s)" % ( lname, export_name) else: if self.debug: print "Skipping external OBJ %s" % lname self.file.write("\n") # # Write headers # tt.write_tex_header(self.file) if has_prop(obj, 'macro'): macro = get_macro(get_prop(obj, 'macro', '')) if macro != None: self.file.write(macro) else: raise ExportError("WARNING: missing macro %s." % get_prop(obj, 'macro', '')) self.file.write("\n") for g in global_props: self.file.write("%s\n" % g) self.file.write("\n") for n in self.obj_name_list: self.file.write("OBJECT %s\n" % n) for n in self.fac_name_list: self.file.write("FACADE %s\n" % n) self.file.write("\n") tile_list = [] # # TILE ANNOTATION EXPORT # for o in top_level_objects: if not has_prefix(o.name, 'obj'): if is_ags and want_tile_ids: self.export_ag_tile(o, getChildren(o, scene.objects), scene.objects, lib_root, tile_list) else: self.export_ag_tile(o, getChildren(o, scene.objects), scene.objects, lib_root, None) for g in text_props: self.file.write("%s\n" % g) print tile_list self.file.close if self.log: r = Draw.PupMenu('|'.join([a[0] for a in self.log]))
# # See ReadMe-XPlane2Blender.html for usage. # import Blender from Blender import Draw, Window from XPlaneExport import OBJexport7, ExportError if Window.EditMode(): Window.EditMode(0) try: obj = None scene = Blender.Scene.GetCurrent() baseFileName = Blender.Get('filename') l = baseFileName.lower().rfind('.blend') if l == -1: raise ExportError('Save this .blend file first') baseFileName = baseFileName[:l] obj = OBJexport7(baseFileName + '.obj', __version__, False) obj.export(scene) except ExportError, e: for o in scene.objects: o.select(0) if e.objs: layers = [] if isinstance(e.objs, tuple): (o, mesh, faces) = e.objs o.select(1) layers = o.layers for f in mesh.faces: f.sel = 0 if faces:
def decode(obj): properties = obj.getAllProperties() objname = obj.name #setup default manipulator attribute values manip_iscommand_br = False manip_is_push_tk = False manip_is_toggle_tk = False manip_command_br = "<command>" manip_cursor_br = "<cursor>" manip_x_br = "<x>" manip_y_br = "<y>" manip_z_br = "<z>" manip_val1_br = "<val1>" manip_val2_br = "<val2>" manip_dref_br = "<dref>" manip_tooltip_br = "<tooltip>" manip_bone_name_br = "" #--leave this blank by default, if its not blank the code will try and find the bone name for prop in properties: if( prop.name == "mnp_iscommand" ): manip_iscommand_br = prop.data #--expects a boolean value if( prop.name == "mnp_command" ): manip_command_br = prop.data.strip() if( prop.name == "mnp_cursor" ): manip_cursor_br = prop.data.strip() if( prop.name == "mnp_dref" ): manip_dref_br = prop.data.strip() if( prop.name == "mnp_tooltip" ): manip_tooltip_br = prop.data.strip() if( prop.name == "mnp_bone" ): manip_bone_name_br = prop.data.strip() if( prop.name == "mnp_v1" ): manip_val1_br = str(prop.data) if( prop.name == "mnp_v2" ): manip_val2_br = str(prop.data) if( prop.name == "mnp_is_push" ): manip_is_push_tk = prop.data if( prop.name == "mnp_is_toggle" ): manip_is_toggle_tk = prop.data # BR's weird scheme: if there is NO mnp_bone there is no manip, get out. But the magic # bone names arm_ are place-holders - they're not REAL armatures, it's just a place-holder # to make the export work. if manip_bone_name_br == "": return anim_decode(obj) if( manip_bone_name_br != "" and manip_bone_name_br != "arm_" ): obj_manip_armature_br = Blender.Object.Get( manip_bone_name_br ) if( obj_manip_armature_br != None ): obj_manip_armature_data_br = obj_manip_armature_br.getData() obj_manip_bone_br = obj_manip_armature_data_br.bones.values()[0] vec_tail = obj_manip_bone_br.tail['ARMATURESPACE'] vec_arm = [obj_manip_armature_br.LocX, obj_manip_armature_br.LocY, obj_manip_armature_br.LocZ] #blender Y = x-plane Z, transpose manip_x_br = str( round(vec_tail[0],3) ) manip_y_br = str( round(vec_tail[2],3) ) manip_z_br = str( round(-vec_tail[1],3) ) #note: value is inverted. #self.file.write( str( vec_tail ) + "\n" ) #self.file.write( str( vec_arm ) + "\n" ) data = "" if( manip_iscommand_br ): #wiki def: ATTR_manip_command <cursor> <command> <tooltip> data = ("ATTR_manip_command %s %s %s" % (manip_cursor_br, manip_command_br, manip_tooltip_br)) elif( manip_is_push_tk): data = ("ATTR_manip_push %s %s %s %s" % (manip_cursor_br, manip_val1_br, manip_val2_br, manip_dref_br)) elif( manip_is_toggle_tk): data = ("ATTR_manip_toggle %s %s %s %s" % (manip_cursor_br, manip_val1_br, manip_val2_br, manip_dref_br)) else: #wiki def: ATTR_manip_drag_axis <cursor> <x> <y> <z> <value1> < value2> <dataref> <tooltip> data = ("ATTR_manip_drag_axis %s %s %s %s %s %s %s %s" % (manip_cursor_br, manip_x_br, manip_y_br, manip_z_br, manip_val1_br, manip_val2_br, manip_dref_br, manip_tooltip_br)) if data.find("<x>") != -1: print properties raise ExportError("%s: Manipulator '%s' is incomplete but was still exported." % (objname, data)) return data