From ad700ba24fbc8ee8e216090bdb8157234409b29d Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 16 Nov 2007 14:47:31 +0000 Subject: [PATCH 01/29] * wizard_curve2tree.py - Automatic alpha blended, textured image joins using material textures and UV layers. Also added some detail options and made it easier to get low poly results. * Mesh.c bugfix, "mesh.verts = None" didn't set the mesh->mselect pointer to NULL, wizard_curve2tree so would crash when in editmode. * Texture.py - MTex.uvlayer doc was missing * buttons_shading.c - Stencil tooltip was stupid. --- release/scripts/wizard_curve2tree.py | 617 +++++++++++++++---- source/blender/python/api2_2x/Mesh.c | 2 +- source/blender/python/api2_2x/doc/Texture.py | 2 + source/blender/src/buttons_shading.c | 6 +- 4 files changed, 509 insertions(+), 118 deletions(-) diff --git a/release/scripts/wizard_curve2tree.py b/release/scripts/wizard_curve2tree.py index 42dcddc9a7b..f7ecd53bbcf 100644 --- a/release/scripts/wizard_curve2tree.py +++ b/release/scripts/wizard_curve2tree.py @@ -79,6 +79,24 @@ def debug_pt(co): Blender.Window.RedrawAll() print 'debugging', co +def freshMesh(mesh): + ''' + Utility function to get a new mesh or clear the existing one, but dont clear everything. + ''' + if mesh: + materials = mesh.materials + mesh.verts = None + for group in mesh.getVertGroupNames(): + mesh.removeVertGroup(group) + + # Add materials back + mesh.materials = materials + else: + mesh = bpy.data.meshes.new() + + return mesh + + def closestVecIndex(vec, vecls): best= -1 best_dist = 100000000 @@ -134,7 +152,6 @@ class tree: # self.limbScale = (bb[0] - bb[7]).length / 2.825 # THIS IS GOOD WHEN NON SUBSURRFED self.limbScale = (bb[0] - bb[7]).length / 1.8 - # forward_diff_bezier will fill in the blanks # nice we can reuse these for every curve segment :) pointlist = [[None, None, None] for i in xrange(steps+1)] @@ -211,13 +228,13 @@ class tree: twig_random_orientation = 180,\ twig_random_angle = 33,\ twig_recursive=True,\ + twig_recursive_limit=3,\ twig_ob_bounds=None,\ twig_ob_bounds_prune=True,\ twig_ob_bounds_prune_taper=True,\ ): ''' build tree data - fromCurve must run first - ''' # Sort the branchs by the first radius, so big branchs get joins first @@ -285,6 +302,9 @@ class tree: if twig_ob_bounds: # Only spawn twigs inside this mesh self.setTwigBounds(twig_ob_bounds) + if not twig_recursive: + twig_recursive_limit = 0 + self.buildTwigs(twig_ratio) branches_twig_attached = [] @@ -303,8 +323,8 @@ class tree: branches_twig_sort.sort() # this will sort the branches with best braches for adding twigs to at the start of the list for tmp_sortval, twig_pt_index, brch_parent in branches_twig_sort: # tmp_sortval is not used. - - if twig_pt_index != -1: + if twig_pt_index != -1 and (twig_recursive_limit==0 or brch_parent.generation <= twig_recursive_limit): + if brch_twig_index >= len(self.branches_twigs): break @@ -364,9 +384,9 @@ class tree: # we would not have been but here if the bounds were outside if twig_ob_bounds_prune: brch_twig.boundsTrim() - if twig_ob_bounds_prune_taper: # taper to a point. we could use some nice taper algo here - just linear atm. + brch_twig.taper() # Make sure this dosnt mess up anything else @@ -375,8 +395,9 @@ class tree: # Add to the branches #self.branches_all.append(brch_twig) - if len(brch_twig.bpoints) > 4: + if len(brch_twig.bpoints) > 2: branches_twig_attached.append(brch_twig) + brch_twig.generation = brch_parent.generation + 1 else: # Dont add the branch parent_pt.childCount -= 1 @@ -437,7 +458,7 @@ class tree: print None ''' - def optimizeSpacing(self, density=1.0, joint_compression=1.0, joint_smooth=1.0): + def optimizeSpacing(self, seg_density=0.5, seg_density_angle=20.0, seg_density_radius=0.3, joint_compression=1.0, joint_smooth=1.0): ''' Optimize spacing, taking branch hierarchy children into account, can add or subdivide segments so branch joins dont look horrible. @@ -452,7 +473,7 @@ class tree: # Collapsing for brch in self.branches_all: - brch.collapsePoints(density, joint_smooth) + brch.collapsePoints(seg_density, seg_density_angle, seg_density_radius, joint_smooth) for brch in self.branches_all: brch.branchReJoin() @@ -514,25 +535,8 @@ class tree: - def toMesh(self, mesh=None, do_uv=True, do_uv_keep_vproportion=True, do_uv_uscale=False, uv_image = None, uv_x_scale=1.0, uv_y_scale=4.0, do_cap_ends=False): - # Simple points - ''' - self.mesh = bpy.data.meshes.new() - self.objectCurve = bpy.data.scenes.active.objects.new(self.mesh) - self.mesh.verts.extend([ pt.co for brch in self.branches_all for pt in brch.bpoints ]) - ''' - if mesh: - self.mesh = mesh - materials = mesh.materials - mesh.verts = None - for group in mesh.getVertGroupNames(): - mesh.removeVertGroup(group) - - # Add materials back - mesh.materials = materials - else: - self.mesh = bpy.data.meshes.new() - + def toMesh(self, mesh=None, do_uv=True, do_uv_keep_vproportion=True, do_uv_vnormalize=False, do_uv_uscale=False, uv_image = None, uv_x_scale=1.0, uv_y_scale=4.0, do_uv_blend_layer= False, do_cap_ends=False): + self.mesh = freshMesh(mesh) totverts = 0 for brch in self.branches_all: @@ -669,20 +673,37 @@ class tree: for pt in brch.bpoints: pt.toMesh(self.mesh) - faces = self.mesh.faces - faces_extend = [ face for brch in self.branches_all for pt in brch.bpoints for face in pt.faces if face ] + #faces_extend = [ face for brch in self.branches_all for pt in brch.bpoints for face in pt.faces if face ] + + + + faces_extend = [] + for brch in self.branches_all: + if brch.parent_pt: + faces_extend.extend(brch.faces) + for pt in brch.bpoints: + for face in pt.faces: + if face: + faces_extend.append(face) + if do_cap_ends: # TODO - UV map and image? faces_extend.extend([ brch.bpoints[-1].verts for brch in self.branches_all ]) - - faces.extend(faces_extend) + faces = self.mesh.faces + faces.extend(faces_extend) if do_uv: # Assign the faces back face_index = 0 for brch in self.branches_all: + if brch.parent_pt: + for i in (0,1,2,3): + face = brch.faces[i] = faces[face_index+i] + face.smooth = 1 + face_index +=4 + for pt in brch.bpoints: for i in (0,1,2,3): if pt.faces[i]: @@ -690,8 +711,12 @@ class tree: pt.faces[i].smooth = True face_index +=1 - if self.mesh.faces: - self.mesh.faceUV = True + #if self.mesh.faces: + # self.mesh.faceUV = True + mesh.addUVLayer( 'base' ) + + # rename the uv layer + #mesh.renameUVLayer(mesh.getUVLayerNames()[0], 'base') for brch in self.branches_all: @@ -703,41 +728,162 @@ class tree: uv_x_scale_branch = uv_x_scale_branch / len(brch.bpoints) # uv_x_scale_branch = brch.bpoints[0].radius + + if do_uv_vnormalize: + uv_normalize = [] + + def uvmap_faces(my_faces, y_val, y_size): + ''' + Accept a branch or pt faces + ''' + uv_ls = [None, None, None, None] + for i in (0,1,2,3): + if my_faces[i]: + if uv_image: + my_faces[i].image = uv_image + uvs = my_faces[i].uv + else: + # Use these for calculating blending values + uvs = [Vector(0,0), Vector(0,0), Vector(0,0), Vector(0,0)] + + uv_ls[i] = uvs + + x1 = i*0.25 * uv_x_scale * uv_x_scale_branch + x2 = (i+1)*0.25 * uv_x_scale * uv_x_scale_branch + + uvs[3].x = x1; + uvs[3].y = y_val+y_size + + uvs[0].x = x1 + uvs[0].y = y_val + + uvs[1].x = x2 + uvs[1].y = y_val + + uvs[2].x = x2 + uvs[2].y = y_val+y_size + + if do_uv_vnormalize: + uv_normalize.extend(uvs) + return uv_ls + + # Done uvmap_faces y_val = 0.0 + + if brch.parent_pt: + y_size = (brch.getParentFaceCent() - brch.bpoints[0].co).length + + if do_uv_keep_vproportion: + y_size = y_size / ((brch.bpoints[0].radius + brch.parent_pt.radius)/2) * uv_y_scale + + brch.uv = uvmap_faces(brch.faces, 0.0, y_size) + + y_val += y_size + for pt in brch.bpoints: if pt.next: y_size = (pt.co-pt.next.co).length - # scale the uvs by the radius, avoids stritching. if do_uv_keep_vproportion: y_size = y_size / pt.radius * uv_y_scale + pt.uv = uvmap_faces(pt.faces, y_val, y_size) + y_val += y_size + + + if do_uv_vnormalize and uv_normalize: + # Use yscale here so you can choose to have half the normalized value say. + vscale = (1/uv_normalize[-1].y) * uv_y_scale + for uv in uv_normalize: + uv.y *= vscale + + + + # Done with UV mapping the first layer! now map the blend layers + if do_uv_blend_layer: + + + + # Set up the blend UV layer - this is simply the blending for branch joints + mesh.addUVLayer( 'blend' ) + mesh.activeUVLayer = 'blend' + + # Set all faces to be on full blend + for f in mesh.faces: + for uv in f.uv: + uv.y = uv.x = 0.0 + + for brch in self.branches_all: + if brch.parent_pt: + for f in brch.faces: + if f: + uvs = f.uv + uvs[0].x = uvs[1].x = uvs[2].x = uvs[3].x = 0.0 + uvs[0].y = uvs[1].y = 1.0 # swap these? - same as inverting the blend + uvs[2].y = uvs[3].y = 0.0 + + # Set up the join UV layer, this overlays nice blended + mesh.addUVLayer( 'join' ) + mesh.activeUVLayer = 'join' + + # Set all faces to be on full blend + for f in mesh.faces: + for uv in f.uv: + uv.y = uv.x = 0.0 + + for brch in self.branches_all: + if brch.parent_pt: + # The UV's that this branch would cover if it was a face, + uvs_base = brch.parent_pt.uv[brch.getParentQuadIndex()] - for i in (0,1,2,3): - if pt.faces[i]: - if uv_image: - pt.faces[i].image = uv_image - - uvs = pt.faces[i].uv - - x1 = i*0.25 * uv_x_scale * uv_x_scale_branch - x2 = (i+1)*0.25 * uv_x_scale * uv_x_scale_branch - - uvs[3].x = x1; - uvs[3].y = y_val+y_size - - uvs[0].x = x1 - uvs[0].y = y_val - - uvs[1].x = x2 - uvs[1].y = y_val - - uvs[2].x = x2 - uvs[2].y = y_val+y_size + uvs_base_mid = Vector(0,0) + for uv in uvs_base: + uvs_base_mid += uv + + uvs_base_mid *= 0.25 - if pt.next: - y_val += y_size + # TODO - Factor scale and distance in here + ## uvs_base_small = [(uv+uvs_base_mid)*0.5 for uv in uvs_base] + uvs_base_small = [uvs_base_mid, uvs_base_mid, uvs_base_mid, uvs_base_mid] + + if brch.faces[0]: + f = brch.faces[0] + uvs = f.uv + uvs[0][:] = uvs_base[0] + uvs[1][:] = uvs_base[1] + + uvs[2][:] = uvs_base_small[1] + uvs[3][:] = uvs_base_small[0] + + if brch.faces[1]: + f = brch.faces[1] + uvs = f.uv + uvs[0][:] = uvs_base[1] + uvs[1][:] = uvs_base[2] + + uvs[2][:] = uvs_base_small[2] + uvs[3][:] = uvs_base_small[1] + + if brch.faces[2]: + f = brch.faces[2] + uvs = f.uv + uvs[0][:] = uvs_base[2] + uvs[1][:] = uvs_base[3] + + uvs[2][:] = uvs_base_small[3] + uvs[3][:] = uvs_base_small[2] + + if brch.faces[3]: + f = brch.faces[3] + uvs = f.uv + uvs[0][:] = uvs_base[3] + uvs[1][:] = uvs_base[0] + + uvs[2][:] = uvs_base_small[0] + uvs[3][:] = uvs_base_small[3] + + mesh.activeUVLayer = 'base' # just so people dont get worried the texture is not there - dosnt effect rendering. else: # no UV's for f in self.mesh.faces: @@ -764,11 +910,99 @@ class tree: for ed in self.mesh.edges: if ed.v1.sel==False and ed.v2.sel==False: ed.crease = 255 + ed.sel = True # so its all selected still del faces_extend return self.mesh + + def toLeafMesh(self, mesh_leaf, leaf_branch_limit = 0.5, leaf_size = 0.5): + ''' + return a mesh with leaves seperate from the tree + + Add to the existing mesh. + ''' + + # first collect stats, we want to know the average radius and total segments + #radius = [(pt.radius for pt in self.branches_all for pt in brch.bpoints for pt in brch.bpoints] + mesh_leaf = freshMesh(mesh_leaf) + self.mesh_leaf = mesh_leaf + + totpoints = 0 + radius = 0.0 + max_radius = 0.0 + for brch in self.branches_all: + for pt in brch.bpoints: + radius += pt.radius + if pt.radius > max_radius: + max_radius = pt.radius + + #totpoints += len(brch.bpoints) + + radius_max = max_radius * leaf_branch_limit + + + verts_extend = [] + faces_extend = [] + + co1,co2,co3,co4 = Vector(),Vector(),Vector(),Vector() + + for brch in self.branches_all: + + # quick test, do we need leaves on this branch? + if brch.bpoints[-1].radius > radius_max: + continue + + count = 0 + for pt in brch.bpoints: + if pt.childCount == 0 and pt.radius < radius_max: + # Ok we can add a leaf here. set the co's correctly + co1[:] = pt.co + co2[:] = pt.co + co3[:] = pt.co + co4[:] = pt.co + + cross_leafdir = CrossVecs( zup, pt.no ) + cross_leafdir.length = leaf_size + + #cross_leafwidth = CrossVecs(pt.no, cross_leafdir) + + # Facing up + cross_leafwidth_up = CrossVecs(zup, cross_leafdir).normalize() * leaf_size + cross_leafwidth_aligned = pt.no + + #cross_leafwidth = (cross_leafwidth_up + cross_leafwidth_aligned)/2 + cross_leafwidth = cross_leafwidth_aligned + + cross_leafwidth.length = leaf_size/2 + + if count % 2: + cross_leafwidth.negate() + cross_leafdir.negate() + + co1 += cross_leafdir + co2 += cross_leafdir + + co2 += cross_leafwidth + co3 += cross_leafwidth + + co1 -= cross_leafwidth + co4 -= cross_leafwidth + + + i = len(verts_extend) + faces_extend.append( (i,i+1,i+2,i+3) ) + verts_extend.extend([tuple(co1), tuple(co2), tuple(co3), tuple(co4)]) + count += 1 + + self.mesh_leaf.verts.extend(verts_extend) + self.mesh_leaf.faces.extend(faces_extend) + + + return self.mesh_leaf + + def toArmature(self, ob_arm, armature): armature.drawType = Blender.Armature.STICK @@ -909,8 +1143,6 @@ class tree: except: pass cu.driver = 2 # Python expression cu.driverExpression = '%.3f*(%s.evaluate((%.3f,%.3f,(b.Get("curframe")*%.3f)+%.3f)).w-0.5)' % (anim_magnitude, tex_str, anim_offset.x, anim_offset.y, anim_speed_final, anim_offset.z) - - #(%s.evaluate((b.Get("curframe")*%.3f,0,0)).w-0.5)*%.3f xyzup = Vector(1,1,1).normalize() xup = Vector(1,0,0) @@ -927,7 +1159,7 @@ class bpoint_bone: class bpoint(object): ''' The point in the middle of the branch, not the mesh points ''' - __slots__ = 'branch', 'co', 'no', 'radius', 'vecs', 'verts', 'children', 'faces', 'next', 'prev', 'childCount', 'bpbone', 'roll_angle', 'nextMidCo', 'childrenMidCo', 'childrenMidRadius', 'targetCos', 'inTwigBounds' + __slots__ = 'branch', 'co', 'no', 'radius', 'vecs', 'verts', 'children', 'faces', 'uv', 'next', 'prev', 'childCount', 'bpbone', 'roll_angle', 'nextMidCo', 'childrenMidCo', 'childrenMidRadius', 'targetCos', 'inTwigBounds' def __init__(self, brch, co, no, radius): self.branch = brch self.co = co @@ -937,6 +1169,7 @@ class bpoint(object): self.verts = [None, None, None, None] self.children = [None, None, None, None] # child branches, dont fill in faces here self.faces = [None, None, None, None] + self.uv = None # matching faces, except - UV's are calculated even if there is no face, this is so we can calculate the blending UV's self.next = None self.prev = None self.childCount = 0 @@ -1233,34 +1466,32 @@ class bpoint(object): if not self.next: return - verts = self.verts - next_verts = self.next.verts - ls = [] if self.prev == None and self.branch.parent_pt: # join from parent branch # which side are we of the parents quad index = self.branch.parent_pt.children.index(self.branch) + # collect the points we are to merge into between the parent its next point if index==0: verts = [self.branch.parent_pt.verts[0], self.branch.parent_pt.verts[1], self.branch.parent_pt.next.verts[1], self.branch.parent_pt.next.verts[0]] if index==1: verts = [self.branch.parent_pt.verts[1], self.branch.parent_pt.verts[2], self.branch.parent_pt.next.verts[2], self.branch.parent_pt.next.verts[1]] if index==2: verts = [self.branch.parent_pt.verts[2], self.branch.parent_pt.verts[3], self.branch.parent_pt.next.verts[3], self.branch.parent_pt.next.verts[2]] if index==3: verts = [self.branch.parent_pt.verts[3], self.branch.parent_pt.verts[0], self.branch.parent_pt.next.verts[0], self.branch.parent_pt.next.verts[3]] - - if not self.children[0]: self.faces[0] = [verts[0], verts[1], next_verts[1], next_verts[0]] - if not self.children[1]: self.faces[1] = [verts[1], verts[2], next_verts[2], next_verts[1]] - if not self.children[2]: self.faces[2] = [verts[2], verts[3], next_verts[3], next_verts[2]] - if not self.children[3]: self.faces[3] = [verts[3], verts[0], next_verts[0], next_verts[3]] - - else: - # normal join - if not self.children[0]: self.faces[0] = [verts[0], verts[1], next_verts[1], next_verts[0]] - if not self.children[1]: self.faces[1] = [verts[1], verts[2], next_verts[2], next_verts[1]] - if not self.children[2]: self.faces[2] = [verts[2], verts[3], next_verts[3], next_verts[2]] - if not self.children[3]: self.faces[3] = [verts[3], verts[0], next_verts[0], next_verts[3]] + + + # Watchout for overlapping faces! + self.branch.faces[:] =\ + [verts[0], verts[1], self.verts[1], self.verts[0]],\ + [verts[1], verts[2], self.verts[2], self.verts[1]],\ + [verts[2], verts[3], self.verts[3], self.verts[2]],\ + [verts[3], verts[0], self.verts[0], self.verts[3]] - mesh.faces.extend(ls) + # normal join, parents or no parents + if not self.children[0]: self.faces[0] = [self.verts[0], self.verts[1], self.next.verts[1], self.next.verts[0]] + if not self.children[1]: self.faces[1] = [self.verts[1], self.verts[2], self.next.verts[2], self.next.verts[1]] + if not self.children[2]: self.faces[2] = [self.verts[2], self.verts[3], self.next.verts[3], self.next.verts[2]] + if not self.children[3]: self.faces[3] = [self.verts[3], self.verts[0], self.next.verts[0], self.next.verts[3]] def calcVerts(self): if self.prev == None: @@ -1305,8 +1536,13 @@ class branch: self.length = -1 # self.totchildren = 0 # Bones per branch + self.faces = [None, None, None, None] + self.uv = None # face uvs can be fake, always 4 self.bones = [] + self.generation = 0 # use to limit twig reproduction + # self.myindex = -1 + ### self.segment_spacing_scale = 1.0 # use this to scale up the spacing - so small twigs dont get WAY too many polys def __repr__(self): s = '' @@ -1378,10 +1614,12 @@ class branch: # could do this properly but it would be slower and its a corner case. # # if 3) this point is within the branch, remove it. + # Scale this value by the difference in radius, a low trim looks better when the parent is a lot bigger.. + # while len(self.bpoints)>2 and\ self.bpoints[0].childCount == 0 and\ - (self.bpoints[0].co - self.parent_pt.nextMidCo).length < self.parent_pt.radius * base_trim: + (self.bpoints[0].co - self.parent_pt.nextMidCo).length / (1+ ((self.bpoints[0].radius/self.parent_pt.radius) / base_trim)) < self.parent_pt.radius * base_trim: del self.bpoints[0] self.bpoints[0].prev = None @@ -1628,33 +1866,30 @@ class branch: for pt in self.bpoints: pt.applyTargetLocation() - def collapsePoints(self, density, smooth_joint=1.0): - - # to avoid an overcomplex UI, just use this value when checking if these can collapse - HARD_CODED_RADIUS_DIFFERENCE_LIMIT = 0.3 - HARD_CODED_ANGLE_DIFFERENCE_LIMIT = 20 + def collapsePoints(self, seg_density=0.5, seg_density_angle=20.0, seg_density_radius=0.3, smooth_joint=1.0): collapse = True while collapse: collapse = False - pt = self.bpoints[0] while pt: if pt.prev and pt.next and pt.prev.childCount == 0: - if abs(pt.radius - pt.prev.radius) / (pt.radius + pt.prev.radius) < HARD_CODED_RADIUS_DIFFERENCE_LIMIT: - if AngleBetweenVecs(pt.no, pt.prev.no) < HARD_CODED_ANGLE_DIFFERENCE_LIMIT: - if (pt.prev.nextMidCo-pt.co).length < ((pt.radius + pt.prev.radius)/2) * density: + if abs(pt.radius - pt.prev.radius) / (pt.radius + pt.prev.radius) < seg_density_radius: + if seg_density_angle == 180 or AngleBetweenVecs(pt.no, pt.prev.no) < seg_density_angle: + ## if (pt.prev.nextMidCo-pt.co).length < ((pt.radius + pt.prev.radius)/2) * seg_density: + if (pt.prev.nextMidCo-pt.co).length < seg_density: pt_save = pt.prev if pt.next.collapseUp(): # collapse this point collapse = True pt = pt_save # so we never reference a removed point if pt.childCount == 0 and pt.next: #if pt.childrenMidCo == None: - if abs(pt.radius - pt.next.radius) / (pt.radius + pt.next.radius) < HARD_CODED_RADIUS_DIFFERENCE_LIMIT: - if AngleBetweenVecs(pt.no, pt.next.no) < HARD_CODED_ANGLE_DIFFERENCE_LIMIT: + if abs(pt.radius - pt.next.radius) / (pt.radius + pt.next.radius) < seg_density_radius: + if seg_density_angle == 180 or AngleBetweenVecs(pt.no, pt.next.no) < seg_density_angle: # do here because we only want to run this on points with no children, # Are we closer theto eachother then the radius? - if (pt.nextMidCo-pt.co).length < ((pt.radius + pt.next.radius)/2) * density: + ## if (pt.nextMidCo-pt.co).length < ((pt.radius + pt.next.radius)/2) * seg_density: + if (pt.nextMidCo-pt.co).length < seg_density: if pt.collapseDown(): collapse = True @@ -1810,15 +2045,22 @@ PREFS = {} PREFS['connect_sloppy'] = Draw.Create(1.0) PREFS['connect_base_trim'] = Draw.Create(1.0) PREFS['seg_density'] = Draw.Create(0.5) +PREFS['seg_density_angle'] = Draw.Create(20.0) +PREFS['seg_density_radius'] = Draw.Create(0.3) PREFS['seg_joint_compression'] = Draw.Create(1.0) PREFS['seg_joint_smooth'] = Draw.Create(2.0) PREFS['image_main'] = Draw.Create('') PREFS['do_uv'] = Draw.Create(0) PREFS['uv_x_scale'] = Draw.Create(4.0) PREFS['uv_y_scale'] = Draw.Create(1.0) +PREFS['do_material'] = Draw.Create(1) +PREFS['material_use_existing'] = Draw.Create(1) +PREFS['material_texture'] = Draw.Create(1) +PREFS['material_stencil'] = Draw.Create(1) PREFS['do_subsurf'] = Draw.Create(1) PREFS['do_cap_ends'] = Draw.Create(0) PREFS['do_uv_keep_vproportion'] = Draw.Create(1) +PREFS['do_uv_vnormalize'] = Draw.Create(0) PREFS['do_uv_uscale'] = Draw.Create(0) PREFS['do_armature'] = Draw.Create(0) PREFS['do_anim'] = Draw.Create(1) @@ -1830,17 +2072,21 @@ PREFS['anim_magnitude'] = Draw.Create(0.2) PREFS['anim_speed_size_scale'] = Draw.Create(1) PREFS['anim_offset_scale'] = Draw.Create(1.0) -PREFS['do_twigs'] = Draw.Create(1) +PREFS['do_twigs'] = Draw.Create(0) PREFS['twig_ratio'] = Draw.Create(2.0) PREFS['twig_scale'] = Draw.Create(0.8) PREFS['twig_lengthen'] = Draw.Create(1.0) PREFS['twig_random_orientation'] = Draw.Create(180) PREFS['twig_random_angle'] = Draw.Create(33) PREFS['twig_recursive'] = Draw.Create(1) +PREFS['twig_recursive_limit'] = Draw.Create(3) PREFS['twig_ob_bounds'] = Draw.Create('') PREFS['twig_ob_bounds_prune'] = Draw.Create(1) PREFS['twig_ob_bounds_prune_taper'] = Draw.Create(1) +PREFS['do_leaf'] = Draw.Create(1) +PREFS['leaf_branch_limit'] = Draw.Create(0.25) +PREFS['leaf_size'] = Draw.Create(0.5) GLOBAL_PREFS = {} GLOBAL_PREFS['realtime_update'] = Draw.Create(0) @@ -1893,7 +2139,7 @@ def IDProp2Prefs(idprop, prefs): return True -def buildTree(ob, single=False): +def buildTree(ob_curve, single=False): ''' Must be a curve object, write to a child mesh Must check this is a curve object! @@ -1901,7 +2147,7 @@ def buildTree(ob, single=False): print 'Curve2Tree, starting...' # if were only doing 1 object, just use the current prefs prefs = {} - if single or not (IDProp2Prefs(ob.properties, prefs)): + if single or not (IDProp2Prefs(ob_curve.properties, prefs)): prefs = PREFS @@ -1910,19 +2156,19 @@ def buildTree(ob, single=False): sce = bpy.data.scenes.active - def getCurveChild(obtype): + def getObChild(parent, obtype): try: - return [ _ob for _ob in sce.objects if _ob.type == obtype if _ob.parent == ob ][0] + return [ _ob for _ob in sce.objects if _ob.type == obtype if _ob.parent == parent ][0] except: return None - def newCurveChild(obdata): + def newObChild(parent, obdata): ob_new = bpy.data.scenes.active.objects.new(obdata) - ob_new.Layers = ob.Layers + ob_new.Layers = parent.Layers # new object settings - ob.makeParent([ob_new]) + parent.makeParent([ob_new]) ob_new.setMatrix(Matrix()) ob_new.sel = 0 return ob_new @@ -1944,7 +2190,7 @@ def buildTree(ob, single=False): time1 = Blender.sys.time() t = tree() - t.fromCurve(ob) + t.fromCurve(ob_curve) if not t.branches_all: return # Empty curve? - may as well not throw an error @@ -1980,6 +2226,7 @@ def buildTree(ob, single=False): twig_random_orientation = PREFS['twig_random_orientation'].val,\ twig_random_angle = PREFS['twig_random_angle'].val,\ twig_recursive = PREFS['twig_recursive'].val,\ + twig_recursive_limit = PREFS['twig_recursive_limit'].val,\ twig_ob_bounds = twig_ob_bounds,\ twig_ob_bounds_prune = PREFS['twig_ob_bounds_prune'].val,\ twig_ob_bounds_prune_taper = PREFS['twig_ob_bounds_prune_taper'].val,\ @@ -1990,7 +2237,9 @@ def buildTree(ob, single=False): print '\toptimizing point spacing...', t.optimizeSpacing(\ - density=PREFS['seg_density'].val,\ + seg_density=PREFS['seg_density'].val,\ + seg_density_angle=PREFS['seg_density_angle'].val,\ + seg_density_radius=PREFS['seg_density_radius'].val,\ joint_compression = PREFS['seg_joint_compression'].val,\ joint_smooth = PREFS['seg_joint_smooth'].val\ ) @@ -1999,32 +2248,93 @@ def buildTree(ob, single=False): print '%.4f sec' % (time5-time4) print '\tbuilding mesh...', - ob_mesh = getCurveChild('Mesh') + ob_mesh = getObChild(ob_curve, 'Mesh') if not ob_mesh: # New object - mesh = bpy.data.meshes.new('tree_' + ob.name) - ob_mesh = newCurveChild(mesh) + mesh = bpy.data.meshes.new('tree_' + ob_curve.name) + ob_mesh = newObChild(ob_curve, mesh) # do subsurf later - + else: # Existing object mesh = ob_mesh.getData(mesh=1) ob_mesh.setMatrix(Matrix()) - + # Do we need a do_uv_blend_layer? + if PREFS['material_stencil'].val and PREFS['material_texture'].val: + do_uv_blend_layer = True + else: + do_uv_blend_layer = False mesh = t.toMesh(mesh,\ do_uv = PREFS['do_uv'].val,\ uv_image = image,\ do_uv_keep_vproportion = PREFS['do_uv_keep_vproportion'].val,\ + do_uv_vnormalize = PREFS['do_uv_vnormalize'].val,\ do_uv_uscale = PREFS['do_uv_uscale'].val,\ uv_x_scale = PREFS['uv_x_scale'].val,\ uv_y_scale = PREFS['uv_y_scale'].val,\ - do_cap_ends = PREFS['do_cap_ends'].val\ + do_uv_blend_layer = do_uv_blend_layer,\ + do_cap_ends = PREFS['do_cap_ends'].val ) - + """ + if PREFS['do_leaf'].val: + ob_leaf = getObChild(ob_mesh, 'Mesh') + if not ob_leaf: # New object + mesh_leaf = bpy.data.meshes.new('tree_' + ob_curve.name) + ob_leaf = newObChild(ob_mesh, mesh_leaf) + else: + mesh_leaf = ob_leaf.getData(mesh=1) + ob_leaf.setMatrix(Matrix()) + + mesh_leaf = t.toLeafMesh(mesh_leaf,\ + leaf_branch_limit = PREFS['leaf_branch_limit'].val,\ + leaf_size = PREFS['leaf_size'].val,\ + ) + """ mesh.calcNormals() + if PREFS['do_material'].val: + + materials = mesh.materials + if PREFS['material_use_existing'].val and materials: + t.material = materials[0] + else: + t.material = bpy.data.materials.new(ob_curve.name) + mesh.materials = [t.material] + + if PREFS['material_texture'].val: + + # Set up the base image texture + t.texBase = bpy.data.textures.new('base_' + ob_curve.name) + t.material.setTexture(0, t.texBase, Blender.Texture.TexCo.UV, Blender.Texture.MapTo.COL) + t.texBase.type = Blender.Texture.Types.IMAGE + if image: + t.texBase.image = image + t.texBaseMTex = t.material.getTextures()[0] + t.texBaseMTex.uvlayer = 'base' + + if PREFS['material_stencil'].val: + # Set up the blend texture + t.texBlend = bpy.data.textures.new('blend_' + ob_curve.name) + t.material.setTexture(1, t.texBlend, Blender.Texture.TexCo.UV, 0) # map to None + t.texBlend.type = Blender.Texture.Types.BLEND + t.texBlend.flags |= Blender.Texture.Flags.FLIPBLEND + t.texBlendMTex = t.material.getTextures()[1] + t.texBlendMTex.stencil = True + t.texBlendMTex.uvlayer = 'blend' + + + # Now make the texture for the stencil to blend, can reuse texBase here, jus tdifferent settings for the mtex + t.material.setTexture(2, t.texBase, Blender.Texture.TexCo.UV, Blender.Texture.MapTo.COL) + t.texJoinMTex = t.material.getTextures()[2] + t.texJoinMTex.uvlayer = 'join' + + # Add a UV layer for blending + + + + time6 = Blender.sys.time() # time print print '%.4f sec' % (time6-time5) @@ -2033,13 +2343,13 @@ def buildTree(ob, single=False): print '\tbuilding armature & animation...', - ob_arm = getCurveChild('Armature') + ob_arm = getObChild(ob_curve, 'Armature') if ob_arm: armature = ob_arm.data ob_arm.setMatrix(Matrix()) else: armature = bpy.data.armatures.new() - ob_arm = newCurveChild(armature) + ob_arm = newObChild(ob_curve, armature) t.toArmature(ob_arm, armature) @@ -2074,7 +2384,7 @@ def buildTree(ob, single=False): # Add subsurf last it needed. so armature skinning is done first. # Do subsurf? - if PREFS['seg_density'].val: + if PREFS['do_subsurf'].val: if not hasModifier(Blender.Modifier.Types.SUBSURF): mod = ob_mesh.modifiers.append(Blender.Modifier.Types.SUBSURF) @@ -2235,6 +2545,13 @@ def gui(): Blender.Draw.BeginAlign() PREFS['seg_density'] = Draw.Number('Segment Spacing',EVENT_UPDATE, xtmp, y, but_width*4, but_height, PREFS['seg_density'].val, 0.05, 10.0, 'Scale the limit points collapse, that are closer then the branch width'); xtmp += but_width*4; + y-=but_height + xtmp = x + + # ---------- ---------- ---------- ---------- + PREFS['seg_density_angle'] = Draw.Number('Angle Spacing', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['seg_density_angle'].val, 0.0, 180.0, 'Segments above this angle will not collapse (lower value for more detail)'); xtmp += but_width*2; + PREFS['seg_density_radius'] = Draw.Number('Radius Spacing', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['seg_density_radius'].val, 0.0, 1.0, 'Segments above this difference in radius will not collapse (lower value for more detail)'); xtmp += but_width*2; + y-=but_height xtmp = x # ---------- ---------- ---------- ---------- @@ -2262,13 +2579,13 @@ def gui(): PREFS['do_twigs'] = Draw.Toggle('Generate Twigs',EVENT_UPDATE_AND_UI, xtmp, y, but_width*2, but_height, PREFS['do_twigs'].val, 'Generate child branches based existing branches'); xtmp += but_width*2; if PREFS['do_twigs'].val: - PREFS['twig_recursive'] = Draw.Toggle('Recursive Twigs',EVENT_UPDATE_AND_UI, xtmp, y, but_width*2, but_height, PREFS['twig_recursive'].val, 'Recursively add twigs into eachother'); xtmp += but_width*2; + PREFS['twig_ratio'] = Draw.Number('Twig Multiply', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['twig_ratio'].val, 0.01, 500.0, 'How many twigs to generate per branch'); xtmp += but_width*2; y-=but_height xtmp = x # ---------- ---------- ---------- ---------- - - PREFS['twig_ratio'] = Draw.Number('Twig Multiply', EVENT_UPDATE, xtmp, y, but_width*4, but_height, PREFS['twig_ratio'].val, 0.01, 500.0, 'How many twigs to generate per branch'); xtmp += but_width*4; + PREFS['twig_recursive'] = Draw.Toggle('Recursive Twigs',EVENT_UPDATE_AND_UI, xtmp, y, but_width*2, but_height, PREFS['twig_recursive'].val, 'Recursively add twigs into eachother'); xtmp += but_width*2; + PREFS['twig_recursive_limit'] = Draw.Number('Generations', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['twig_recursive_limit'].val, 0.0, 16, 'Number of generations allowed, 0 is inf'); xtmp += but_width*2; y-=but_height xtmp = x @@ -2309,11 +2626,27 @@ def gui(): xtmp = x # ---------- ---------- ---------- ---------- + + + """ Blender.Draw.BeginAlign() - PREFS['do_uv'] = Draw.Toggle('Generate UVs',EVENT_UPDATE_AND_UI, xtmp, y, but_width*2, but_height, PREFS['do_uv'].val, 'Calculate UVs coords'); xtmp += but_width*2; - if PREFS['do_uv'].val: + if PREFS['do_leaf'].val == 0: + but_width_tmp = but_width*2 + else: + but_width_tmp = but_width*4 + PREFS['do_leaf'] = Draw.Toggle('Generate Leaves',EVENT_UPDATE_AND_UI, xtmp, y, but_width_tmp, but_height, PREFS['do_leaf'].val, 'Generate a separate leaf mesh'); xtmp += but_width_tmp; + + if PREFS['do_leaf'].val: + # ---------- ---------- ---------- ---------- + y-=but_height + xtmp = x + + PREFS['leaf_branch_limit'] = Draw.Number('Branch Limit', EVENT_UPDATE, xtmp, y, but_width*4, but_height, PREFS['leaf_branch_limit'].val, 0.1, 2.0, 'Maximum thichness where a branch can bare leaves'); xtmp += but_width*4; + + ''' PREFS['do_uv_uscale'] = Draw.Toggle('U-Scale', EVENT_UPDATE, xtmp, y, but_width, but_height, PREFS['do_uv_uscale'].val, 'Scale the width according to the face size (will NOT tile)'); xtmp += but_width; PREFS['do_uv_keep_vproportion'] = Draw.Toggle('V-Aspect', EVENT_UPDATE, xtmp, y, but_width, but_height, PREFS['do_uv_keep_vproportion'].val, 'Correct the UV aspect with the branch width'); xtmp += but_width; + PREFS['do_uv_vnormalize'] = Draw.Toggle('V-Normaize', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['do_uv_vnormalize'].val, 'Scale the UVs to fit onto the image verticaly'); xtmp += but_width*2; @@ -2330,6 +2663,62 @@ def gui(): PREFS['image_main'] = Draw.String('IM: ', EVENT_UPDATE, xtmp, y, but_width*3, but_height, PREFS['image_main'].val, 64, 'Image to apply to faces'); xtmp += but_width*3; Draw.PushButton('Use Active', EVENT_UPDATE, xtmp, y, but_width, but_height, 'Get the image from the active image window', do_active_image); xtmp += but_width; + ''' + Blender.Draw.EndAlign() + + y-=but_height+MARGIN + xtmp = x + # ---------- ---------- ---------- ---------- + """ + + + + + Blender.Draw.BeginAlign() + if PREFS['do_uv'].val == 0: but_width_tmp = but_width*2 + else: but_width_tmp = but_width*4 + PREFS['do_uv'] = Draw.Toggle('Generate UVs',EVENT_UPDATE_AND_UI, xtmp, y, but_width_tmp, but_height, PREFS['do_uv'].val, 'Calculate UVs coords'); xtmp += but_width_tmp; + + if PREFS['do_uv'].val: + # ---------- ---------- ---------- ---------- + y-=but_height + xtmp = x + + PREFS['do_uv_uscale'] = Draw.Toggle('U-Scale', EVENT_UPDATE, xtmp, y, but_width, but_height, PREFS['do_uv_uscale'].val, 'Scale the width according to the face size (will NOT tile)'); xtmp += but_width; + PREFS['do_uv_keep_vproportion'] = Draw.Toggle('V-Aspect', EVENT_UPDATE, xtmp, y, but_width, but_height, PREFS['do_uv_keep_vproportion'].val, 'Correct the UV aspect with the branch width'); xtmp += but_width; + PREFS['do_uv_vnormalize'] = Draw.Toggle('V-Normaize', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['do_uv_vnormalize'].val, 'Scale the UVs to fit onto the image verticaly'); xtmp += but_width*2; + + y-=but_height + xtmp = x + # ---------- ---------- ---------- ---------- + + PREFS['uv_x_scale'] = Draw.Number('Scale U', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['uv_x_scale'].val, 0.01, 10.0, 'Edge loop spacing around branch join, lower value for less webed joins'); xtmp += but_width*2; + PREFS['uv_y_scale'] = Draw.Number('Scale V', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['uv_y_scale'].val, 0.01, 10.0, 'Edge loop spacing around branch join, lower value for less webed joins'); xtmp += but_width*2; + + y-=but_height + xtmp = x + # ---------- ---------- ---------- ---------- + + PREFS['image_main'] = Draw.String('IM: ', EVENT_UPDATE, xtmp, y, but_width*3, but_height, PREFS['image_main'].val, 64, 'Image to apply to faces'); xtmp += but_width*3; + Draw.PushButton('Use Active', EVENT_UPDATE, xtmp, y, but_width, but_height, 'Get the image from the active image window', do_active_image); xtmp += but_width; + Blender.Draw.EndAlign() + + y-=but_height+MARGIN + xtmp = x + # ---------- ---------- ---------- ---------- + + Blender.Draw.BeginAlign() + PREFS['do_material'] = Draw.Toggle('Generate Material',EVENT_UPDATE_AND_UI, xtmp, y, but_width*2, but_height, PREFS['do_material'].val, 'Create material and textures (for seamless joints)'); xtmp += but_width*2; + + if PREFS['do_material'].val: + PREFS['material_use_existing'] = Draw.Toggle('ReUse Existing',EVENT_UPDATE_AND_UI, xtmp, y, but_width*2, but_height, PREFS['material_use_existing'].val, 'Modify the textures of the existing material'); xtmp += but_width*2; + + # ---------- ---------- ---------- ---------- + y-=but_height + xtmp = x + + PREFS['material_texture'] = Draw.Toggle('Texture', EVENT_UPDATE_AND_UI, xtmp, y, but_width*2, but_height, PREFS['material_texture'].val, 'Create an image texture for this material to use'); xtmp += but_width*2; + PREFS['material_stencil'] = Draw.Toggle('Blend Joints', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['material_stencil'].val, 'Use a second texture and UV layer to blend joints'); xtmp += but_width*2; Blender.Draw.EndAlign() y-=but_height+MARGIN diff --git a/source/blender/python/api2_2x/Mesh.c b/source/blender/python/api2_2x/Mesh.c index 88fa09bd607..7430c2a6e91 100644 --- a/source/blender/python/api2_2x/Mesh.c +++ b/source/blender/python/api2_2x/Mesh.c @@ -7585,7 +7585,7 @@ static int Mesh_setVerts( BPy_Mesh * self, PyObject * args ) free_mesh( me ); me->mvert = NULL; me->medge = NULL; me->mface = NULL; me->mtface = NULL; me->dvert = NULL; me->mcol = NULL; - me->msticky = NULL; me->mat = NULL; me->bb = NULL; + me->msticky = NULL; me->mat = NULL; me->bb = NULL; me->mselect = NULL; me->totvert = me->totedge = me->totface = me->totcol = 0; mesh_update( me ); return 0; diff --git a/source/blender/python/api2_2x/doc/Texture.py b/source/blender/python/api2_2x/doc/Texture.py index 823f34b14bd..dfba93c9978 100644 --- a/source/blender/python/api2_2x/doc/Texture.py +++ b/source/blender/python/api2_2x/doc/Texture.py @@ -532,6 +532,8 @@ class MTex: @ivar mtAmb: How texture maps to ambient value @ivar mtDisp: How texture maps to displacement @ivar mtWarp: How texture maps to warp + @ivar uvlayer: The name of the UV Layer this texture is mapped to (when left blank uses render layer) + @type uvlayer: string """ def getIpo(): diff --git a/source/blender/src/buttons_shading.c b/source/blender/src/buttons_shading.c index f422a39266a..e42a0570fe7 100644 --- a/source/blender/src/buttons_shading.c +++ b/source/blender/src/buttons_shading.c @@ -1953,7 +1953,7 @@ static void world_panel_mapto(World *wrld) /* TEXTURE OUTPUT */ uiBlockBeginAlign(block); - uiDefButBitS(block, TOG, MTEX_STENCIL, B_WORLDPRV, "Stencil", 10,125,45,19, &(mtex->texflag), 0, 0, 0, 0, "Sets the texture mapping to stencil mode"); + uiDefButBitS(block, TOG, MTEX_STENCIL, B_WORLDPRV, "Stencil", 10,125,45,19, &(mtex->texflag), 0, 0, 0, 0, "Use this texture as a blending value on the next texture"); uiDefButBitS(block, TOG, MTEX_NEGATIVE, B_WORLDPRV, "Neg", 55,125,30,19, &(mtex->texflag), 0, 0, 0, 0, "Inverts the values of the texture to reverse its effect"); uiDefButBitS(block, TOG, MTEX_RGBTOINT, B_WORLDPRV, "No RGB", 85,125,60,19, &(mtex->texflag), 0, 0, 0, 0, "Converts texture RGB values to intensity (gray) values"); uiBlockEndAlign(block); @@ -2384,7 +2384,7 @@ static void lamp_panel_mapto(Object *ob, Lamp *la) /* TEXTURE OUTPUT */ uiBlockBeginAlign(block); - uiDefButBitS(block, TOG, MTEX_STENCIL, B_LAMPPRV, "Stencil", 10,125,45,19, &(mtex->texflag), 0, 0, 0, 0, "Sets the texture mapping to stencil mode"); + uiDefButBitS(block, TOG, MTEX_STENCIL, B_LAMPPRV, "Stencil", 10,125,45,19, &(mtex->texflag), 0, 0, 0, 0, "Use this texture as a blending value on the next texture"); uiDefButBitS(block, TOG, MTEX_NEGATIVE, B_LAMPPRV, "Neg", 55,125,30,19, &(mtex->texflag), 0, 0, 0, 0, "Inverts the values of the texture to reverse its effect"); uiDefButBitS(block, TOG, MTEX_RGBTOINT, B_LAMPPRV, "No RGB", 85,125,60,19, &(mtex->texflag), 0, 0, 0, 0, "Converts texture RGB values to intensity (gray) values"); uiBlockEndAlign(block); @@ -3065,7 +3065,7 @@ static void material_panel_map_to(Material *ma, int from_nodes) /* TEXTURE OUTPUT */ uiBlockBeginAlign(block); - uiDefButBitS(block, TOG, MTEX_STENCIL, B_MATPRV, "Stencil", 10,125,45,19, &(mtex->texflag), 0, 0, 0, 0, "Sets the texture mapping to stencil mode"); + uiDefButBitS(block, TOG, MTEX_STENCIL, B_MATPRV, "Stencil", 10,125,45,19, &(mtex->texflag), 0, 0, 0, 0, "Use this texture as a blending value on the next texture"); uiDefButBitS(block, TOG, MTEX_NEGATIVE, B_MATPRV, "Neg", 55,125,30,19, &(mtex->texflag), 0, 0, 0, 0, "Inverts the values of the texture to reverse its effect"); uiDefButBitS(block, TOG,MTEX_RGBTOINT, B_MATPRV, "No RGB", 85,125,60,19, &(mtex->texflag), 0, 0, 0, 0, "Converts texture RGB values to intensity (gray) values"); uiBlockEndAlign(block); From 7accd3a662569b3c23e456f1560e35cab95280f6 Mon Sep 17 00:00:00 2001 From: Ton Roosendaal Date: Fri, 16 Nov 2007 15:46:59 +0000 Subject: [PATCH 02/29] Long outstanding feature request: "Multi Modifier" This allows to mix between the result of 2 modifiers, with both using the same input state. This is useful for having a mesh deform and armature deform working together. However! This functionality could have been presented better... this is actually Node editor stuff! Now it works by adding a "MM" button, next to the "overall vgroup" option. If MM is pressed, the input of this modifier is the same as the input of the previous modifier. Only the armature modifier has this option now... --- source/blender/blenkernel/BKE_lattice.h | 4 +-- source/blender/blenkernel/intern/armature.c | 25 +++++++++++++-- source/blender/blenkernel/intern/modifier.c | 33 ++++++++++++++++++-- source/blender/makesdna/DNA_modifier_types.h | 3 +- source/blender/src/buttons_editing.c | 4 ++- 5 files changed, 59 insertions(+), 10 deletions(-) diff --git a/source/blender/blenkernel/BKE_lattice.h b/source/blender/blenkernel/BKE_lattice.h index 3dc4b49b52b..bf505fa23d7 100644 --- a/source/blender/blenkernel/BKE_lattice.h +++ b/source/blender/blenkernel/BKE_lattice.h @@ -64,8 +64,8 @@ void lattice_deform_verts(struct Object *laOb, struct Object *target, int numVerts, char *vgroup); void armature_deform_verts(struct Object *armOb, struct Object *target, struct DerivedMesh *dm, float (*vertexCos)[3], - float (*defMats)[3][3], int numVerts, - int deformflag, const char *defgrp_name); + float (*defMats)[3][3], int numVerts, int deformflag, + float (*prevCos)[3], const char *defgrp_name); float (*lattice_getVertexCos(struct Object *ob, int *numVerts_r))[3]; void lattice_applyVertexCos(struct Object *ob, float (*vertexCos)[3]); void lattice_calc_modifiers(struct Object *ob); diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c index f688c573bc8..477ee982138 100644 --- a/source/blender/blenkernel/intern/armature.c +++ b/source/blender/blenkernel/intern/armature.c @@ -790,7 +790,8 @@ static void pchan_bone_deform(bPoseChannel *pchan, float weight, float *vec, Dua void armature_deform_verts(Object *armOb, Object *target, DerivedMesh *dm, float (*vertexCos)[3], float (*defMats)[3][3], - int numVerts, int deformflag, const char *defgrp_name) + int numVerts, int deformflag, + float (*prevCos)[3], const char *defgrp_name) { bPoseChannel *pchan, **defnrToPC = NULL; MDeformVert *dverts = NULL; @@ -881,11 +882,12 @@ void armature_deform_verts(Object *armOb, Object *target, DerivedMesh *dm, for(i = 0; i < numVerts; i++) { MDeformVert *dvert; DualQuat sumdq, *dq = NULL; - float *co = vertexCos[i], dco[3]; + float *co, dco[3]; float sumvec[3], summat[3][3]; float *vec = NULL, (*smat)[3] = NULL; float contrib = 0.0f; - float armature_weight = 1.0f; /* default to 1 if no overall def group */ + float armature_weight = 1.0f; /* default to 1 if no overall def group */ + float prevco_weight = 1.0f; /* weight for optional cached vertexcos */ int j; if(use_quaternion) { @@ -917,11 +919,19 @@ void armature_deform_verts(Object *armOb, Object *target, DerivedMesh *dm, break; } } + /* hackish: the blending factor can be used for blending with prevCos too */ + if(prevCos) { + prevco_weight= armature_weight; + armature_weight= 1.0f; + } } /* check if there's any point in calculating for this vert */ if(armature_weight == 0.0f) continue; + /* get the coord we work on */ + co= prevCos?prevCos[i]:vertexCos[i]; + /* Apply the object's matrix */ Mat4MulVecfl(premat, co); @@ -1005,6 +1015,15 @@ void armature_deform_verts(Object *armOb, Object *target, DerivedMesh *dm, /* always, check above code */ Mat4MulVecfl(postmat, co); + + + /* interpolate with previous modifier position using weight group */ + if(prevCos && prevco_weight!=1.0f) { + float mw= 1.0f - prevco_weight; + vertexCos[i][0]= mw*vertexCos[i][0] + prevco_weight*co[0]; + vertexCos[i][1]= mw*vertexCos[i][1] + prevco_weight*co[1]; + vertexCos[i][2]= mw*vertexCos[i][2] + prevco_weight*co[2]; + } } if(dualquats) MEM_freeN(dualquats); diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c index c2f3880ec19..3a6611a2be7 100644 --- a/source/blender/blenkernel/intern/modifier.c +++ b/source/blender/blenkernel/intern/modifier.c @@ -238,12 +238,29 @@ static void latticeModifier_updateDepgraph(ModifierData *md, DagForest *forest, } } +static void modifier_vgroup_cache(ModifierData *md, float (*vertexCos)[3]) +{ + md= md->next; + if(md) { + if(md->type==eModifierType_Armature) { + ArmatureModifierData *amd = (ArmatureModifierData*) md; + if(amd->multi) + amd->prevCos= MEM_dupallocN(vertexCos); + } + /* lattice/mesh modifier too */ + } +} + + static void latticeModifier_deformVerts( ModifierData *md, Object *ob, DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts) { LatticeModifierData *lmd = (LatticeModifierData*) md; + + modifier_vgroup_cache(md, vertexCos); /* if next modifier needs original vertices */ + lattice_deform_verts(lmd->object, ob, derivedData, vertexCos, numVerts, lmd->name); } @@ -4664,8 +4681,16 @@ static void armatureModifier_deformVerts( { ArmatureModifierData *amd = (ArmatureModifierData*) md; + modifier_vgroup_cache(md, vertexCos); /* if next modifier needs original vertices */ + armature_deform_verts(amd->object, ob, derivedData, vertexCos, NULL, - numVerts, amd->deformflag, amd->defgrp_name); + numVerts, amd->deformflag, + amd->prevCos, amd->defgrp_name); + /* free cache */ + if(amd->prevCos) { + MEM_freeN(amd->prevCos); + amd->prevCos= NULL; + } } static void armatureModifier_deformVertsEM( @@ -4678,7 +4703,7 @@ static void armatureModifier_deformVertsEM( if(!derivedData) dm = CDDM_from_editmesh(editData, ob->data); armature_deform_verts(amd->object, ob, dm, vertexCos, NULL, numVerts, - amd->deformflag, amd->defgrp_name); + amd->deformflag, NULL, amd->defgrp_name); if(!derivedData) dm->release(dm); } @@ -4694,7 +4719,7 @@ static void armatureModifier_deformMatricesEM( if(!derivedData) dm = CDDM_from_editmesh(editData, ob->data); armature_deform_verts(amd->object, ob, dm, vertexCos, defMats, numVerts, - amd->deformflag, amd->defgrp_name); + amd->deformflag, NULL, amd->defgrp_name); if(!derivedData) dm->release(dm); } @@ -5241,6 +5266,8 @@ static void meshdeformModifier_deformVerts( else dm= derivedData; + modifier_vgroup_cache(md, vertexCos); /* if next modifier needs original vertices */ + meshdeformModifier_do(md, ob, dm, vertexCos, numVerts); if(dm != derivedData) diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h index c55ae752ffb..0802fbf0e40 100644 --- a/source/blender/makesdna/DNA_modifier_types.h +++ b/source/blender/makesdna/DNA_modifier_types.h @@ -313,9 +313,10 @@ typedef struct WaveModifierData { typedef struct ArmatureModifierData { ModifierData modifier; - short deformflag, pad1; /* deformflag replaces armature->deformflag */ + short deformflag, multi; /* deformflag replaces armature->deformflag */ int pad2; struct Object *object; + float *prevCos; /* stored input of previous modifier, for vertexgroup blending */ char defgrp_name[32]; } ArmatureModifierData; diff --git a/source/blender/src/buttons_editing.c b/source/blender/src/buttons_editing.c index c6c5668fdbd..9dcd7f9921b 100644 --- a/source/blender/src/buttons_editing.c +++ b/source/blender/src/buttons_editing.c @@ -1957,8 +1957,10 @@ static void draw_modifier(uiBlock *block, Object *ob, ModifierData *md, int *xco ArmatureModifierData *amd = (ArmatureModifierData*) md; uiDefIDPoinBut(block, modifier_testArmatureObj, ID_OB, B_CHANGEDEP, "Ob: ", lx, (cy-=19), buttonWidth,19, &amd->object, "Armature object to deform with"); - but=uiDefBut(block, TEX, B_MODIFIER_RECALC, "VGroup: ", lx, (cy-=19), buttonWidth,19, &amd->defgrp_name, 0.0, 31.0, 0, 0, "Vertex Group name to control overall armature influence"); + but=uiDefBut(block, TEX, B_MODIFIER_RECALC, "VGroup: ", lx, (cy-=19), buttonWidth-40,19, &amd->defgrp_name, 0.0, 31.0, 0, 0, "Vertex Group name to control overall armature influence"); uiButSetCompleteFunc(but, autocomplete_vgroup, (void *)ob); + uiDefButS(block, TOG, B_ARM_RECALCDATA, "MM", lx+buttonWidth-40,cy, 40, 20, &amd->multi, 0, 0, 0, 0, "MultiModifier: This modifier uses same input as previous modifier, and mixes using this vgroup"); + uiDefButBitS(block, TOG, ARM_DEF_VGROUP, B_ARM_RECALCDATA, "Vert.Groups", lx,cy-=19,buttonWidth/2,20, &amd->deformflag, 0, 0, 0, 0, "Enable VertexGroups defining deform"); uiDefButBitS(block, TOG, ARM_DEF_ENVELOPE, B_ARM_RECALCDATA, "Envelopes", lx+buttonWidth/2,cy,(buttonWidth + 1)/2,20, &amd->deformflag, 0, 0, 0, 0, "Enable Bone Envelopes defining deform"); uiDefButBitS(block, TOG, ARM_DEF_QUATERNION, B_ARM_RECALCDATA, "Quaternion", lx,(cy-=19),buttonWidth/2,20, &amd->deformflag, 0, 0, 0, 0, "Enable deform rotation interpolation with Quaternions"); From e0fb0a1783d98454a733561ae524526478372ecc Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Sat, 17 Nov 2007 01:17:23 +0000 Subject: [PATCH 03/29] wizard_curve2tree - more twig options - gravity (like particles) - follow parent (like gravity but use the parent normal) - limit the number of twigs on each branch - limit the radius that a twig may be placed on a branch - trim the base of branches in a way that better deals with small branches on large branches --- release/scripts/wizard_curve2tree.py | 136 +++++++++++++++++++++------ 1 file changed, 107 insertions(+), 29 deletions(-) diff --git a/release/scripts/wizard_curve2tree.py b/release/scripts/wizard_curve2tree.py index f7ecd53bbcf..6dcdef8d8fa 100644 --- a/release/scripts/wizard_curve2tree.py +++ b/release/scripts/wizard_curve2tree.py @@ -220,11 +220,11 @@ class tree: def buildConnections( self,\ sloppy = 1.0,\ - base_trim = 1.0,\ + connect_base_trim = 1.0,\ do_twigs = False,\ twig_ratio = 2.0,\ twig_scale = 0.8,\ - twig_lengthen = 1.0,\ + twig_scale_width = 1.0,\ twig_random_orientation = 180,\ twig_random_angle = 33,\ twig_recursive=True,\ @@ -232,6 +232,12 @@ class tree: twig_ob_bounds=None,\ twig_ob_bounds_prune=True,\ twig_ob_bounds_prune_taper=True,\ + twig_placement_maxradius=10.0,\ + twig_placement_maxtwig=0,\ + twig_follow_parent=0.0,\ + twig_follow_x=0.0,\ + twig_follow_y=0.0,\ + twig_follow_z=0.0,\ ): ''' build tree data - fromCurve must run first @@ -262,7 +268,7 @@ class tree: brch_i.parent_pt = pt_best_j pt_best_j.childCount += 1 # dont remove me - brch_i.baseTrim(base_trim) + brch_i.baseTrim(connect_base_trim) ''' if pt_best_j.childCount>4: @@ -323,7 +329,10 @@ class tree: branches_twig_sort.sort() # this will sort the branches with best braches for adding twigs to at the start of the list for tmp_sortval, twig_pt_index, brch_parent in branches_twig_sort: # tmp_sortval is not used. - if twig_pt_index != -1 and (twig_recursive_limit==0 or brch_parent.generation <= twig_recursive_limit): + if twig_pt_index != -1 and \ + (twig_recursive_limit == 0 or brch_parent.generation < twig_recursive_limit) and \ + (twig_placement_maxtwig == 0 or brch_parent.twig_count < twig_placement_maxtwig) and \ + brch_parent.bpoints[twig_pt_index].radius < twig_placement_maxradius: if brch_twig_index >= len(self.branches_twigs): break @@ -343,8 +352,10 @@ class tree: # Random orientation # THIS IS NOT RANDOM - Dont be real random so we can always get re-produceale results. - rnd1 = (((irational_num * scale * 10000000) % 360) - 180) * twig_random_orientation - rnd2 = (((irational_num * scale * 66666666) % 360) - 180) * twig_random_angle + if twig_random_orientation: rnd1 = (((irational_num * scale * 10000000) % 360) - 180) * twig_random_orientation + else: rnd1 = 0.0 + if twig_random_angle: rnd2 = (((irational_num * scale * 66666666) % 360) - 180) * twig_random_angle + else: rnd2 = 0.0 # Align this with the existing branch @@ -367,16 +378,55 @@ class tree: mat_orientation = RotationMatrix(rnd2, 3, 'r', parent_pt.no) - if twig_lengthen != 1.0: + if twig_scale_width != 1.0: # adjust length - no radius adjusting for pt in brch_twig.bpoints: - pt.co *= twig_lengthen + pt.radius *= twig_scale_width brch_twig.transform(mat_scale * mat_branch_angle * mat_align * mat_orientation, parent_pt.co) + # Follow the parent normal + if twig_follow_parent or twig_follow_x or twig_follow_y or twig_follow_z: + + vecs = [] + brch_twig_len = float(len(brch_twig.bpoints)) + + if twig_follow_parent: + no = parent_pt.no.copy() * twig_follow_parent + else: + no = Vector() + + no.x += twig_follow_x + no.x += twig_follow_y + no.x += twig_follow_z + + for i, pt in enumerate(brch_twig.bpoints): + if pt.prev: + fac = i / brch_twig_len + + # Scale this value + fac_inv = 1-fac + + no_orig = pt.co - pt.prev.co + len_orig = no_orig.length + + no_new = (fac_inv * no_orig) + (fac * no) + no_new.length = len_orig + + # Mix the 2 normals + vecs.append(no_new) + + # Apply the coords + for i, pt in enumerate(brch_twig.bpoints): + if pt.prev: + pt.co = pt.prev.co + vecs[i-1] + + brch_twig.calcPointExtras() + + # When using a bounding mesh, clip and calculate points in bounds. #print "Attempting to trim base" - brch_twig.baseTrim(base_trim) + brch_twig.baseTrim(connect_base_trim) if twig_ob_bounds and (twig_ob_bounds_prune or twig_recursive): brch_twig.calcTwigBounds(self) @@ -398,6 +448,7 @@ class tree: if len(brch_twig.bpoints) > 2: branches_twig_attached.append(brch_twig) brch_twig.generation = brch_parent.generation + 1 + brch_parent.twig_count += 1 else: # Dont add the branch parent_pt.childCount -= 1 @@ -1540,7 +1591,7 @@ class branch: self.uv = None # face uvs can be fake, always 4 self.bones = [] self.generation = 0 # use to limit twig reproduction - + self.twig_count = 0 # count the number of twigs - so as to limit how many twigs a branch gets # self.myindex = -1 ### self.segment_spacing_scale = 1.0 # use this to scale up the spacing - so small twigs dont get WAY too many polys @@ -1606,9 +1657,10 @@ class branch: pt.inTwigBounds = tree.isPointInTwigBounds(pt.co) #if pt.inTwigBounds: # debug_pt(pt.co) - - def baseTrim(self, base_trim): + + + def baseTrim(self, connect_base_trim): # if 1) dont remove the whole branch, maybe an option but later # if 2) we are alredy a parent, cant remove me now.... darn :/ not nice... # could do this properly but it would be slower and its a corner case. @@ -1619,10 +1671,14 @@ class branch: while len(self.bpoints)>2 and\ self.bpoints[0].childCount == 0 and\ - (self.bpoints[0].co - self.parent_pt.nextMidCo).length / (1+ ((self.bpoints[0].radius/self.parent_pt.radius) / base_trim)) < self.parent_pt.radius * base_trim: + (self.parent_pt.nextMidCo - self.bpoints[0].co).length < ((self.parent_pt.radius + self.parent_pt.next.radius)/4) + (self.bpoints[0].radius * connect_base_trim): + # Note /4 - is a bit odd, since /2 is correct, but /4 lets us have more tight joints by default + del self.bpoints[0] self.bpoints[0].prev = None + + def boundsTrim(self): ''' @@ -2075,7 +2131,7 @@ PREFS['anim_offset_scale'] = Draw.Create(1.0) PREFS['do_twigs'] = Draw.Create(0) PREFS['twig_ratio'] = Draw.Create(2.0) PREFS['twig_scale'] = Draw.Create(0.8) -PREFS['twig_lengthen'] = Draw.Create(1.0) +PREFS['twig_scale_width'] = Draw.Create(1.0) PREFS['twig_random_orientation'] = Draw.Create(180) PREFS['twig_random_angle'] = Draw.Create(33) PREFS['twig_recursive'] = Draw.Create(1) @@ -2083,6 +2139,12 @@ PREFS['twig_recursive_limit'] = Draw.Create(3) PREFS['twig_ob_bounds'] = Draw.Create('') PREFS['twig_ob_bounds_prune'] = Draw.Create(1) PREFS['twig_ob_bounds_prune_taper'] = Draw.Create(1) +PREFS['twig_placement_maxradius'] = Draw.Create(10.0) +PREFS['twig_placement_maxtwig'] = Draw.Create(4) +PREFS['twig_follow_parent'] = Draw.Create(0.0) +PREFS['twig_follow_x'] = Draw.Create(0.0) +PREFS['twig_follow_y'] = Draw.Create(0.0) +PREFS['twig_follow_z'] = Draw.Create(0.0) PREFS['do_leaf'] = Draw.Create(1) PREFS['leaf_branch_limit'] = Draw.Create(0.25) @@ -2215,14 +2277,14 @@ def buildTree(ob_curve, single=False): except: twig_ob_bounds = None else: twig_ob_bounds = None - #print t + t.buildConnections(\ sloppy = PREFS['connect_sloppy'].val,\ - base_trim = PREFS['connect_base_trim'].val,\ + connect_base_trim = PREFS['connect_base_trim'].val,\ do_twigs = PREFS['do_twigs'].val,\ twig_ratio = PREFS['twig_ratio'].val,\ twig_scale = PREFS['twig_scale'].val,\ - twig_lengthen = PREFS['twig_lengthen'].val,\ + twig_scale_width = PREFS['twig_scale_width'].val,\ twig_random_orientation = PREFS['twig_random_orientation'].val,\ twig_random_angle = PREFS['twig_random_angle'].val,\ twig_recursive = PREFS['twig_recursive'].val,\ @@ -2230,6 +2292,12 @@ def buildTree(ob_curve, single=False): twig_ob_bounds = twig_ob_bounds,\ twig_ob_bounds_prune = PREFS['twig_ob_bounds_prune'].val,\ twig_ob_bounds_prune_taper = PREFS['twig_ob_bounds_prune_taper'].val,\ + twig_placement_maxradius = PREFS['twig_placement_maxradius'].val,\ + twig_placement_maxtwig = PREFS['twig_placement_maxtwig'].val,\ + twig_follow_parent = PREFS['twig_follow_parent'].val,\ + twig_follow_x = PREFS['twig_follow_x'].val,\ + twig_follow_y = PREFS['twig_follow_y'].val,\ + twig_follow_z = PREFS['twig_follow_z'].val,\ ) time4 = Blender.sys.time() # time print @@ -2520,13 +2588,13 @@ def bevt(e): pass def gui(): - MARGIN = 10 + MARGIN = 4 rect = BPyWindow.spaceRect() but_width = int((rect[2]-MARGIN*2)/4.0) # 72 # Clamp if but_width>100: but_width = 100 - but_height = 20 + but_height = 17 x=MARGIN @@ -2563,13 +2631,8 @@ def gui(): xtmp = x # ---------- ---------- ---------- ---------- - PREFS['connect_sloppy'] = Draw.Number('Connect Limit',EVENT_UPDATE, xtmp, y, but_width*4, but_height, PREFS['connect_sloppy'].val, 0.1, 2.0, 'Strictness when connecting branches'); xtmp += but_width*4; - - y-=but_height - xtmp = x - # ---------- ---------- ---------- ---------- - - PREFS['connect_base_trim'] = Draw.Number('Trim Base', EVENT_UPDATE, xtmp, y, but_width*4, but_height, PREFS['connect_base_trim'].val, 0.1, 2.0, 'Trim branch base to better connect with parent branch'); xtmp += but_width*4; + PREFS['connect_sloppy'] = Draw.Number('Connect Limit',EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['connect_sloppy'].val, 0.1, 2.0, 'Strictness when connecting branches'); xtmp += but_width*2; + PREFS['connect_base_trim'] = Draw.Number('Trim Base', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['connect_base_trim'].val, 0.0, 2.0, 'Trim branch base to better connect with parent branch'); xtmp += but_width*2; Blender.Draw.EndAlign() y-=but_height+MARGIN xtmp = x @@ -2591,8 +2654,8 @@ def gui(): # ---------- ---------- ---------- ---------- - PREFS['twig_scale'] = Draw.Number('Twig Scale', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['twig_scale'].val, 0.01, 1.0, 'Scale down twigs in relation to their parents each generation'); xtmp += but_width*2; - PREFS['twig_lengthen'] = Draw.Number('Twig Lengthen', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['twig_lengthen'].val, 0.01, 20.0, 'Scale the twig length only (not thickness)'); xtmp += but_width*2; + PREFS['twig_scale'] = Draw.Number('Twig Scale', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['twig_scale'].val, 0.01, 10.0, 'Scale down twigs in relation to their parents each generation'); xtmp += but_width*2; + PREFS['twig_scale_width'] = Draw.Number('Twig Scale Width', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['twig_scale_width'].val, 0.01, 20.0, 'Scale the twig length only (not thickness)'); xtmp += but_width*2; y-=but_height xtmp = x @@ -2600,13 +2663,28 @@ def gui(): PREFS['twig_random_orientation'] = Draw.Number('Rand Orientation', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['twig_random_orientation'].val, 0.0, 360.0, 'Random rotation around the parent'); xtmp += but_width*2; PREFS['twig_random_angle'] = Draw.Number('Rand Angle', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['twig_random_angle'].val, 0.0, 360.0, 'Random rotation to the parent joint'); xtmp += but_width*2; + y-=but_height + xtmp = x - #PREFS['uv_y_scale'] = Draw.Number('Scale V', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['uv_y_scale'].val, 0.01, 10.0, 'Edge loop spacing around branch join, lower value for less webed joins'); xtmp += but_width*2; + # ---------- ---------- ---------- ---------- + + PREFS['twig_placement_maxradius'] = Draw.Number('Place Max Radius', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['twig_placement_maxradius'].val, 0.0, 50.0, 'Limit twig placement to branches with this maximum radius'); xtmp += but_width*2; + PREFS['twig_placement_maxtwig'] = Draw.Number('Place Max Count', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['twig_placement_maxtwig'].val, 0.0, 50.0, 'Limit twig placement to this many per branch'); xtmp += but_width*2; y-=but_height xtmp = x # ---------- ---------- ---------- ---------- + PREFS['twig_follow_parent'] = Draw.Number('ParFollow', EVENT_UPDATE, xtmp, y, but_width, but_height, PREFS['twig_follow_parent'].val, 0.0, 10.0, 'Follow the parent branch'); xtmp += but_width; + PREFS['twig_follow_x'] = Draw.Number('Grav X', EVENT_UPDATE, xtmp, y, but_width, but_height, PREFS['twig_follow_x'].val, -10.0, 10.0, 'Twigs gravitate on the X axis'); xtmp += but_width; + PREFS['twig_follow_y'] = Draw.Number('Grav Y', EVENT_UPDATE, xtmp, y, but_width, but_height, PREFS['twig_follow_y'].val, -10.0, 10.0, 'Twigs gravitate on the Y axis'); xtmp += but_width; + PREFS['twig_follow_z'] = Draw.Number('Grav Z', EVENT_UPDATE, xtmp, y, but_width, but_height, PREFS['twig_follow_z'].val, -10.0, 10.0, 'Twigs gravitate on the Z axis'); xtmp += but_width; + + y-=but_height + xtmp = x + + # ---------- ---------- ---------- ---------- + PREFS['twig_ob_bounds'] = Draw.String('OB Bound: ', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['twig_ob_bounds'].val, 64, 'Only grow twigs inside this mesh object', do_ob_check); xtmp += but_width*2; if PREFS['twig_ob_bounds_prune'].val: but_width_tmp = but_width From 6ce8374990ef9d98129b02f3b38d6b1454581109 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Sat, 17 Nov 2007 14:21:53 +0000 Subject: [PATCH 04/29] Selecting an image in editmode now adds UV's if they are not there (before assigning the image) --- source/blender/src/drawimage.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/source/blender/src/drawimage.c b/source/blender/src/drawimage.c index e7a43086fa3..342e361d869 100644 --- a/source/blender/src/drawimage.c +++ b/source/blender/src/drawimage.c @@ -309,9 +309,25 @@ void image_changed(SpaceImage *sima, Image *image) return; /* skip assigning these procedural images... */ - if(image && (image->type==IMA_TYPE_R_RESULT || image->type==IMA_TYPE_COMPOSITE)) {; + if(image && (image->type==IMA_TYPE_R_RESULT || image->type==IMA_TYPE_COMPOSITE)) { return; - } else if (EM_texFaceCheck()) { + } else if ((G.obedit) && + (G.obedit->type == OB_MESH) && + (G.editMesh) && + (G.editMesh->faces.first) + ) { + + /* Add a UV layer if there is none, editmode only */ + if ( !CustomData_has_layer(&G.editMesh->fdata, CD_MTFACE) ) { + EM_add_data_layer(&em->fdata, CD_MTFACE); + CustomData_set_layer_active(&em->fdata, CD_MTFACE, 0); /* always zero because we have no other UV layers */ + change = 1; /* so we update the object, incase no faces are selected */ + + /* BIF_undo_push("New UV Texture"); - undo should be done by whatever changes the image */ + allqueue(REDRAWVIEW3D, 0); + allqueue(REDRAWBUTSEDIT, 0); + } + for (efa= em->faces.first; efa; efa= efa->next) { tface = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); if (efa->h==0 && efa->f & SELECT) { From 6d5396fc65fe81f0d999d12df6b64156358b1e60 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Sat, 17 Nov 2007 21:12:25 +0000 Subject: [PATCH 05/29] Fix for multimodifier commit breaking game engine compile. --- source/gameengine/Converter/BL_SkinDeformer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/gameengine/Converter/BL_SkinDeformer.cpp b/source/gameengine/Converter/BL_SkinDeformer.cpp index 90b5fc5308d..e9ec6f9116b 100644 --- a/source/gameengine/Converter/BL_SkinDeformer.cpp +++ b/source/gameengine/Converter/BL_SkinDeformer.cpp @@ -175,7 +175,7 @@ void BL_SkinDeformer::Update(void) for (int v =0; vtotvert; v++) VECCOPY(m_transverts[v], m_bmesh->mvert[v].co); - armature_deform_verts( par_arma, m_objMesh, NULL, m_transverts, NULL, m_bmesh->totvert, ARM_DEF_VGROUP, NULL ); + armature_deform_verts( par_arma, m_objMesh, NULL, m_transverts, NULL, m_bmesh->totvert, ARM_DEF_VGROUP, NULL, NULL ); RecalcNormals(); /* Update the current frame */ From dc6ac56d318ad9f2952a1d91dba13f1bd723768a Mon Sep 17 00:00:00 2001 From: Peter Schlaile Date: Sun, 18 Nov 2007 17:39:30 +0000 Subject: [PATCH 06/29] General cleanup in sequencer: - Seperated StripData into StripData TStripData where StripData holds only image-filenames and TStripData holds the working information needed for ImBuf caching. => Large drop in memory usage, if you used a lot of movie and meta strips. => Fixed bugs in "duplicate" on the way (imbufs where copied around without taking reference counting seriously...) => Code is much cleaner now - Added defines for TStripData->ok Finally figured out, what the magic values ment and named them properly :) - Got rid of Sequence->curelem. Reason: very bad idea(tm) for multi threading with more than one render thread. Still not there, but this was a real show stopper on the way. --- source/blender/blenloader/intern/readfile.c | 63 +-- source/blender/include/BSE_sequence.h | 12 +- source/blender/makesdna/DNA_sequence_types.h | 15 +- source/blender/python/api2_2x/sceneSequence.c | 11 +- source/blender/src/drawseq.c | 31 +- source/blender/src/editseq.c | 116 ++---- source/blender/src/sequence.c | 387 ++++++++++-------- 7 files changed, 301 insertions(+), 334 deletions(-) diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 75c746f7213..0903062461b 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -3204,7 +3204,6 @@ static void direct_link_scene(FileData *fd, Scene *sce) Editing *ed; Sequence *seq; MetaStack *ms; - StripElem *se; int a; sce->theDag = NULL; @@ -3240,8 +3239,6 @@ static void direct_link_scene(FileData *fd, Scene *sce) /* a patch: after introduction of effects with 3 input strips */ if(seq->seq3==0) seq->seq3= seq->seq2; - seq->curelem= 0; - seq->plugin= newdataadr(fd, seq->plugin); seq->effectdata= newdataadr(fd, seq->effectdata); @@ -3252,59 +3249,17 @@ static void direct_link_scene(FileData *fd, Scene *sce) seq->strip= newdataadr(fd, seq->strip); if(seq->strip && seq->strip->done==0) { seq->strip->done= 1; + seq->strip->tstripdata = 0; - /* standard: strips from effects/metas are not written, but are mallocced */ - - if(seq->type==SEQ_IMAGE) { - seq->strip->stripdata= newdataadr(fd, seq->strip->stripdata); - se= seq->strip->stripdata; - if(se) { - for(a=0; astrip->len; a++, se++) { - se->ok= 1; - se->ibuf= 0; - } - } + if(seq->type == SEQ_IMAGE || + seq->type == SEQ_MOVIE || + seq->type == SEQ_RAM_SOUND || + seq->type == SEQ_HD_SOUND) { + seq->strip->stripdata = newdataadr( + fd, seq->strip->stripdata); + } else { + seq->strip->stripdata = 0; } - else if(seq->type==SEQ_MOVIE) { - /* only first stripelem is in file */ - se= newdataadr(fd, seq->strip->stripdata); - - if(se) { - seq->strip->stripdata= MEM_callocN(seq->len*sizeof(StripElem), "stripelem"); - *seq->strip->stripdata= *se; - MEM_freeN(se); - - se= seq->strip->stripdata; - - for(a=0; astrip->len; a++, se++) { - se->ok= 1; - se->ibuf= 0; - se->nr= a + 1; - } - } - } - else if(seq->type==SEQ_RAM_SOUND - || seq->type == SEQ_HD_SOUND) { - /* only first stripelem is in file */ - se= newdataadr(fd, seq->strip->stripdata); - - if(se) { - seq->strip->stripdata= MEM_callocN(seq->len*sizeof(StripElem), "stripelem"); - *seq->strip->stripdata= *se; - MEM_freeN(se); - - se= seq->strip->stripdata; - - for(a=0; astrip->len; a++, se++) { - se->ok= 2; /* why? */ - se->ibuf= 0; - se->nr= a + 1; - } - } - } - else if(seq->len>0) - seq->strip->stripdata= MEM_callocN(seq->len*sizeof(StripElem), "stripelem"); - } } END_SEQ diff --git a/source/blender/include/BSE_sequence.h b/source/blender/include/BSE_sequence.h index ff79d417537..fdf584b38f4 100644 --- a/source/blender/include/BSE_sequence.h +++ b/source/blender/include/BSE_sequence.h @@ -37,6 +37,7 @@ struct PluginSeq; struct StripElem; +struct TStripElem; struct Strip; struct Sequence; struct ListBase; @@ -44,9 +45,9 @@ struct Editing; struct ImBuf; struct Scene; -void free_stripdata(int len, struct StripElem *se); +void free_tstripdata(int len, struct TStripElem *se); void free_strip(struct Strip *strip); -void new_stripdata(struct Sequence *seq); +void new_tstripdata(struct Sequence *seq); void free_sequence(struct Sequence *seq); void build_seqar(struct ListBase *seqbase, struct Sequence ***seqar, int *totseq); void free_editing(struct Editing *ed); @@ -57,17 +58,20 @@ void clear_scene_in_allseqs(struct Scene *sce); int evaluate_seq_frame(int cfra); struct StripElem *give_stripelem(struct Sequence *seq, int cfra); +struct TStripElem *give_tstripelem(struct Sequence *seq, int cfra); void set_meta_stripdata(struct Sequence *seqm); struct ImBuf *give_ibuf_seq(int rectx, int recty, int cfra, int chansel); /* chansel: render this channel. Default=0 (renders end result)*/ +struct ImBuf *give_ibuf_seq_direct(int rectx, int recty, int cfra, + struct Sequence * seq); /* sequence prefetch API */ void seq_start_threads(); void seq_stop_threads(); void give_ibuf_prefetch_request(int rectx, int recty, int cfra, int chanshown); void seq_wait_for_prefetch_ready(); -struct ImBuf * give_ibuf_threaded(int rectx, int recty, int cfra, - int chanshown); +struct ImBuf * give_ibuf_seq_threaded(int rectx, int recty, int cfra, + int chanshown); void free_imbuf_seq_except(int cfra); diff --git a/source/blender/makesdna/DNA_sequence_types.h b/source/blender/makesdna/DNA_sequence_types.h index 839d804fbea..bc574228cca 100644 --- a/source/blender/makesdna/DNA_sequence_types.h +++ b/source/blender/makesdna/DNA_sequence_types.h @@ -46,12 +46,15 @@ struct Scene; typedef struct StripElem { char name[80]; +} StripElem; + +typedef struct TStripElem { struct ImBuf *ibuf; - struct StripElem *se1, *se2, *se3; + struct TStripElem *se1, *se2, *se3; short ok; short pad; int nr; -} StripElem; +} TStripElem; typedef struct Strip { struct Strip *next, *prev; @@ -59,6 +62,7 @@ typedef struct Strip { StripElem *stripdata; char dir[160]; int orx, ory; + TStripElem *tstripdata; } Strip; @@ -87,7 +91,6 @@ typedef struct PluginSeq { /* WATCH IT: first part identical to ID (for use in ipo's) */ typedef struct Sequence { - struct Sequence *next, *prev; void *tmp; /* tmp var for copying, and tagging for linked selection */ void *lib; /* needed (to be like ipo), else it will raise libdata warnings, this should never be used */ @@ -104,7 +107,8 @@ typedef struct Sequence { int sfra; /* starting frame according to the timeline of the scene. */ Strip *strip; - StripElem *curelem; /* reference the current frame - value from give_stripelem */ + int pad2; + int pad3; struct Ipo *ipo; struct Scene *scene; @@ -234,6 +238,9 @@ typedef struct SpeedControlVars { #define SEQ_COLOR 28 #define SEQ_SPEED 29 +#define STRIPELEM_FAILED 0 +#define STRIPELEM_OK 1 +#define STRIPELEM_META 2 #endif diff --git a/source/blender/python/api2_2x/sceneSequence.c b/source/blender/python/api2_2x/sceneSequence.c index 6ddaaf345c3..fee1bde149c 100644 --- a/source/blender/python/api2_2x/sceneSequence.c +++ b/source/blender/python/api2_2x/sceneSequence.c @@ -156,7 +156,6 @@ static PyObject *NewSeq_internal(ListBase *seqbase, PyObject * args, Scene *sce) for(a=0; alen; a++) { name = PyString_AsString(PyList_GetItem( list, a )); strncpy(se->name, name, FILE_MAXFILE-1); - se->ok= 1; se++; } @@ -179,16 +178,10 @@ static PyObject *NewSeq_internal(ListBase *seqbase, PyObject * args, Scene *sce) strip->len= totframe; strip->us= 1; strncpy(strip->dir, sound->name, FILE_MAXDIR-1); - strip->stripdata= se= MEM_callocN(totframe*sizeof(StripElem), "stripelem"); + strip->stripdata= se= MEM_callocN(sizeof(StripElem), "stripelem"); /* name sound in first strip */ strncpy(se->name, sound->name, FILE_MAXFILE-1); - - for(a=1; a<=totframe; a++, se++) { - se->ok= 2; /* why? */ - se->ibuf= 0; - se->nr= a; - } } else if (BPy_Scene_Check(py_data)) { /* scene */ @@ -205,8 +198,6 @@ static PyObject *NewSeq_internal(ListBase *seqbase, PyObject * args, Scene *sce) sizeof(seq->name) - 2); strip->len= seq->len; strip->us= 1; - if(seq->len>0) strip->stripdata= MEM_callocN(seq->len*sizeof(StripElem), "stripelem"); - } else { /* movie, pydata is a path to a movie file */ char *name = PyString_AsString ( py_data ); diff --git a/source/blender/src/drawseq.c b/source/blender/src/drawseq.c index 36a857abfe1..77006353640 100644 --- a/source/blender/src/drawseq.c +++ b/source/blender/src/drawseq.c @@ -775,7 +775,6 @@ void set_special_seq_update(int val) static void draw_image_seq(ScrArea *sa) { SpaceSeq *sseq; - StripElem *se; struct ImBuf *ibuf; int x1, y1, rectx, recty; int free_ibuf = 0; @@ -800,10 +799,18 @@ static void draw_image_seq(ScrArea *sa) return; else { recursive= 1; - if (!U.prefetchframes || (G.f & G_PLAYANIM) == 0) { - ibuf= (ImBuf *)give_ibuf_seq(rectx, recty, (G.scene->r.cfra), sseq->chanshown); + if (special_seq_update) { + ibuf= give_ibuf_seq_direct( + rectx, recty, (G.scene->r.cfra), + special_seq_update); + } else if (!U.prefetchframes || (G.f & G_PLAYANIM) == 0) { + ibuf= (ImBuf *)give_ibuf_seq( + rectx, recty, (G.scene->r.cfra), + sseq->chanshown); } else { - ibuf= (ImBuf *)give_ibuf_threaded(rectx, recty, (G.scene->r.cfra), sseq->chanshown); + ibuf= (ImBuf *)give_ibuf_seq_threaded( + rectx, recty, (G.scene->r.cfra), + sseq->chanshown); } recursive= 0; @@ -815,16 +822,6 @@ static void draw_image_seq(ScrArea *sa) } } - if(special_seq_update) { - se = special_seq_update->curelem; - if(se) { - if(se->ok==2) { - if(se->se1) - ibuf= se->se1->ibuf; - } - else ibuf= se->ibuf; - } - } if(ibuf==NULL) return; if(ibuf->rect_float && ibuf->rect==NULL) @@ -862,7 +859,7 @@ static void draw_image_seq(ScrArea *sa) if (free_ibuf) { IMB_freeImBuf(ibuf); - } + } sa->win_swap= WIN_BACK_OK; } @@ -917,7 +914,7 @@ static void draw_extra_seqinfo(void) if(last_seq->type==SEQ_IMAGE) { if (last_seq->len > 1) { /* CURRENT */ - se= (StripElem *)give_stripelem(last_seq, (G.scene->r.cfra)); + se= give_stripelem(last_seq, (G.scene->r.cfra)); if(se) { sprintf(str, "Cur: %s", se->name); glRasterPos3f(xco, yco, 0.0); @@ -966,7 +963,7 @@ static void draw_extra_seqinfo(void) BMF_DrawString(G.font, str); } else if(last_seq->type==SEQ_SCENE) { - se= (StripElem *)give_stripelem(last_seq, (G.scene->r.cfra)); + TStripElem * se= give_tstripelem(last_seq, (G.scene->r.cfra)); if(se && last_seq->scene) { sprintf(str, "Cur: %d First: %d Last: %d", last_seq->sfra+se->nr, last_seq->sfra, last_seq->sfra+last_seq->len-1); glRasterPos3f(xco, yco, 0.0); diff --git a/source/blender/src/editseq.c b/source/blender/src/editseq.c index 8f328afc222..8565a302f45 100644 --- a/source/blender/src/editseq.c +++ b/source/blender/src/editseq.c @@ -985,7 +985,6 @@ static Sequence *sfile_to_sequence(SpaceFile *sfile, int cfra, int machine, int if(sfile->filelist[a].flags & ACTIVE) { if( (sfile->filelist[a].type & S_IFDIR)==0 ) { strncpy(se->name, sfile->filelist[a].relname, FILE_MAXFILE-1); - se->ok= 1; se++; } } @@ -993,7 +992,6 @@ static Sequence *sfile_to_sequence(SpaceFile *sfile, int cfra, int machine, int /* no selected file: */ if(totsel==1 && se==strip->stripdata) { strncpy(se->name, sfile->file, FILE_MAXFILE-1); - se->ok= 1; } /* last active name */ @@ -1010,7 +1008,7 @@ static int sfile_to_mv_sequence_load(SpaceFile *sfile, int cfra, struct anim *anim; Strip *strip; StripElem *se; - int totframe, a; + int totframe; char name[160], rel[160]; char str[FILE_MAXDIR+FILE_MAXFILE]; @@ -1054,7 +1052,7 @@ static int sfile_to_mv_sequence_load(SpaceFile *sfile, int cfra, strip->len= totframe; strip->us= 1; strncpy(strip->dir, name, FILE_MAXDIR-1); - strip->stripdata= se= MEM_callocN(totframe*sizeof(StripElem), "stripelem"); + strip->stripdata= se= MEM_callocN(sizeof(StripElem), "stripelem"); /* name movie in first strip */ if(index<0) @@ -1062,11 +1060,6 @@ static int sfile_to_mv_sequence_load(SpaceFile *sfile, int cfra, else strncpy(se->name, sfile->filelist[index].relname, FILE_MAXFILE-1); - for(a=1; a<=totframe; a++, se++) { - se->ok= 1; - se->nr= a; - } - /* last active name */ strncpy(last_imagename, seq->strip->dir, FILE_MAXDIR-1); return(cfra+totframe); @@ -1111,7 +1104,6 @@ static Sequence *sfile_to_ramsnd_sequence(SpaceFile *sfile, Strip *strip; StripElem *se; double totframe; - int a; char name[160], rel[160]; char str[256]; @@ -1157,17 +1149,11 @@ static Sequence *sfile_to_ramsnd_sequence(SpaceFile *sfile, strip->len= totframe; strip->us= 1; strncpy(strip->dir, name, FILE_MAXDIR-1); - strip->stripdata= se= MEM_callocN(totframe*sizeof(StripElem), "stripelem"); + strip->stripdata= se= MEM_callocN(sizeof(StripElem), "stripelem"); /* name sound in first strip */ strncpy(se->name, sfile->file, FILE_MAXFILE-1); - for(a=1; a<=totframe; a++, se++) { - se->ok= 2; /* why? */ - se->ibuf= 0; - se->nr= a; - } - /* last active name */ strncpy(last_sounddir, seq->strip->dir, FILE_MAXDIR-1); @@ -1181,7 +1167,7 @@ static int sfile_to_hdsnd_sequence_load(SpaceFile *sfile, int cfra, struct hdaudio *hdaudio; Strip *strip; StripElem *se; - int totframe, a; + int totframe; char name[160], rel[160]; char str[FILE_MAXDIR+FILE_MAXFILE]; @@ -1224,7 +1210,7 @@ static int sfile_to_hdsnd_sequence_load(SpaceFile *sfile, int cfra, strip->len= totframe; strip->us= 1; strncpy(strip->dir, name, FILE_MAXDIR-1); - strip->stripdata= se= MEM_callocN(totframe*sizeof(StripElem), "stripelem"); + strip->stripdata= se= MEM_callocN(sizeof(StripElem), "stripelem"); /* name movie in first strip */ if(index<0) @@ -1232,12 +1218,6 @@ static int sfile_to_hdsnd_sequence_load(SpaceFile *sfile, int cfra, else strncpy(se->name, sfile->filelist[index].relname, FILE_MAXFILE-1); - for(a=1; a<=totframe; a++, se++) { - se->ok= 2; - se->ibuf = 0; - se->nr= a; - } - /* last active name */ strncpy(last_sounddir, seq->strip->dir, FILE_MAXDIR-1); return(cfra+totframe); @@ -2013,7 +1993,7 @@ void change_sequence(void) last_seq->sfra= sce->r.sfra; /* bad code to change seq->len? update_changed_seq_and_deps() expects the strip->len to be OK */ - new_stripdata(last_seq); + new_tstripdata(last_seq); update_changed_seq_and_deps(last_seq, 1, 1); @@ -2169,25 +2149,23 @@ void del_seq(void) static void recurs_dupli_seq(ListBase *old, ListBase *new) { - Sequence *seq, *seqn; + Sequence *seq; + Sequence *seqn = 0; Sequence *last_seq = get_last_seq(); - StripElem *se; - int a; seq= old->first; while(seq) { seq->tmp= NULL; if(seq->flag & SELECT) { - if(seq->type==SEQ_META) { seqn= MEM_dupallocN(seq); seq->tmp= seqn; BLI_addtail(new, seqn); seqn->strip= MEM_dupallocN(seq->strip); - - if(seq->len>0) seq->strip->stripdata= MEM_callocN(seq->len*sizeof(StripElem), "stripelem"); + seqn->strip->stripdata = 0; + seqn->strip->tstripdata = 0; seq->flag &= SEQ_DESEL; seqn->flag &= ~(SEQ_LEFTSEL+SEQ_RIGHTSEL); @@ -2202,8 +2180,8 @@ static void recurs_dupli_seq(ListBase *old, ListBase *new) BLI_addtail(new, seqn); seqn->strip= MEM_dupallocN(seq->strip); - - if(seq->len>0) seqn->strip->stripdata = MEM_callocN(seq->len*sizeof(StripElem), "stripelem"); + seqn->strip->stripdata = 0; + seqn->strip->tstripdata = 0; seq->flag &= SEQ_DESEL; seqn->flag &= ~(SEQ_LEFTSEL+SEQ_RIGHTSEL); @@ -2214,20 +2192,11 @@ static void recurs_dupli_seq(ListBase *old, ListBase *new) BLI_addtail(new, seqn); seqn->strip= MEM_dupallocN(seq->strip); + seqn->strip->stripdata = + MEM_dupallocN(seq->strip->stripdata); + seqn->strip->tstripdata = 0; seqn->anim= 0; - if(seqn->len>0) { - seqn->strip->stripdata= MEM_callocN(seq->len*sizeof(StripElem), "stripelem"); - /* copy first elem */ - *seqn->strip->stripdata= *seq->strip->stripdata; - se= seqn->strip->stripdata; - a= seq->len; - while(a--) { - se->ok= 1; - se++; - } - } - seq->flag &= SEQ_DESEL; seqn->flag &= ~(SEQ_LEFTSEL+SEQ_RIGHTSEL); } @@ -2237,22 +2206,14 @@ static void recurs_dupli_seq(ListBase *old, ListBase *new) BLI_addtail(new, seqn); seqn->strip= MEM_dupallocN(seq->strip); + seqn->strip->stripdata = + MEM_dupallocN(seq->strip->stripdata); + seqn->strip->tstripdata = 0; + seqn->anim= 0; seqn->sound->id.us++; if(seqn->ipo) seqn->ipo->id.us++; - if(seqn->len>0) { - seqn->strip->stripdata= MEM_callocN(seq->len*sizeof(StripElem), "stripelem"); - /* copy first elem */ - *seqn->strip->stripdata= *seq->strip->stripdata; - se= seqn->strip->stripdata; - a= seq->len; - while(a--) { - se->ok= 1; - se++; - } - } - seq->flag &= SEQ_DESEL; seqn->flag &= ~(SEQ_LEFTSEL+SEQ_RIGHTSEL); } @@ -2262,36 +2223,29 @@ static void recurs_dupli_seq(ListBase *old, ListBase *new) BLI_addtail(new, seqn); seqn->strip= MEM_dupallocN(seq->strip); + seqn->strip->stripdata = + MEM_dupallocN(seq->strip->stripdata); + seqn->strip->tstripdata = 0; seqn->anim= 0; seqn->hdaudio = 0; if(seqn->ipo) seqn->ipo->id.us++; - if(seqn->len>0) { - seqn->strip->stripdata= MEM_callocN(seq->len*sizeof(StripElem), "stripelem"); - /* copy first elem */ - *seqn->strip->stripdata= *seq->strip->stripdata; - se= seqn->strip->stripdata; - a= seq->len; - while(a--) { - se->ok= 1; - se++; - } - } - seq->flag &= SEQ_DESEL; seqn->flag &= ~(SEQ_LEFTSEL+SEQ_RIGHTSEL); - } - else if(seq->type < SEQ_EFFECT) { + } else if(seq->type == SEQ_IMAGE) { seqn= MEM_dupallocN(seq); seq->tmp= seqn; BLI_addtail(new, seqn); - seqn->strip->us++; + seqn->strip= MEM_dupallocN(seq->strip); + seqn->strip->stripdata = + MEM_dupallocN(seq->strip->stripdata); + seqn->strip->tstripdata = 0; + seq->flag &= SEQ_DESEL; seqn->flag &= ~(SEQ_LEFTSEL+SEQ_RIGHTSEL); - } - else { + } else if(seq->type >= SEQ_EFFECT) { seqn= MEM_dupallocN(seq); seq->tmp= seqn; BLI_addtail(new, seqn); @@ -2310,12 +2264,16 @@ static void recurs_dupli_seq(ListBase *old, ListBase *new) } seqn->strip= MEM_dupallocN(seq->strip); - - if(seq->len>0) seq->strip->stripdata= MEM_callocN(seq->len*sizeof(StripElem), "stripelem"); + seqn->strip->stripdata = 0; + seqn->strip->tstripdata = 0; seq->flag &= SEQ_DESEL; seqn->flag &= ~(SEQ_LEFTSEL+SEQ_RIGHTSEL); + } else { + fprintf(stderr, "Aiiiiekkk! sequence type not " + "handled in duplicate!\nExpect a crash" + " now...\n"); } if (seq == last_seq) { set_last_seq(seqn); @@ -2564,7 +2522,7 @@ void make_meta(void) seqm->strip= MEM_callocN(sizeof(Strip), "metastrip"); seqm->strip->len= seqm->len; seqm->strip->us= 1; - if(seqm->len) seqm->strip->stripdata= MEM_callocN(seqm->len*sizeof(StripElem), "metastripdata"); + set_meta_stripdata(seqm); BIF_undo_push("Make Meta Strip, Sequencer"); @@ -3496,8 +3454,6 @@ void seq_separate_images(void) /* new stripdata */ strip_new->stripdata= se_new= MEM_callocN(sizeof(StripElem)*1, "stripelem"); strncpy(se_new->name, se->name, FILE_MAXFILE-1); - se_new->ok= 1; - calc_sequence(seq_new); seq_new->flag &= ~SEQ_OVERLAP; if (test_overlap_seq(seq_new)) { diff --git a/source/blender/src/sequence.c b/source/blender/src/sequence.c index e93cc1b1075..1e0026cde93 100644 --- a/source/blender/src/sequence.c +++ b/source/blender/src/sequence.c @@ -75,15 +75,18 @@ int seqrectx, seqrecty; -void free_stripdata(int len, StripElem *se) +void free_tstripdata(int len, TStripElem *se) { - StripElem *seo; + TStripElem *seo; int a; seo= se; + if (!se) { + return; + } for(a=0; aibuf && se->ok!=2) { + if(se->ibuf && se->ok != STRIPELEM_META) { IMB_freeImBuf(se->ibuf); se->ibuf = 0; } @@ -103,18 +106,20 @@ void free_strip(Strip *strip) } if(strip->stripdata) { - free_stripdata(strip->len, strip->stripdata); + MEM_freeN(strip->stripdata); } + + free_tstripdata(strip->len, strip->tstripdata); + MEM_freeN(strip); } -void new_stripdata(Sequence *seq) +void new_tstripdata(Sequence *seq) { if(seq->strip) { - if(seq->strip->stripdata) free_stripdata(seq->strip->len, seq->strip->stripdata); - seq->strip->stripdata= 0; + free_tstripdata(seq->strip->len, seq->strip->tstripdata); + seq->strip->tstripdata= 0; seq->strip->len= seq->len; - if(seq->len>0) seq->strip->stripdata= MEM_callocN(seq->len*sizeof(StripElem), "stripelems"); } } @@ -265,7 +270,7 @@ void calc_sequence(Sequence *seq) } if(seq->strip && seq->len!=seq->strip->len) { - new_stripdata(seq); + new_tstripdata(seq); } } @@ -284,7 +289,7 @@ void calc_sequence(Sequence *seq) seq->len= max-min; if(seq->strip && seq->len!=seq->strip->len) { - new_stripdata(seq); + new_tstripdata(seq); } } } @@ -426,9 +431,9 @@ static void multibuf(ImBuf *ibuf, float fmul) } } -static void do_effect(int cfra, Sequence *seq, StripElem *se) +static void do_effect(int cfra, Sequence *seq, TStripElem *se) { - StripElem *se1, *se2, *se3; + TStripElem *se1, *se2, *se3; float fac, facf; int x, y; int early_out; @@ -464,14 +469,13 @@ static void do_effect(int cfra, Sequence *seq, StripElem *se) return; } - /* if metastrip: other se's */ - if(se->se1->ok==2) se1= se->se1->se1; + if(se->se1->ok == STRIPELEM_META) se1= se->se1->se1; else se1= se->se1; - if(se->se2->ok==2) se2= se->se2->se1; + if(se->se2->ok == STRIPELEM_META) se2= se->se2->se1; else se2= se->se2; - if(se->se3->ok==2) se3= se->se3->se1; + if(se->se3->ok == STRIPELEM_META) se3= se->se3->se1; else se3= se->se3; if ( (se1==0 || se2==0 || se3==0) @@ -487,8 +491,7 @@ static void do_effect(int cfra, Sequence *seq, StripElem *se) return; } - /* if metastrip: other se's */ - if(se->se1->ok==2) se1= se->se1->se1; + if(se->se1->ok == STRIPELEM_META) se1= se->se1->se1; else se1= se->se1; if (se1 == 0 || se1->ibuf == 0) { @@ -508,8 +511,7 @@ static void do_effect(int cfra, Sequence *seq, StripElem *se) return; } - /* if metastrip: other se's */ - if(se->se2->ok==2) se2= se->se2->se1; + if(se->se2->ok == STRIPELEM_META) se2= se->se2->se1; else se2= se->se2; if (se2 == 0 || se2->ibuf == 0) { @@ -548,17 +550,11 @@ static void do_effect(int cfra, Sequence *seq, StripElem *se) se->ibuf); } -StripElem *give_stripelem(Sequence *seq, int cfra) +static int give_stripelem_index(Sequence *seq, int cfra) { - Strip *strip; - StripElem *se; int nr; - strip= seq->strip; - se= strip->stripdata; - - if(se==0) return 0; - if(seq->startdisp >cfra || seq->enddisp <= cfra) return 0; + if(seq->startdisp >cfra || seq->enddisp <= cfra) return -1; if(seq->flag&SEQ_REVERSE_FRAMES) { /*reverse frame in this sequence */ @@ -574,13 +570,51 @@ StripElem *give_stripelem(Sequence *seq, int cfra) if (seq->strobe > 1.0) { nr -= (int)fmod((double)nr, (double)seq->strobe); } + + return nr; +} + +TStripElem *give_tstripelem(Sequence *seq, int cfra) +{ + TStripElem *se; + int nr; + + se = seq->strip->tstripdata; + if (se == 0 && seq->len > 0) { + int i; + se = seq->strip->tstripdata = MEM_callocN( + seq->len*sizeof(TStripElem), "tstripelems"); + for (i = 0; i < seq->len; i++) { + se[i].ok = STRIPELEM_OK; + } + } + nr = give_stripelem_index(seq, cfra); + + if (nr == -1) return 0; + if (se == 0) return 0; - se+= nr; /* don't get confused by the increment, this is the same as strip->stripdata[nr], which works on some compilers...*/ + se+= nr; se->nr= nr; return se; } +StripElem *give_stripelem(Sequence *seq, int cfra) +{ + StripElem *se; + int nr; + + se = seq->strip->stripdata; + nr = give_stripelem_index(seq, cfra); + + if (nr == -1) return 0; + if (se == 0) return 0; + + se += nr; + + return se; +} + static int evaluate_seq_frame_gen( Sequence ** seq_arr, ListBase *seqbase, int cfra) { @@ -664,36 +698,57 @@ static Sequence * get_shown_seq_from_metastrip(Sequence * seqm, int cfra) void set_meta_stripdata(Sequence *seqm) { Sequence *seq; - StripElem *se; + TStripElem *se; int a, cfra; + se= seqm->strip->tstripdata; + + if (se == 0 && seqm->len > 0) { + int i; + se = seqm->strip->tstripdata = MEM_callocN( + seqm->len*sizeof(TStripElem), "tstripelems"); + for (i = 0; i < seqm->len; i++) { + se[i].ok = STRIPELEM_META; + } + } + /* sets all ->se1 pointers in stripdata, to read the ibuf from it */ - se= seqm->strip->stripdata; for(a=0; alen; a++, se++) { cfra= a+seqm->start; seq = get_shown_seq_from_metastrip(seqm, cfra); if (seq) { - se->se1= give_stripelem(seq, cfra); + se->se1= give_tstripelem(seq, cfra); } else { se->se1= 0; } } } -static void do_build_seq_ibuf(Sequence * seq, int cfra) +static TStripElem* do_build_seq_recursively(Sequence * seq, int cfra); + +static void do_build_seq_ibuf(Sequence * seq, TStripElem *se, int cfra) { - StripElem *se = seq->curelem; char name[FILE_MAXDIR+FILE_MAXFILE]; if(seq->type == SEQ_META) { - se->ok= 2; - if(se->se1==0) set_meta_stripdata(seq); + if(seq->seqbase.first) { + Sequence * seqmshown= + get_shown_seq_from_metastrip(seq, cfra); + if (seqmshown) { + if(cfra< seq->start) + do_build_seq_recursively(seqmshown, seq->start); + else if(cfra> seq->start+seq->len-1) + do_build_seq_recursively(seqmshown, seq->start + seq->len-1); + else do_build_seq_recursively(seqmshown, cfra); + } + } + + se->ok = STRIPELEM_META; + if(se->se1 == 0) set_meta_stripdata(seq); if(se->se1) { se->ibuf= se->se1->ibuf; } - } else if(seq->type == SEQ_RAM_SOUND || seq->type == SEQ_HD_SOUND) { - se->ok= 2; } else if(seq->type & SEQ_EFFECT) { /* test if image is too small or discarded from cache: reload */ @@ -706,22 +761,13 @@ static void do_build_seq_ibuf(Sequence * seq, int cfra) /* should the effect be recalculated? */ - if(se->ibuf==0 - || (seq->seq1 && se->se1 != seq->seq1->curelem) - || (seq->seq2 && se->se2 != seq->seq2->curelem) - || (seq->seq3 && se->se3 != seq->seq3->curelem)) { - if (seq->seq1) se->se1= seq->seq1->curelem; - if (seq->seq2) se->se2= seq->seq2->curelem; - if (seq->seq3) se->se3= seq->seq3->curelem; - - if(se->ibuf==NULL) { - /* if one of two first inputs are rectfloat, output is float too */ - if((se->se1 && se->se1->ibuf && se->se1->ibuf->rect_float) || - (se->se2 && se->se2->ibuf && se->se2->ibuf->rect_float)) - se->ibuf= IMB_allocImBuf((short)seqrectx, (short)seqrecty, 32, IB_rectfloat, 0); - else - se->ibuf= IMB_allocImBuf((short)seqrectx, (short)seqrecty, 32, IB_rect, 0); - } + if(se->ibuf == 0) { + /* if one of two first inputs are rectfloat, output is float too */ + if((se->se1 && se->se1->ibuf && se->se1->ibuf->rect_float) || + (se->se2 && se->se2->ibuf && se->se2->ibuf->rect_float)) + se->ibuf= IMB_allocImBuf((short)seqrectx, (short)seqrecty, 32, IB_rectfloat, 0); + else + se->ibuf= IMB_allocImBuf((short)seqrectx, (short)seqrecty, 32, IB_rect, 0); do_effect(cfra, seq, se); } @@ -743,27 +789,30 @@ static void do_build_seq_ibuf(Sequence * seq, int cfra) if(se->ibuf->x < seqrectx || se->ibuf->y < seqrecty || !(se->ibuf->rect || se->ibuf->rect_float)) { IMB_freeImBuf(se->ibuf); se->ibuf= 0; - se->ok= 1; + se->ok= STRIPELEM_OK; } } if(seq->type==SEQ_IMAGE) { - if(se->ok && se->ibuf==0) { + if(se->ok == STRIPELEM_OK && se->ibuf==0) { + StripElem * s_elem = give_stripelem(seq, cfra); + /* if playanim or render: no waitcursor */ if((G.f & G_PLAYANIM)==0) waitcursor(1); strncpy(name, seq->strip->dir, FILE_MAXDIR-1); - strncat(name, se->name, FILE_MAXFILE); + strncat(name, s_elem->name, FILE_MAXFILE); BLI_convertstringcode(name, G.sce, G.scene->r.cfra); se->ibuf= IMB_loadiffname(name, IB_rect); if((G.f & G_PLAYANIM)==0) waitcursor(0); - if(se->ibuf==0) se->ok= 0; - else { + if(se->ibuf == 0) { + se->ok = STRIPELEM_FAILED; + } else { if(seq->flag & SEQ_MAKE_PREMUL) { if(se->ibuf->depth==32 && se->ibuf->zbuf==0) converttopremul(se->ibuf); } @@ -778,7 +827,7 @@ static void do_build_seq_ibuf(Sequence * seq, int cfra) } } else if(seq->type==SEQ_MOVIE) { - if(se->ok && se->ibuf==0) { + if(se->ok == STRIPELEM_OK && se->ibuf==0) { if(seq->anim==0) { strncpy(name, seq->strip->dir, FILE_MAXDIR-1); strncat(name, seq->strip->stripdata->name, FILE_MAXFILE-1); @@ -791,8 +840,9 @@ static void do_build_seq_ibuf(Sequence * seq, int cfra) se->ibuf = IMB_anim_absolute(seq->anim, se->nr); } - if(se->ibuf==0) se->ok= 0; - else { + if(se->ibuf == 0) { + se->ok = STRIPELEM_FAILED; + } else { if(seq->flag & SEQ_MAKE_PREMUL) { if(se->ibuf->depth==32) converttopremul(se->ibuf); } @@ -893,21 +943,23 @@ static void do_build_seq_ibuf(Sequence * seq, int cfra) } } - if (se->ibuf) { + if (se->ibuf && seq->type != SEQ_META) { IMB_cache_limiter_insert(se->ibuf); IMB_cache_limiter_ref(se->ibuf); IMB_cache_limiter_touch(se->ibuf); } } -static void do_build_seq_recursively(Sequence * seq, int cfra); - -static void do_effect_seq_recursively(int cfra, Sequence * seq, StripElem *se) +static void do_effect_seq_recursively(Sequence * seq, TStripElem *se, int cfra) { float fac, facf; struct SeqEffectHandle sh = get_sequence_effect(seq); int early_out; + se->se1 = 0; + se->se2 = 0; + se->se3 = 0; + if(seq->ipo && seq->ipo->curve.first) { do_seq_ipo(seq); fac= seq->facf0; @@ -924,79 +976,50 @@ static void do_effect_seq_recursively(int cfra, Sequence * seq, StripElem *se) /* no input needed */ break; case 0: - do_build_seq_recursively(seq->seq1, cfra); - do_build_seq_recursively(seq->seq2, cfra); + se->se1 = do_build_seq_recursively(seq->seq1, cfra); + se->se2 = do_build_seq_recursively(seq->seq2, cfra); if (seq->seq3) { - do_build_seq_recursively(seq->seq3, cfra); + se->se3 = do_build_seq_recursively(seq->seq3, cfra); } break; case 1: - do_build_seq_recursively(seq->seq1, cfra); + se->se1 = do_build_seq_recursively(seq->seq1, cfra); break; case 2: - do_build_seq_recursively(seq->seq2, cfra); + se->se2 = do_build_seq_recursively(seq->seq2, cfra); break; } - do_build_seq_ibuf(seq, cfra); + do_build_seq_ibuf(seq, se, cfra); /* children are not needed anymore ... */ - switch (early_out) { - case 0: - if (seq->seq1->curelem && seq->seq1->curelem->ibuf) - IMB_cache_limiter_unref(seq->seq1->curelem->ibuf); - if (seq->seq2->curelem && seq->seq2->curelem->ibuf) - IMB_cache_limiter_unref(seq->seq2->curelem->ibuf); - if (seq->seq3) { - if (seq->seq3->curelem && seq->seq3->curelem->ibuf) - IMB_cache_limiter_unref( - seq->seq3->curelem->ibuf); - } - break; - case 1: - if (seq->seq1->curelem && seq->seq1->curelem->ibuf) - IMB_cache_limiter_unref(seq->seq1->curelem->ibuf); - break; - case 2: - if (seq->seq2->curelem && seq->seq2->curelem->ibuf) - IMB_cache_limiter_unref(seq->seq2->curelem->ibuf); - break; + if (se->se1 && se->se1->ibuf) { + IMB_cache_limiter_unref(se->se1->ibuf); + } + if (se->se2 && se->se2->ibuf) { + IMB_cache_limiter_unref(se->se2->ibuf); + } + if (se->se3 && se->se3->ibuf) { + IMB_cache_limiter_unref(se->se3->ibuf); } } -static void do_build_seq_recursively_impl(Sequence * seq, int cfra) +static TStripElem* do_build_seq_recursively_impl(Sequence * seq, int cfra) { - StripElem *se; + TStripElem *se; - se = seq->curelem = give_stripelem(seq, cfra); + se = give_tstripelem(seq, cfra); if(se) { - int unref_meta = FALSE; - if(seq->seqbase.first) { - Sequence * seqmshown= get_shown_seq_from_metastrip(seq, cfra); - if (seqmshown) { - if(cfra< seq->start) - do_build_seq_recursively(seqmshown, seq->start); - else if(cfra> seq->start+seq->len-1) - do_build_seq_recursively(seqmshown, seq->start + seq->len-1); - else do_build_seq_recursively(seqmshown, cfra); - - unref_meta = TRUE; - } - } - if (seq->type & SEQ_EFFECT) { - do_effect_seq_recursively(cfra, seq, se); + do_effect_seq_recursively(seq, se, cfra); } else { - do_build_seq_ibuf(seq, cfra); - } - - if(unref_meta && seq->curelem->ibuf) { - IMB_cache_limiter_unref(seq->curelem->ibuf); + do_build_seq_ibuf(seq, se, cfra); } } + return se; } /* FIXME: @@ -1007,16 +1030,16 @@ instead of faking using the blend code below... */ -static void do_handle_speed_effect(Sequence * seq, int cfra) +static TStripElem* do_handle_speed_effect(Sequence * seq, int cfra) { SpeedControlVars * s = (SpeedControlVars *)seq->effectdata; int nr = cfra - seq->start; float f_cfra; int cfra_left; int cfra_right; - StripElem * se = 0; - StripElem * se1 = 0; - StripElem * se2 = 0; + TStripElem * se = 0; + TStripElem * se1 = 0; + TStripElem * se2 = 0; sequence_effect_speed_rebuild_map(seq, 0); @@ -1025,7 +1048,7 @@ static void do_handle_speed_effect(Sequence * seq, int cfra) cfra_left = (int) floor(f_cfra); cfra_right = (int) ceil(f_cfra); - se = seq->curelem = give_stripelem(seq, cfra); + se = give_tstripelem(seq, cfra); if (cfra_left == cfra_right || (s->flags & SEQ_SPEED_BLEND) == 0) { @@ -1038,9 +1061,8 @@ static void do_handle_speed_effect(Sequence * seq, int cfra) } if (se->ibuf == NULL) { - do_build_seq_recursively_impl(seq->seq1, cfra_left); - - se1 = seq->seq1->curelem; + se1 = do_build_seq_recursively_impl( + seq->seq1, cfra_left); if((se1 && se1->ibuf && se1->ibuf->rect_float)) se->ibuf= IMB_allocImBuf((short)seqrectx, (short)seqrecty, 32, IB_rectfloat, 0); @@ -1072,11 +1094,10 @@ static void do_handle_speed_effect(Sequence * seq, int cfra) } if (se->ibuf == NULL) { - do_build_seq_recursively_impl(seq->seq1, cfra_left); - se1 = seq->seq1->curelem; - do_build_seq_recursively_impl(seq->seq1, cfra_right); - se2 = seq->seq1->curelem; - + se1 = do_build_seq_recursively_impl( + seq->seq1, cfra_left); + se2 = do_build_seq_recursively_impl( + seq->seq1, cfra_right); if((se1 && se1->ibuf && se1->ibuf->rect_float)) se->ibuf= IMB_allocImBuf((short)seqrectx, (short)seqrecty, 32, IB_rectfloat, 0); @@ -1110,35 +1131,43 @@ static void do_handle_speed_effect(Sequence * seq, int cfra) IMB_cache_limiter_unref(se1->ibuf); if (se2 && se2->ibuf) IMB_cache_limiter_unref(se2->ibuf); + + return se; } /* * build all ibufs recursively * - * if successfull, seq->curelem->ibuf contains the (referenced!) imbuf + * if successfull, the returned TStripElem contains the (referenced!) imbuf * that means: you _must_ call * - * IMB_cache_limiter_unref(seq->curelem->ibuf); + * IMB_cache_limiter_unref(rval); * - * if seq->curelem exists! + * if rval != 0 * */ -static void do_build_seq_recursively(Sequence * seq, int cfra) +static TStripElem* do_build_seq_recursively(Sequence * seq, int cfra) { if (seq->type == SEQ_SPEED) { - do_handle_speed_effect(seq, cfra); + return do_handle_speed_effect(seq, cfra); } else { - do_build_seq_recursively_impl(seq, cfra); + return do_build_seq_recursively_impl(seq, cfra); } } -ImBuf *give_ibuf_seq(int rectx, int recty, int cfra, int chanshown) +/* + * returned ImBuf is refed! + * you have to unref after usage! + */ + +static ImBuf *give_ibuf_seq_impl(int rectx, int recty, int cfra, int chanshown) { Sequence *seqfirst=0; Editing *ed; int count; ListBase *seqbasep; + TStripElem *se; ed= G.scene->ed; if(ed==0) return 0; @@ -1160,18 +1189,44 @@ ImBuf *give_ibuf_seq(int rectx, int recty, int cfra, int chanshown) return 0; } - do_build_seq_recursively(seqfirst, cfra); + se = do_build_seq_recursively(seqfirst, cfra); - if(!seqfirst->curelem) { + if(!se) { return 0; } - if (seqfirst->curelem->ibuf) { - IMB_cache_limiter_unref(seqfirst->curelem->ibuf); + return se->ibuf; +} + +ImBuf *give_ibuf_seq_direct(int rectx, int recty, int cfra, + Sequence * seq) +{ + TStripElem* se; + + seqrectx= rectx; /* bad bad global! */ + seqrecty= recty; + + se = do_build_seq_recursively(seq, cfra); + + if(!se) { + return 0; } - return seqfirst->curelem->ibuf; + if (se->ibuf) { + IMB_cache_limiter_unref(se->ibuf); + } + return se->ibuf; +} + +ImBuf *give_ibuf_seq(int rectx, int recty, int cfra, int chanshown) +{ + ImBuf* i = give_ibuf_seq_impl(rectx, recty, cfra, chanshown); + + if (i) { + IMB_cache_limiter_unref(i); + } + return i; } /* threading api */ @@ -1253,12 +1308,8 @@ static void * seq_prefetch_thread(void * This_) This->running = TRUE; if (e->cfra >= s_last) { - e->ibuf = give_ibuf_seq(e->rectx, e->recty, e->cfra, - e->chanshown); - } - - if (e->ibuf) { - IMB_cache_limiter_ref(e->ibuf); + e->ibuf = give_ibuf_seq_impl( + e->rectx, e->recty, e->cfra, e->chanshown); } pthread_mutex_lock(&queue_lock); @@ -1413,7 +1464,7 @@ void seq_wait_for_prefetch_ready() fprintf(stderr, "SEQ-THREAD: prefetch done\n"); } -ImBuf * give_ibuf_threaded(int rectx, int recty, int cfra, int chanshown) +ImBuf * give_ibuf_seq_threaded(int rectx, int recty, int cfra, int chanshown) { PrefetchQueueElem * e = 0; int found_something = FALSE; @@ -1493,13 +1544,13 @@ ImBuf * give_ibuf_threaded(int rectx, int recty, int cfra, int chanshown) /* Functions to free imbuf and anim data on changes */ -static void free_imbuf_strip_elem(StripElem *se) +static void free_imbuf_strip_elem(TStripElem *se) { if (se->ibuf) { - if (se->ok != 2) + if (se->ok != STRIPELEM_META && se->ibuf != 0) IMB_freeImBuf(se->ibuf); se->ibuf= 0; - se->ok= 1; + se->ok= STRIPELEM_OK; se->se1= se->se2= se->se3= 0; } } @@ -1516,15 +1567,17 @@ void free_imbuf_seq_except(int cfra) { Editing *ed= G.scene->ed; Sequence *seq; - StripElem *se; + TStripElem *se; int a; if(ed==0) return; WHILE_SEQ(&ed->seqbase) { if(seq->strip) { - for(a=0, se= seq->strip->stripdata; alen; a++, se++) - if(se!=seq->curelem) + TStripElem * curelem = give_tstripelem(seq, cfra); + + for(a=0, se= seq->strip->tstripdata; alen; a++, se++) + if(se != curelem) free_imbuf_strip_elem(se); if(seq->type==SEQ_MOVIE) @@ -1539,15 +1592,17 @@ void free_imbuf_seq() { Editing *ed= G.scene->ed; Sequence *seq; - StripElem *se; + TStripElem *se; int a; if(ed==0) return; WHILE_SEQ(&ed->seqbase) { if(seq->strip) { - for(a=0, se= seq->strip->stripdata; alen; a++, se++) - free_imbuf_strip_elem(se); + if (seq->strip->tstripdata) { + for(a=0, se= seq->strip->tstripdata; alen; a++, se++) + free_imbuf_strip_elem(se); + } if(seq->type==SEQ_MOVIE) free_anim_seq(seq); @@ -1582,7 +1637,7 @@ static int update_changed_seq_recurs(Sequence *seq, Sequence *changed_seq, int l { Sequence *subseq; int a, free_imbuf = 0; - StripElem *se; + TStripElem *se; /* recurs downwards to see if this seq depends on the changed seq */ @@ -1594,24 +1649,27 @@ static int update_changed_seq_recurs(Sequence *seq, Sequence *changed_seq, int l for(subseq=seq->seqbase.first; subseq; subseq=subseq->next) if(update_changed_seq_recurs(subseq, changed_seq, len_change, ibuf_change)) - free_imbuf = 1; + free_imbuf = TRUE; if(seq->seq1) if(update_changed_seq_recurs(seq->seq1, changed_seq, len_change, ibuf_change)) - free_imbuf = 1; + free_imbuf = TRUE; if(seq->seq2 && (seq->seq2 != seq->seq1)) if(update_changed_seq_recurs(seq->seq2, changed_seq, len_change, ibuf_change)) - free_imbuf = 1; + free_imbuf = TRUE; if(seq->seq3 && (seq->seq3 != seq->seq1) && (seq->seq3 != seq->seq2)) if(update_changed_seq_recurs(seq->seq3, changed_seq, len_change, ibuf_change)) - free_imbuf = 1; + free_imbuf = TRUE; if(free_imbuf) { if(ibuf_change) { - for(a=0, se= seq->strip->stripdata; alen; a++, se++) - free_imbuf_strip_elem(se); + se= seq->strip->tstripdata; + if (se) { + for(a=0; alen; a++, se++) + free_imbuf_strip_elem(se); + } - if(seq->type==SEQ_MOVIE) + if(seq->type == SEQ_MOVIE) free_anim_seq(seq); if(seq->type == SEQ_SPEED) { sequence_effect_speed_rebuild_map(seq, 1); @@ -1646,7 +1704,6 @@ void do_render_seq(RenderResult *rr, int cfra) ibuf= give_ibuf_seq(rr->rectx, rr->recty, cfra, 0); if(ibuf) { - if(ibuf->rect_float) { if (!rr->rectf) rr->rectf= MEM_mallocN(4*sizeof(float)*rr->rectx*rr->recty, "render_seq rectf"); From 00ca12c34dd1165d2830bb406396d8792746b1df Mon Sep 17 00:00:00 2001 From: Peter Schlaile Date: Sun, 18 Nov 2007 17:44:48 +0000 Subject: [PATCH 07/29] == Sequencer == Well, added unnecessary pad variables after a fight with makesdna... --- source/blender/makesdna/DNA_sequence_types.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/source/blender/makesdna/DNA_sequence_types.h b/source/blender/makesdna/DNA_sequence_types.h index bc574228cca..0f9b55723bc 100644 --- a/source/blender/makesdna/DNA_sequence_types.h +++ b/source/blender/makesdna/DNA_sequence_types.h @@ -107,8 +107,6 @@ typedef struct Sequence { int sfra; /* starting frame according to the timeline of the scene. */ Strip *strip; - int pad2; - int pad3; struct Ipo *ipo; struct Scene *scene; From cf60bf576b741f031450886c5dc4f0a11bbd4d06 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 19 Nov 2007 10:17:55 +0000 Subject: [PATCH 08/29] simple weight invert script for the weightpaint menu, removed a print from weightpaint_average.py --- release/scripts/weightpaint_average.py | 1 - release/scripts/weightpaint_invert.py | 93 ++++++++++++++++++++++++++ 2 files changed, 93 insertions(+), 1 deletion(-) create mode 100644 release/scripts/weightpaint_invert.py diff --git a/release/scripts/weightpaint_average.py b/release/scripts/weightpaint_average.py index 57c27605da5..4e8830256b2 100644 --- a/release/scripts/weightpaint_average.py +++ b/release/scripts/weightpaint_average.py @@ -103,7 +103,6 @@ def main(): if PREF_ALL_VGROUPS==-1: return - print "sd", PREF_ALL_VGROUPS Window.WaitCursor(1) me = ob_act.getData(mesh=1) # old NMesh api is default t = sys.time() diff --git a/release/scripts/weightpaint_invert.py b/release/scripts/weightpaint_invert.py new file mode 100644 index 00000000000..87aec77ad8d --- /dev/null +++ b/release/scripts/weightpaint_invert.py @@ -0,0 +1,93 @@ +#!BPY +""" +Name: 'Vertex Group Invert' +Blender: 245 +Group: 'WeightPaint' +Tooltip: 'Invert the active vertex group' +""" + +# -------------------------------------------------------------------------- +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- +import Blender +from Blender import Scene, Mesh, Window, sys + +import BPyMessages +import bpy + +def vgroup_invert(ob_orig, me): + if not me.getVertGroupNames(): + return + group_act = me.activeGroup + if group_act == None: + return + + group_data = me.getVertsFromGroup(group_act, 1) + + weights= [1.0] * len(me.verts) # 1.0 - initialize inverted + + group_data = me.getVertsFromGroup(group_act, 1) # (i,w) tuples. + + me.removeVertGroup(group_act) # messes up the active group. + for i,w in group_data: + weights[i] = 1.0-w + + me.addVertGroup(group_act) + rep = Blender.Mesh.AssignModes.REPLACE + vertList= [None] + for i,weight in enumerate(weights): + vertList[0] = i + if weight != 0.0: + me.assignVertsToGroup(group_act, vertList, weight, rep) + me.update() + +def main(): + + # Gets the current scene, there can be many scenes in 1 blend file. + sce = bpy.data.scenes.active + + # Get the active object, there can only ever be 1 + # and the active object is always the editmode object. + ob_act = sce.objects.active + + if not ob_act or ob_act.type != 'Mesh': + BPyMessages.Error_NoMeshActive() + return + + # Saves the editmode state and go's out of + # editmode if its enabled, we cant make + # changes to the mesh data while in editmode. + is_editmode = Window.EditMode() + Window.EditMode(0) + + Window.WaitCursor(1) + me = ob_act.getData(mesh=1) # old NMesh api is default + t = sys.time() + + # Run the mesh editing function + vgroup_invert(ob_act, me) + + # Timing the script is a good way to be aware on any speed hits when scripting + print 'Invert VGroup in %.2f seconds' % (sys.time()-t) + Window.WaitCursor(0) + if is_editmode: Window.EditMode(1) + +# This lets you can import the script without running it +if __name__ == '__main__': + main() \ No newline at end of file From 0b0542c7851f06f6ab1f6b5cc28db511657eec73 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 19 Nov 2007 10:49:12 +0000 Subject: [PATCH 09/29] typo in Text3d, weightpaint_invert wasnt working properly --- release/scripts/weightpaint_invert.py | 8 +++++--- source/blender/python/api2_2x/doc/Text3d.py | 4 ++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/release/scripts/weightpaint_invert.py b/release/scripts/weightpaint_invert.py index 87aec77ad8d..cdae83a9d50 100644 --- a/release/scripts/weightpaint_invert.py +++ b/release/scripts/weightpaint_invert.py @@ -1,6 +1,6 @@ #!BPY """ -Name: 'Vertex Group Invert' +Name: 'Invert Active Group' Blender: 245 Group: 'WeightPaint' Tooltip: 'Invert the active vertex group' @@ -49,12 +49,14 @@ def vgroup_invert(ob_orig, me): weights[i] = 1.0-w me.addVertGroup(group_act) + rep = Blender.Mesh.AssignModes.REPLACE vertList= [None] for i,weight in enumerate(weights): vertList[0] = i - if weight != 0.0: - me.assignVertsToGroup(group_act, vertList, weight, rep) + me.assignVertsToGroup(group_act, vertList, weight, rep) + + me.activeGroup = group_act me.update() def main(): diff --git a/source/blender/python/api2_2x/doc/Text3d.py b/source/blender/python/api2_2x/doc/Text3d.py index 78993b9e8f3..a7d8c585078 100644 --- a/source/blender/python/api2_2x/doc/Text3d.py +++ b/source/blender/python/api2_2x/doc/Text3d.py @@ -153,13 +153,13 @@ class Text3d: @param width: The new text3d's width value. """ - def getgetExtrudeDepth(): + def getExtrudeDepth(): """ Get the text3d's ext1 value. @rtype: float """ - def setgetExtrudeDepth(ext1): + def setExtrudeDepth(ext1): """ Set the text3d's ext1 value. @rtype: None From 80357d7f28d93bd1c9fcf82d65eab27601ce1be7 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 19 Nov 2007 14:00:48 +0000 Subject: [PATCH 10/29] initial leaf support (need to use in production, at the moment its really simple) Option to generate variation's - This modifies the original shape to make a variation on the original. --- release/scripts/wizard_curve2tree.py | 562 +++++++++++++++++++-------- 1 file changed, 405 insertions(+), 157 deletions(-) diff --git a/release/scripts/wizard_curve2tree.py b/release/scripts/wizard_curve2tree.py index 6dcdef8d8fa..457b438ddb6 100644 --- a/release/scripts/wizard_curve2tree.py +++ b/release/scripts/wizard_curve2tree.py @@ -96,6 +96,14 @@ def freshMesh(mesh): return mesh +def getObFromName(name): + if name: + try: return bpy.data.objects[name] + except: return None + else: + return None + + def closestVecIndex(vec, vecls): best= -1 @@ -121,9 +129,16 @@ class tree: self.armature = None self.objectCurve = None self.objectCurveMat = None + self.objectCurveIMat = None + self.objectTwigBounds = None # use for twigs only at the moment. self.objectTwigBoundsIMat = None self.objectTwigBoundsMesh = None + + self.objectLeafBounds = None + self.objectLeafBoundsIMat = None + self.objectLeafBoundsMesh = None + self.limbScale = 1.0 self.debug_objects = [] @@ -142,6 +157,7 @@ class tree: # Now calculate the normals self.objectCurve = objectCurve self.objectCurveMat = objectCurve.matrixWorld + self.objectCurveIMat = self.objectCurveMat.copy().invert() curve = objectCurve.data steps = curve.resolu # curve resolution @@ -201,19 +217,41 @@ class tree: # Sort from big to small, so big branches get priority self.branches_all.sort( key = lambda brch: -brch.bpoints[0].radius ) - + + + def closestBranchPt(self, co): + best_brch = None + best_pt = None + best_dist = 10000000000 + for brch in self.branches_all: + for pt in brch.bpoints: + # if pt.inTwigBounds: # only find twigs, give different results for leaves + l = (pt.co-co).length + if l < best_dist: + best_dist = l + best_brch = brch + best_pt = pt + return best_brch, best_pt + def setTwigBounds(self, objectMesh): self.objectTwigBounds = objectMesh self.objectTwigBoundsMesh = objectMesh.getData(mesh=1) self.objectTwigBoundsIMat = objectMesh.matrixWorld.copy().invert() - #self.objectTwigBoundsIMat = objectMesh.matrixWorld.copy() for brch in self.branches_all: brch.calcTwigBounds(self) + + def setLeafBounds(self, objectMesh): + self.objectLeafBounds = objectMesh + self.objectLeafBoundsMesh = objectMesh.getData(mesh=1) + self.objectLeafBoundsIMat = objectMesh.matrixWorld.copy().invert() def isPointInTwigBounds(self, co): return self.objectTwigBoundsMesh.pointInside(co * self.objectCurveMat * self.objectTwigBoundsIMat) - + + def isPointInLeafBounds(self, co): + return self.objectLeafBoundsMesh.pointInside(co * self.objectCurveMat * self.objectLeafBoundsIMat) + def resetTags(self, value): for brch in self.branches_all: brch.tag = value @@ -223,6 +261,8 @@ class tree: connect_base_trim = 1.0,\ do_twigs = False,\ twig_ratio = 2.0,\ + twig_select_mode = 0,\ + twig_select_factor = 0.5,\ twig_scale = 0.8,\ twig_scale_width = 1.0,\ twig_random_orientation = 180,\ @@ -238,6 +278,11 @@ class tree: twig_follow_x=0.0,\ twig_follow_y=0.0,\ twig_follow_z=0.0,\ + do_variation = 0,\ + variation_seed = 1,\ + variation_orientation = 0.0,\ + variation_scale = 0.0,\ + ): ''' build tree data - fromCurve must run first @@ -284,7 +329,7 @@ class tree: children = [brch_child for brch_child in pt.children] if children: # This pt is one side of the segment, pt.next joins this segment. - # calculate the median point the 2 segments would span + # calculate the median point the 2 segments would spanal # Once this is done we need to adjust 2 things # 1) move both segments up/down so they match the branches best. # 2) set the spacing of the segments around the point. @@ -300,9 +345,38 @@ class tree: brch.checkPointList() ''' - # Important we so this with existing parent/child but before connecting and calculating verts. + # Variations - use for making multiple versions of the same tree. + if do_variation: + irational_num = 22.0/7.0 # use to make the random number more odd + rnd = [variation_seed] + def next_random_num(): + ''' + return a random number between 0.0 and 1.0 + ''' + + rnd[0] += (rnd[0] * irational_num) % 1 + # prevent + if rnd[0] > 1000000: + rnd[0]-=1000000 + return rnd[0] % 1 + + # Add children temporarily + for brch in self.branches_all: + if brch.parent_pt: + rnd_rot = ((next_random_num() * variation_orientation) - 0.5) * 720 + mat_orientation = RotationMatrix(rnd_rot, 3, 'r', brch.parent_pt.no) + rnd_sca = 1 + ((next_random_num()-0.5)* variation_scale ) + mat_scale = Matrix([rnd_sca,0,0],[0,rnd_sca,0],[0,0,rnd_sca]) + # mat_orientation = RotationMatrix(0, 3, 'r', brch.parent_pt.no) + brch.transformRecursive(self, mat_scale * mat_orientation, brch.parent_pt.co) + # Important we so this with existing parent/child but before connecting and calculating verts. if do_twigs: + + # scale values down + twig_random_orientation= twig_random_orientation/360.0 + twig_random_angle= twig_random_angle/360.0 + irational_num = 22.0/7.0 # use to make the random number more odd if twig_ob_bounds: # Only spawn twigs inside this mesh @@ -311,7 +385,7 @@ class tree: if not twig_recursive: twig_recursive_limit = 0 - self.buildTwigs(twig_ratio) + self.buildTwigs(twig_ratio, twig_select_mode, twig_select_factor) branches_twig_attached = [] @@ -357,7 +431,6 @@ class tree: if twig_random_angle: rnd2 = (((irational_num * scale * 66666666) % 360) - 180) * twig_random_angle else: rnd2 = 0.0 - # Align this with the existing branch angle = AngleBetweenVecs(zup, parent_pt.no) cross = CrossVecs(zup, parent_pt.no) @@ -397,8 +470,8 @@ class tree: no = Vector() no.x += twig_follow_x - no.x += twig_follow_y - no.x += twig_follow_z + no.y += twig_follow_y + no.z += twig_follow_z for i, pt in enumerate(brch_twig.bpoints): if pt.prev: @@ -529,7 +602,7 @@ class tree: for brch in self.branches_all: brch.branchReJoin() - def buildTwigs(self, twig_ratio=1.0): + def buildTwigs(self, twig_ratio, twig_select_mode, twig_select_factor): ratio_int = int(len(self.branches_all) * twig_ratio) if ratio_int == 0: @@ -537,6 +610,20 @@ class tree: # So we only mix branches of similar lengths branches_sorted = self.branches_all[:] + + # Get the branches based on our selection method! + if twig_select_mode==0: + branches_sorted.sort( key = lambda brch: brch.getLength()) + elif twig_select_mode==1: + branches_sorted.sort( key = lambda brch:-brch.getLength()) + elif twig_select_mode==2: + branches_sorted.sort( key = lambda brch:brch.getStraightness()) + elif twig_select_mode==3: + branches_sorted.sort( key = lambda brch:-brch.getStraightness()) + + factor_int = int(len(self.branches_all) * twig_select_factor) + branches_sorted[factor_int:] = [] # remove the last part of the list + branches_sorted.sort( key = lambda brch: len(brch.bpoints)) branches_new = [] @@ -967,7 +1054,8 @@ class tree: return self.mesh - def toLeafMesh(self, mesh_leaf, leaf_branch_limit = 0.5, leaf_size = 0.5): + def toLeafMesh(self, mesh_leaf, leaf_branch_limit = 0.5, leaf_size = 0.5, leaf_fill=True, leaf_fill_count=1000, leaf_fill_ob_bounds=None): + ''' return a mesh with leaves seperate from the tree @@ -979,80 +1067,151 @@ class tree: mesh_leaf = freshMesh(mesh_leaf) self.mesh_leaf = mesh_leaf - totpoints = 0 - radius = 0.0 - max_radius = 0.0 - for brch in self.branches_all: - for pt in brch.bpoints: - radius += pt.radius - if pt.radius > max_radius: - max_radius = pt.radius + # Fill an object with leaves, kind of primitive but useful at times. + if leaf_fill and leaf_fill_count and leaf_fill_ob_bounds: - #totpoints += len(brch.bpoints) - - radius_max = max_radius * leaf_branch_limit - - - verts_extend = [] - faces_extend = [] - - co1,co2,co3,co4 = Vector(),Vector(),Vector(),Vector() - - for brch in self.branches_all: + self.setLeafBounds(leaf_fill_ob_bounds) - # quick test, do we need leaves on this branch? - if brch.bpoints[-1].radius > radius_max: - continue + # Get bounds - count = 0 - for pt in brch.bpoints: - if pt.childCount == 0 and pt.radius < radius_max: - # Ok we can add a leaf here. set the co's correctly - co1[:] = pt.co - co2[:] = pt.co - co3[:] = pt.co - co4[:] = pt.co + xmin = ymin = zmin = 10000000 + xmax = ymax = zmax =-10000000 + + for v in self.objectLeafBoundsMesh.verts: + x,y,z = tuple(v.co) + + if x < xmin: xmin = x + if y < ymin: ymin = y + if z < zmin: zmin = z + + if x > xmax: xmax = x + if y > ymax: ymax = y + if z > zmax: zmax = z + + verts_extend = [] + faces_extend = [] + + i = leaf_fill_count + while i: + # randomize branch values for leaves for now. + vec = Vector(Rand(xmin, xmax), Rand(ymin, ymax), Rand(zmin, zmax)) + + if self.objectLeafBoundsMesh.pointInside(vec): + vec = (vec * self.objectLeafBoundsIMat) * self.objectCurveIMat - cross_leafdir = CrossVecs( zup, pt.no ) - cross_leafdir.length = leaf_size + # Find the closest branch + brch_close, pt_close = self.closestBranchPt(vec) + + no = pt_close.co - vec + #cross = CrossVecs(no, zup) + cross = CrossVecs(no, pt_close.no) + cross.length = leaf_size + + vec2 = vec - cross + vec1 = vec + cross + + vec3 = vec - cross + vec4 = vec + cross + + + no_pt = pt_close.no.copy() + no_pt.length = leaf_size + vec3 += no_pt + vec4 += no_pt + + ''' + no_pt = pt_close.no.copy() + no_pt.length = leaf_size + vec3 += no_pt + vec4 += no_pt + ''' + cross + + faces_extend.append([len(verts_extend), len(verts_extend)+1, len(verts_extend)+2, len(verts_extend)+3]) + verts_extend.extend([vec1, vec2, vec3, vec4]) + i-=1 + + self.mesh_leaf.verts.extend(verts_extend) + self.mesh_leaf.faces.extend(faces_extend) - - #cross_leafwidth = CrossVecs(pt.no, cross_leafdir) - - # Facing up - cross_leafwidth_up = CrossVecs(zup, cross_leafdir).normalize() * leaf_size - cross_leafwidth_aligned = pt.no - - #cross_leafwidth = (cross_leafwidth_up + cross_leafwidth_aligned)/2 - cross_leafwidth = cross_leafwidth_aligned - - cross_leafwidth.length = leaf_size/2 - - if count % 2: - cross_leafwidth.negate() - cross_leafdir.negate() - - co1 += cross_leafdir - co2 += cross_leafdir - - co2 += cross_leafwidth - co3 += cross_leafwidth - - co1 -= cross_leafwidth - co4 -= cross_leafwidth - - - i = len(verts_extend) - faces_extend.append( (i,i+1,i+2,i+3) ) - verts_extend.extend([tuple(co1), tuple(co2), tuple(co3), tuple(co4)]) - count += 1 - - self.mesh_leaf.verts.extend(verts_extend) - self.mesh_leaf.faces.extend(faces_extend) + + ''' + if 0: + totpoints = 0 + radius = 0.0 + max_radius = 0.0 + for brch in self.branches_all: + for pt in brch.bpoints: + radius += pt.radius + if pt.radius > max_radius: + max_radius = pt.radius + + #totpoints += len(brch.bpoints) + + radius_max = max_radius * leaf_branch_limit + + + verts_extend = [] + faces_extend = [] + + co1,co2,co3,co4 = Vector(),Vector(),Vector(),Vector() + + for brch in self.branches_all: + + # quick test, do we need leaves on this branch? + if brch.bpoints[-1].radius > radius_max: + continue + + count = 0 + for pt in brch.bpoints: + if pt.childCount == 0 and pt.radius < radius_max: + # Ok we can add a leaf here. set the co's correctly + co1[:] = pt.co + co2[:] = pt.co + co3[:] = pt.co + co4[:] = pt.co + + cross_leafdir = CrossVecs( zup, pt.no ) + cross_leafdir.length = leaf_size + + + #cross_leafwidth = CrossVecs(pt.no, cross_leafdir) + + # Facing up + cross_leafwidth_up = CrossVecs(zup, cross_leafdir).normalize() * leaf_size + cross_leafwidth_aligned = pt.no + + #cross_leafwidth = (cross_leafwidth_up + cross_leafwidth_aligned)/2 + cross_leafwidth = cross_leafwidth_aligned + + cross_leafwidth.length = leaf_size/2 + + if count % 2: + cross_leafwidth.negate() + cross_leafdir.negate() + + co1 += cross_leafdir + co2 += cross_leafdir + + co2 += cross_leafwidth + co3 += cross_leafwidth + + co1 -= cross_leafwidth + co4 -= cross_leafwidth + + + i = len(verts_extend) + faces_extend.append( (i,i+1,i+2,i+3) ) + verts_extend.extend([tuple(co1), tuple(co2), tuple(co3), tuple(co4)]) + count += 1 + + self.mesh_leaf.verts.extend(verts_extend) + self.mesh_leaf.faces.extend(faces_extend) + ''' return self.mesh_leaf - + def toArmature(self, ob_arm, armature): @@ -1617,10 +1776,18 @@ class branch: else: return 0.8 - - def getLength(self): return (self.bpoints[0].co - self.bpoints[-1].co).length + + def getStraightness(self): + straight = 0.0 + pt = self.bpoints[0] + while pt.next: + straight += AngleBetweenVecs(pt.no, pt.next.no) + pt = pt.next + return straight + + ''' def calcTotChildren(self): for pt in self.bpoints: @@ -1658,8 +1825,6 @@ class branch: #if pt.inTwigBounds: # debug_pt(pt.co) - - def baseTrim(self, connect_base_trim): # if 1) dont remove the whole branch, maybe an option but later # if 2) we are alredy a parent, cant remove me now.... darn :/ not nice... @@ -1677,8 +1842,6 @@ class branch: del self.bpoints[0] self.bpoints[0].prev = None - - def boundsTrim(self): ''' @@ -1809,6 +1972,29 @@ class branch: for pt in self.bpoints: pt.co -= ofs + def transformRecursive(self, tree, mat3x3, cent, scale=None): + + if scale==None: + # incase this is a translation matrix + scale = ((xyzup * mat3x3) - (Vector(0,0,0) * mat3x3)).length + + for pt in self.bpoints: pt.co = ((pt.co-cent) * mat3x3) + cent + #for pt in self.bpoints: pt.co = (pt.co * mat3x3) + for pt in self.bpoints: self.calcPointExtras() + + + for brch in tree.branches_all: + if brch.parent_pt: + if brch.parent_pt.branch == self: + + brch.transformRecursive(tree, mat3x3, cent, scale) + + ''' + for pt in self.bpoints: + for brch in pt.children: + if brch: + brch.transformRecursive(mat3x3, cent, scale) + ''' def bestTwigSegment(self): ''' Return the most free part on the branch to place a new twig @@ -2109,7 +2295,7 @@ PREFS['image_main'] = Draw.Create('') PREFS['do_uv'] = Draw.Create(0) PREFS['uv_x_scale'] = Draw.Create(4.0) PREFS['uv_y_scale'] = Draw.Create(1.0) -PREFS['do_material'] = Draw.Create(1) +PREFS['do_material'] = Draw.Create(0) PREFS['material_use_existing'] = Draw.Create(1) PREFS['material_texture'] = Draw.Create(1) PREFS['material_stencil'] = Draw.Create(1) @@ -2130,6 +2316,8 @@ PREFS['anim_offset_scale'] = Draw.Create(1.0) PREFS['do_twigs'] = Draw.Create(0) PREFS['twig_ratio'] = Draw.Create(2.0) +PREFS['twig_select_mode'] = Draw.Create(0) +PREFS['twig_select_factor'] = Draw.Create(0.5) PREFS['twig_scale'] = Draw.Create(0.8) PREFS['twig_scale_width'] = Draw.Create(1.0) PREFS['twig_random_orientation'] = Draw.Create(180) @@ -2146,10 +2334,19 @@ PREFS['twig_follow_x'] = Draw.Create(0.0) PREFS['twig_follow_y'] = Draw.Create(0.0) PREFS['twig_follow_z'] = Draw.Create(0.0) -PREFS['do_leaf'] = Draw.Create(1) +PREFS['do_leaf'] = Draw.Create(0) +PREFS['leaf_fill'] = Draw.Create(1) +PREFS['leaf_fill_count'] = Draw.Create(1000) +PREFS['leaf_fill_ob_bounds'] = Draw.Create('') + PREFS['leaf_branch_limit'] = Draw.Create(0.25) PREFS['leaf_size'] = Draw.Create(0.5) +PREFS['do_variation'] = Draw.Create(0) +PREFS['variation_seed'] = Draw.Create(1) +PREFS['variation_orientation'] = Draw.Create(0.0) +PREFS['variation_scale'] = Draw.Create(0.0) + GLOBAL_PREFS = {} GLOBAL_PREFS['realtime_update'] = Draw.Create(0) @@ -2227,7 +2424,7 @@ def buildTree(ob_curve, single=False): def newObChild(parent, obdata): ob_new = bpy.data.scenes.active.objects.new(obdata) - ob_new.Layers = parent.Layers + # ob_new.Layers = parent.Layers # new object settings parent.makeParent([ob_new]) @@ -2271,18 +2468,15 @@ def buildTree(ob_curve, single=False): print '\tconnecting branches...', - twig_ob_bounds = PREFS['twig_ob_bounds'].val - if twig_ob_bounds: - try: twig_ob_bounds = bpy.data.objects[twig_ob_bounds] - except: twig_ob_bounds = None - else: - twig_ob_bounds = None + twig_ob_bounds = getObFromName(PREFS['twig_ob_bounds'].val) t.buildConnections(\ sloppy = PREFS['connect_sloppy'].val,\ connect_base_trim = PREFS['connect_base_trim'].val,\ do_twigs = PREFS['do_twigs'].val,\ twig_ratio = PREFS['twig_ratio'].val,\ + twig_select_mode = PREFS['twig_select_mode'].val,\ + twig_select_factor = PREFS['twig_select_factor'].val,\ twig_scale = PREFS['twig_scale'].val,\ twig_scale_width = PREFS['twig_scale_width'].val,\ twig_random_orientation = PREFS['twig_random_orientation'].val,\ @@ -2298,8 +2492,13 @@ def buildTree(ob_curve, single=False): twig_follow_x = PREFS['twig_follow_x'].val,\ twig_follow_y = PREFS['twig_follow_y'].val,\ twig_follow_z = PREFS['twig_follow_z'].val,\ + do_variation = PREFS['do_variation'].val,\ + variation_seed = PREFS['variation_seed'].val,\ + variation_orientation = PREFS['variation_orientation'].val,\ + variation_scale = PREFS['variation_scale'].val,\ ) + time4 = Blender.sys.time() # time print print '%.4f sec' % (time4-time3) print '\toptimizing point spacing...', @@ -2345,21 +2544,27 @@ def buildTree(ob_curve, single=False): do_uv_blend_layer = do_uv_blend_layer,\ do_cap_ends = PREFS['do_cap_ends'].val ) - """ + if PREFS['do_leaf'].val: ob_leaf = getObChild(ob_mesh, 'Mesh') if not ob_leaf: # New object - mesh_leaf = bpy.data.meshes.new('tree_' + ob_curve.name) + mesh_leaf = bpy.data.meshes.new('leaf_' + ob_curve.name) ob_leaf = newObChild(ob_mesh, mesh_leaf) else: mesh_leaf = ob_leaf.getData(mesh=1) ob_leaf.setMatrix(Matrix()) + leaf_fill_ob_bounds = getObFromName(PREFS['leaf_fill_ob_bounds'].val) + print "LEAF!!!" mesh_leaf = t.toLeafMesh(mesh_leaf,\ leaf_branch_limit = PREFS['leaf_branch_limit'].val,\ leaf_size = PREFS['leaf_size'].val,\ + + leaf_fill = PREFS['leaf_fill'].val,\ + leaf_fill_count = PREFS['leaf_fill_count'].val,\ + leaf_fill_ob_bounds = leaf_fill_ob_bounds,\ ) - """ + mesh.calcNormals() if PREFS['do_material'].val: @@ -2460,22 +2665,30 @@ def buildTree(ob_curve, single=False): #mesh.update() bpy.data.scenes.active.update() -def do_pref_read(e,v): +def do_pref_read(e=0,v=0, quiet=False): + ''' + We dont care about e and v values, only there because its a callback + ''' sce = bpy.data.scenes.active ob = sce.objects.active if not ob: - Blender.Draw.PupMenu('No active curve object') + if not quiet: + Blender.Draw.PupMenu('No active curve object') + return if ob.type != 'Curve': ob = ob.parent if ob.type != 'Curve': - Blender.Draw.PupMenu('No active curve object') + if not quiet: + Blender.Draw.PupMenu('No active curve object') return if not IDProp2Prefs(ob.properties, PREFS): - Blender.Draw.PupMenu('Curve object has no settings stored on it') + if not quiet: + Blender.Draw.PupMenu('Curve object has no settings stored on it') + return Blender.Draw.Redraw() @@ -2602,41 +2815,8 @@ def gui(): xtmp = x # ---------- ---------- ---------- ---------- - Blender.Draw.BeginAlign() - PREFS['do_cap_ends'] = Draw.Toggle('Cap Ends',EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['do_cap_ends'].val, 'Add faces onto branch endpoints'); xtmp += but_width*2; - PREFS['do_subsurf'] = Draw.Toggle('SubSurf',EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['do_subsurf'].val, 'Enable subsurf for newly generated objects'); xtmp += but_width*2; - Blender.Draw.EndAlign() - y-=but_height+MARGIN - xtmp = x - # ---------- ---------- ---------- ---------- - Blender.Draw.BeginAlign() - PREFS['seg_density'] = Draw.Number('Segment Spacing',EVENT_UPDATE, xtmp, y, but_width*4, but_height, PREFS['seg_density'].val, 0.05, 10.0, 'Scale the limit points collapse, that are closer then the branch width'); xtmp += but_width*4; - y-=but_height - xtmp = x - - # ---------- ---------- ---------- ---------- - PREFS['seg_density_angle'] = Draw.Number('Angle Spacing', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['seg_density_angle'].val, 0.0, 180.0, 'Segments above this angle will not collapse (lower value for more detail)'); xtmp += but_width*2; - PREFS['seg_density_radius'] = Draw.Number('Radius Spacing', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['seg_density_radius'].val, 0.0, 1.0, 'Segments above this difference in radius will not collapse (lower value for more detail)'); xtmp += but_width*2; - - y-=but_height - xtmp = x - # ---------- ---------- ---------- ---------- - - PREFS['seg_joint_compression'] = Draw.Number('Joint Width', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['seg_joint_compression'].val, 0.1, 2.0, 'Edge loop spacing around branch join, lower value for less webed joins'); xtmp += but_width*2; - PREFS['seg_joint_smooth'] = Draw.Number('Joint Smooth', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['seg_joint_smooth'].val, 0.0, 1.0, 'Edge loop spacing around branch join, lower value for less webed joins'); xtmp += but_width*2; - - y-=but_height - xtmp = x - # ---------- ---------- ---------- ---------- - - PREFS['connect_sloppy'] = Draw.Number('Connect Limit',EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['connect_sloppy'].val, 0.1, 2.0, 'Strictness when connecting branches'); xtmp += but_width*2; - PREFS['connect_base_trim'] = Draw.Number('Trim Base', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['connect_base_trim'].val, 0.0, 2.0, 'Trim branch base to better connect with parent branch'); xtmp += but_width*2; - Blender.Draw.EndAlign() - y-=but_height+MARGIN - xtmp = x - # ---------- ---------- ---------- ---------- Blender.Draw.BeginAlign() PREFS['do_twigs'] = Draw.Toggle('Generate Twigs',EVENT_UPDATE_AND_UI, xtmp, y, but_width*2, but_height, PREFS['do_twigs'].val, 'Generate child branches based existing branches'); xtmp += but_width*2; @@ -2646,6 +2826,12 @@ def gui(): y-=but_height xtmp = x + # ---------- ---------- ---------- ---------- + PREFS['twig_select_mode'] = Draw.Menu('Branch Selection Method%t|From Short%x0|From Long%x1|From Straight%x2|From Bent%x3|',EVENT_UPDATE_AND_UI, xtmp, y, but_width*2, but_height, PREFS['twig_select_mode'].val, 'Select branches to use as twigs based on this attribute'); xtmp += but_width*2; + PREFS['twig_select_factor'] = Draw.Number('From Factor', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['twig_select_factor'].val, 0.0, 16, 'Select branches, lower value is more strict and will give you less variation'); xtmp += but_width*2; + y-=but_height + xtmp = x + # ---------- ---------- ---------- ---------- PREFS['twig_recursive'] = Draw.Toggle('Recursive Twigs',EVENT_UPDATE_AND_UI, xtmp, y, but_width*2, but_height, PREFS['twig_recursive'].val, 'Recursively add twigs into eachother'); xtmp += but_width*2; PREFS['twig_recursive_limit'] = Draw.Number('Generations', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['twig_recursive_limit'].val, 0.0, 16, 'Number of generations allowed, 0 is inf'); xtmp += but_width*2; @@ -2706,7 +2892,6 @@ def gui(): - """ Blender.Draw.BeginAlign() if PREFS['do_leaf'].val == 0: but_width_tmp = but_width*2 @@ -2719,37 +2904,30 @@ def gui(): y-=but_height xtmp = x - PREFS['leaf_branch_limit'] = Draw.Number('Branch Limit', EVENT_UPDATE, xtmp, y, but_width*4, but_height, PREFS['leaf_branch_limit'].val, 0.1, 2.0, 'Maximum thichness where a branch can bare leaves'); xtmp += but_width*4; + # Dont use yet + # PREFS['leaf_branch_limit'] = Draw.Number('Branch Limit', EVENT_UPDATE, xtmp, y, but_width*4, but_height, PREFS['leaf_branch_limit'].val, 0.1, 2.0, 'Maximum thichness where a branch can bare leaves'); xtmp += but_width*4; - ''' - PREFS['do_uv_uscale'] = Draw.Toggle('U-Scale', EVENT_UPDATE, xtmp, y, but_width, but_height, PREFS['do_uv_uscale'].val, 'Scale the width according to the face size (will NOT tile)'); xtmp += but_width; - PREFS['do_uv_keep_vproportion'] = Draw.Toggle('V-Aspect', EVENT_UPDATE, xtmp, y, but_width, but_height, PREFS['do_uv_keep_vproportion'].val, 'Correct the UV aspect with the branch width'); xtmp += but_width; - PREFS['do_uv_vnormalize'] = Draw.Toggle('V-Normaize', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['do_uv_vnormalize'].val, 'Scale the UVs to fit onto the image verticaly'); xtmp += but_width*2; + if PREFS['leaf_fill'].val == 0: + but_width_tmp = but_width*2 + else: + but_width_tmp = but_width*4 + PREFS['leaf_fill'] = Draw.Toggle('Fill Object', EVENT_UPDATE_AND_UI, xtmp, y, but_width*2, but_height, PREFS['leaf_fill'].val, 'Fill an object with leaves'); xtmp += but_width*2; + if PREFS['leaf_fill'].val: + PREFS['leaf_fill_ob_bounds'] = Draw.String('OB Bound: ', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['leaf_fill_ob_bounds'].val, 64, 'Fill this object with leaves', do_ob_check); xtmp += but_width*2; + + # ---------- ---------- ---------- ---------- + y-=but_height + xtmp = x + + PREFS['leaf_fill_count'] = Draw.Number('Fill #', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['leaf_fill_count'].val, 10, 100000, 'Number of leaves to fill in'); xtmp += but_width*2; + PREFS['leaf_size'] = Draw.Number('Size', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['leaf_size'].val, 0.001, 10.0, 'size of the leaf'); xtmp += but_width*2; - - y-=but_height - xtmp = x - # ---------- ---------- ---------- ---------- - - PREFS['uv_x_scale'] = Draw.Number('Scale U', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['uv_x_scale'].val, 0.01, 10.0, 'Edge loop spacing around branch join, lower value for less webed joins'); xtmp += but_width*2; - PREFS['uv_y_scale'] = Draw.Number('Scale V', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['uv_y_scale'].val, 0.01, 10.0, 'Edge loop spacing around branch join, lower value for less webed joins'); xtmp += but_width*2; - - y-=but_height - xtmp = x - # ---------- ---------- ---------- ---------- - - PREFS['image_main'] = Draw.String('IM: ', EVENT_UPDATE, xtmp, y, but_width*3, but_height, PREFS['image_main'].val, 64, 'Image to apply to faces'); xtmp += but_width*3; - Draw.PushButton('Use Active', EVENT_UPDATE, xtmp, y, but_width, but_height, 'Get the image from the active image window', do_active_image); xtmp += but_width; - ''' Blender.Draw.EndAlign() y-=but_height+MARGIN xtmp = x # ---------- ---------- ---------- ---------- - """ - - Blender.Draw.BeginAlign() @@ -2804,7 +2982,13 @@ def gui(): # ---------- ---------- ---------- ---------- Blender.Draw.BeginAlign() - PREFS['do_armature'] = Draw.Toggle('Generate Armature & Skin Mesh', EVENT_UPDATE_AND_UI, xtmp, y, but_width*4, but_height, PREFS['do_armature'].val, 'Generate Armatuer'); xtmp += but_width*4; + if PREFS['do_armature'].val == 0: + but_width_tmp = but_width*2 + else: + but_width_tmp = but_width*4 + + Blender.Draw.BeginAlign() + PREFS['do_armature'] = Draw.Toggle('Generate Motion', EVENT_UPDATE_AND_UI, xtmp, y, but_width_tmp, but_height, PREFS['do_armature'].val, 'Generate Armatuer animation and apply to branches'); xtmp += but_width_tmp; # ---------- ---------- ---------- ---------- if PREFS['do_armature'].val: @@ -2840,6 +3024,67 @@ def gui(): xtmp = x + + + # ---------- ---------- ---------- ---------- + + Blender.Draw.BeginAlign() + PREFS['do_variation'] = Draw.Toggle('Generate Variation', EVENT_UPDATE_AND_UI, xtmp, y, but_width*2, but_height, PREFS['do_variation'].val, 'Create a variant by moving the branches'); xtmp += but_width*2; + + # ---------- ---------- ---------- ---------- + if PREFS['do_variation'].val: + PREFS['variation_seed'] = Draw.Number('Rand Seed', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['variation_seed'].val, 1, 100000, 'Change this to get a different variation'); xtmp += but_width*2; + y-=but_height + xtmp = x + + + PREFS['variation_orientation'] = Draw.Number('Orientation', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['variation_orientation'].val, 0, 1.0, 'Randomize rotation of the branch around its parent'); xtmp += but_width*2; + PREFS['variation_scale'] = Draw.Number('Scale', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['variation_scale'].val, 0.0, 1.0, 'Randomize the scale of branches'); xtmp += but_width*2; + + Blender.Draw.EndAlign() + + y-=but_height+(MARGIN*2) + xtmp = x + + + + # ---------- ---------- ---------- ---------- + Blender.Draw.BeginAlign() + PREFS['seg_density'] = Draw.Number('Segment Spacing',EVENT_UPDATE, xtmp, y, but_width*4, but_height, PREFS['seg_density'].val, 0.05, 10.0, 'Scale the limit points collapse, that are closer then the branch width'); xtmp += but_width*4; + + y-=but_height + xtmp = x + + # ---------- ---------- ---------- ---------- + PREFS['seg_density_angle'] = Draw.Number('Angle Spacing', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['seg_density_angle'].val, 0.0, 180.0, 'Segments above this angle will not collapse (lower value for more detail)'); xtmp += but_width*2; + PREFS['seg_density_radius'] = Draw.Number('Radius Spacing', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['seg_density_radius'].val, 0.0, 1.0, 'Segments above this difference in radius will not collapse (lower value for more detail)'); xtmp += but_width*2; + + y-=but_height + xtmp = x + # ---------- ---------- ---------- ---------- + + PREFS['seg_joint_compression'] = Draw.Number('Joint Width', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['seg_joint_compression'].val, 0.1, 2.0, 'Edge loop spacing around branch join, lower value for less webed joins'); xtmp += but_width*2; + PREFS['seg_joint_smooth'] = Draw.Number('Joint Smooth', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['seg_joint_smooth'].val, 0.0, 1.0, 'Edge loop spacing around branch join, lower value for less webed joins'); xtmp += but_width*2; + + y-=but_height + xtmp = x + # ---------- ---------- ---------- ---------- + + PREFS['connect_sloppy'] = Draw.Number('Connect Limit',EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['connect_sloppy'].val, 0.1, 2.0, 'Strictness when connecting branches'); xtmp += but_width*2; + PREFS['connect_base_trim'] = Draw.Number('Trim Base', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['connect_base_trim'].val, 0.0, 2.0, 'Trim branch base to better connect with parent branch'); xtmp += but_width*2; + Blender.Draw.EndAlign() + y-=but_height+MARGIN + xtmp = x + + # ---------- ---------- ---------- ---------- + Blender.Draw.BeginAlign() + PREFS['do_cap_ends'] = Draw.Toggle('Cap Ends',EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['do_cap_ends'].val, 'Add faces onto branch endpoints'); xtmp += but_width*2; + PREFS['do_subsurf'] = Draw.Toggle('SubSurf',EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['do_subsurf'].val, 'Enable subsurf for newly generated objects'); xtmp += but_width*2; + Blender.Draw.EndAlign() + y-=but_height+MARGIN + xtmp = x + + # ---------- ---------- ---------- ---------- Blender.Draw.BeginAlign() Draw.PushButton('Read Active Prefs', EVENT_REDRAW, xtmp, y, but_width*2, but_height, 'Read the ID Property settings from the active curve object', do_pref_read); xtmp += but_width*2; @@ -2869,4 +3114,7 @@ def gui(): if __name__ == '__main__': + # Read the active objects prefs on load. if they exist + do_pref_read(quiet=True) + Draw.Register(gui, evt, bevt) From aaba5d1a188b2c3edc4a1f384ed1730aef66d2f9 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 19 Nov 2007 17:39:52 +0000 Subject: [PATCH 11/29] Update v1.0.11 from Migius You can find the update v1.0.11 on http://wiki.blender.org/index.php/Scripts/Manual/Import/DXF-3D changelog: c4 added "analyse DXF-file" UI-option: print LAYER/BLOCK-dependences into a textfile c3 human-formating of data in INI-Files c2 added "caps" for closed Bezier-curves c2 added "set elevation" UI-option c1 rewrite POLYLINE2d-arc-segments Bezier-interpreter b9 many bugs fixed b9 rewrite POLYLINE2d-arc-segments trimming (clean-trim) b8 added "import from frozen layers" UI-option b8 added "import from paper space" UI-option b8 support Bezier curves for LINEs incl.thickness(0.0-10.0) b8 added meshSmooth_on for circle/arc/polyline b8 added vertexGroups for circle/arc b7 added width_force for ARCs/CIRCLEs = "thin_box" option b3 cleanup code, rename f_drawArc/Bulg->f_calcArc/Bulg b2 fixing material assignment by LAYER+COLOR b1 fixing Bezier curves representation of POLYLINEs-arc-segments b0 added global_scale_presets: "yard/feet/inch to meter" --- release/scripts/import_dxf.py | 1708 ++++++++++++++++++++++++--------- 1 file changed, 1232 insertions(+), 476 deletions(-) diff --git a/release/scripts/import_dxf.py b/release/scripts/import_dxf.py index 3f2fef72aa2..2a1081420e4 100644 --- a/release/scripts/import_dxf.py +++ b/release/scripts/import_dxf.py @@ -7,7 +7,7 @@ Group: 'Import' Tooltip: 'Import for DXF geometry data (Drawing eXchange Format).' """ __author__ = 'Kitsu(Ed Blake) & migius(Remigiusz Fiedler)' -__version__ = '1.0.beta10 - 2007.09.09 by migius' +__version__ = '1.0.11 - 2007.11.17 by migius' __url__ = ["http://blenderartists.org/forum/showthread.php?t=84319", "http://wiki.blender.org/index.php/Scripts/Manual/Import/DXF-3D"] __email__ = ["Kitsune_e(at)yahoo.com", "migius(at)4d-vectors.de"] @@ -18,69 +18,96 @@ This script imports 2d and 3d Geometery from DXFr12 format files. This version is focused on import of 3d-objects. Supported DXF Objects: -LINE -POINT -SOLID -TRACE -TEXT -INSERT (=block) -MINSERT (=array) -CIRCLE -ARC -3DFACE -2d-POLYLINE (=plane, incl. arc, variable-width, curve, spline) -3d-POLYLINE (=no-plane) -3d-POLYMESH +LINE, +POINT, +SOLID, +TRACE, +TEXT, +INSERT (=block), +MINSERT (=arrays of blocks), +CIRCLE, +ARC, +3DFACE, +2d-POLYLINE (=plane, incl. arc, variable-width, curve, spline), +3d-POLYLINE (=non-plane polylines), +3d-POLYMESH, 3d-POLYFACE -under construction, partly supported DXF>r12: + +under construction, partly supported DXF>r12 Objects: LWPOLYLINE (LightWeight), MLINE, MTEXT, ELLIPSE Unsupported DXF Objects: -DXF r12: DIMENSION, XREF (External Reference) +DXF r12: DIMENSION, XREF (External Reference), DXF>r12: SPLINE, GROUP, RAY/XLINE, LEADER, 3DSOLID, BODY, REGION, dynamic BLOCK Supported Properties: Hierarchy: Entire DXF BLOCKs hierarchy is preserved after import into Blender -visibility, frozen -COLOR -LAYER -thickness -width +visibility, frozen, +COLOR, LAYER, +thickness, width, (todo: grouped, XDATA) It is recommended to use DXF-object properties for coding Blender materials. Notes: - Recommend that you run 'RemoveDoubles' on each imported mesh after using this script - Blocks are created on layer 19 then referenced at each insert point. -* Big DXF-files (over 1500 objects) decrease import performance. The problem is not the inefficiency of python-scripting but Blenders performance in creating new objects in his database - probably a database management problem. -* The Blender curves of imported ARCs and POLYLINE-arc-segments have light malformed ends.(to fix in beta10) +- Big DXF-files (over 1500 objects) decrease import performance. The problem is not the inefficiency of python-scripting but Blenders performance in creating new objects in his database - probably a database management problem. TODO: - the new style object visibility -- support for Spline-curves, Besier-curves - support for real 3d-solids (ACIS) - (to see more, search for "-todo-" in script) +""" +""" History: - v1.0 - 2007.09 by migius: "full 3d"-release + v1.0 - 2007.11. by migius: "full 3d"-release planned tasks: + -- command-line-mode/batch-mode + -- in-place-editing for dupliGroups -- filtering of unused/not-inserted BLOCKs - -- human-formating of data in INI-File - -- suport for MLine - -- suport for Ellipse - -- suport for Mtext + -- support for MLine + -- support for Ellipse + -- support for Mtext -- blender_object.ID.properties[dxf_layer_name] + -- better support for long dxf-layer-names -- Configuration files(.ini) should/can handle various material setups -- added f_layerFilter -- to-check: obj/mat/group/_mapping-idea from ideasman42: - -- better support for long dxf-layer-names - -- support width_force for LINEs/ARCs/CIRCLEs/ELLIPSEs = "solidify" - -- curves: added fill/non-fill option for closed curves: CIRCLEs,ELLIPSEs,POLYLINEs + -- curves: added "fill/non-fill" option for closed curves: CIRCLEs,ELLIPSEs,POLYLINEs -- bug:? object = Object.Get(obname) -> = SCENE.getChildren(obname) - -- command-line-mode/batch-mode - -- fixed malformed endpoints of Blender curves of imported ARCs and POLYLINE-arc segments. - beta10: 2007.09.09 by migius + -- "normalize Z" option to correct non-planar figures + -- LINEs need "width" in 3d-space incl vGroups + -- support width_force for LINEs/ELLIPSEs = "solidify" + -- bug: dxf-files without layer-section missing layersmap{} + -- color BYLAYER=256,BYBLOCK=0 + -- blocknames conventions length + v1.0.11: 2007.11.17 by migius + c4 added "analyze DXF-file" UI-option: print LAYER/BLOCK-dependences into a textfile + c3 human-formating of data in INI-Files + c2 added "caps" for closed Bezier-curves + c2 added "set elevation" UI-option + c1 rewrite POLYLINE2d-arc-segments Bezier-interpreter + b9 many bugs fixed + b9 rewrite POLYLINE2d-arc-segments trimming (clean-trim) + b8 added "import from frozen layers" UI-option + b8 added "import from paper space" UI-option + b8 support Bezier curves for LINEs incl.thickness(0.0-10.0) + b8 added meshSmooth_on for circle/arc/polyline + b8 added vertexGroups for circle/arc + b7 added width_force for ARCs/CIRCLEs = "thin_box" option + b3 cleanup code, rename f_drawArc/Bulg->f_calcArc/Bulg + b2 fixing material assignment by LAYER+COLOR + b1 fixing Bezier curves representation of POLYLINEs-arc-segments + b0 added global_scale_presets: "yard/feet/inch to meter" + v1.0.10: 2007.10.18 by migius + a6 bugfix CircleDrawCaps for OSX + a5 added two "curve_res" UI-buttons for Bezier curves representation + a5 improved Bezier curves representation of circles/arcs: correct handlers + a4 first try to fix malformed endpoints of Blender curves of imported ARCs and POLYLINE-arc segments. + a3 bugfix: open POLYLINEs with end_point.loc==start_point.loc + a2 bugfix: f_transform for OCS=(0,0,-1) oriented objects a1 added "fill_on" option to draw top and bottom sides of CIRCLEs and ELLIPSEs a1 rewrite f_CIRCLE.Draw: from Mesh.Primitive to Mesh a1 bugfix "newScene"-mode: Cylinders/Arcs were drawn at <0,0,0>location @@ -100,13 +127,13 @@ History: d4 added: f_set_thick(cntrolled by ini-parameters) d4 bugfix: face-normals in objects with minus thickness d4 added: placeholder'Empty'-size in f_Insert.draw - d3 rewrite f_Text.Draw: added suport for all Text's parameters + d3 rewrite f_Text.Draw: added support for all Text's parameters d2 redesign: progressbar e- tuning by ideasman42: better use of the Py API. c- tuning by ideasman42 b- rewrite f_Text.Draw rotation/transform b- bugfix: POLYLINE-segment-intersection more reliable now - b- bugfix: circle:_thic, 'Empties':no material_assignement + b- bugfix: circle:_thic, 'Empties':no material_assignment b- added material assignment (from layer and/or color) a- added empty, cylinder and UVsphere for POINTs a- added support for 2d-POLYLINE: splines, fitted curves, fitted surfaces @@ -129,7 +156,7 @@ History: g- rewrote: insert-point-handle-object is a small tetrahedron e- bugfix: closed-polymesh3d - rewrote: startUI, type_map.keys, f_drawer, for all class_f_draw(added "settings" as attribut) - - added 2d/3d-support for Polyline_Width incl. angleintersection + - added 2d/3d-support for Polyline_Width incl. angle intersection beta07: 2007.06.19 by migius - added 3d-support for LWPolylines - added 2d/3d-support for Points @@ -140,7 +167,7 @@ History: - added 2d/3d-support for 3d-PolyLine, PolyMesh and PolyFace - added Global-Scale for size control of imported scenes beta04: 2007.06.12 by migius - - rewrote the f_drawBulge for correct import the arc-segments of Polylines + - rewrote the f_calcBulge for correct import the arc-segments of Polylines beta03: 2007.06.10 by migius - rewrote interface beta02: 2007.06.09 by migius @@ -186,30 +213,34 @@ History: # -------------------------------------------------------------------------- import Blender -import bpy +#import bpy from Blender import * #from Blender.Mathutils import Vector, Matrix #import BPyMessages - -from dxfReader import readDXF # get_name, get_layer +from dxfReader import readDXF +#from dxfReader import get_name, get_layer from dxfReader import Object as dxfObject from dxfColorMap import color_map + from math import * try: import os if os.name:# != 'mac': import psyco - psyco.log() + psyco.log(Blender.Get('tempdir')+"/blender.log-psyco") + #psyco.log() psyco.full(memory=100) psyco.profile(0.05, memory=100) psyco.profile(0.2) + #print 'psyco imported' except ImportError: + #print 'psyco not imported' pass print '\n\n\n\n' -print 'Import DXF to Blender *** START ***' #--------------------- +print 'Import DXF to Blender *** start ***' #--------------------- SCENE = None WORLDX = Mathutils.Vector((1,0,0)) @@ -220,10 +251,14 @@ G_SCALE = 1.0 #(0.0001-1000) global scaling factor for all dxf data MIN_DIST = 0.001 #cut-off value for sort out short-distance polyline-"duoble_vertex" ARC_RESOLUTION = 64 #(4-500) arc/circle resolution - number of segments ARC_RADIUS = 1.0 #(0.01-100) arc/circle radius for number of segments algorithm -THIN_RESOLUTION = 8 #(4-500) thin_cylinder arc_resolution - number of segments +CURV_RESOLUTION = 12 #(3-50) Bezier curves resolution +CURVARC_RESOLUTION = 4 #(3-32) resolution of circle represented as Bezier curve +THIN_RESOLUTION = 8 #(4-64) thin_cylinder arc_resolution - number of segments MIN_THICK = MIN_DIST * 10.0 #minimal thickness by forced thickness MIN_WIDTH = MIN_DIST * 10.0 #minimal width by forced width -ANGLECUT_LIMIT = 3.0 #limit for anglecut of polylines-wide-segments (values:1.0 - 5.0) +TRIM_LIMIT = 3.0 #limit for triming of polylines-wide-segments (values:0.0 - 5.0) +ELEVATION = 0.0 #standard elevation = coordinate Z + TARGET_LAYER = 3 #target blender_layer GROUP_BYLAYER = 0 #(0/1) all entities from same layer import into one blender-group @@ -232,6 +267,7 @@ MAX_NAMELENGTH = 17 #max_effective_obnamelength in blender =21=17+(.001) INIFILE_DEFAULT_NAME = 'importDXF' INIFILE_EXTENSION = '.ini' INIFILE_HEADER = 'ImportDXF.py ver.1.0 config data' +INFFILE_HEADER = 'ImportDXF.py ver.1.0 analyze of DXF-data' AUTO = BezTriple.HandleTypes.AUTO FREE = BezTriple.HandleTypes.FREE @@ -252,8 +288,8 @@ cur_COUNTER = 0 #counter for progress_bar # from Stani's dxf writer v1.1 (c)www.stani.be (GPL) #---color values -BYBLOCK=0 -BYLAYER=256 +BYBLOCK = 0 +BYLAYER = 256 #---block-type flags (bit coded values, may be combined): ANONYMOUS =1 # This is an anonymous block generated by hatching, associative dimensioning, other internal operations, or an application @@ -310,7 +346,7 @@ EXACT = 2 #taller characters will not override class Layer: #----------------------------------------------------------------- - """Class for objects representing dxf layers. + """Class for objects representing dxf LAYERs. """ def __init__(self, obj, name=None, color=None, frozen=None): """Expects an object of type layer as input. @@ -320,7 +356,7 @@ class Layer: #----------------------------------------------------------------- if name: self.name = name - #self.bfname = name #remi--todo----------- + #self.bfname = name #--todo---see layernamesmap in f_getLayersmap --- else: self.name = obj.get_type(2)[0] #layer name of object @@ -333,7 +369,7 @@ class Layer: #----------------------------------------------------------------- self.frozen = frozen else: self.flags = obj.get_type(70)[0] - self.frozen = self.flags&1 + self.frozen = self.flags & 1 def __repr__(self): @@ -353,7 +389,7 @@ def getit(obj, typ, default=None): #------------------------------------------ it = item[1] break #as soon as the first found except: - # TODO - I found one case where item was a text instance + # --todo-- I found one case where item was a text instance # that failed with no __getitem__ pass else: #else searching in Object with get_type-Methode @@ -368,7 +404,7 @@ def getit(obj, typ, default=None): #------------------------------------------ def get_extrusion(data): #------------------------------------------------- """Find the axis of extrusion. - Used to get from object_data the objects Object Coordinate System (ocs). + Used to get from object_data the objects Object_Coordinate_System (ocs). """ #print 'deb:get_extrusion: data: \n', data #--------------- vec = [0,0,1] @@ -380,10 +416,8 @@ def get_extrusion(data): #------------------------------------------------- - - class Solid: #----------------------------------------------------------------- - """Class for objects representing dxf solid or trace. + """Class for objects representing dxf SOLID or TRACE. """ def __init__(self, obj): """Expects an entity object of type solid or trace as input. @@ -418,7 +452,7 @@ class Solid: #----------------------------------------------------------------- d = [0, 0, 0] a[0] = getit(data, 10, None) # 10 = x a[1] = getit(data, 20, None) # 20 = y - a[2] = getit(data, 30, 0) # 30 = z + a[2] = getit(data, 30, 0) # 30 = z b[0] = getit(data, 11, None) b[1] = getit(data, 21, None) b[2] = getit(data, 31, 0) @@ -492,7 +526,7 @@ class Solid: #----------------------------------------------------------------- ob = SCENE.objects.new(me) # create a new mesh_object if settings.var['vGroup_on']: - # each MeshSite becomes vertexGroup for easier material assignment --------------------- + # each MeshSide becomes vertexGroup for easier material assignment --------------------- replace = Blender.Mesh.AssignModes.ADD #or .AssignModes.ADD/REPLACE if vg_left: me.addVertGroup('side.left') ; me.assignVertsToGroup('side.left', vg_left, 1.0, replace) if vg_right:me.addVertGroup('side.right') ; me.assignVertsToGroup('side.right', vg_right, 1.0, replace) @@ -509,7 +543,7 @@ class Solid: #----------------------------------------------------------------- class Line: #----------------------------------------------------------------- - """Class for objects representing dxf lines. + """Class for objects representing dxf LINEs. """ def __init__(self, obj): """Expects an entity object of type line as input. @@ -558,66 +592,101 @@ class Line: #----------------------------------------------------------------- #settings.var['curves_on']=False points = self.points + thic = set_thick(self.thic, settings) + width = 0.0 + if settings.var['lines_as'] == 4: # as thin_box + thic = settings.var['thick_min'] + width = settings.var['width_min'] + if settings.var['lines_as'] == 3: # as thin cylinder + cyl_rad = 0.5 * settings.var['width_min'] - global activObjectLayer - global activObjectName - #print 'deb:draw:line.ob IN activObjectName: ', activObjectName #--------------------- - - if activObjectLayer == self.layer and settings.var['one_mesh_on']: - obname = activObjectName - #print 'deb:line.draw obname from activObjectName: ', obname #--------------------- - ob = Object.Get(obname) # open an existing mesh_object - #ob = SCENE.getChildren(obname) # open an existing mesh_object - me = Mesh.Get(ob.name) # open objects mesh data - else: + if settings.var['curves_on']: # LINE curve representation------------------------- obname = 'li_%s' %self.layer # create object name from layer name obname = obname[:MAX_NAMELENGTH] - me = Mesh.New(obname) # create a new mesh - ob = SCENE.objects.new(me) # create a new mesh_object - activObjectName = ob.name - activObjectLayer = self.layer - #print ('deb:line.draw new line.ob+mesh:"%s" created!' %ob.name) #--------------------- - #if settings.var['width_force']: # -todo----------- + c = Curve.New(obname) # create new curve data + curve = c.appendNurb(BezTriple.New(points[0])) + curve.append(BezTriple.New(points[1])) + for point in curve: + point.handleTypes = [VECT, VECT] + curve.flagU = 0 # 0 sets the curve not cyclic=open + c.update() #important for handles calculation - faces, edges = [], [] - n = len(me.verts) - thic = set_thick(self.thic, settings) - if thic != 0: - t, e = thic, self.extrusion - #print 'deb:thic, extr: ', t, e #--------------------- - points.extend([[v[0]+t*e[0], v[1]+t*e[1], v[2]+t*e[2]] for v in points[:]]) - faces = [[0+n, 1+n, 3+n, 2+n]] - else: - me.verts.extend(points) # add vertices to mesh - edges = [[0+n, 1+n]] + ob = SCENE.objects.new(c) # create a new curve_object - me.verts.extend(points) # add vertices to mesh - if faces: me.faces.extend(faces) # add faces to the mesh - if edges: me.edges.extend(edges) # add faces to the mesh + #if False: # --todo-- better support for 210-group + if thic != 0.0: #hack: Blender2.45 curve-extrusion + t = thic * 0.5 + if abs(t) > 5.0: t = 5.0 * cmp(t,0) # Blender2.45 accepts only (0.0 - 5.0) + e = self.extrusion + c.setExt1(abs(t)) # curve-extrusion + ob.LocX += t * e[0] + ob.LocY += t * e[1] + ob.LocZ += t * e[2] + #c.setExt1(1.0) # curve-extrusion: Blender2.45 accepts only (0.0 - 5.0) + #ob.LocZ = t + self.loc[2] + #ob.SizeZ *= abs(t) + return ob - if settings.var['vGroup_on']: - # entities with the same color build one vertexGroup for easier material assignment --------------------- - ob.link(me) # link mesh to that object - vG_name = 'color_%s' %self.color_index - if edges: faces = edges - replace = Blender.Mesh.AssignModes.ADD #or .AssignModes.REPLACE or ADD - try: - me.assignVertsToGroup(vG_name, faces[0], 1.0, replace) - #print 'deb: existed vGroup:', vG_name #--------------------- - except: - me.addVertGroup(vG_name) - me.assignVertsToGroup(vG_name, faces[0], 1.0, replace) - #print 'deb: create new vGroup:', vG_name #--------------------- + else: # LINE mesh representation ------------------------------ + global activObjectLayer + global activObjectName + #print 'deb:draw:line.ob IN activObjectName: ', activObjectName #--------------------- + + if activObjectLayer == self.layer and settings.var['one_mesh_on']: + obname = activObjectName + #print 'deb:line.draw obname from activObjectName: ', obname #--------------------- + ob = Object.Get(obname) # open an existing mesh_object + #ob = SCENE.getChildren(obname) # open an existing mesh_object + me = Mesh.Get(ob.name) # open objects mesh data + else: + obname = 'li_%s' %self.layer # create object name from layer name + obname = obname[:MAX_NAMELENGTH] + me = Mesh.New(obname) # create a new mesh + ob = SCENE.objects.new(me) # create a new mesh_object + activObjectName = ob.name + activObjectLayer = self.layer + #print ('deb:line.draw new line.ob+mesh:"%s" created!' %ob.name) #--------------------- + + faces, edges = [], [] + n = len(me.verts) + #if settings.var['width_force']: #--todo----------- - #print 'deb:draw:line.ob OUT activObjectName: ', activObjectName #--------------------- - return ob - + if thic != 0: + t, e = thic, self.extrusion + #print 'deb:thic, extr: ', t, e #--------------------- + points.extend([[v[0]+t*e[0], v[1]+t*e[1], v[2]+t*e[2]] for v in points[:]]) + faces = [[0+n, 1+n, 3+n, 2+n]] + else: + edges = [[0+n, 1+n]] + + me.verts.extend(points) # adds vertices to global mesh + if faces: me.faces.extend(faces) # add faces to the mesh + if edges: me.edges.extend(edges) # add faces to the mesh + + if settings.var['vGroup_on']: + # entities with the same color build one vertexGroup for easier material assignment ---- + ob.link(me) # link mesh to that object + vG_name = 'color_%s' %self.color_index + if edges: faces = edges + replace = Blender.Mesh.AssignModes.ADD #or .AssignModes.REPLACE or ADD + try: + me.assignVertsToGroup(vG_name, faces[0], 1.0, replace) + #print 'deb: existed vGroup:', vG_name #--------------------- + except: + me.addVertGroup(vG_name) + me.assignVertsToGroup(vG_name, faces[0], 1.0, replace) + #print 'deb: create new vGroup:', vG_name #--------------------- + + + #print 'deb:draw:line.ob OUT activObjectName: ', activObjectName #--------------------- + return ob + class Point: #----------------------------------------------------------------- - """Class for objects representing dxf points. + """Class for objects representing dxf POINTs. """ def __init__(self, obj): """Expects an entity object of type point as input. @@ -700,7 +769,7 @@ class Point: #----------------------------------------------------------------- class LWpolyline: #----------------------------------------------------------------- - """Class for objects representing dxf LWpolylines. + """Class for objects representing dxf LWPOLYLINEs. """ def __init__(self, obj): """Expects an entity object of type lwpolyline as input. @@ -793,7 +862,7 @@ class LWpolyline: #------------------------------------------------------------ else: point2 = self.points[i+1] arc_res = settings.var['arc_res']/sqrt(settings.var['arc_rad']) - verts = drawBulge(point, point2, arc_res) + verts, center = calcBulge(point, point2, arc_res) # if i == len(self.points)-1: # if self.closed: # verts.pop() #remove last(=first) vertex @@ -835,7 +904,7 @@ class LWpolyline: #------------------------------------------------------------ class Polyline: #----------------------------------------------------------------- - """Class for objects representing dxf Polylines. + """Class for objects representing dxf POLYLINEs. """ def __init__(self, obj): """Expects an entity object of type polyline as input. @@ -910,7 +979,7 @@ class Polyline: #-------------------------------------------------------------- elif self.plmesh: #---- 3dPolyMesh - mesh with ortogonal topology ob = self.drawPlMesh(settings) #---- 2dPolyline - plane polyline with arc/wide/thic segments - #---- 3dPolyline - noplane polyline (thin segments = without arc/wide/thic) + #---- 3dPolyline - non-plane polyline (thin segments = without arc/wide/thic) elif self.poly2d or self.poly3d: if settings.var['curves_on']: # and self.spline: ob = self.drawPolyCurve(settings) @@ -944,9 +1013,12 @@ class Polyline: #-------------------------------------------------------------- me.verts.extend(points) # add vertices to mesh me.faces.extend(faces) # add faces to the mesh + if settings.var['meshSmooth_on']: # ---------------------- + for i in xrange(len(faces)): + me.faces[i].smooth = True + #me.Mode(AUTOSMOOTH) transform(self.extrusion, 0, ob) #print 'deb:polyface.draw.END:----------------' #------------------------ - return ob @@ -987,6 +1059,11 @@ class Polyline: #-------------------------------------------------------------- me.verts.extend([point.loc for point in self.points]) # add vertices to mesh me.faces.extend(faces) # add faces to the mesh + if settings.var['meshSmooth_on']: # ---------------------- + for i in xrange(len(faces)): + me.faces[i].smooth = True + #me.Mode(AUTOSMOOTH) + transform(self.extrusion, 0, ob) #print 'deb:polymesh.draw.END:----------------' #------------------------ return ob @@ -1006,14 +1083,19 @@ class Polyline: #-------------------------------------------------------------- obname = '%s_%s' %(pline_typ, self.layer) # create object_name from layer name obname = obname[:MAX_NAMELENGTH] d_points = [] - #for DXFr10-format: update all points[].loc[2] == None -> 0.0 - for point in self.points: - if point.loc[2] == None: + + if settings.var['Z_force_on']: + self.elevation = settings.var['Z_elev'] + for point in self.points: point.loc[2] = self.elevation - d_points.append(point) + d_points.append(point) + else: #for DXFr10-format: update all points[].loc[2] == None -> 0.0 + for point in self.points: + if point.loc[2] == None: + point.loc[2] = self.elevation + d_points.append(point) thic = set_thick(self.thic, settings) - if thic != 0.0: #hack: Blender<2.45 curve-extrusion LocZ = d_points[0].loc[2] temp_points = [] @@ -1024,6 +1106,7 @@ class Polyline: #-------------------------------------------------------------- #print 'deb:polyline2dCurve.draw d_points=', d_points #--------------- pline = Curve.New(obname) # create new curve data + #pline.setResolu(24) #--todo----- if False: #self.spline: # NURBSplines-----FAKE(with Bezier)----- #print 'deb:polyline2dCurve.draw self.spline!' #--------------- @@ -1039,7 +1122,7 @@ class Polyline: #-------------------------------------------------------------- curve[0].handleTypes = [FREE, ALIGN] #remi--todo----- curve[-1].handleTypes = [ALIGN, FREE] #remi--todo----- - elif self.spline: # NURBSplines-----TODO--:if curvQBspline: generate middlepoints--- + elif self.spline: # NURBSplines-----OK----- #print 'deb:polyline2dCurve.draw self.spline!' #--------------- weight1 = 0.5 weight2 = 1.0 @@ -1111,33 +1194,99 @@ class Polyline: #-------------------------------------------------------------- curve[0].handleTypes = [FREE, ALIGN] #remi--todo----- curve[-1].handleTypes = [ALIGN, FREE] #remi--todo----- - else: #--straight line/arc-segments----OK------ + else: #--straight line- and arc-segments----OK------ + #print 'deb:polyline2dCurve.draw curve:', curve #----- points = [] - d_points.append(d_points[0]) #------ first vertex added ------------- + arc_res = settings.var['curve_arc'] + prevHandleType = VECT + #d_points.append(d_points[0]) #------ first vertex added at the end of list -------- #curve.setType(0) #polygon_type of Blender_curve - for i in xrange(len(d_points)-1): + for i in xrange(len(d_points)): point1 = d_points[i] - point2 = d_points[i+1] - if point1.bulge and (i < len(d_points)-2 or self.closed): - verts = drawBulge(point1, point2, arc_res=8, curve_on=True) #calculate additional points for bulge - if i == 0: curve = pline.appendNurb(BezTriple.New(verts[0])) - else: curve.append(BezTriple.New(verts[0])) - curve[-1].handleTypes = [VECT, VECT] #--todo--calculate bezier-tangents - for p in verts[1:]: - curve.append(BezTriple.New(p)) - curve[-1].handleTypes = [AUTO, AUTO] #--todo--calculate bezier-tangents -# curve[-1].handleTypes = [VECT, VECT] #--todo--calculate bezier-tangents - else: - if i == 0: curve = pline.appendNurb(BezTriple.New(point1.loc)) - else: curve.append(BezTriple.New(point1.loc)) - curve[-1].handleTypes = [VECT, VECT] #--todo--calculate bezier-tangents + #point2 = d_points[i+1] + if False: #-----outdated!- standard calculation ---------------------------------- + if point1.bulge and (i < len(d_points)-2 or self.closed): + verts, center = calcBulge(point1, point2, arc_res, triples=False) + if i == 0: curve = pline.appendNurb(BezTriple.New(verts[0])) + else: curve.append(BezTriple.New(verts[0])) + curve[-1].handleTypes = [VECT, VECT] #--todo--calculation of bezier-tangents + for p in verts[1:]: + curve.append(BezTriple.New(p)) + curve[-1].handleTypes = [AUTO, AUTO] + else: + if i == 0: curve = pline.appendNurb(BezTriple.New(point1.loc)) + else: curve.append(BezTriple.New(point1.loc)) + curve[-1].handleTypes = [VECT, VECT] #--todo--calculation of bezier-tangents + + elif True: #----- optimised Bezier-Handles calculation -------------------------------- + #print 'deb:drawPlineCurve: i:', i #--------- + if point1.bulge and not (i == len(d_points)-1 and point1.bulge and not self.closed): + if i == len(d_points)-1: point2 = d_points[0] + else: point2 = d_points[i+1] + + + # calculate additional points for bulge + VectorTriples = calcBulge(point1, point2, arc_res, triples=True) + + if prevHandleType == FREE: + #print 'deb:drawPlineCurve: VectorTriples[0]:', VectorTriples[0] #--------- + VectorTriples[0][:3] = prevHandleVect + #print 'deb:drawPlineCurve: VectorTriples[0]:', VectorTriples[0] #--------- + + if i == 0: curve = pline.appendNurb(BezTriple.New(VectorTriples[0])) + else: curve.append(BezTriple.New(VectorTriples[0])) + curve[-1].handleTypes = [prevHandleType, FREE] + + for p in VectorTriples[1:-1]: + curve.append(BezTriple.New(p)) + curve[-1].handleTypes = [FREE, FREE] + + prevHandleVect = VectorTriples[-1][:3] + prevHandleType = FREE + #print 'deb:drawPlineCurve: prevHandleVect:', prevHandleVect #--------- + else: + #print 'deb:drawPlineCurve: else' #---------- + if prevHandleType == FREE: + VectorTriples = prevHandleVect + list(point1) + list(point1) + #print 'deb:drawPlineCurve: VectorTriples:', VectorTriples #--------- + curve.append(BezTriple.New(VectorTriples)) + curve[-1].handleTypes = [FREE, VECT] + prevHandleType = VECT + else: + if i == 0: curve = pline.appendNurb(BezTriple.New(point1.loc)) + else: curve.append(BezTriple.New(point1.loc)) + curve[-1].handleTypes = [VECT, VECT] + + + + #print 'deb:drawPlineCurve: curve[-1].vec[0]', curve[-1].vec[0] #---------- + if self.closed: curve.flagU = 1 # Set curve cyclic=close -# curve[0].handleTypes = [VECT, VECT] #--todo--calculate bezier-tangents - else: + if prevHandleType == FREE: + #print 'deb:drawPlineCurve:closed curve[0].vec:', curve[0].vec #---------- + #print 'deb:drawPlineCurve:closed curve[0].handleTypes:', curve[0].handleTypes #---------- + prevHandleType2 = curve[0].handleTypes[1] + p0h1,p0,p0h2 = curve[0].vec + #print 'deb:drawPlineCurve:closed p0h1:', p0h1 #---------- + p0h1 = prevHandleVect + #p0h1 = [0,0,0] + #print 'deb:drawPlineCurve:closed p0h1:', p0h1 #---------- + #curve[0].vec = [p0h1,p0,p0h2] + curve.__setitem__(0,BezTriple.New(p0h1+p0+p0h2)) + + curve[0].handleTypes = [FREE,prevHandleType2] + #print 'deb:drawPlineCurve:closed curve[0].vec:', curve[0].vec #---------- + #print 'deb:drawPlineCurve:closed curve[0].handleTypes:', curve[0].handleTypes #---------- + else: + curve[0].handleTypes[0] = VECT + else: curve.flagU = 0 # Set curve not cyclic=open - curve[0].handleTypes = [FREE, VECT] #--todo--calculate bezier-tangents - curve[-1].handleTypes = [VECT, FREE] #--todo--calculate bezier-tangents + + if settings.var['fill_on']: + pline.setFlag(6) # 2+4 set top and button caps + else: + pline.setFlag(pline.getFlag() & ~6) # dont set top and button caps pline.update() ob = SCENE.objects.new(pline) # create a new curve_object @@ -1155,7 +1304,7 @@ class Polyline: #-------------------------------------------------------------- return ob - def drawPoly2d(self, settings): #---- 2dPolyline - plane wide/thic lines + def drawPoly2d(self, settings): #---- 2dPolyline - plane lines/arcs with wide/thic """Generate the geometery of regular polyline. """ #print 'deb:polyline2d.draw.START:----------------' #------------------------ @@ -1170,28 +1319,39 @@ class Polyline: #-------------------------------------------------------------- elif self.curved: pline_typ = 'pc' else: pline_typ = 'pl' obname = '%s_%s' %(pline_typ, self.layer) # create object_name from layer name -# obname = 'pl_%s' %self.layer # create object name from layer name obname = obname[:MAX_NAMELENGTH] if len(self.points) < 2: #print 'deb:drawPoly2d exit, cause POLYLINE has less than 2 vertices' #--------- return - #d_points = self.points[:] - #for DXFr10-format: update all points[].loc[2] == None -> 0.0 - for point in self.points: - if point.loc[2] == None: + + if settings.var['Z_force_on']: + self.elevation = settings.var['Z_elev'] + for point in self.points: point.loc[2] = self.elevation - d_points.append(point) - #print 'deb:len of d_pointsList ====== ', len(d_points) #------------------------ - - #add duplic of the first vertex at the end of pointslist - d_points.append(d_points[0]) - - #print 'deb:len of d_pointsList ====== ', len(d_points) #------------------------ - #print 'deb:d_pointsList ======:\n ', d_points #------------------------ + d_points.append(point) + else: #for DXFr10-format: update all non-existing LocZ points[].loc[2] == None -> 0.0 elevation + for point in self.points: + if point.loc[2] == None: + point.loc[2] = self.elevation + d_points.append(point) + #print 'deb:drawPoly2d len of d_pointsList ====== ', len(d_points) #------------------------ + #print 'deb:drawPoly2d d_pointsList ======:\n ', d_points #------------------------ - #routine to sort out of "double.vertices" -------- + #if closed polyline, add duplic of the first vertex at the end of pointslist + if self.closed: #new_b8 + if d_points[-1].loc != d_points[0].loc: # if not equal, then set the first at the end of pointslist + d_points.append(d_points[0]) + else: + if d_points[-1].loc == d_points[0].loc: # if equal, then set to closed, and modify the last point + d_points[-1] = d_points[0] + self.closed = True + #print 'deb:drawPoly2d len of d_pointsList ====== ', len(d_points) #------------------------ + #print 'deb:drawPoly2d d_pointsList ======:\n ', d_points #------------------------ + + + # routine to sort out of "double.vertices" ------------------------------------ minimal_dist = settings.var['dist_min'] * 0.1 temp_points = [] for i in xrange(len(d_points)-1): @@ -1201,64 +1361,78 @@ class Polyline: #-------------------------------------------------------------- delta = Mathutils.Vector(point2.loc) - Mathutils.Vector(point.loc) if delta.length > minimal_dist: temp_points.append(point) - #else: print 'deb:double.vertex sort out!' #------------------------ - temp_points.append(d_points[-1]) #------ last vertex added ------------- + #else: print 'deb:drawPoly2d double.vertex sort out!' #------------------------ + temp_points.append(d_points[-1]) #------ incl. last vertex ------------- + #if self.closed: temp_points.append(d_points[1]) #------ loop start vertex ------------- d_points = temp_points #-----vertex.list without "double.vertices" - #print 'deb:d_pointsList =after DV-outsorting=====:\n ', d_points #------------------------ + #print 'deb:drawPoly2d d_pointsList =after DV-outsorting=====:\n ', d_points #------------------------ - #print 'deb:len of d_pointsList ====== ', len(d_points) #------------------------ - if len(d_points) < 2: + #print 'deb:drawPoly2d len of d_pointsList ====== ', len(d_points) #------------------------ + if len(d_points) < 2: #if too few vertex, then return #print 'deb:drawPoly2d corrupted Vertices' #--------- return - #analyse of straight- and bulge-segments (generation of additional points for bulge) - exist_wide_segment = False + # analyze of straight- and bulge-segments + # generation of additional points for bulge segments + arc_res = settings.var['arc_res']/sqrt(settings.var['arc_rad']) + wide_segment_exist = False + bulg_points = [] # for each point set None (or center for arc-subPoints) for i in xrange(len(d_points)-1): point1 = d_points[i] point2 = d_points[i+1] - #print 'deb:pline.tocalc.point1:', point1 #------------------------ - #print 'deb:pline.tocalc.point2:', point2 #------------------------ + #print 'deb:drawPoly2d_bulg tocalc.point1:', point1 #------------------------ + #print 'deb:drawPoly2d_bulg tocalc.point2:', point2 #------------------------ swidth = point1.swidth ewidth = point1.ewidth if swidth == None: swidth = swidth_default if ewidth == None: ewidth = ewidth_default - - if swidth != 0.0 or ewidth != 0.0: exist_wide_segment = True + if swidth != 0.0 or ewidth != 0.0: wide_segment_exist = True if settings.var['width_force']: # force minimal width for thin segments - if swidth < settings.var['width_min']: swidth = settings.var['width_min'] - if ewidth < settings.var['width_min']: ewidth = settings.var['width_min'] + width_min = settings.var['width_min'] + if swidth < width_min: swidth = width_min + if ewidth < width_min: ewidth = width_min if not settings.var['width_on']: # then force minimal width for all segments - swidth = settings.var['width_min'] - ewidth = settings.var['width_min'] + swidth = width_min + ewidth = width_min - if point1.bulge and (i < (len(d_points)-2) or self.closed): - arc_res = settings.var['arc_res']/sqrt(settings.var['arc_rad']) - verts = drawBulge(point1, point2, arc_res) #calculate additional points for bulge + #if point1.bulge and (i < (len(d_points)-1) or self.closed): + if point1.bulge and i < (len(d_points)-1): #10_b8 + verts, center = calcBulge(point1, point2, arc_res) #calculate additional points for bulge points.extend(verts) delta_width = (ewidth - swidth) / len(verts) width_list = [swidth + (delta_width * ii) for ii in xrange(len(verts)+1)] - swidths.extend(width_list[0:-1]) + swidths.extend(width_list[:-1]) ewidths.extend(width_list[1:]) + bulg_list = [center for ii in xrange(len(verts))] + #the last point in bulge has index False for better indexing of bulg_end! + bulg_list[-1] = None + bulg_points.extend(bulg_list) + else: points.append(point1.loc) swidths.append(swidth) ewidths.append(ewidth) + bulg_points.append(None) + points.append(d_points[-1].loc) #--calculate width_vectors: left-side- and right-side-points ---------------- # 1.level:IF width --------------------------------------- - if (settings.var['width_on'] and exist_wide_segment) or settings.var['width_force']: - points.append(d_points[0].loc) #temporarly add first vertex at the end (for better loop) - + if (settings.var['width_on'] and wide_segment_exist) or settings.var['width_force']: + #new_b8 points.append(d_points[0].loc) #temporarly add first vertex at the end (for better loop) + dist_min05 = 0.5 * settings.var['dist_min'] #minimal width for zero_witdh + pointsLs = [] # list of left-start-points pointsLe = [] # list of left-end-points pointsRs = [] # list of right-start-points pointsRe = [] # list of right-end-points - pointsW = [] # list of entire-border-points + pointsW = [] # list of all border-points #rotMatr90 = Mathutils.Matrix(rotate 90 degree around Z-axis) = normalvectorXY rotMatr90 = Mathutils.Matrix([0, -1, 0], [1, 0, 0], [0, 0, 1]) + bulg_in = False + last_bulg_point = False for i in xrange(len(points)-1): point1 = points[i] point2 = points[i+1] @@ -1266,92 +1440,205 @@ class Polyline: #-------------------------------------------------------------- point2vec = Mathutils.Vector(point2) swidth05 = swidths[i] * 0.5 ewidth05 = ewidths[i] * 0.5 - if swidth05 == 0: swidth05 = 0.5 * settings.var['dist_min'] #minimal width - if ewidth05 == 0: ewidth05 = 0.5 * settings.var['dist_min'] #minimal width - + if swidth05 == 0: swidth05 = dist_min05 + if ewidth05 == 0: ewidth05 = dist_min05 normal_vector = rotMatr90 * (point2vec-point1vec).normalize() - swidth05vec = swidth05 * normal_vector - ewidth05vec = ewidth05 * normal_vector - pointsLs.append(point1vec + swidth05vec) #vertex left start - pointsRs.append(point1vec - swidth05vec) #vertex right start - pointsLe.append(point2vec + ewidth05vec) #vertex left end - pointsRe.append(point2vec - ewidth05vec) #vertex right end + if last_bulg_point: + last_bulg_point = False + bulg_in = True + elif bulg_points[i] != None: + centerVec = Mathutils.Vector(bulg_points[i]) + if bulg_points[i+1] == None: last_bulg_point = True + bulg_in = True + else: bulg_in = False - pointsLc, pointsRc = [], [] + if bulg_in: + #makes clean intersections for arc-segments + radius1vec = point1vec - centerVec + radius2vec = point2vec - centerVec + angle = Mathutils.AngleBetweenVecs(normal_vector, radius1vec) + if angle < 90.0: + normal_vector1 = radius1vec.normalize() + normal_vector2 = radius2vec.normalize() + else: + normal_vector1 = - radius1vec.normalize() + normal_vector2 = - radius2vec.normalize() - # 2.level:IF width and corner-intersection activated - if settings.var['pl_section_on']: #optional clean corner-intersections + swidth05vec = swidth05 * normal_vector1 + ewidth05vec = ewidth05 * normal_vector2 + pointsLs.append(point1vec + swidth05vec) #vertex left start + pointsRs.append(point1vec - swidth05vec) #vertex right start + pointsLe.append(point2vec + ewidth05vec) #vertex left end + pointsRe.append(point2vec - ewidth05vec) #vertex right end + + else: + swidth05vec = swidth05 * normal_vector + ewidth05vec = ewidth05 * normal_vector + pointsLs.append(point1vec + swidth05vec) #vertex left start + pointsRs.append(point1vec - swidth05vec) #vertex right start + pointsLe.append(point2vec + ewidth05vec) #vertex left end + pointsRe.append(point2vec - ewidth05vec) #vertex right end + + # additional last point is also calculated + #pointsLs.append(pointsLs[0]) + #pointsRs.append(pointsRs[0]) + #pointsLe.append(pointsLe[0]) + #pointsRe.append(pointsRe[0]) + + pointsLc, pointsRc = [], [] # lists Left/Right corners = intersection points + + # 2.level:IF width and corner-trim + if settings.var['pl_trim_on']: #optional clean corner-intersections + # loop preset + # set STARTpoints of the first point points[0] if not self.closed: pointsLc.append(pointsLs[0]) pointsRc.append(pointsRs[0]) - lenL = len(pointsLs)-2 #without the last point at the end of the list else: pointsLs.append(pointsLs[0]) pointsRs.append(pointsRs[0]) pointsLe.append(pointsLe[0]) pointsRe.append(pointsRe[0]) points.append(points[0]) - lenL = len(pointsLs)-1 #without the duplic of the first point at the end of the list - #print 'deb:pointsLs():\n', pointsLs #---------------- - #print 'deb:lenL, len.pointsLs():', lenL,',', len(pointsLs) #---------------- + vecL3, vecL4 = pointsLs[0], pointsLe[0] + vecR3, vecR4 = pointsRs[0], pointsRe[0] + lenL = len(pointsLs)-1 + #print 'deb:drawPoly2d pointsLs():\n', pointsLs #---------------- + #print 'deb:drawPoly2d lenL, len.pointsLs():', lenL,',', len(pointsLs) #---------------- + bulg_in = False + last_bulg_point = False + + # LOOP: makes (ENDpoints[i],STARTpoints[i+1]) for i in xrange(lenL): - pointVec = Mathutils.Vector(points[i+1]) - #print 'deb:pointVec: ', pointVec #------------- - #compute left-corner-points - vecL1 = pointsLs[i] - vecL2 = pointsLe[i] - vecL3 = pointsLs[i+1] - vecL4 = pointsLe[i+1] - #print 'deb:vectorsL:---------\n', vecL1,'\n',vecL2,'\n',vecL3,'\n',vecL4 #------------- + if bulg_points[i] != None: + if bulg_points[i+1] == None: #makes clean intersections for arc-segments + last_bulg_point = True + if not bulg_in: + bulg_in = True + #pointsLc.extend((points[i], pointsLs[i])) + #pointsRc.extend((points[i], pointsRs[i])) + vecL1, vecL2 = vecL3, vecL4 + vecR1, vecR2 = vecR3, vecR4 + vecL3, vecL4 = pointsLs[i+1], pointsLe[i+1] + vecR3, vecR4 = pointsRs[i+1], pointsRe[i+1] + #compute left- and right-cornerpoints #cornerpointL = Geometry.LineIntersect2D(vec1, vec2, vec3, vec4) cornerpointL = Mathutils.LineIntersect(vecL1, vecL2, vecL3, vecL4) - #print 'deb:cornerpointL: ', cornerpointL #------------- - - #compute right-corner-points - vecR1 = pointsRs[i] - vecR2 = pointsRe[i] - vecR3 = pointsRs[i+1] - vecR4 = pointsRe[i+1] - #print 'deb:vectorsR:---------\n', vecR1,'\n',vecR2,'\n',vecR3,'\n',vecR4 #------------- - #cornerpointR = Geometry.LineIntersect2D(vec1, vec2, vec3, vec4) cornerpointR = Mathutils.LineIntersect(vecR1, vecR2, vecR3, vecR4) - #print 'deb:cornerpointR: ', cornerpointR #------------- + #print 'deb:drawPoly2d cornerpointL: ', cornerpointL #------------- + #print 'deb:drawPoly2d cornerpointR: ', cornerpointR #------------- - #if diststance(cornerL-center-cornerR) < limiter * (seg1_endWidth + seg2_startWidth) - if cornerpointL != None and cornerpointR != None: - cornerpointL = cornerpointL[0] + # IF not cornerpoint THEN check if identic start-endpoints (=collinear segments) + if cornerpointL == None or cornerpointR == None: + if vecL2 == vecL3 and vecR2 == vecR3: + #print 'deb:drawPoly2d pointVec: ####### identic ##########' #---------------- + pointsLc.append(pointsLe[i]) + pointsRc.append(pointsRe[i]) + else: + pointsLc.extend((pointsLe[i],points[i+1],pointsLs[i+1])) + pointsRc.extend((pointsRe[i],points[i+1],pointsRs[i+1])) + else: + cornerpointL = cornerpointL[0] # because Mathutils.LineIntersect() -> (pkt1,pkt2) cornerpointR = cornerpointR[0] + #print 'deb:drawPoly2d cornerpointL: ', cornerpointL #------------- + #print 'deb:drawPoly2d cornerpointR: ', cornerpointR #------------- + pointVec0 = Mathutils.Vector(points[i]) + pointVec = Mathutils.Vector(points[i+1]) + pointVec2 = Mathutils.Vector(points[i+2]) + #print 'deb:drawPoly2d pointVec0: ', pointVec0 #------------- + #print 'deb:drawPoly2d pointVec: ', pointVec #------------- + #print 'deb:drawPoly2d pointVec2: ', pointVec2 #------------- + # if diststance(cornerL-center-cornerR) < limiter * (seg1_endWidth + seg2_startWidth) max_cornerDist = (vecL2 - vecR2).length + (vecL3 - vecR3).length is_cornerDist = (cornerpointL - pointVec).length + (cornerpointR - pointVec).length - # anglecut --------- limited by ANGLECUT_LIMIT (1.0 - 5.0) - if is_cornerDist < max_cornerDist * settings.var['angle_cut']: + #corner_angle = Mathutils.AngleBetweenVecs((pointVec0 - pointVec),(pointVec - pointVec2)) + #print 'deb:drawPoly2d corner_angle: ', corner_angle #------------- + #print 'deb:drawPoly2d max_cornerDist, is_cornerDist: ', max_cornerDist, is_cornerDist #------------- + #if abs(corner_angle) < 90.0: + # intersection --------- limited by TRIM_LIMIT (1.0 - 5.0) + if is_cornerDist < max_cornerDist * settings.var['pl_trim_max']: + # clean corner intersection pointsLc.append(cornerpointL) pointsRc.append(cornerpointR) - else: + elif False: # the standard no-intersection + # --todo-- not optimal, because produces X-face pointsLc.extend((pointsLe[i],pointsLs[i+1])) pointsRc.extend((pointsRe[i],pointsRs[i+1])) - else: - pointsLc.extend((pointsLe[i],pointsLs[i+1])) - pointsRc.extend((pointsRe[i],pointsRs[i+1])) + elif False: # --todo-- the optimised non-intersection + if (cornerpointL - vecL1).length < (cornerpointR - vecR1).length: + left_angle = True + else: + left_angle = False + limit_dist = settings.var['dist_min'] + if left_angle: # if left turning angle + print 'deb:drawPoly2d it is left turning angle' #------------- + # to avoid triangelface/doubleVertex + delta1 = (cornerpointL - vecL1).normalize() * limit_dist + delta4 = (cornerpointL - vecL4).normalize() * limit_dist + pointsLc.extend((cornerpointL - delta1, cornerpointL - delta4)) + pointsRc.extend((pointsRe[i],pointsRs[i+1])) + else: # if right turning angle + print 'deb:drawPoly2d right turning angle' #------------- + delta1 = (cornerpointR - vecR1).normalize() * limit_dist + delta4 = (cornerpointR - vecR4).normalize() * limit_dist + pointsRc.extend((cornerpointR - delta1, cornerpointR - delta4)) + pointsLc.extend((pointsLe[i],pointsLs[i+1])) + else: + pointsLc.extend((pointsLe[i],points[i+1],pointsLs[i+1])) + pointsRc.extend((pointsRe[i],points[i+1],pointsRs[i+1])) if not self.closed: - pointsLc.append(pointsLe[-2]) - pointsRc.append(pointsRe[-2]) - else: - """ """ + pointsLc.append(pointsLe[-1]) + pointsRc.append(pointsRe[-1]) - # 2.level:IF width but not corner-intersection activated + # 2.level:IF width but no-trim else: - # points_multiplexer of start-points and end-points - lenL = len(pointsLs) - 1 #without the duplic of the first point at the end of list - if self.closed: lenL += 1 #inclusive the duplic of the first point at the end of list - for i in xrange(lenL): - pointsLc.extend((pointsLs[i], pointsLe[i])) - pointsRc.extend((pointsRs[i], pointsRe[i])) + # loop preset + # set STARTpoints of the first point points[0] + if not self.closed: + pointsLc.append(pointsLs[0]) + pointsRc.append(pointsRs[0]) + else: + pointsLs.append(pointsLs[0]) + pointsRs.append(pointsRs[0]) + pointsLe.append(pointsLe[0]) + pointsRe.append(pointsRe[0]) + points.append(points[0]) + vecL3, vecL4 = pointsLs[0], pointsLe[0] + vecR3, vecR4 = pointsRs[0], pointsRe[0] + lenL = len(pointsLs)-1 + #print 'deb:drawPoly2d pointsLs():\n', pointsLs #---------------- + #print 'deb:drawPoly2d lenL, len.pointsLs():', lenL,',', len(pointsLs) #---------------- + bulg_in = False + last_bulg_point = False + # LOOP: makes (ENDpoints[i],STARTpoints[i+1]) + for i in xrange(lenL): + vecL1, vecL2 = vecL3, vecL4 + vecR1, vecR2 = vecR3, vecR4 + vecL3, vecL4 = pointsLs[i+1], pointsLe[i+1] + vecR3, vecR4 = pointsRs[i+1], pointsRe[i+1] + if bulg_points[i] != None: + #compute left- and right-cornerpoints + if True: + cornerpointL = Mathutils.LineIntersect(vecL1, vecL2, vecL3, vecL4) + cornerpointR = Mathutils.LineIntersect(vecR1, vecR2, vecR3, vecR4) + pointsLc.append(cornerpointL[0]) + pointsRc.append(cornerpointR[0]) + else: + pointVec = Mathutils.Vector(point[i]) + + else: # IF non-bulg + pointsLc.extend((pointsLe[i],points[i+1],pointsLs[i+1])) + pointsRc.extend((pointsRe[i],points[i+1],pointsRs[i+1])) + if not self.closed: + pointsLc.append(pointsLe[-1]) + pointsRc.append(pointsRe[-1]) + + len1 = len(pointsLc) + #print 'deb:drawPoly2d len1:', len1 #----------------------- + #print 'deb:drawPoly2d len1 len(pointsLc),len(pointsRc):', len(pointsLc),len(pointsRc) #----------------------- pointsW = pointsLc + pointsRc # all_points_List = left_side + right_side - #print 'deb:pointsW():\n', pointsW #---------------- - len1 = int(len(pointsW) * 0.5) - #print 'deb:len1:', len1 #----------------------- + #print 'deb:drawPoly2d pointsW():\n', pointsW #---------------- # 2.level:IF width and thickness --------------------- if thic != 0: @@ -1378,7 +1665,7 @@ class Polyline: #-------------------------------------------------------------- f_start = [[0, len1, len1+len1+len1, len1+len1]] f_end = [[len1+len1-1, 0+len1-1, len1+len1+len1-1, len1+len1+len1+len1-1]] - faces = f_bottom + f_top + f_left + f_right + f_start + f_end + faces = f_left + f_right + f_bottom + f_top + f_start + f_end #faces = f_bottom + f_top #faces = f_left + f_right + f_start + f_end #print 'deb:faces_list:\n', faces #----------------------- @@ -1387,12 +1674,12 @@ class Polyline: #-------------------------------------------------------------- me.verts.extend(pointsW) # add vertices to mesh me.faces.extend(faces) # add faces to the mesh - # each MeshSite becomes vertexGroup for easier material assignment --------------------- + # each MeshSide becomes vertexGroup for easier material assignment --------------------- # The mesh must first be linked to an object so the method knows which object to update. # This is because vertex groups in Blender are stored in the object -- not in the mesh, # which may be linked to more than one object. if settings.var['vGroup_on']: - # each MeshSite becomes vertexGroup for easier material assignment --------------------- + # each MeshSide becomes vertexGroup for easier material assignment --------------------- replace = Blender.Mesh.AssignModes.REPLACE #or .AssignModes.ADD vg_left, vg_right, vg_top, vg_bottom = [], [], [], [] for v in f_left: vg_left.extend(v) @@ -1407,6 +1694,13 @@ class Polyline: #-------------------------------------------------------------- me.addVertGroup('side.start'); me.assignVertsToGroup('side.start', f_start[0], 1.0, replace) me.addVertGroup('side.end') ; me.assignVertsToGroup('side.end', f_end[0], 1.0, replace) + if settings.var['meshSmooth_on']: # left and right side become smooth ---------------------- + #if self.spline or self.curved: + if True: + smooth_len = len(f_left) + len(f_right) + for i in xrange(smooth_len): + me.faces[i].smooth = True + #me.Modes(AUTOSMOOTH) # 2.level:IF width, but no-thickness --------------------- else: @@ -1439,6 +1733,13 @@ class Polyline: #-------------------------------------------------------------- me.verts.extend(points) # add vertices to mesh me.faces.extend(faces) # add faces to the mesh + if settings.var['meshSmooth_on']: # left and right side become smooth ---------------------- + #if self.spline or self.curved: + if True: + for i in xrange(len(faces)): + me.faces[i].smooth = True + #me.Modes(AUTOSMOOTH) + # 1.level:IF no-width and no-thickness --------------------- else: edges = [[num, num+1] for num in xrange(len(points)-1)] @@ -1457,7 +1758,7 @@ class Polyline: #-------------------------------------------------------------- class Vertex(object): #----------------------------------------------------------------- - """Generic vertex object used by polylines (and maybe others). + """Generic vertex object used by POLYLINEs (and maybe others). """ def __init__(self, obj=None): @@ -1570,7 +1871,7 @@ class Vertex(object): #-------------------------------------------------------- class Text: #----------------------------------------------------------------- - """Class for objects representing dxf Text. + """Class for objects representing dxf TEXT. """ def __init__(self, obj): """Expects an entity object of type text as input. @@ -1705,7 +2006,7 @@ def set_thick(thickness, settings): if settings.var['thick_force']: if settings.var['thick_on']: if abs(thickness) < settings.var['thick_min']: - thic = settings.var['thick_min'] * cmp(self.thic,0) + thic = settings.var['thick_min'] * cmp(thickness,0) else: thic = thickness else: thic = settings.var['thick_min'] else: @@ -1717,7 +2018,7 @@ def set_thick(thickness, settings): class Mtext: #----------------------------------------------------------------- - """Class for objects representing dxf Mtext. + """Class for objects representing dxf MTEXT. """ def __init__(self, obj): @@ -1816,7 +2117,7 @@ class Mtext: #----------------------------------------------------------------- class Circle: #----------------------------------------------------------------- - """Class for objects representing dxf Circles. + """Class for objects representing dxf CIRCLEs. """ def __init__(self, obj): @@ -1867,28 +2168,56 @@ class Circle: #---------------------------------------------------------------- thic = set_thick(self.thic, settings) if settings.var['curves_on']: - c = Curve.New(obname) # create new curve data - p1 = (0, -radius, 0) - p2 = (radius, 0, 0) - p3 = (0, radius, 0) - p4 = (-radius, 0, 0) + if False: # universal version + arc_res = 4 # ONLY 4 works well for point.handleTypes = [AUTO, AUTO] + start, end = 0.0, 360.0 + verts = calcArc(None, radius, start, end, arc_res, True) + c = Curve.New(obname) # create new curve data + curve = c.appendNurb(BezTriple.New(verts[0])) + for p in verts[1:-1]: + curve.append(BezTriple.New(p)) + for point in curve: + point.handleTypes = [AUTO, AUTO] + elif True: # universal version + arc_res = settings.var['curve_arc'] + #arc_res = 3 + start, end = 0.0, 360.0 + VectorTriples = calcArc(None, radius, start, end, arc_res, True) + c = Curve.New(obname) # create new curve data + curve = c.appendNurb(BezTriple.New(VectorTriples[0])) + for p in VectorTriples[1:-1]: + curve.append(BezTriple.New(p)) + for point in curve: + point.handleTypes = [FREE, FREE] + else: # standard version + c = Curve.New(obname) # create new curve data + p1 = (0, -radius, 0) + p2 = (radius, 0, 0) + p3 = (0, radius, 0) + p4 = (-radius, 0, 0) + + p1 = BezTriple.New(p1) + p2 = BezTriple.New(p2) + p3 = BezTriple.New(p3) + p4 = BezTriple.New(p4) + + curve = c.appendNurb(p1) + curve.append(p2) + curve.append(p3) + curve.append(p4) + for point in curve: + point.handleTypes = [AUTO, AUTO] - p1 = BezTriple.New(p1) - p2 = BezTriple.New(p2) - p3 = BezTriple.New(p3) - p4 = BezTriple.New(p4) + curve.flagU = 1 # 1 sets the curve cyclic=closed + if settings.var['fill_on']: + c.setFlag(6) # 2+4 set top and button caps + else: + c.setFlag(c.getFlag() & ~6) # dont set top and button caps - curve = c.appendNurb(p1) - curve.append(p2) - curve.append(p3) - curve.append(p4) - for point in curve: - point.handleTypes = [AUTO, AUTO] - curve.flagU = 1 # Set curve cyclic=closed c.update() #remi --todo-----to check--------------------------- - ob = SCENE.objects.new(c) # create a new circle_mesh_object + ob = SCENE.objects.new(c) # create a new curve_object ob.loc = tuple(self.loc) if thic != 0.0: #hack: Blender<2.45 curve-extrusion thic = thic * 0.5 @@ -1899,7 +2228,7 @@ class Circle: #---------------------------------------------------------------- ob.SizeZ *= abs(thic) return ob - elif False: + elif False: # create a new mesh_object with buildin_circle_primitive verts_num = settings.var['arc_res'] * sqrt(radius / settings.var['arc_rad']) if verts_num > 100: verts_num = 100 # Blender accepts only values [3:500] if verts_num < 4: verts_num = 4 # Blender accepts only values [3:500] @@ -1917,17 +2246,15 @@ class Circle: #---------------------------------------------------------------- transform(self.extrusion, 0, ob) return ob - else: + else: # draw CIRCLE as mesh ----------------------------------------------- cir = Mesh.New(obname) # create a new mesh - ob = SCENE.objects.new(cir) # create a new arc_object + ob = SCENE.objects.new(cir) # create a new circle_object # set a number of segments in entire circle arc_res = settings.var['arc_res'] * sqrt(radius) / sqrt(settings.var['arc_rad']) start, end = 0.0 , 360.0 - verts, edges = drawArc(None, radius, start, end, arc_res) - verts = verts[:-2] #list without last point (cause first piont equal) - edges = edges[:-1] - edges[-1][1] = 0 - print 'deb:edges:', edges #remi-todo----- why is this List inhomogene ? ---------- + verts = calcArc(None, radius, start, end, arc_res, False) + verts = verts[:-1] #list without last point/edge (cause by circle it is equal to the first point) + #print 'deb:circleDraw:edges:', edges #--------------- if thic != 0: len1 = len(verts) thic_verts = [] @@ -1938,8 +2265,11 @@ class Circle: #---------------------------------------------------------------- else: verts.extend(thic_verts) faces = [] - faces = [[num, num+1, num+len1+1, num+len1] for num in xrange(len1 - 1)] - faces.append([len1 - 1, 0, len1, len1 + len1 -1]) + f_band = [[num, num+1, num+len1+1, num+len1] for num in xrange(len1 - 1)] + #f_band = [[num, num+1, num+len1+1, num+len1] for num in xrange(len1)] + f_band.append([len1 - 1, 0, len1, len1 + len1 -1]) + faces = f_band + smooth_len = len(f_band) if settings.var['fill_on']: if thic < 0.0: verts.append([0,0,thic]) #center of top side @@ -1949,17 +2279,49 @@ class Circle: #---------------------------------------------------------------- verts.append([0,0,thic]) #center of top side center1 = len(verts)-2 center2 = len(verts)-1 - faces.extend([num+1, num, center1] for num in xrange(len1 - 1)) - faces.append([0, len1 - 1, center1]) - faces.extend([num+len1, num+1+len1, center2] for num in xrange(len1 - 1)) - faces.append([len1-1+len1, 0+len1, center2]) - #print 'deb:verts:', verts #--------------- - #print 'deb:faces:', faces #--------------- + f_bottom = [[num+1, num, center1] for num in xrange(len1 - 1)] + f_bottom.append([0, len1 - 1, center1]) + f_top = [[num+len1, num+1+len1, center2] for num in xrange(len1 - 1)] + f_top.append([len1-1+len1, 0+len1, center2]) + #print 'deb:circleDraw:verts:', verts #--------------- + faces = f_band + f_bottom + f_top + #print 'deb:circleDraw:faces:', faces #--------------- cir.verts.extend(verts) # add vertices to mesh cir.faces.extend(faces) # add faces to the mesh - else: - cir.verts.extend(verts) # add vertices to mesh - cir.edges.extend(edges) # add edges to the mesh + + if settings.var['meshSmooth_on']: # left and right side become smooth ---------------------- + for i in xrange(smooth_len): + cir.faces[i].smooth = True + # each MeshSide becomes vertexGroup for easier material assignment --------------------- + if settings.var['vGroup_on']: + # each MeshSide becomes vertexGroup for easier material assignment --------------------- + replace = Blender.Mesh.AssignModes.REPLACE #or .AssignModes.ADD + vg_band, vg_top, vg_bottom = [], [], [] + for v in f_band: vg_band.extend(v) + cir.addVertGroup('side.band') ; cir.assignVertsToGroup('side.band', list(set(vg_band)), 1.0, replace) + if settings.var['fill_on']: + for v in f_top: vg_top.extend(v) + for v in f_bottom: vg_bottom.extend(v) + cir.addVertGroup('side.top') ; cir.assignVertsToGroup('side.top', list(set(vg_top)), 1.0, replace) + cir.addVertGroup('side.bottom'); cir.assignVertsToGroup('side.bottom',list(set(vg_bottom)), 1.0, replace) + + else: # if thic == 0 + if settings.var['fill_on']: + len1 = len(verts) + verts.append([0,0,0]) #center of circle + center1 = len1 + faces = [] + faces.extend([[num, num+1, center1] for num in xrange(len1)]) + faces.append([len1-1, 0, center1]) + #print 'deb:circleDraw:verts:', verts #--------------- + #print 'deb:circleDraw:faces:', faces #--------------- + cir.verts.extend(verts) # add vertices to mesh + cir.faces.extend(faces) # add faces to the mesh + else: + cir.verts.extend(verts) # add vertices to mesh + edges = [[num, num+1] for num in xrange(len(verts))] + edges[-1][1] = 0 # it points the "new" last edge to the first vertex + cir.edges.extend(edges) # add edges to the mesh ob.loc = tuple(self.loc) transform(self.extrusion, 0, ob) @@ -1969,7 +2331,7 @@ class Circle: #---------------------------------------------------------------- class Arc: #----------------------------------------------------------------- - """Class for objects representing dxf arcs. + """Class for objects representing dxf ARCs. """ def __init__(self, obj): @@ -1993,6 +2355,7 @@ class Arc: #----------------------------------------------------------------- self.layer = getit(obj.data, 8, None) self.loc = self.get_loc(obj.data) self.extrusion = get_extrusion(obj.data) + #print 'deb:Arc__init__: center, radius, start, end:\n', self.loc, self.radius, self.start_angle, self.end_angle #--------- @@ -2023,44 +2386,126 @@ class Arc: #----------------------------------------------------------------- radius = self.radius start = self.start_angle end = self.end_angle - #print 'deb:drawArc: center, radius, start, end:\n', center, radius, start, end #--------- + #print 'deb:calcArcPoints:\n center, radius, start, end:\n', center, radius, start, end #--------- thic = set_thick(self.thic, settings) + width = 0.0 + if settings.var['lines_as'] == 4: # as thin_box + thic = settings.var['thick_min'] + width = settings.var['width_min'] + if settings.var['lines_as'] == 3: # as thin cylinder + cyl_rad = 0.5 * settings.var['width_min'] - if settings.var['curves_on']: - arc_res = 8 - verts, edges = drawArc(None, radius, start, end, arc_res) + if settings.var['curves_on']: # draw ARC as curve ------------- + arc_res = settings.var['curve_arc'] + triples = True + VectorTriples = calcArc(None, radius, start, end, arc_res, triples) arc = Curve.New(obname) # create new curve data - curve = arc.appendNurb(BezTriple.New(verts[0])) - for p in verts[1:]: + curve = arc.appendNurb(BezTriple.New(VectorTriples[0])) + for p in VectorTriples[1:]: curve.append(BezTriple.New(p)) for point in curve: - point.handleTypes = [AUTO, AUTO] - #print 'deb:arc.draw point=', point #--------------- - curve[0].handleTypes = [FREE, VECT] #remi--todo----- - curve[-1].handleTypes = [VECT, FREE] #remi--todo----- - curve.flagU = 0 # Set curve not cyclic=open - arc.update() + point.handleTypes = [FREE, FREE] + curve.flagU = 0 # 0 sets the curve not cyclic=open + arc.update() #important for handles calculation - #remi --todo-----to check--------------------------- - ob = SCENE.objects.new(arc) # create a new circle_mesh_object + ob = SCENE.objects.new(arc) # create a new curve_object ob.loc = tuple(self.loc) if thic != 0.0: #hack: Blender<2.45 curve-extrusion thic = thic * 0.5 - arc.setExt1(1.0) # curve-extrusion accepts only (0.0 - 2.0) + arc.setExt1(1.0) # curve-extrusion: Blender2.45 accepts only (0.0 - 5.0) ob.LocZ = thic + self.loc[2] transform(self.extrusion, 0, ob) if thic != 0.0: ob.SizeZ *= abs(thic) return ob - else: + else: # draw ARC as mesh -------------------- arc = Mesh.New(obname) # create a new mesh ob = SCENE.objects.new(arc) # create a new arc_object # set a number of segments in entire circle arc_res = settings.var['arc_res'] * sqrt(radius) / sqrt(settings.var['arc_rad']) - verts, edges = drawArc(None, radius, start, end, arc_res) - if thic != 0: - len1 = len(verts) + + verts = calcArc(None, radius, start, end, arc_res, False) + #verts = [list(point) for point in verts] + len1 = len(verts) + #print 'deb:len1:', len1 #----------------------- + if width != 0: + if False: + radius_out = radius + (0.5 * width) + radius_in = radius - (0.5 * width) + if radius_in <= 0.0: + radius_in = settings.var['dist_min'] + #radius_in = 0.0 + verts_in = [] + verts_out = [] + for point in verts: + pointVec = Mathutils.Vector(point) + pointVec = pointVec.normalize() + verts_in.append(list(radius_in * pointVec)) #vertex inside + verts_out.append(list(radius_out * pointVec)) #vertex outside + verts = verts_in + verts_out + else: + radius_out = radius + (0.5 * width) + radius_in = radius - (0.5 * width) + if radius_in <= 0.0: + radius_in = settings.var['dist_min'] + #radius_in = 0.0 + verts_in = [] + verts_out = [] + for point in verts: + pointVec = Mathutils.Vector(point) + pointVec = pointVec.normalize() + verts_in.append(list(radius_in * pointVec)) #vertex inside + verts_out.append(list(radius_out * pointVec)) #vertex outside + verts = verts_in + verts_out + + #print 'deb:verts:', verts #--------------------- + if thic != 0: + thic_verts = [] + thic_verts.extend([[point[0], point[1], point[2]+thic] for point in verts]) + if thic < 0.0: + thic_verts.extend(verts) + verts = thic_verts + else: + verts.extend(thic_verts) + f_bottom = [[num, num+1, len1+num+1, len1+num] for num in xrange(len1-1)] + f_top = [[num, len1+num, len1+num+1, num+1] for num in xrange(len1+len1, len1+len1+len1-1)] + f_left = [[num, len1+len1+num, len1+len1+num+1, num+1] for num in xrange(len1-1)] + f_right = [[num, num+1, len1+len1+num+1, len1+len1+num] for num in xrange(len1, len1+len1-1)] + f_start = [[0, len1, len1+len1+len1, len1+len1]] + f_end = [[len1+len1-1, 0+len1-1, len1+len1+len1-1, len1+len1+len1+len1-1]] + faces = f_left + f_right + f_bottom + f_top + f_start + f_end + + arc.verts.extend(verts) # add vertices to mesh + arc.faces.extend(faces) # add faces to the mesh + + if settings.var['meshSmooth_on']: # left and right side become smooth ---------------------- + smooth_len = len(f_left) + len(f_right) + for i in xrange(smooth_len): + arc.faces[i].smooth = True + # each MeshSide becomes vertexGroup for easier material assignment --------------------- + if settings.var['vGroup_on']: + # each MeshSide becomes vertexGroup for easier material assignment --------------------- + replace = Blender.Mesh.AssignModes.REPLACE #or .AssignModes.ADD + vg_left, vg_right, vg_top, vg_bottom = [], [], [], [] + for v in f_left: vg_left.extend(v) + for v in f_right: vg_right.extend(v) + for v in f_top: vg_top.extend(v) + for v in f_bottom: vg_bottom.extend(v) + arc.addVertGroup('side.left') ; arc.assignVertsToGroup('side.left', list(set(vg_left)), 1.0, replace) + arc.addVertGroup('side.right') ; arc.assignVertsToGroup('side.right', list(set(vg_right)), 1.0, replace) + arc.addVertGroup('side.top') ; arc.assignVertsToGroup('side.top', list(set(vg_top)), 1.0, replace) + arc.addVertGroup('side.bottom'); arc.assignVertsToGroup('side.bottom',list(set(vg_bottom)), 1.0, replace) + arc.addVertGroup('side.start'); arc.assignVertsToGroup('side.start', f_start[0], 1.0, replace) + arc.addVertGroup('side.end') ; arc.assignVertsToGroup('side.end', f_end[0], 1.0, replace) + + + else: # if thick=0 - draw only flat ring + faces = [[num, len1+num, len1+num+1, num+1] for num in xrange(len1 - 1)] + arc.verts.extend(verts) # add vertices to mesh + arc.faces.extend(faces) # add faces to the mesh + + elif thic != 0: thic_verts = [] thic_verts.extend([[point[0], point[1], point[2]+thic] for point in verts]) if thic < 0.0: @@ -2070,12 +2515,17 @@ class Arc: #----------------------------------------------------------------- verts.extend(thic_verts) faces = [] #print 'deb:len1:', len1 #----------------------- - #print 'deb:verts:', verts #remi-todo----- why is this List inhomogene ---------- + #print 'deb:verts:', verts #--------------------- faces = [[num, num+1, num+len1+1, num+len1] for num in xrange(len1 - 1)] arc.verts.extend(verts) # add vertices to mesh arc.faces.extend(faces) # add faces to the mesh + if settings.var['meshSmooth_on']: # left and right side become smooth ---------------------- + for i in xrange(len(faces)): + arc.faces[i].smooth = True + else: + edges = [[num, num+1] for num in xrange(len(verts)-1)] arc.verts.extend(verts) # add vertices to mesh arc.edges.extend(edges) # add edges to the mesh @@ -2124,7 +2574,7 @@ class BlockRecord: #----------------------------------------------------------- class Block: #----------------------------------------------------------------- - """Class for objects representing dxf blocks. + """Class for objects representing dxf BLOCKs. """ def __init__(self, obj): @@ -2166,7 +2616,7 @@ class Block: #----------------------------------------------------------------- class Insert: #----------------------------------------------------------------- - """Class for objects representing dxf inserts. + """Class for objects representing dxf INSERTs. """ def __init__(self, obj): @@ -2194,7 +2644,7 @@ class Insert: #---------------------------------------------------------------- def get_loc(self, data): - """Gets the center location for block type objects. + """Gets the origin location of the insert. """ loc = [0, 0, 0] loc[0] = getit(data, 10, 0.0) @@ -2205,7 +2655,7 @@ class Insert: #---------------------------------------------------------------- def get_scale(self, data): - """Gets the x/y/z scale factor for the block. + """Gets the x/y/z scale factors of the insert. """ scale = [1, 1, 1] scale[0] = getit(data, 41, 1.0) @@ -2236,22 +2686,20 @@ class Insert: #---------------------------------------------------------------- Blocks are made of three objects: the block_record in the tables section the block in the blocks section - the insert object in the entities section - - block_records give the insert units, blocks provide the objects drawn in the - block, and the insert object gives the location/scale/rotation of the block - instances. To draw a block you must first get a group with all the - blocks entities drawn in it, then scale the entities to match the world - units, then dupligroup that data to an object matching each insert object. + the insert object (one or more) in the entities section + block_record gives the insert units, + block provides the objects drawn in the block, + insert object gives the location/scale/rotation of the block instances. """ - obname = 'in_%s' %self.blockname # create object name from block name - obname = obname[:MAX_NAMELENGTH] + obname = settings.blocknamesmap[self.blockname] + obname = 'in_%s' %obname # create object name from block name + #obname = obname[:MAX_NAMELENGTH] if settings.drawTypes['insert']: #if insert_drawType activated ob = SCENE.objects.new('Empty', obname) # create a new empty_object empty_size = 1.0 * settings.var['g_scale'] - if empty_size < 0.01: empty_size = 0.01 + if empty_size < 0.01: empty_size = 0.01 #Blender limits (0.01-10.0) elif empty_size > 10.0: empty_size = 10.0 ob.drawSize = empty_size @@ -2274,7 +2722,7 @@ class Insert: #---------------------------------------------------------------- class Ellipse: #----------------------------------------------------------------- - """Class for objects representing dxf ellipses. + """Class for objects representing dxf ELLIPSEs. """ def __init__(self, obj): @@ -2354,8 +2802,8 @@ class Ellipse: #--------------------------------------------------------------- # set a number of segments in entire circle arc_res = settings.var['arc_res'] * sqrt(radius) / sqrt(settings.var['arc_rad']) - verts, edges = drawArc(None, radius, start, end, arc_res) - + verts = calcArc(None, radius, start, end, arc_res, False) + #verts = [list(point) for point in verts] if thic != 0: len1 = len(verts) thic_verts = [] @@ -2367,12 +2815,13 @@ class Ellipse: #--------------------------------------------------------------- verts.extend(thic_verts) faces = [] #print 'deb:len1:', len1 #----------------------- - #print 'deb:verts:', verts #remi--todo----- why is this List inhomogene? ---------- + #print 'deb:verts:', verts #---------------------- faces = [[num, num+1, num+len1+1, num+len1] for num in xrange(len1 - 1)] me.verts.extend(verts) # add vertices to mesh me.faces.extend(faces) # add faces to the mesh else: + edges = [[num, num+1] for num in xrange(len(verts)-1)] me.verts.extend(verts) # add vertices to mesh me.edges.extend(edges) # add edges to the mesh @@ -2385,7 +2834,7 @@ class Ellipse: #--------------------------------------------------------------- class Face: #----------------------------------------------------------------- - """Class for objects representing dxf 3d faces. + """Class for objects representing dxf 3DFACEs. """ def __init__(self, obj): @@ -2583,16 +3032,17 @@ class MatColors: #------------------------------------------------------------- """A smart container for dxf-color based materials. This class is a wrapper around a dictionary mapping dxf-color indicies to materials. - When called with a color index it returns a material corrisponding to that index. + When called with a color_index + it returns a material corresponding to that index. Behind the scenes it checks if that index is in its keys, and if not it creates a new material. It then adds the new index:material pair to its dict and returns the material. """ - def __init__(self, map): + def __init__(self, layersmap): """Expects a map - a dictionary mapping layer names to layers. """ - self.map = map # a dictionary of layername:layer + #self.layersmap = layersmap # a dictionary of layername:layerobject self.colMaterials = {} # a dictionary of color_index:blender_material #print 'deb:init_MatColors argument.map: ', map #------------------ @@ -2602,18 +3052,24 @@ class MatColors: #------------------------------------------------------------- If a layer name is provided, the color of that layer is used. """ - if not color: - color = 0 - if type(color) == str: - #print 'deb:color is string:--------------: ', color #--todo---bug with ARC from ARC-T0.DXF layer="T-3DARC-1"----- - try: - color = self.map[color].color + if color == None: + color = 256 # color 256=BYLAYER + if type(color) == str: # looking for color of LAYER named "color" + #--todo---bug with ARC from ARC-T0.DXF layer="T-3DARC-1"----- + #print 'deb:color is string:--------: ', color + #try: + #color = self.layersmap[color].color #print 'deb:color=self.map[color].color:', color #------------------ - except KeyError: - layer = Layer(name=color, color=0, frozen=False) - self.map[color] = layer - color = 0 - color = abs(color) + #except KeyError: + #layer = Layer(name=color, color=256, frozen=False) + #self.layersmap[color] = layer + #color = 0 + color = layersmap[color].color + if color == 0: # color 0 = BYBLOCK + #--todo-- should looking for color of paret-BLOCK + #color = layersmap[color].color + pass + color = abs(color) # cause the value could be nagative = means the layer is turned off if color not in self.colMaterials.keys(): self.add(color) return self.colMaterials[color] @@ -2622,13 +3078,13 @@ class MatColors: #------------------------------------------------------------- def add(self, color): """Create a new material 'ColorNr-N' using the provided color index-N. """ - global color_map + #global color_map #--todo-- has not to be global? mat = Material.New('ColorNr-%s' %color) mat.setRGBCol(color_map[color]) - mat.mode |= Material.Modes.SHADELESS - mat.mode |= Material.Modes.WIRE -# try: mat.setMode('Shadeless', 'Wire') #work-around for 2.45rc-bug -# except: pass + #mat.mode |= Material.Modes.SHADELESS #--todo-- + #mat.mode |= Material.Modes.WIRE +# try: mat.setMode('Shadeless', 'Wire') #work-around for 2.45rc-bug +# except: pass self.colMaterials[color] = mat @@ -2643,41 +3099,48 @@ class MatLayers: #------------------------------------------------------------- the material. """ - def __init__(self, map): + def __init__(self, layersmap): """Expects a map - a dictionary mapping layer names to layers. """ - self.map = map # a dictionary of layername:layer + #self.layersmap = layersmap # a dictionary of layername:layer self.layMaterials = {} # a dictionary of layer_name:blender_material #print 'deb:init_MatLayers argument.map: ', map #------------------ - def __call__(self, layername=None): + def __call__(self, layername=None, color=None): """Return the material associated with dxf-layer. If a dxf-layername is not provided, create a new material """ - if layername not in self.layMaterials.keys(): - self.add(layername) - return self.layMaterials[layername] + #global layernamesmap + layername_short = layername + if layername in layernamesmap.keys(): + layername_short = layernamesmap[layername] + colorlayername = str(color) + layername_short + if colorlayername not in self.layMaterials.keys(): + self.add(layername, color, colorlayername) + return self.layMaterials[colorlayername] - def add(self, layername): + def add(self, layername, color, colorlayername): """Create a new material 'layername'. """ - try: mat = Material.Get('Lay-%s' %layername) - except: mat = Material.New('Lay-%s' %layername) + try: mat = Material.Get('L-%s' %colorlayername) + except: mat = Material.New('L-%s' %colorlayername) #print 'deb:MatLayers material: ', mat #---------- - #print 'deb:MatLayers getMode: ', mat.getMode() #---------- - global layersmap - color = layersmap[layername].color - #print 'deb:MatLayers layer_color: ', color #----------- - global color_map - mat.setRGBCol(color_map[color]) + #global settings + #print 'deb:MatLayers material_from: ', settings.var['material_from'] #---------- + if settings.var['material_from'] == 3: mat_color = color + elif layersmap: mat_color = layersmap[layername].color + else: mat_color = 3 + #print 'deb:MatLayers color: ', color #----------- + #print 'deb:MatLayers mat_color: ', mat_color #----------- + mat.setRGBCol(color_map[mat_color]) mat.mode |= Material.Modes.SHADELESS mat.mode |= Material.Modes.WIRE -# try: mat.setMode('Shadeless', 'Wire') #work-around for 2.45rc-bug -# except: pass - self.layMaterials[layername] = mat +# try: mat.setMode('Shadeless', 'Wire') #work-around for 2.45rc-bug +# except: pass + self.layMaterials[colorlayername] = mat @@ -2706,7 +3169,7 @@ class Blocks: #---------------------------------------------------------------- If that name is not in its keys, it creates a new data block. If no name is provided return entire self.blocks container. """ - if not name: + if name == None: return self.blocks if name not in self.blocks.keys(): self.addBlock(name) @@ -2716,7 +3179,8 @@ class Blocks: #---------------------------------------------------------------- def addBlock(self, name): """Create a new 'block group' for the block name. """ - block_def = Group.New('bl_%s' %name) # groupObject contains definition of BLOCK + + block_def = Group.New('bl_%s' %name) # Blender groupObject contains definition of BLOCK block = self.blocksmap[name] self.settings.write("\nDrawing block:\'%s\' ..." % name) drawEntities(block.entities, self.settings, block_def) @@ -2784,6 +3248,7 @@ class Settings: #-------------------------------------------------------------- self.var['dist_min'] = self.var['dist_min'] / self.var['g_scale'] self.var['thick_min'] = self.var['thick_min'] / self.var['g_scale'] self.var['width_min'] = self.var['width_min'] / self.var['g_scale'] + self.var['arc_rad'] = self.var['arc_rad'] / self.var['g_scale'] # First sort out all the section_items sections = dict([(item.name, item) for item in drawing.data]) @@ -2796,8 +3261,11 @@ class Settings: #-------------------------------------------------------------- # The section:tables may be partialy or completely missing. self.layersTable = False - self.colMaterials = MatColors({}) - self.layMaterials = MatLayers({}) + self.colMaterials = MatColors({}) #A container for dxf-color based materials + self.layMaterials = MatLayers({}) #A container for dxf-layer based materials + #self.collayMaterials = MatColLayers({}) #A container for dxf-color+layer based materials + global layersmap, layernamesmap + layersmap, layernamesmap = {}, {} if 'tables' in sections.keys(): self.write("Found section:tables!") # First sort out all the tables @@ -2806,8 +3274,7 @@ class Settings: #-------------------------------------------------------------- self.write("Found table:layers!") self.layersTable = True # Read the layers table and get the layer colors - global layersmap - layersmap = getLayersmap(drawing) + layersmap, layernamesmap = getLayersmap(drawing) self.colMaterials = MatColors(layersmap) self.layMaterials = MatLayers(layersmap) else: @@ -2821,7 +3288,7 @@ class Settings: #-------------------------------------------------------------- self.write("Found section:blocks!") # Read the block definitions and build our block object if self.drawTypes['insert']: #if drawing of type 'Insert' activated - blocksmap, self.obj_number = getBlocksmap(drawing) #Build a dictionary of blockname:block_data pairs + blocksmap, self.blocknamesmap, self.obj_number = getBlocksmap(drawing) #Build a dictionary of blockname:block_data pairs self.blocks = Blocks(blocksmap, self) # initiates container for blocks_data #print 'deb: self.obj_number', self.obj_number #---------- @@ -2863,34 +3330,128 @@ class Settings: #-------------------------------------------------------------- Window.DrawProgressBar(progressbar, text) #print 'deb:drawer done, progressbar: ', done, progressbar #----------------------- - - def layer_isOff(self, name): + def layer_isOff(self, layername): # no more used ------- """Given a layer name, and return its visible status. """ - # colors are negative if layer is off - try: - #print 'deb:layer_isOff self.colMaterials.map:\n', self.colMaterials.map #-------------- - layer = self.colMaterials.map[name] - except KeyError: return False - if layer.color < 0: return True + # if layer is off then color_index is negative + if layersmap[layername].color < 0: return True #print 'deb:layer_isOff: layer is ON' #--------------- return False - def layer_isFrozen(self, name): + def layer_isFrozen(self, layername): # no more used ------- """Given a layer name, and return its frozen status. """ - # colors are negative if layer is off - try: - #print 'deb:layer_isFrozen self.colMaterials.map:\n', self.colMaterials.map #--------------- - layer = self.colMaterials.map[name] - except KeyError: return False - if layer.frozen: return True + if layersmap[layername].frozen: return True #print 'deb:layer_isFrozen: layer is not FROZEN' #--------------- return False +def analyzeDXF(dxfFile): #--------------------------------------- + """list LAYER and BLOCK dependences into textfile + + """ + Window.WaitCursor(True) # Let the user know we are thinking + print 'start reading DXF file: %s.' % dxfFile + time1 = Blender.sys.time() #time marker1 + drawing = readDXF(dxfFile, objectify) + print 'finished reading DXF file in %.4f sec.' % (Blender.sys.time()-time1) + Window.WaitCursor(False) + + # First sort out all the section_items + sections = dict([(item.name, item) for item in drawing.data]) + + # The section:header may be omited + if 'header' in sections.keys(): print "Found section:header!" + else: print "File contains no section:header!" + + # The section:tables may be partialy or completely missing. + layersTable = False + global layersmap + layersmap = {} + if 'tables' in sections.keys(): + print "Found section:tables!" + for table in drawing.tables.data: + if table.name == 'layer': + print "Found table:layers!" + layers = table + break + if layers: + layersmap = {} + for item in layers.data: + if type(item) != list and item.type == 'layer': + #print dir(item) + layersmap[item.name] = [item.color, item.frozen] + #print 'deb:analyzeDXF: layersmap=' , layersmap #------------- + layersmap_str = '#list of LAYERs: layername, layercolor, frozen\n' + + key_list = layersmap.keys() + key_list.sort() + for key in key_list: + #for layer_name, layer_data in layersmap.iteritems(): + layer_name, layer_data = key, layersmap[key] + layer_str = '\'%s\': col=%s' %(layer_name,layer_data[0])#------------- + if layer_data[1]: layer_str += ', frozen' + layersmap_str += layer_str + '\n' + #print 'deb:analyzeDXF: layersmap_str=\n' , layersmap_str #------------- + else: + print "File contains no table:layers!" + else: + print "File contains no section:tables!" + print "File contains no table:layers!" + + # The section:blocks may be omited + if 'blocks' in sections.keys(): + print "Found section:blocks!" + blocksmap = {} + for item in drawing.blocks.data: + #print 'deb:getBlocksmap item=' ,item #-------- + #print 'deb:getBlocksmap item.entities=' ,item.entities #-------- + #print 'deb:getBlocksmap item.entities.data=' ,item.entities.data #-------- + if type(item) != list and item.type == 'block': + insertList = [] + for item2 in item.entities.data: + if type(item2) != list and item2.type == 'insert': + #print dir(item2) + item2str = [item2.blockname, item2.layer, item2.color_index, item2.scale, item2.space] + insertList.append(item2str) + try: + blocksmap[item.name] = insertList + except KeyError: + # annon block + print 'Cannot map "%s" - "%s" as Block!' %(item.name, item) + #print 'deb:analyzeDXF: blocksmap=' , blocksmap #------------- + blocksmap_str = '#list of BLOCKs: child, layer, color, scale, space\n' + key_list = blocksmap.keys() + key_list.sort() + for key in key_list: + #for block_name, block_data in blocksmap.iteritems(): + block_name, block_data = key, blocksmap[key] + block_str = '\''+block_name + '\':\n' #------------- + blocksmap_str += block_str + if block_data: + for block_item in block_data: + block_data_str = ' - %s\n' %block_item + blocksmap_str += block_data_str + #print 'deb:analyzeDXF: blocksmap_str=\n' , blocksmap_str #------------- + else: + print "File contains no section:blocks!" + + output_str = '%s\n%s' %(layersmap_str, blocksmap_str) + infFile = dxfFile[:-4] + '_DXF.inf' # replace last char:'.dxf' with '.INF' + try: + f = file(infFile, 'w') + f.write(INFFILE_HEADER + '\n# this is a comment line\n') + f.write(output_str) + f.close() + Draw.PupMenu('DXF importer: INF-file: Done!%t|see listing of DXF-model saved in:|' + '\'%s\'' %infFile) + except: + Draw.PupMenu('DXF importer: INF-file: Error!%t|failure by writing to ' + '\'%s\'|no listings saved!' %infFile) + + + + def main(dxfFile): #---------------#############################----------- #print 'deb:filename:', filename #-------------- @@ -2909,7 +3470,13 @@ def main(dxfFile): #---------------#############################----------- print "Getting settings..." global GUI_A, GUI_B if GUI_A['g_scale_on'].val: - GUI_A['g_scale'].val = 10.0 ** int(GUI_A['g_scale_as'].val) + if GUI_A['g_scale_as'].val == 6: #scale inches to meters + GUI_A['g_scale'].val = 0.02540 + elif GUI_A['g_scale_as'].val == 7: #scale feets to meters + GUI_A['g_scale'].val = 0.30480 + elif GUI_A['g_scale_as'].val == 8: #scale yards to meters + GUI_A['g_scale'].val = 0.91440 + else: GUI_A['g_scale'].val = 10.0 ** int(GUI_A['g_scale_as'].val) else: GUI_A['g_scale'].val = 1.0 @@ -2928,7 +3495,8 @@ def main(dxfFile): #---------------#############################----------- if not settings: #Draw.PupMenu('DXF importer: EXIT!%t') - print '\nDXF Import: terminated by user!' + #print '\nDXF Import: terminated by user!' + print '\nDXF Import: terminated, cause settings failure!' Window.WaitCursor(False) if editmode: Window.EditMode(1) # and put things back how we fond them return None @@ -2993,8 +3561,14 @@ def getOCS(az): #-------------------------------------------------------------- """An implimentation of the Arbitrary Axis Algorithm. """ #decide if we need to transform our coords - if az[0] == 0 and az[1] == 0: - return False + if az[0] == 0 and az[1] == 0: + if az[2] == 1.0: + return False + elif az[2] == -1.0: + ax = Mathutils.Vector(-1.0, 0, 0) + ay = Mathutils.Vector(0, 1.0, 0) + az = Mathutils.Vector(0, 0, -1.0) + return ax, ay, az #elif abs(az[0]) < 0.0001 and abs(az[1]) < 0.0001: # return False @@ -3052,7 +3626,7 @@ def rotXY_Vec(rotation, vec): #------------------------------------------------ def getLayersmap(drawing): #------------------------------------------------------ - """Build a dictionary of layername:layer pairs for the given drawing. + """Build two dictionaries: 1.layername:layer pairs and 2.layername:layername_short """ tables = drawing.tables for table in tables.data: @@ -3060,17 +3634,27 @@ def getLayersmap(drawing): #--------------------------------------------------- layers = table break layersmap = {} + layernamesmap = {} for item in layers.data: if type(item) != list and item.type == 'layer': layersmap[item.name] = item - return layersmap + layername_short = item.name[:MAX_NAMELENGTH-1] + i = 0 #sufix for layernames cause Blender-objectnames-limits + while layername_short in layernamesmap.keys(): + i += 1 + suffix = str(i) + layername_short = layername_short[:-2] + suffix + layernamesmap[item.name] = layername_short + return layersmap, layernamesmap def getBlocksmap(drawing): #-------------------------------------------------------- - """Build a dictionary of blockname:block_data pairs for the given drawing. + """Build a dictionary of blockname:block_data pairs and 2.blockname:blockname_short pairs """ blocksmap = {} + blocksmap_short = {} + blocknamesmap = {} obj_number = 0 for item in drawing.blocks.data: #print 'deb:getBlocksmap item=' ,item #-------- @@ -3083,9 +3667,16 @@ def getBlocksmap(drawing): #--------------------------------------------------- except KeyError: # annon block print 'Cannot map "%s" - "%s" as Block!' %(item.name, item) - return blocksmap, obj_number + blockname_short = item.name[:MAX_NAMELENGTH-1] + i = 0 #sufix for blockname cause Blender-objectnamelength-limit + while blockname_short in blocknamesmap.keys(): + i += 1 + suffix = str(i) + blockname_short = blockname_short[:-2] + suffix + blocknamesmap[item.name] = blockname_short + return blocksmap, blocknamesmap, obj_number @@ -3105,6 +3696,8 @@ def drawer(_type, entities, settings, block_def): #---------------------------- If 'block_def': the entities are to be added to the Blender 'group'. """ + #print 'deb:drawer _type, entities:\n ', _type, entities #----------------------- + if entities: # Break out early if settings says we aren't drawing the current dxf-type global cur_COUNTER #counter for progress_bar @@ -3118,10 +3711,14 @@ def drawer(_type, entities, settings, block_def): #---------------------------- settings.progress(cur_COUNTER, message) return #print 'deb:drawer.todo:_type:', _type #----------------------- + #print 'deb:drawer entities:\n ', entities #----------------------- len_temp = len(entities) # filtering only model-space enitities (no paper-space enitities) - entities = [entity for entity in entities if entity.space == 0] + if settings.var['paper_space_on']: + entities = [entity for entity in entities if entity.space != 0] + else: + entities = [entity for entity in entities if entity.space == 0] # filtering only objects with color from acceptedColorsList if settings.var['colorFilter_on']: @@ -3129,11 +3726,12 @@ def drawer(_type, entities, settings, block_def): #---------------------------- # filtering only objects on layers from acceptedLayersList if settings.var['layerFilter_on']: -# entities = [entity for entity in entities if entity.layer[0] in ['M','3','0'] and not entity.layer.endswith('H')] + #entities = [entity for entity in entities if entity.layer[0] in ['M','3','0'] and not entity.layer.endswith('H')] entities = [entity for entity in entities if entity.layer in settings.acceptedLayers] # filtering only objects on not-frozen layers - entities = [entity for entity in entities if not settings.layer_isFrozen(entity.layer)] + if layersmap and not settings.var['layFrozen_on']: + entities = [entity for entity in entities if not layersmap[entity.layer].frozen] global activObjectLayer, activObjectName activObjectLayer = '' @@ -3162,7 +3760,7 @@ def drawer(_type, entities, settings, block_def): #---------------------------- # get the layer group (just to make things a little cleaner) if settings.var['group_bylayer_on'] and not block_def: - group = getGroup('l:%s' % entity.layer[:MAX_NAMELENGTH-2]) + group = getGroup('l:%s' % layernamesmap[entity.layer]) if _type == 'insert': #---- INSERT and MINSERT=array ------------------------ #print 'deb:insert entity.loc:', entity.loc #---------------- @@ -3249,7 +3847,8 @@ def setObjectProperties(ob, group, entity, settings, block_def): #------------- setMaterial_from(entity, ob, settings, block_def) # Set the visibility - if settings.layer_isOff(entity.layer): + #if settings.layer_isOff(entity.layer): + if layersmap and layersmap[entity.layer].color < 0: # color is negative if layer is off #ob.layers = [20] #remi--todo------------- ob.restrictDisplay = True ob.restrictRender = True @@ -3287,17 +3886,25 @@ def setMaterial_from(entity, ob, settings, block_def): #----------------------- if settings.var['material_from'] == 1: # 1= material from color if entity.color_index == BYLAYER: mat = settings.colMaterials(entity.layer) + elif entity.color_index == BYBLOCK: + #--todo-- looking for block.color_index + #mat = settings.colMaterials(block.color_index) + mat = settings.colMaterials(entity.color_index) else: mat = settings.colMaterials(entity.color_index) - elif settings.var['material_from'] == 2: # 2= material from layer - mat = settings.layMaterials(entity.layer) -# elif settings.var['material_from'] == 3: # 3= material from layer+color -# mat = settings.layMaterials(entity.layer) -# color = entity.color_index -# if type(color) == int: -# mat.setRGBCol(color_map[abs(color)]) -# elif settings.var['material_from'] == 4: # 4= material from block -# elif settings.var['material_from'] == 5: # 5= material from INI-file + + elif settings.var['material_from'] == 2: # 2= material from layer_name + mat = settings.layMaterials(layername=entity.layer) + + elif settings.var['material_from'] == 3: # 3= material from layer+color + mat = settings.layMaterials(layername=entity.layer, color=entity.color_index) + +# elif settings.var['material_from'] == 4: # 4= material from block_name + +# elif settings.var['material_from'] == 5: # 5= material from XDATA + +# elif settings.var['material_from'] == 6: # 6= material from INI-file + else: # set neutral material try: mat = Material.Get('dxf-neutral') @@ -3316,8 +3923,8 @@ def setMaterial_from(entity, ob, settings, block_def): #----------------------- -def drawBulge(p1, p2, arc_res, curve_on=False): #------------------------------------------------- - """return the center, radius, start angle, and end angle given two points. +def calcBulge(p1, p2, arc_res, triples=False): #------------------------------------------------- + """given startpoint, endpoint and bulge of arc, returns points/segments of its representation. Needs to take into account bulge sign. negative = clockwise @@ -3335,54 +3942,114 @@ def drawBulge(p1, p2, arc_res, curve_on=False): #----------------------------- rotate around p1 by angle to center, point to center. start angle = angle between (center - p1) and worldX end angle = angle between (center - p2) and worldX + + calculate the center, radius, start angle, and end angle + returns points/segments of its mesh representation + incl.startpoint, without endpoint """ bulge = p1.bulge - p2 = Mathutils.Vector(p2.loc) p1 = Mathutils.Vector(p1.loc) + p2 = Mathutils.Vector(p2.loc) cord = p2 - p1 # vector from p1 to p2 clength = cord.length s = (bulge * clength)/2.0 # sagitta (height) radius = abs(((clength/2.0)**2.0 + s**2.0)/(2.0*s)) # magic formula angle = (degrees(4.0*atan(bulge))) # theta (included angle) - if curve_on: - verts_num = 8 - else: - verts_num = arc_res * sqrt(radius) # set a number of segments in entire circle - if verts_num > 1024: verts_num = 1024 # Blender accepts only values [3:500] - if verts_num < 4: verts_num = 4 # Blender accepts only values [3:500] - pieces = int(abs(angle)/(360.0/verts_num)) - if pieces < 3: pieces = 3 #bulge under arc_resolution - #if pieces < 3: points = [p1, p2] ;return points - step = angle/pieces # set step so pieces * step = degrees in arc + radial = cord.normalize() * radius # a radius length vector aligned with cord delta = (180.0 - abs(angle))/2.0 # the angle from cord to center if bulge < 0: delta = -delta - radial = cord.normalize() * radius # a radius length vector aligned with cord rmat = Mathutils.RotationMatrix(-delta, 3, 'Z') center = p1 + (rmat * radial) # rotate radial by delta degrees, then add to p1 to find center #length = radians(abs(angle)) * radius - #print 'deb:drawBulge:\n angle, delta: ', angle, delta #---------------- + #print 'deb:calcBulge:\n angle, delta: ', angle, delta #---------------- #print 'deb:center, radius: ', center, radius #---------------------- - startpoint = p1 - center - #endpoint = p2 - center + endpoint = p2 - center + #print 'deb:calcBulg: startpoint:', startpoint #--------- + #print 'deb:calcBulg: endpoint:', endpoint #--------- + + if not triples: #IF mesh-representation ----------- + if arc_res > 1024: arc_res = 1024 + elif arc_res < 4: arc_res = 4 + pieces = int(abs(angle)/(360.0/arc_res)) # set a fixed step of ARC_RESOLUTION + if pieces < 3: pieces = 3 + else: #IF curve-representation ------------------------------- + if arc_res > 32: arc_res = 32 + elif arc_res < 3: arc_res = 3 + pieces = int(abs(angle)/(360.0/arc_res)) # set a fixed step of ARC_RESOLUTION + if pieces < 2: pieces = 2 + + step = angle/pieces # set step so pieces * step = degrees in arc stepmatrix = Mathutils.RotationMatrix(-step, 3, "Z") - points = [startpoint] - point = Mathutils.Vector(startpoint) - for i in xrange(int(pieces)-1): #fast (but not so acurate as: vector * RotMatrix(step * i) - point = stepmatrix * point - points.append(point) - points = [[point[0]+center[0], point[1]+center[1], point[2]+center[2]] for point in points] - return points + + if not triples: #IF mesh-representation ----------- + points = [startpoint] + point = startpoint + for i in xrange(int(pieces)-1): #fast (but not so acurate as: vector * RotMatrix(-step*i,3,"Z") + point = stepmatrix * point + points.append(point) + points = [ point+center for point in points] + # vector to point convertion: + points = [list(point) for point in points] + return points, list(center) + + else: #IF curve-representation ------------------------------- + # correct Bezier curves representation for free segmented circles/arcs + step2 = radians(step * 0.5) + bulg = radius * (1 - cos(step2)) + deltaY = 4.0 * bulg / (3.0 * sin(step2) ) + #print 'deb:calcArcCurve: bulg, deltaY:\n', bulg, deltaY #--------- + #print 'deb:calcArcCurve: step:\n', step #--------- + + #org handler0 = Mathutils.Vector(0.0, -deltaY, 0.0) + #handler = startmatrix * handler0 + #endhandler = endmatrix * handler0 + rotMatr90 = Mathutils.Matrix([0, -1, 0], [1, 0, 0], [0, 0, 1]) + handler = rotMatr90 * startpoint + handler = - deltaY * handler.normalize() + endhandler = rotMatr90 * endpoint + endhandler = - deltaY * endhandler.normalize() + + points = [startpoint] + handlers1 = [startpoint + handler] + handlers2 = [startpoint - handler] + point = Mathutils.Vector(startpoint) + for i in xrange(int(pieces)-1): + point = stepmatrix * point + handler = stepmatrix * handler + handler1 = point + handler + handler2 = point - handler + points.append(point) + handlers1.append(handler1) + handlers2.append(handler2) + points.append(endpoint) + handlers1.append(endpoint + endhandler) + handlers2.append(endpoint - endhandler) + + points = [point + center for point in points] + handlers1 = [point + center for point in handlers1] + handlers2 = [point + center for point in handlers2] + + VectorTriples = [list(h1)+list(p)+list(h2) for h1,p,h2 in zip(handlers1, points, handlers2)] + #print 'deb:calcBulgCurve: handlers1:\n', handlers1 #--------- + #print 'deb:calcBulgCurve: points:\n', points #--------- + #print 'deb:calcBulgCurve: handlers2:\n', handlers2 #--------- + #print 'deb:calcBulgCurve: VectorTriples:\n', VectorTriples #--------- + return VectorTriples + -def drawArc(center, radius, start, end, arc_res): #----------------------------------------- - """Draw a mesh arc with the given parameters. +def calcArc(center, radius, start, end, arc_res, triples): #----------------------------------------- + """calculate Points (or BezierTriples) for ARC/CIRCLEs representation. + + Given parameters of the ARC/CIRCLE, + returns points/segments (or BezierTriples) and centerPoint """ # center is currently set by object # if start > end: start = start - 360 - if end > 360: end = end%360.0 + if end > 360: end = end % 360.0 startmatrix = Mathutils.RotationMatrix(-start, 3, "Z") startpoint = startmatrix * Mathutils.Vector(radius, 0, 0) @@ -3393,27 +4060,68 @@ def drawArc(center, radius, start, end, arc_res): #---------------------------- angle = end - start #length = radians(angle) * radius - #if radius < MIN_DIST * 10: # if circumfence is too small - if arc_res > 1024: arc_res = 1024 - if arc_res < 4: arc_res = 4 - pieces = int(abs(angle)/(360.0/arc_res)) # set a fixed step of ARC_RESOLUTION - if pieces < 3: pieces = 3 #cambo----- - step = angle/pieces # set step so pieces * step = degrees in arc + if not triples: #IF mesh-representation ----------- + if arc_res > 1024: arc_res = 1024 + elif arc_res < 4: arc_res = 4 + pieces = int(abs(angle)/(360.0/arc_res)) # set a fixed step of ARC_RESOLUTION + if pieces < 3: pieces = 3 + step = angle/pieces # set step so pieces * step = degrees in arc + stepmatrix = Mathutils.RotationMatrix(-step, 3, "Z") - stepmatrix = Mathutils.RotationMatrix(-step, 3, "Z") - points = [startpoint] - point = Mathutils.Vector(startpoint) - for i in xrange(int(pieces)): - point = stepmatrix * point - points.append(point) - points.append(endpoint) + points = [startpoint] + point = startpoint + for i in xrange(int(pieces)-1): + point = stepmatrix * point + points.append(point) + points.append(endpoint) + + if center: + centerVec = Mathutils.Vector(center) + #points = [point + centerVec for point in points()] + points = [point + centerVec for point in points] + # vector to point convertion: + points = [list(point) for point in points] + return points - if center: - points = [[point[0]+center[0], point[1]+center[1], point[2]+center[2]] for point in points] - edges = [[num, num+1] for num in xrange(len(points)-1)] - - return points, edges + else: #IF curve-representation --------------- + if arc_res > 32: arc_res = 32 + elif arc_res < 3: arc_res = 3 + pieces = int(abs(angle)/(360.0/arc_res)) # set a fixed step of ARC_RESOLUTION + if pieces < 2: pieces = 2 + step = angle/pieces # set step so pieces * step = degrees in arc + stepmatrix = Mathutils.RotationMatrix(-step, 3, "Z") + # correct Bezier curves representation for free segmented circles/arcs + step2 = radians(step * 0.5) + bulg = radius * (1 - cos(step2)) + deltaY = 4.0 * bulg / (3.0 * sin(step2) ) + #print 'deb:calcArcCurve: bulg, deltaY:\n', bulg, deltaY #--------- + #print 'deb:calcArcCurve: step:\n', step #--------- + handler0 = Mathutils.Vector(0.0, -deltaY, 0.0) + + points = [startpoint] + handler = startmatrix * handler0 + endhandler = endmatrix * handler0 + handlers1 = [startpoint + handler] + handlers2 = [startpoint - handler] + point = Mathutils.Vector(startpoint) + for i in xrange(int(pieces)-1): + point = stepmatrix * point + handler = stepmatrix * handler + handler1 = point + handler + handler2 = point - handler + points.append(point) + handlers1.append(handler1) + handlers2.append(handler2) + points.append(endpoint) + handlers1.append(endpoint + endhandler) + handlers2.append(endpoint - endhandler) + VectorTriples = [list(h1)+list(p)+list(h2) for h1,p,h2 in zip(handlers1, points, handlers2)] + #print 'deb:calcArcCurve: handlers1:\n', handlers1 #--------- + #print 'deb:calcArcCurve: points:\n', points #--------- + #print 'deb:calcArcCurve: handlers2:\n', handlers2 #--------- + #print 'deb:calcArcCurve: VectorTriples:\n', VectorTriples #--------- + return VectorTriples def drawCurveCircle(circle): #--- no more used -------------------------------------------- @@ -3504,6 +4212,7 @@ EVENT_HELP = 9 EVENT_CONFIG = 10 EVENT_PRESETS = 11 EVENT_DXF_DIR = 12 +EVENT_LIST = 13 EVENT_PRESET2D = 20 EVENT_EXIT = 100 GUI_EVENT = EVENT_NONE @@ -3522,8 +4231,8 @@ plmesh_as_menu = "convert to: %t|mesh %x1" solids_as_menu = "convert to: %t|mesh %x1" blocks_as_menu = "convert to: %t|dupl.group %x1|*real.group %x2|*exploded %x3" texts_as_menu = "convert to: %t|text %x1|*mesh %x2" -material_from_menu= "material from: %t|COLOR %x1|LAYER %x2|*LAYER+COLOR %x3|*BLOCK %x4|*XDATA %x5|*INI-File %x6" -g_scale_list = "scale factor: %t|x 1000 %x3|x 100 %x2|x 10 %x1|x 1 %x0|x 0.1 %x-1|x 0.01 %x-2|x 0.001 %x-3|x 0.0001 %x-4|x 0.00001 %x-5" +material_from_menu= "material from: %t|*LINESTYLE %x7|COLOR %x1|LAYER %x2|*LAYER+COLOR %x3|*BLOCK %x4|*XDATA %x5|*INI-File %x6" +g_scale_list = "scale factor: %t|yard to m %x8|feet to m %x7|inch to m %x6|x 1000 %x3|x 100 %x2|x 10 %x1|x 1 %x0|x 0.1 %x-1|cm to m %x-2|mm to m %x-3|x 0.0001 %x-4|x 0.00001 %x-5" dxfFileName = Draw.Create("") iniFileName = Draw.Create(INIFILE_DEFAULT_NAME + INIFILE_EXTENSION) @@ -3555,11 +4264,18 @@ keywords_org = { 'material_from': 2, 'pl_3d' : 1, 'fill_on' : 1, + 'meshSmooth_on': 1, + 'curve_res' : CURV_RESOLUTION, + 'curve_arc' : CURVARC_RESOLUTION, 'arc_res' : ARC_RESOLUTION, 'arc_rad' : ARC_RADIUS, 'thin_res' : THIN_RESOLUTION, - 'angle_cut' : ANGLECUT_LIMIT, - 'pl_section_on': 1, + 'pl_trim_max' : TRIM_LIMIT, + 'pl_trim_on': 1, + 'paper_space_on': 0, + 'layFrozen_on': 0, + 'Z_force_on': 0, + 'Z_elev': float(ELEVATION), 'points_as' : 2, 'lines_as' : 2, 'mlines_as' : 2, @@ -3615,8 +4331,8 @@ def saveConfig(): #remi--todo----------------------------------------------- iniFile = iniFileName.val #print 'deb:saveConfig inifFile: ', inifFile #---------------------- if iniFile.lower().endswith(INIFILE_EXTENSION): - output = '[%s,%s]' %(GUI_A, GUI_B) - if output =='None': + output_str = '[%s,%s]' %(GUI_A, GUI_B) + if output_str =='None': Draw.PupMenu('DXF importer: INI-file: Alert!%t|no config-data present to save!') else: #if BPyMessages.Warning_SaveOver(iniFile): #<- remi find it too abstarct @@ -3632,10 +4348,16 @@ def saveConfig(): #remi--todo----------------------------------------------- else: save_ok = True if save_ok: + # replace: ',' -> ',\n' + # replace: '{' -> '\n{\n' + # replace: '}' -> '\n}\n' + output_str = ',\n'.join(output_str.split(',')) + output_str = '\n}'.join(output_str.split('}')) + output_str = '{\n'.join(output_str.split('{')) try: f = file(iniFile, 'w') - f.write(INIFILE_HEADER + '\n') - f.write(output) + f.write(INIFILE_HEADER + '\n# this is a comment line\n') + f.write(output_str) f.close() Draw.PupMenu('DXF importer: INI-file: Done!%t|config-data saved in ' + '\'%s\'' %iniFile) except: @@ -3668,7 +4390,7 @@ def loadConfig(): #remi--todo----------------------------------------------- else: data_str = f.read() f.close() - #print 'deb:loadConfig data_str from %s: \n' %iniFile , data_str #-------------------------- + print 'deb:loadConfig data_str from %s: \n' %iniFile , data_str #-------------------------- data = eval(data_str) for k, v in data[0].iteritems(): try: @@ -3719,7 +4441,9 @@ def resetDefaultConfig_2D(): #----------------------------------------------- 'dist_force': 0, 'pl_3d' : 0, 'fill_on' : 0, - 'pl_section_on': 1, + 'pl_trim_on': 1, + 'Z_force_on': 0, + 'meshSmooth_on': 0, 'points_as' : 2, 'lines_as' : 2, 'mlines_as' : 2, @@ -3772,7 +4496,7 @@ def draw_UI(): #--------------------------------------------------------------- menu_w = (3 * butt_margin) + but_0c + but_1c + but_2c + but_3c #menu width simple_menu_h = 110 - extend_menu_h = 380 + extend_menu_h = 400 y = simple_menu_h # y is menu upper.y if config_UI.val: y += extend_menu_h x = 20 #menu left.x @@ -3848,7 +4572,8 @@ def draw_UI(): #--------------------------------------------------------------- y -= 20 Draw.BeginAlign() - GUI_B['block'] = Draw.Toggle('BLOCK / ARRAY', EVENT_NONE, but0c, y, but_0c+but_1c, 20, GUI_B['block'].val, "support dxf-BLOCK and ARRAY on/off") + GUI_B['block'] = Draw.Toggle('BLOCK', EVENT_NONE, but0c, y, but_0c, 20, GUI_B['block'].val, "support dxf-BLOCK and ARRAY on/off") + GUI_A['dummy_on'] = Draw.Toggle('*XREF', EVENT_NONE, but1c, y, but_1c-butt_margin, 20, GUI_A['dummy_on'].val, "(*wip)support XREF-BLOCK on/off") Draw.Label('-->', but2c, y, but_2c, 20) GUI_A['blocks_as'] = Draw.Menu(blocks_as_menu, EVENT_NONE, but3c, y, but_3c, 20, GUI_A['blocks_as'].val, "select target Blender-object") Draw.EndAlign() @@ -3856,35 +4581,55 @@ def draw_UI(): #--------------------------------------------------------------- y -= 20 Draw.BeginAlign() - GUI_A['material_from'] = Draw.Menu(material_from_menu, EVENT_NONE, but0c, y, but_0c+but_1c, 20, GUI_A['material_from'].val, "material assignment from?") - Draw.Label('-->', but2c, y, but_2c, 20) - GUI_A['material_on'] = Draw.Toggle('material', EVENT_NONE, but3c, y, but_3c, 20, GUI_A['material_on'].val, "support for material assignment on/off") + GUI_A['dummy_on'] = Draw.Toggle('*views', EVENT_NONE, but0c, y, but_0c-25, 20, GUI_A['dummy_on'].val, "(*wip)support VIEWPORTs on/off") + GUI_A['dummy_on'] = Draw.Toggle('*cams', EVENT_NONE, but1c-25, y, but_1c-25, 20, GUI_A['dummy_on'].val, "(*wip)support CAMERAs on/off") + GUI_A['dummy_on'] = Draw.Toggle('*lights', EVENT_NONE, but1c+25, y, but_1c-25, 20, GUI_A['dummy_on'].val, "(*wip)support LIGHTs on/off") + Draw.EndAlign() + Draw.BeginAlign() + GUI_A['material_on'] = Draw.Toggle('material', EVENT_NONE, but2c, y, but_2c-20, 20, GUI_A['material_on'].val, "support for material assignment on/off") + GUI_A['material_from'] = Draw.Menu(material_from_menu, EVENT_NONE, but3c-20, y, but_3c+20, 20, GUI_A['material_from'].val, "material assignment from?") Draw.EndAlign() - y -= 30 - GUI_A['group_bylayer_on'] = Draw.Toggle('oneGroup', EVENT_NONE, but0c, y, but_0c, 20, GUI_A['group_bylayer_on'].val, "grouping entities from the same layer on/off") - GUI_A['curves_on'] = Draw.Toggle('to Curves', EVENT_NONE, but1c, y, but_1c, 20, GUI_A['curves_on'].val, "drawing LINE/ARC/POLYLINE into Blender-Curves instead of Meshes on/off") + y -= 20 + Draw.BeginAlign() + GUI_A['paper_space_on'] = Draw.Toggle('paperSpace', EVENT_NONE, but0c, y, but_0c+20, 20, GUI_A['paper_space_on'].val, "import from paper space only on/off") + GUI_A['layFrozen_on'] = Draw.Toggle('frozen', EVENT_NONE, but1c+20, y, but_1c-20, 20, GUI_A['layFrozen_on'].val, "import also from frozen layers on/off") + #GUI_A['dummy_on'] = Draw.Toggle('-', EVENT_NONE, but3c, y, but_3c, 20, GUI_A['dummy_on'].val, "dummy on/off") + Draw.EndAlign() Draw.BeginAlign() GUI_A['g_scale_on'] = Draw.Toggle('glob.Scale', EVENT_NONE, but2c, y, but_2c, 20, GUI_A['g_scale_on'].val, "scaling all DXF objects on/off") GUI_A['g_scale_as'] = Draw.Menu(g_scale_list, EVENT_NONE, but3c, y, but_3c, 20, GUI_A['g_scale_as'].val, "10^ factor for scaling the DXFdata") Draw.EndAlign() - y -= 20 - #Draw.Label('', but1c+but_1c/2, y, but_1c/2, 20) - GUI_A['one_mesh_on'] = Draw.Toggle('oneMesh', EVENT_NONE, but0c, y, but_0c, 20, GUI_A['one_mesh_on'].val, "drawing DXF-entities into one mesh-object. Recommended for big DXF-files. on/off") + y -= 30 + GUI_A['group_bylayer_on'] = Draw.Toggle('oneGroup', EVENT_NONE, but0c, y, but_0c, 20, GUI_A['group_bylayer_on'].val, "grouping entities from the same layer on/off") GUI_A['vGroup_on'] = Draw.Toggle('vGroups', EVENT_NONE, but1c, y, but_1c, 20, GUI_A['vGroup_on'].val, "support Blender-VertexGroups on/off") Draw.BeginAlign() + GUI_A['Z_force_on'] = Draw.Toggle('*elevation', EVENT_NONE, but2c, y, but_2c, 20, GUI_A['Z_force_on'].val, "*set objects Z-coordinates to elevation on/off") + GUI_A['Z_elev'] = Draw.Number('', EVENT_NONE, but3c, y, but_3c, 20, GUI_A['Z_elev'].val, -1000, 1000, "set default elevation(Z)") + Draw.EndAlign() + + + y -= 20 + Draw.BeginAlign() + GUI_A['meshSmooth_on'] = Draw.Toggle('smooth', EVENT_NONE, but0c, y, but_0c-20, 20, GUI_A['meshSmooth_on'].val, "mesh smooth for circles/arcsegments on/off") + GUI_A['pl_trim_on'] = Draw.Toggle('trim', EVENT_NONE, but1c-20, y, 32, 20, GUI_A['pl_trim_on'].val, "intersection of POLYLINE-wide-segments on/off") + GUI_A['pl_trim_max'] = Draw.Number('', EVENT_NONE, but1c+12, y, but_1c-12, 20, GUI_A['pl_trim_max'].val, 0, 5, "limit for intersection of POLYLINE-wide-segments: 0.0-5.0") + Draw.EndAlign() + Draw.BeginAlign() GUI_A['dist_on'] = Draw.Toggle('dist.:', EVENT_NONE, but2c, y, but_2c-20, 20, GUI_A['dist_on'].val, "support distance on/off") GUI_A['dist_force'] = Draw.Toggle('F', EVENT_NONE, but2c+but_2c-20, y, 20, 20, GUI_A['dist_force'].val, "force minimal distance on/off") - GUI_A['dist_min'] = Draw.Number('', EVENT_NONE, but3c, y, but_3c, 20, GUI_A['dist_min'].val, 0, 10, "minimal lenght/distance (double.vertex removing)") + GUI_A['dist_min'] = Draw.Number('', EVENT_NONE, but3c, y, but_3c, 20, GUI_A['dist_min'].val, 0, 10, "minimal length/distance (double.vertex removing)") Draw.EndAlign() y -= 20 Draw.BeginAlign() - GUI_A['pl_section_on'] = Draw.Toggle('int.section', EVENT_NONE, but0c, y, but_0c, 20, GUI_A['pl_section_on'].val, "support POLYLINE-wide-segment-intersection on/off") - GUI_A['angle_cut'] = Draw.Number('', EVENT_NONE, but1c, y, but_1c, 20, GUI_A['angle_cut'].val, 1, 5, "it limits POLYLINE-wide-segment-intersection: 1.0-5.0") +# GUI_A['thin_res'] = Draw.Number('thin:', EVENT_NONE, but0c, y, but_0c, 20, GUI_A['thin_res'].val, 4, 64, "thin cylinder resolution - number of segments (4-64)") + GUI_A['arc_rad'] = Draw.Number('bR:', EVENT_NONE, but0c, y, but_0c, 20, GUI_A['arc_rad'].val, 0.01, 100, "basis radius for arc/circle resolution (0.01-100)") + GUI_A['arc_res'] = Draw.Number('', EVENT_NONE, but1c, y, but_1c/2, 20, GUI_A['arc_res'].val, 3, 500, "arc/circle resolution - number of segments (3-500)") + GUI_A['fill_on'] = Draw.Toggle('caps', EVENT_NONE, but1c+but_1c/2, y, but_1c/2, 20, GUI_A['fill_on'].val, "draws top and bottom caps of CYLINDERs/closed curves on/off") Draw.EndAlign() Draw.BeginAlign() GUI_A['thick_on'] = Draw.Toggle('thick:', EVENT_NONE, but2c, y, but_2c-20, 20, GUI_A['thick_on'].val, "support thickness on/off") @@ -3895,10 +4640,10 @@ def draw_UI(): #--------------------------------------------------------------- y -= 20 Draw.BeginAlign() -# GUI_A['thin_res'] = Draw.Number('thin:', EVENT_NONE, but0c, y, but_0c, 20, GUI_A['thin_res'].val, 4, 500, "thin cylinder resolution - number of segments") - GUI_A['arc_rad'] = Draw.Number('radi:', EVENT_NONE, but0c, y, but_0c, 20, GUI_A['arc_rad'].val, 0.01, 100, "basis radius for arc/circle resolution") - GUI_A['arc_res'] = Draw.Number('res:', EVENT_NONE, but1c, y, but_1c-25, 20, GUI_A['arc_res'].val, 4, 500, "arc/circle resolution - number of segments") - GUI_A['fill_on'] = Draw.Toggle('cap', EVENT_NONE, but1c+but_1c-25, y, 25, 20, GUI_A['fill_on'].val, "draws top and bottom caps of CYLINDERs on/off") + #GUI_A['group_bylayer_on'] = Draw.Toggle('oneGroup', EVENT_NONE, but0c, y, but_0c, 20, GUI_A['group_bylayer_on'].val, "grouping entities from the same layer on/off") + GUI_A['curves_on'] = Draw.Toggle('to Curves', EVENT_NONE, but0c, y, but_0c, 20, GUI_A['curves_on'].val, "drawing LINE/ARC/POLYLINE into Blender-Curves instead of Meshes on/off") + GUI_A['curve_arc'] = Draw.Number('', EVENT_NONE, but1c, y, but_1c/2, 20, GUI_A['curve_arc'].val, 3, 32, "Bezier circle resolution - number of segments: 3-32") + GUI_A['curve_res'] = Draw.Number('', EVENT_NONE, but1c+but_1c/2, y, but_1c/2, 20, GUI_A['curve_res'].val, 3, 50, "Bezier curve resolution: 3-50") Draw.EndAlign() Draw.BeginAlign() GUI_A['width_on'] = Draw.Toggle('width:', EVENT_NONE, but2c, y, but_2c-20, 20, GUI_A['width_on'].val, "support width on/off") @@ -3908,6 +4653,7 @@ def draw_UI(): #--------------------------------------------------------------- y -= 30 #GUI_A['dummy_on'] = Draw.Toggle(' - ', EVENT_NONE, but0c, y, but_0c, 20, GUI_A['dummy_on'].val, "reserved") + GUI_A['one_mesh_on'] = Draw.Toggle('oneMesh', EVENT_NONE, but0c, y, but_0c, 20, GUI_A['one_mesh_on'].val, "draw DXF-entities into one mesh-object. Recommended for big DXF-files. on/off") GUI_A['newScene_on'] = Draw.Toggle('newScene', EVENT_NONE, but1c, y, but_1c, 20, GUI_A['newScene_on'].val, "creates new Blender-Scene for each import on/off") GUI_A['target_layer'] = Draw.Number('layer', EVENT_NONE, but2c, y, but_2c, 20, GUI_A['target_layer'].val, 1, 18, "imports into this Blender-layer (<19> reserved for block_definitions)") GUI_A['optimization'] = Draw.Number('optim:', EVENT_NONE, but3c, y, but_3c, 20, GUI_A['optimization'].val, 0, 3, "Optimization Level: 0=Debug/directDrawing, 1=Verbose, 2=ProgressBar, 3=silentMode/fastest") @@ -3940,7 +4686,8 @@ def draw_UI(): #--------------------------------------------------------------- y -= 50 Draw.BeginAlign() Draw.PushButton('EXIT', EVENT_EXIT, but0c, y, but_0c, 40, '' ) - Draw.PushButton('HELP', EVENT_HELP, but1c, y, but_1c, 20, 'calls BlenderWiki for Manual, Updates and Support.') + Draw.PushButton('HELP', EVENT_HELP, but1c, y, but_1c-20, 20, 'calls BlenderWiki for Manual, Updates and Support.') + Draw.PushButton('?', EVENT_LIST, but1c+but_1c-20, y, 20, 20, 'analyze DXF-file: print listing of LAYERs and BLOCKs into the text-file.INF') Draw.PushButton('START IMPORT', EVENT_START, but2c, y, but_2c+but_3c+butt_margin, 40, 'Start the import procedure') Draw.EndAlign() @@ -3993,6 +4740,14 @@ def bevent(evt): if user_preset > 5: user_preset = 1 iniFileName.val = INIFILE_DEFAULT_NAME + str(user_preset) + INIFILE_EXTENSION Draw.Redraw() + elif (evt==EVENT_LIST): + dxfFile = dxfFileName.val + if dxfFile.lower().endswith('.dxf') and sys.exists(dxfFile): + analyzeDXF(dxfFile) + else: + Draw.PupMenu('DXF importer: Alert!%t|no valid DXF-file selected!') + print "DXF importer: error, no valid DXF-file selected! try again" + Draw.Redraw() elif (evt==EVENT_HELP): try: import webbrowser @@ -4032,6 +4787,7 @@ http://wiki.blender.org/index.php?title=Scripts/Manual/Import/DXF-3D') else: Draw.Redraw() elif dxfFile.lower().endswith('.dxf') and sys.exists(dxfFile): + print '\nStandard Mode: active' if GUI_A['newScene_on'].val: _dxf_file = dxfFile.split('/')[-1].split('\\')[-1] _dxf_file = _dxf_file[:-4] # cut last char:'.dxf' @@ -4066,7 +4822,7 @@ def multi_import(DIR): batchTIME = Blender.sys.time() #if #DIR == "": DIR = os.path.curdir if DIR == "": DIR = Blender.sys.dirname(Blender.Get('filename')) - print 'Searching for DXF-files in %s' %DIR + print 'Multifile Mode: searching for DXF-files in %s' %DIR files = \ [sys.join(DIR, f) for f in os.listdir(DIR) if f.lower().endswith('.dxf')] if not files: @@ -4076,7 +4832,7 @@ def multi_import(DIR): i = 0 for dxfFile in files: i += 1 - print 'Importing', dxfFile, ' NUMBER', i, 'of', len(files) + print '\nImporting', dxfFile, ' NUMBER', i, 'of', len(files) if GUI_A['newScene_on'].val: _dxf_file = dxfFile.split('/')[-1].split('\\')[-1] _dxf_file = _dxf_file[:-4] # cut last char:'.dxf' @@ -4136,4 +4892,4 @@ if 1: main(_dxf) print 'TOTAL TIME: %.6f' % (Blender.sys.time() - TIME) -""" \ No newline at end of file +""" From 1199744188def6f4570ae7994f4cb4639e9d507a Mon Sep 17 00:00:00 2001 From: Ton Roosendaal Date: Mon, 19 Nov 2007 18:00:48 +0000 Subject: [PATCH 12/29] Revamp of multi modifier option! - error fix: overall weight group value was used inverted - added "Inv" button to make weight group work inverted - added bigger, more clear Multi Modifier button --- source/blender/blenkernel/intern/armature.c | 14 +++++++++----- source/blender/makesdna/DNA_armature_types.h | 9 +++++---- source/blender/src/buttons_editing.c | 7 +++++-- 3 files changed, 19 insertions(+), 11 deletions(-) diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c index 477ee982138..9450e32806f 100644 --- a/source/blender/blenkernel/intern/armature.c +++ b/source/blender/blenkernel/intern/armature.c @@ -801,6 +801,7 @@ void armature_deform_verts(Object *armOb, Object *target, DerivedMesh *dm, int use_envelope = deformflag & ARM_DEF_ENVELOPE; int use_quaternion = deformflag & ARM_DEF_QUATERNION; int bbone_rest_def = deformflag & ARM_DEF_B_BONE_REST; + int invert_vgroup= deformflag & ARM_DEF_INVERT_VGROUP; int numGroups = 0; /* safety for vertexgroup index overflow */ int i, target_totvert = 0; /* safety for vertexgroup overflow */ int use_dverts = 0; @@ -921,7 +922,10 @@ void armature_deform_verts(Object *armOb, Object *target, DerivedMesh *dm, } /* hackish: the blending factor can be used for blending with prevCos too */ if(prevCos) { - prevco_weight= armature_weight; + if(invert_vgroup) + prevco_weight= 1.0f-armature_weight; + else + prevco_weight= armature_weight; armature_weight= 1.0f; } } @@ -1018,11 +1022,11 @@ void armature_deform_verts(Object *armOb, Object *target, DerivedMesh *dm, /* interpolate with previous modifier position using weight group */ - if(prevCos && prevco_weight!=1.0f) { + if(prevCos) { float mw= 1.0f - prevco_weight; - vertexCos[i][0]= mw*vertexCos[i][0] + prevco_weight*co[0]; - vertexCos[i][1]= mw*vertexCos[i][1] + prevco_weight*co[1]; - vertexCos[i][2]= mw*vertexCos[i][2] + prevco_weight*co[2]; + vertexCos[i][0]= prevco_weight*vertexCos[i][0] + mw*co[0]; + vertexCos[i][1]= prevco_weight*vertexCos[i][1] + mw*co[1]; + vertexCos[i][2]= prevco_weight*vertexCos[i][2] + mw*co[2]; } } diff --git a/source/blender/makesdna/DNA_armature_types.h b/source/blender/makesdna/DNA_armature_types.h index 82d120533d6..f5eacede809 100644 --- a/source/blender/makesdna/DNA_armature_types.h +++ b/source/blender/makesdna/DNA_armature_types.h @@ -112,10 +112,11 @@ typedef struct bArmature { #define ARM_ENVELOPE 3 /* armature->deformflag */ -#define ARM_DEF_VGROUP 1 -#define ARM_DEF_ENVELOPE 2 -#define ARM_DEF_QUATERNION 4 -#define ARM_DEF_B_BONE_REST 8 +#define ARM_DEF_VGROUP 1 +#define ARM_DEF_ENVELOPE 2 +#define ARM_DEF_QUATERNION 4 +#define ARM_DEF_B_BONE_REST 8 +#define ARM_DEF_INVERT_VGROUP 16 /* armature->pathflag */ #define ARM_PATH_FNUMS (1<<0) diff --git a/source/blender/src/buttons_editing.c b/source/blender/src/buttons_editing.c index 9dcd7f9921b..b1d13d86f38 100644 --- a/source/blender/src/buttons_editing.c +++ b/source/blender/src/buttons_editing.c @@ -1632,7 +1632,7 @@ static void draw_modifier(uiBlock *block, Object *ob, ModifierData *md, int *xco if(wmd->flag & MOD_WAVE_NORM) height += 19; } else if (md->type==eModifierType_Armature) { - height = 86; + height = 105; } else if (md->type==eModifierType_Hook) { HookModifierData *hmd = (HookModifierData*) md; height = 86; @@ -1959,12 +1959,15 @@ static void draw_modifier(uiBlock *block, Object *ob, ModifierData *md, int *xco but=uiDefBut(block, TEX, B_MODIFIER_RECALC, "VGroup: ", lx, (cy-=19), buttonWidth-40,19, &amd->defgrp_name, 0.0, 31.0, 0, 0, "Vertex Group name to control overall armature influence"); uiButSetCompleteFunc(but, autocomplete_vgroup, (void *)ob); - uiDefButS(block, TOG, B_ARM_RECALCDATA, "MM", lx+buttonWidth-40,cy, 40, 20, &amd->multi, 0, 0, 0, 0, "MultiModifier: This modifier uses same input as previous modifier, and mixes using this vgroup"); + uiDefButBitS(block, TOG, ARM_DEF_INVERT_VGROUP, B_ARM_RECALCDATA, "Inv", lx+buttonWidth-40,cy, 40, 20, &amd->deformflag, 0, 0, 0, 0, "Invert vertex group influence"); uiDefButBitS(block, TOG, ARM_DEF_VGROUP, B_ARM_RECALCDATA, "Vert.Groups", lx,cy-=19,buttonWidth/2,20, &amd->deformflag, 0, 0, 0, 0, "Enable VertexGroups defining deform"); uiDefButBitS(block, TOG, ARM_DEF_ENVELOPE, B_ARM_RECALCDATA, "Envelopes", lx+buttonWidth/2,cy,(buttonWidth + 1)/2,20, &amd->deformflag, 0, 0, 0, 0, "Enable Bone Envelopes defining deform"); uiDefButBitS(block, TOG, ARM_DEF_QUATERNION, B_ARM_RECALCDATA, "Quaternion", lx,(cy-=19),buttonWidth/2,20, &amd->deformflag, 0, 0, 0, 0, "Enable deform rotation interpolation with Quaternions"); uiDefButBitS(block, TOG, ARM_DEF_B_BONE_REST, B_ARM_RECALCDATA, "B-Bone Rest", lx+buttonWidth/2,cy,(buttonWidth + 1)/2,20, &amd->deformflag, 0, 0, 0, 0, "Make B-Bones deform already in rest position"); + + uiDefButS(block, TOG, B_ARM_RECALCDATA, "MultiModifier", lx,cy-=19, buttonWidth, 20, &amd->multi, 0, 0, 0, 0, "Use same input as previous modifier, and mix results using overall vgroup"); + } else if (md->type==eModifierType_Hook) { HookModifierData *hmd = (HookModifierData*) md; uiDefButF(block, NUM, B_MODIFIER_RECALC, "Falloff: ", lx, (cy-=19), buttonWidth,19, &hmd->falloff, 0.0, 100.0, 100, 0, "If not zero, the distance from hook where influence ends"); From a92173d4799d869f8c1a008825b5c8d139eb91e1 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 19 Nov 2007 19:00:28 +0000 Subject: [PATCH 13/29] ==Python API== removing vertex groups was broken, the function being called was for editmode, this would remove the vertex group but apply the weights from the removed group to the next vertex group. --- source/blender/python/api2_2x/Mesh.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/source/blender/python/api2_2x/Mesh.c b/source/blender/python/api2_2x/Mesh.c index 7430c2a6e91..5dffb488b3d 100644 --- a/source/blender/python/api2_2x/Mesh.c +++ b/source/blender/python/api2_2x/Mesh.c @@ -6409,6 +6409,10 @@ static PyObject *Mesh_removeVertGroup( PyObject * self, PyObject * value ) int nIndex; bDeformGroup *pGroup; + if( G.obedit ) + return EXPP_ReturnPyObjError(PyExc_RuntimeError, + "can't use removeVertGroup() while in edit mode" ); + if( !groupStr ) return EXPP_ReturnPyObjError( PyExc_TypeError, "expected string argument" ); @@ -6431,8 +6435,8 @@ static PyObject *Mesh_removeVertGroup( PyObject * self, PyObject * value ) nIndex++; object->actdef = (unsigned short)nIndex; - del_defgroup( object ); - + del_defgroup_in_object_mode( object ); + EXPP_allqueue( REDRAWBUTSALL, 1 ); Py_RETURN_NONE; From 7ade8141416097a6682f8f2f284148e002f10966 Mon Sep 17 00:00:00 2001 From: Andrea Weikert Date: Mon, 19 Nov 2007 20:13:14 +0000 Subject: [PATCH 14/29] Bugfix #7510: Doesn't save .blend file name with [ * Added Windows specific implementation for fnmatch taken from GNU/MINGW/MSYS C library * behaviour should now be the same as under Linux and other OSs * changed filename for fnmatch.h to ensure we include the correct one if we link with the included implementation * tested compile with MSVC 7.1 and gcc(MinGW-5.1.3) on Windows. --- .../blender/blenlib/BLI_blenlib.vcproj | 6 + source/blender/blenlib/BLI_fnmatch.h | 69 +++++ source/blender/blenlib/intern/fnmatch.c | 250 ++++++++++++++++++ source/blender/src/editimasel.c | 6 +- source/blender/src/filesel.c | 5 +- 5 files changed, 333 insertions(+), 3 deletions(-) create mode 100644 source/blender/blenlib/BLI_fnmatch.h create mode 100644 source/blender/blenlib/intern/fnmatch.c diff --git a/projectfiles_vc7/blender/blenlib/BLI_blenlib.vcproj b/projectfiles_vc7/blender/blenlib/BLI_blenlib.vcproj index f7038e610f1..0951c40d891 100644 --- a/projectfiles_vc7/blender/blenlib/BLI_blenlib.vcproj +++ b/projectfiles_vc7/blender/blenlib/BLI_blenlib.vcproj @@ -364,6 +364,9 @@ + + @@ -434,6 +437,9 @@ + + diff --git a/source/blender/blenlib/BLI_fnmatch.h b/source/blender/blenlib/BLI_fnmatch.h new file mode 100644 index 00000000000..af1dcf523bf --- /dev/null +++ b/source/blender/blenlib/BLI_fnmatch.h @@ -0,0 +1,69 @@ +/* Copyright (C) 1991, 1992, 1993 Free Software Foundation, Inc. + +NOTE: The canonical source of this file is maintained with the GNU C Library. +Bugs can be reported to bug-glibc@prep.ai.mit.edu. + +This program is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software Foundation, +Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef _FNMATCH_H + +#define _FNMATCH_H 1 + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined (__cplusplus) || (defined (__STDC__) && __STDC__) +#undef __P +#define __P(protos) protos +#else /* Not C++ or ANSI C. */ +#undef __P +#define __P(protos) () +/* We can get away without defining `const' here only because in this file + it is used only inside the prototype for `fnmatch', which is elided in + non-ANSI C where `const' is problematical. */ +#endif /* C++ or ANSI C. */ + + +/* We #undef these before defining them because some losing systems + (HP-UX A.08.07 for example) define these in . */ +#undef FNM_PATHNAME +#undef FNM_NOESCAPE +#undef FNM_PERIOD + +/* Bits set in the FLAGS argument to `fnmatch'. */ +#define FNM_PATHNAME (1 << 0) /* No wildcard can ever match `/'. */ +#define FNM_NOESCAPE (1 << 1) /* Backslashes don't quote special chars. */ +#define FNM_PERIOD (1 << 2) /* Leading `.' is matched only explicitly. */ + +#if !defined (_POSIX_C_SOURCE) || _POSIX_C_SOURCE < 2 || defined (_GNU_SOURCE) +#define FNM_FILE_NAME FNM_PATHNAME /* Preferred GNU name. */ +#define FNM_LEADING_DIR (1 << 3) /* Ignore `/...' after a match. */ +#define FNM_CASEFOLD (1 << 4) /* Compare without regard to case. */ +#endif + +/* Value returned by `fnmatch' if STRING does not match PATTERN. */ +#define FNM_NOMATCH 1 + +/* Match STRING against the filename pattern PATTERN, + returning zero if it matches, FNM_NOMATCH if not. */ +extern int fnmatch __P ((const char *__pattern, const char *__string, + int __flags)); + +#ifdef __cplusplus +} +#endif + +#endif /* fnmatch.h */ diff --git a/source/blender/blenlib/intern/fnmatch.c b/source/blender/blenlib/intern/fnmatch.c new file mode 100644 index 00000000000..54114ad3448 --- /dev/null +++ b/source/blender/blenlib/intern/fnmatch.c @@ -0,0 +1,250 @@ +/* Copyright (C) 1991, 1992, 1993, 1996, 1997 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef WIN32 + +#if HAVE_CONFIG_H +# include +#endif + +/* Enable GNU extensions in fnmatch.h. */ +#ifndef _GNU_SOURCE +# define _GNU_SOURCE 1 +#endif + +#include +#include +#include + + +/* Comment out all this code if we are using the GNU C Library, and are not + actually compiling the library itself. This code is part of the GNU C + Library, but also included in many other GNU distributions. Compiling + and linking in this code is a waste when using the GNU C library + (especially if it is a shared library). Rather than having every GNU + program understand `configure --with-gnu-libc' and omit the object files, + it is simpler to just do this in the source for each such file. */ + +#if defined _LIBC || !defined __GNU_LIBRARY__ + + +# if defined STDC_HEADERS || !defined isascii +# define ISASCII(c) 1 +# else +# define ISASCII(c) isascii(c) +# endif + +# define ISUPPER(c) (ISASCII (c) && isupper (c)) + + +# ifndef errno +extern int errno; +# endif + +/* Match STRING against the filename pattern PATTERN, returning zero if + it matches, nonzero if not. */ +int +fnmatch (const char *pattern, const char *string, int flags) +{ + register const char *p = pattern, *n = string; + register char c; + +/* Note that this evaluates C many times. */ +# define FOLD(c) ((flags & FNM_CASEFOLD) && ISUPPER (c) ? tolower (c) : (c)) + + while ((c = *p++) != '\0') + { + c = FOLD (c); + + switch (c) + { + case '?': + if (*n == '\0') + return FNM_NOMATCH; + else if ((flags & FNM_FILE_NAME) && *n == '/') + return FNM_NOMATCH; + else if ((flags & FNM_PERIOD) && *n == '.' && + (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/'))) + return FNM_NOMATCH; + break; + + case '\\': + if (!(flags & FNM_NOESCAPE)) + { + c = *p++; + if (c == '\0') + /* Trailing \ loses. */ + return FNM_NOMATCH; + c = FOLD (c); + } + if (FOLD (*n) != c) + return FNM_NOMATCH; + break; + + case '*': + if ((flags & FNM_PERIOD) && *n == '.' && + (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/'))) + return FNM_NOMATCH; + + for (c = *p++; c == '?' || c == '*'; c = *p++) + { + if ((flags & FNM_FILE_NAME) && *n == '/') + /* A slash does not match a wildcard under FNM_FILE_NAME. */ + return FNM_NOMATCH; + else if (c == '?') + { + /* A ? needs to match one character. */ + if (*n == '\0') + /* There isn't another character; no match. */ + return FNM_NOMATCH; + else + /* One character of the string is consumed in matching + this ? wildcard, so *??? won't match if there are + less than three characters. */ + ++n; + } + } + + if (c == '\0') + return 0; + + { + char c1 = (!(flags & FNM_NOESCAPE) && c == '\\') ? *p : c; + c1 = FOLD (c1); + for (--p; *n != '\0'; ++n) + if ((c == '[' || FOLD (*n) == c1) && + fnmatch (p, n, flags & ~FNM_PERIOD) == 0) + return 0; + return FNM_NOMATCH; + } + + case '[': + { + /* Nonzero if the sense of the character class is inverted. */ + register int not; + + if (*n == '\0') + return FNM_NOMATCH; + + if ((flags & FNM_PERIOD) && *n == '.' && + (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/'))) + return FNM_NOMATCH; + + not = (*p == '!' || *p == '^'); + if (not) + ++p; + + c = *p++; + for (;;) + { + register char cstart = c, cend = c; + + if (!(flags & FNM_NOESCAPE) && c == '\\') + { + if (*p == '\0') + return FNM_NOMATCH; + cstart = cend = *p++; + } + + cstart = cend = FOLD (cstart); + + if (c == '\0') + /* [ (unterminated) loses. */ + return FNM_NOMATCH; + + c = *p++; + c = FOLD (c); + + if ((flags & FNM_FILE_NAME) && c == '/') + /* [/] can never match. */ + return FNM_NOMATCH; + + if (c == '-' && *p != ']') + { + cend = *p++; + if (!(flags & FNM_NOESCAPE) && cend == '\\') + cend = *p++; + if (cend == '\0') + return FNM_NOMATCH; + cend = FOLD (cend); + + c = *p++; + } + + if (FOLD (*n) >= cstart && FOLD (*n) <= cend) + goto matched; + + if (c == ']') + break; + } + if (!not) + return FNM_NOMATCH; + break; + + matched:; + /* Skip the rest of the [...] that already matched. */ + while (c != ']') + { + if (c == '\0') + /* [... (unterminated) loses. */ + return FNM_NOMATCH; + + c = *p++; + if (!(flags & FNM_NOESCAPE) && c == '\\') + { + if (*p == '\0') + return FNM_NOMATCH; + /* XXX 1003.2d11 is unclear if this is right. */ + ++p; + } + } + if (not) + return FNM_NOMATCH; + } + break; + + default: + if (c != FOLD (*n)) + return FNM_NOMATCH; + } + + ++n; + } + + if (*n == '\0') + return 0; + + if ((flags & FNM_LEADING_DIR) && *n == '/') + /* The FNM_LEADING_DIR flag says that "foo*" matches "foobar/frobozz". */ + return 0; + + return FNM_NOMATCH; + +# undef FOLD +} + +#endif /* _LIBC or not __GNU_LIBRARY__. */ + +#else + +static void BLI_FNMATCH_C_IS_EMPTY_FOR_UNIX(void) +{ + /*intentionally empty*/ +} + +#endif /* WIN32 */ + + diff --git a/source/blender/src/editimasel.c b/source/blender/src/editimasel.c index abc19b53671..d57df3aaccf 100644 --- a/source/blender/src/editimasel.c +++ b/source/blender/src/editimasel.c @@ -117,12 +117,14 @@ static int imasel_has_func(SpaceImaSel *simasel) return 0; } -/* ugly, needs to be moved to platform specific files - elubie */ -#if defined WIN32 || defined __BeOS +#if defined __BeOS static int fnmatch(const char *pattern, const char *string, int flags) { return 0; } +#elif defined WIN32 && !defined _LIBC + /* use fnmatch included in blenlib */ + #include "BLI_fnmatch.h" #else #include #endif diff --git a/source/blender/src/filesel.c b/source/blender/src/filesel.c index 10f234fcd21..599c6d5aae2 100644 --- a/source/blender/src/filesel.c +++ b/source/blender/src/filesel.c @@ -116,11 +116,14 @@ #include "FTF_Api.h" #endif -#if defined WIN32 || defined __BeOS +#if defined __BeOS static int fnmatch(const char *pattern, const char *string, int flags) { return 0; } +#elif defined WIN32 && !defined _LIBC + /* use fnmatch included in blenlib */ + #include "BLI_fnmatch.h" #else #include #endif From 7733696b24975aba4d9430a911c213ba7080b746 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 20 Nov 2007 14:09:34 +0000 Subject: [PATCH 15/29] draw image path and size stats in the sequencer again (removed when making single images act differently) sequencer marker selection didn't work like the marker view. --- source/blender/src/drawseq.c | 17 +++++++++-------- source/blender/src/editseq.c | 2 +- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/source/blender/src/drawseq.c b/source/blender/src/drawseq.c index 77006353640..bb04440bd0f 100644 --- a/source/blender/src/drawseq.c +++ b/source/blender/src/drawseq.c @@ -916,7 +916,7 @@ static void draw_extra_seqinfo(void) /* CURRENT */ se= give_stripelem(last_seq, (G.scene->r.cfra)); if(se) { - sprintf(str, "Cur: %s", se->name); + sprintf(str, "Cur: %s%s", last_seq->strip->dir, se->name); glRasterPos3f(xco, yco, 0.0); BMF_DrawString(G.font, str); xco += xfac*BMF_GetStringWidth(G.font, str) +10.0*xfac; @@ -934,21 +934,22 @@ static void draw_extra_seqinfo(void) glRasterPos3f(xco, yco, 0.0); BMF_DrawString(G.font, str); xco += xfac*BMF_GetStringWidth(G.font, str) +30.0*xfac; - - /* orig size */ - sprintf(str, "OrigSize: %d x %d", last_seq->strip->orx, last_seq->strip->ory); - glRasterPos3f(xco, yco, 0.0); - BMF_DrawString(G.font, str); - xco += xfac*BMF_GetStringWidth(G.font, str) +30.0*xfac; } } else { /* single image */ if (last_seq->strip) { - sprintf(str, "Single: %s len: %d", last_seq->strip->stripdata->name, last_seq->enddisp-last_seq->startdisp); + sprintf(str, "Single: %s%s len: %d", last_seq->strip->dir, last_seq->strip->stripdata->name, last_seq->enddisp-last_seq->startdisp); glRasterPos3f(xco, yco, 0.0); BMF_DrawString(G.font, str); xco += xfac*BMF_GetStringWidth(G.font, str) +30.0*xfac; } } + /* orig size */ + if(last_seq->strip) { + sprintf(str, "OrigSize: %d x %d", last_seq->strip->orx, last_seq->strip->ory); + glRasterPos3f(xco, yco, 0.0); + BMF_DrawString(G.font, str); + xco += xfac*BMF_GetStringWidth(G.font, str) +30.0*xfac; + } } else if(last_seq->type==SEQ_MOVIE) { diff --git a/source/blender/src/editseq.c b/source/blender/src/editseq.c index 8565a302f45..27ee7a14315 100644 --- a/source/blender/src/editseq.c +++ b/source/blender/src/editseq.c @@ -777,7 +777,7 @@ void mouse_select_seq(void) if (marker) { int oldflag; /* select timeline marker */ - if ((G.qual & LR_SHIFTKEY)==0) { + if (G.qual & LR_SHIFTKEY) { oldflag= marker->flag; deselect_markers(0, 0); From 0ec59425210033b9158bd8d2fbc5c6de1bc62bbb Mon Sep 17 00:00:00 2001 From: Ton Roosendaal Date: Tue, 20 Nov 2007 15:01:44 +0000 Subject: [PATCH 16/29] Tiny group-proxy update: When you make proxy, the group-update tags should be set OK. Symptom: you could not move proxy around until you set keys in bones and advance frame. --- source/blender/blenkernel/intern/object.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index a08256eb4a0..095d6f525a9 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -1178,6 +1178,8 @@ void object_make_proxy(Object *ob, Object *target, Object *gob) VECCOPY(ob->loc, gob->loc); VECCOPY(ob->rot, gob->rot); VECCOPY(ob->size, gob->size); + + group_tag_recalc(gob->dup_group); } else { VECCOPY(ob->loc, target->loc); From b7e0da6c3a83bd5aa8d3ad4aa285904d5c121f91 Mon Sep 17 00:00:00 2001 From: Ton Roosendaal Date: Tue, 20 Nov 2007 16:58:25 +0000 Subject: [PATCH 17/29] Another feature request from the animation dept: Relative shapekeys now allow to define the Shape it is relative to! (It used to be relative with respect to the first key, which is still default). The reason for this feature is that keys don't always add together well when they're all derived from the same base shape. A clear example is hard to make... will wait for someone posting it. :) --- source/blender/blenkernel/intern/key.c | 6 +++++- source/blender/makesdna/DNA_key_types.h | 4 ++-- source/blender/src/buttons_editing.c | 16 +++++++++++----- 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/source/blender/blenkernel/intern/key.c b/source/blender/blenkernel/intern/key.c index 8da3ea0b994..234a096edce 100644 --- a/source/blender/blenkernel/intern/key.c +++ b/source/blender/blenkernel/intern/key.c @@ -680,11 +680,15 @@ static void do_rel_key(int start, int end, int tot, char *basispoin, Key *key, i /* only with value, and no difference allowed */ if(icuval!=0.0f && kb->totelem==tot) { + KeyBlock *refb; float weight, *weights= kb->weights; poin= basispoin; - reffrom= key->refkey->data; from= kb->data; + /* reference now can be any block */ + refb= BLI_findlink(&key->block, kb->relative); + if(refb==NULL) continue; + reffrom= refb->data; poin+= start*ofs[0]; reffrom+= key->elemsize*start; // key elemsize yes! diff --git a/source/blender/makesdna/DNA_key_types.h b/source/blender/makesdna/DNA_key_types.h index 3292e07f80e..785cf515a42 100644 --- a/source/blender/makesdna/DNA_key_types.h +++ b/source/blender/makesdna/DNA_key_types.h @@ -44,8 +44,8 @@ typedef struct KeyBlock { float pos; float curval; - short type, adrcode; - int totelem; + short type, adrcode, relative, pad1; /* relative == 0 means first key is reference */ + int totelem, pad2; void *data; float *weights; diff --git a/source/blender/src/buttons_editing.c b/source/blender/src/buttons_editing.c index b1d13d86f38..082353f1174 100644 --- a/source/blender/src/buttons_editing.c +++ b/source/blender/src/buttons_editing.c @@ -2217,7 +2217,7 @@ static void editing_panel_modifiers(Object *ob) if(yco < 0) uiNewPanelHeight(block, 204-yco); } -static char *make_key_menu(Key *key) +static char *make_key_menu(Key *key, int startindex) { KeyBlock *kb; int index= 1; @@ -2227,7 +2227,7 @@ static char *make_key_menu(Key *key) str= MEM_mallocN(index*40, "key string"); str[0]= 0; - index= 1; + index= startindex; for (kb = key->block.first; kb; kb=kb->next, index++) { sprintf (item, "|%s%%x%d", kb->name, index); strcat(str, item); @@ -2273,9 +2273,10 @@ static void editing_panel_shapes(Object *ob) uiDefIconButBitS(block, TOG, OB_SHAPE_LOCK, B_LOCKKEY, icon, 10,150,25,20, &ob->shapeflag, 0, 0, 0, 0, "Always show the current Shape for this Object"); uiSetButLock(G.obedit==ob, "Unable to perform in EditMode"); uiDefIconBut(block, BUT, B_PREVKEY, ICON_TRIA_LEFT, 35,150,20,20, NULL, 0, 0, 0, 0, "Previous Shape Key"); - strp= make_key_menu(key); - uiDefButS(block, MENU, B_SETKEY, strp, 55,150,20,20, &ob->shapenr, 0, 0, 0, 0, "Browses existing choices or adds NEW"); + strp= make_key_menu(key, 1); + uiDefButS(block, MENU, B_SETKEY, strp, 55,150,20,20, &ob->shapenr, 0, 0, 0, 0, "Browse existing choices"); MEM_freeN(strp); + uiDefIconBut(block, BUT, B_NEXTKEY, ICON_TRIA_RIGHT, 75,150,20,20, NULL, 0, 0, 0, 0, "Next Shape Key"); uiClearButLock(); uiDefBut(block, TEX, B_NAMEKEY, "", 95, 150, 190, 20, kb->name, 0.0, 31.0, 0, 0, "Current Shape Key name"); @@ -2289,9 +2290,14 @@ static void editing_panel_shapes(Object *ob) uiDefButF(block, NUM, B_REDR, "Max ", 235,120, 75, 20, &kb->slidermax, -10.0, 10.0, 100, 1, "Maximum for slider"); uiBlockEndAlign(block); } - if(key->type && ob->shapenr!=1) + if(key->type && ob->shapenr!=1) { uiDefBut(block, TEX, B_MODIFIER_RECALC, "VGroup: ", 10, 90, 150,19, &kb->vgroup, 0.0, 31.0, 0, 0, "Vertex Weight Group name, to blend with Basis Shape"); + strp= make_key_menu(key, 0); + uiDefButS(block, MENU, B_MODIFIER_RECALC, strp, 160, 90, 150,19, &kb->relative, 0.0, 0.0, 0, 0, "Shape used as a relative key"); + MEM_freeN(strp); + } + if(key->type==0) uiDefButS(block, NUM, B_DIFF, "Slurph:", 10, 60, 150, 19, &(key->slurph), -500.0, 500.0, 0, 0, "Creates a delay in amount of frames in applying keypositions, first vertex goes first"); From b276050a08a93ea61e4fe085278e8c1feff399d2 Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Wed, 21 Nov 2007 04:08:00 +0000 Subject: [PATCH 18/29] == Auto-Keyframing - 'Only Needed' Improvements == The 'Only Needed' option for Auto-Keyframing now works better with a few of the different transform options. Rotating/Scaling using a pivot point that is not the center of the Object/Bone (3d-cursor, active), also inserts location keyframes if the location also changes. If "Only Centers" option is activated, then only location keyframes are inserted. --- source/blender/src/edit.c | 10 +- source/blender/src/transform_conversions.c | 127 +++++++++++++++------ 2 files changed, 95 insertions(+), 42 deletions(-) diff --git a/source/blender/src/edit.c b/source/blender/src/edit.c index 7d784dcecfd..f6b60a3d8fc 100644 --- a/source/blender/src/edit.c +++ b/source/blender/src/edit.c @@ -1221,7 +1221,7 @@ void snap_sel_to_grid() } ob->pose->flag |= (POSE_LOCKED|POSE_DO_UNLOCK); - /* autokeyframing */ + /* auto-keyframing */ autokeyframe_pose_cb_func(ob, TFM_TRANSLATION, 0); DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA); } @@ -1231,10 +1231,10 @@ void snap_sel_to_grid() vec[0]= -ob->obmat[3][0]+G.vd->gridview*floor(.5+ ob->obmat[3][0]/gridf); vec[1]= -ob->obmat[3][1]+G.vd->gridview*floor(.5+ ob->obmat[3][1]/gridf); vec[2]= -ob->obmat[3][2]+G.vd->gridview*floor(.5+ ob->obmat[3][2]/gridf); - + if(ob->parent) { where_is_object(ob); - + Mat3Inv(imat, originmat); Mat3MulVecfl(imat, vec); ob->loc[0]+= vec[0]; @@ -1334,7 +1334,7 @@ void snap_sel_to_curs() } ob->pose->flag |= (POSE_LOCKED|POSE_DO_UNLOCK); - /* autokeyframing */ + /* auto-keyframing */ autokeyframe_pose_cb_func(ob, TFM_TRANSLATION, 0); DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA); } @@ -1686,7 +1686,7 @@ void snap_to_center() } } - /* autokeyframing */ + /* auto-keyframing */ ob->pose->flag |= POSE_DO_UNLOCK; autokeyframe_pose_cb_func(ob, TFM_TRANSLATION, 0); DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA); diff --git a/source/blender/src/transform_conversions.c b/source/blender/src/transform_conversions.c index 60ff52ec747..fd2e089e169 100644 --- a/source/blender/src/transform_conversions.c +++ b/source/blender/src/transform_conversions.c @@ -2693,11 +2693,11 @@ void autokeyframe_ob_cb_func(Object *ob, int tmode) char *actname=""; if (G.flags & G_RECORDKEYS) { - if(ob->ipoflag & OB_ACTION_OB) + if (ob->ipoflag & OB_ACTION_OB) actname= "Object"; - - if(U.uiflag & USER_KEYINSERTAVAI) { - if(ob->ipo || ob->action) { + + if (U.uiflag & USER_KEYINSERTAVAI) { + if (ob->ipo || ob->action) { ID *id= (ID *)(ob); if (ob->ipo) { @@ -2713,7 +2713,7 @@ void autokeyframe_ob_cb_func(Object *ob, int tmode) icu= NULL; } - while(icu) { + while (icu) { icu->flag &= ~IPO_SELECT; if (U.uiflag & USER_KEYINSERTNEED) insertkey_smarter(id, ID_OB, actname, NULL, icu->adrcode); @@ -2724,36 +2724,65 @@ void autokeyframe_ob_cb_func(Object *ob, int tmode) } } else if (U.uiflag & USER_KEYINSERTNEED) { - if (tmode==TFM_RESIZE) { - insertkey_smarter(&ob->id, ID_OB, actname, NULL, OB_SIZE_X); - insertkey_smarter(&ob->id, ID_OB, actname, NULL, OB_SIZE_Y); - insertkey_smarter(&ob->id, ID_OB, actname, NULL, OB_SIZE_Z); + short doLoc=0, doRot=0, doScale=0; + + /* filter the conditions when this happens (assume that curarea->spacetype==SPACE_VIE3D) */ + if (tmode == TFM_TRANSLATION) { + doLoc = 1; } - else if (tmode==TFM_ROTATION) { + else if (tmode == TFM_ROTATION) { + if (G.vd->around == V3D_ACTIVE) { + if (ob != OBACT) + doLoc = 1; + } + else if (G.vd->around == V3D_CURSOR) + doLoc = 1; + + if ((G.vd->flag & V3D_ALIGN)==0) + doRot = 1; + } + else if (tmode == TFM_RESIZE) { + if (G.vd->around == V3D_ACTIVE) { + if (ob != OBACT) + doLoc = 1; + } + else if (G.vd->around == V3D_CURSOR) + doLoc = 1; + + if ((G.vd->flag & V3D_ALIGN)==0) + doScale = 1; + } + + if (doLoc) { + insertkey_smarter(&ob->id, ID_OB, actname, NULL, OB_LOC_X); + insertkey_smarter(&ob->id, ID_OB, actname, NULL, OB_LOC_Y); + insertkey_smarter(&ob->id, ID_OB, actname, NULL, OB_LOC_Z); + } + if (doRot) { insertkey_smarter(&ob->id, ID_OB, actname, NULL, OB_ROT_X); insertkey_smarter(&ob->id, ID_OB, actname, NULL, OB_ROT_Y); insertkey_smarter(&ob->id, ID_OB, actname, NULL, OB_ROT_Z); } - else if (tmode==TFM_TRANSLATION) { - insertkey_smarter(&ob->id, ID_OB, actname, NULL, OB_LOC_X); - insertkey_smarter(&ob->id, ID_OB, actname, NULL, OB_LOC_Y); - insertkey_smarter(&ob->id, ID_OB, actname, NULL, OB_LOC_Z); + if (doScale) { + insertkey_smarter(&ob->id, ID_OB, actname, NULL, OB_SIZE_X); + insertkey_smarter(&ob->id, ID_OB, actname, NULL, OB_SIZE_Y); + insertkey_smarter(&ob->id, ID_OB, actname, NULL, OB_SIZE_Z); } } else { insertkey(&ob->id, ID_OB, actname, NULL, OB_ROT_X, 0); insertkey(&ob->id, ID_OB, actname, NULL, OB_ROT_Y, 0); insertkey(&ob->id, ID_OB, actname, NULL, OB_ROT_Z, 0); - + insertkey(&ob->id, ID_OB, actname, NULL, OB_LOC_X, 0); insertkey(&ob->id, ID_OB, actname, NULL, OB_LOC_Y, 0); insertkey(&ob->id, ID_OB, actname, NULL, OB_LOC_Z, 0); - + insertkey(&ob->id, ID_OB, actname, NULL, OB_SIZE_X, 0); insertkey(&ob->id, ID_OB, actname, NULL, OB_SIZE_Y, 0); insertkey(&ob->id, ID_OB, actname, NULL, OB_SIZE_Z, 0); } - + remake_object_ipos(ob); allqueue(REDRAWMARKER, 0); } @@ -2784,7 +2813,7 @@ void autokeyframe_pose_cb_func(Object *ob, int tmode, short targetless_ik) pchan->bone->flag &= ~BONE_UNKEYED; /* only insert into available channels? */ - if(U.uiflag & USER_KEYINSERTAVAI) { + if (U.uiflag & USER_KEYINSERTAVAI) { bActionChannel *achan; for (achan = act->chanbase.first; achan; achan=achan->next){ @@ -2802,18 +2831,42 @@ void autokeyframe_pose_cb_func(Object *ob, int tmode, short targetless_ik) } /* only insert keyframe if needed? */ else if (U.uiflag & USER_KEYINSERTNEED) { - if ((tmode==TFM_TRANSLATION) && (targetless_ik==0)) { + short doLoc=0, doRot=0, doScale=0; + + /* filter the conditions when this happens (assume that curarea->spacetype==SPACE_VIE3D) */ + if (tmode == TFM_TRANSLATION) { + if (targetless_ik) + doRot= 1; + else + doLoc = 1; + } + else if (tmode == TFM_ROTATION) { + if (ELEM(G.vd->around, V3D_CURSOR, V3D_ACTIVE)) + doLoc = 1; + + if ((G.vd->flag & V3D_ALIGN)==0) + doRot = 1; + } + else if (tmode == TFM_RESIZE) { + if (ELEM(G.vd->around, V3D_CURSOR, V3D_ACTIVE)) + doLoc = 1; + + if ((G.vd->flag & V3D_ALIGN)==0) + doScale = 1; + } + + if (doLoc) { insertkey_smarter(&ob->id, ID_PO, pchan->name, NULL, AC_LOC_X); insertkey_smarter(&ob->id, ID_PO, pchan->name, NULL, AC_LOC_Y); insertkey_smarter(&ob->id, ID_PO, pchan->name, NULL, AC_LOC_Z); } - if ((tmode==TFM_ROTATION) || ((tmode==TFM_TRANSLATION) && targetless_ik)) { + if (doRot) { insertkey_smarter(&ob->id, ID_PO, pchan->name, NULL, AC_QUAT_W); insertkey_smarter(&ob->id, ID_PO, pchan->name, NULL, AC_QUAT_X); insertkey_smarter(&ob->id, ID_PO, pchan->name, NULL, AC_QUAT_Y); insertkey_smarter(&ob->id, ID_PO, pchan->name, NULL, AC_QUAT_Z); } - if (tmode==TFM_RESIZE) { + if (doScale) { insertkey_smarter(&ob->id, ID_PO, pchan->name, NULL, AC_SIZE_X); insertkey_smarter(&ob->id, ID_PO, pchan->name, NULL, AC_SIZE_Y); insertkey_smarter(&ob->id, ID_PO, pchan->name, NULL, AC_SIZE_Z); @@ -2888,7 +2941,7 @@ void special_aftertrans_update(TransInfo *t) if (t->spacetype==SPACE_VIEW3D) EM_automerge(1); - if(t->spacetype == SPACE_ACTION) { + if (t->spacetype == SPACE_ACTION) { void *data; short datatype; @@ -2928,7 +2981,7 @@ void special_aftertrans_update(TransInfo *t) DAG_object_flush_update(G.scene, OBACT, OB_RECALC_DATA); } } - else if(t->spacetype == SPACE_NLA) { + else if (t->spacetype == SPACE_NLA) { synchronize_action_strips(); /* cleanup */ @@ -2937,35 +2990,35 @@ void special_aftertrans_update(TransInfo *t) recalc_all_ipos(); // bad } - else if(t->spacetype == SPACE_IPO) { + else if (t->spacetype == SPACE_IPO) { // FIXME! is there any code from the old transform_ipo that needs to be added back? /* resetting slow-parents isn't really necessary when editing sequence ipo's */ if (G.sipo->blocktype==ID_SEQ) resetslowpar= 0; } - else if(G.obedit) { - if(t->mode==TFM_BONESIZE || t->mode==TFM_BONE_ENVELOPE) + else if (G.obedit) { + if (t->mode==TFM_BONESIZE || t->mode==TFM_BONE_ENVELOPE) allqueue(REDRAWBUTSEDIT, 0); /* table needs to be created for each edit command, since vertices can move etc */ mesh_octree_table(G.obedit, NULL, 'e'); } - else if( (t->flag & T_POSE) && t->poseobj) { + else if ((t->flag & T_POSE) && (t->poseobj)) { bArmature *arm; bPose *pose; bPoseChannel *pchan; short targetless_ik= 0; - + ob= t->poseobj; arm= ob->data; pose= ob->pose; /* this signal does one recalc on pose, then unlocks, so ESC or edit will work */ pose->flag |= POSE_DO_UNLOCK; - + /* if target-less IK grabbing, we calculate the pchan transforms and clear flag */ - if(!cancelled && t->mode==TFM_TRANSLATION) + if (!cancelled && t->mode==TFM_TRANSLATION) targetless_ik= apply_targetless_ik(ob); else { /* not forget to clear the auto flag */ @@ -2975,15 +3028,15 @@ void special_aftertrans_update(TransInfo *t) } } - if(t->mode==TFM_TRANSLATION) + if (t->mode==TFM_TRANSLATION) pose_grab_with_ik_clear(ob); /* automatic inserting of keys and unkeyed tagging - only if transform wasn't cancelled (or TFM_DUMMY) */ - if(!cancelled && (t->mode != TFM_DUMMY)) { + if (!cancelled && (t->mode != TFM_DUMMY)) { autokeyframe_pose_cb_func(ob, t->mode, targetless_ik); DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA); } - else if(arm->flag & ARM_DELAYDEFORM) { + else if (arm->flag & ARM_DELAYDEFORM) { /* old optimize trick... this enforces to bypass the depgraph */ DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA); ob->recalc= 0; // is set on OK position already by recalcData() @@ -2991,19 +3044,19 @@ void special_aftertrans_update(TransInfo *t) else DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA); - if(t->mode==TFM_BONESIZE || t->mode==TFM_BONE_ENVELOPE) + if (t->mode==TFM_BONESIZE || t->mode==TFM_BONE_ENVELOPE) allqueue(REDRAWBUTSEDIT, 0); } else { base= FIRSTBASE; - while(base) { + while (base) { if(base->flag & BA_DO_IPO) redrawipo= 1; ob= base->object; - if(modifiers_isSoftbodyEnabled(ob)) ob->softflag |= OB_SB_REDO; + if (modifiers_isSoftbodyEnabled(ob)) ob->softflag |= OB_SB_REDO; /* Set autokey if necessary */ if ((!cancelled) && (t->mode != TFM_DUMMY) && (base->flag & SELECT)) { @@ -3017,7 +3070,7 @@ void special_aftertrans_update(TransInfo *t) clear_trans_object_base_flags(); - if(redrawipo) { + if (redrawipo) { allqueue(REDRAWNLA, 0); allqueue(REDRAWACTION, 0); allqueue(REDRAWIPO, 0); From 00762be141fcbb1fca046a33f9045440167c0c1e Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Wed, 21 Nov 2007 04:49:13 +0000 Subject: [PATCH 19/29] Patch #7779: Make the 'Hold' option work with NLA action modifiers Patch by: Matt Ebb (broken) Currently in Blender, NLA action modifiers can work in very wacky and mysterious ways. If an action is being modified with a path deform, when it reaches the end of that strip, it will snap back to the original un-modified location, regardless of whether the strip 'Hold' option is on. It's very frustrating to work with, and causes all sorts of problems - if you use a path to make a character walk from point A to point B, you generally want him to stay at point B, and not jump somewhere completely different, just because the strip ended. This patch fixes this behaviour, and makes it much more sensible and predictable. There is a chance that this will break old files that were reliant on the old broken behaviour though, but I think it's definitely worthwhile to fix this problem. Check the demo file in Blender 2.45 vs one with this patch applied - you can see the difference in behaviour. Demo File Link (attachment in original tracker post): https://projects.blender.org/tracker/download.php/9/127/7779/4856/wheelsetup2.zip --- source/blender/blenkernel/intern/armature.c | 34 +++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c index 9450e32806f..59786afd999 100644 --- a/source/blender/blenkernel/intern/armature.c +++ b/source/blender/blenkernel/intern/armature.c @@ -1888,12 +1888,42 @@ static void where_is_ik_bone(bPoseChannel *pchan, float ik_mat[][3]) // nr = t static void do_strip_modifiers(Object *armob, Bone *bone, bPoseChannel *pchan) { bActionModifier *amod; - bActionStrip *strip; + bActionStrip *strip, *strip2; float scene_cfra= G.scene->r.cfra; + int do_modif; for (strip=armob->nlastrips.first; strip; strip=strip->next) { - if(scene_cfra>=strip->start && scene_cfra<=strip->end) { + do_modif=0; + + if (scene_cfra>=strip->start && scene_cfra<=strip->end) + do_modif=1; + + if ((scene_cfra > strip->end) && (strip->flag & ACTSTRIP_HOLDLASTFRAME)) { + do_modif=1; + /* if there are any other strips active, ignore modifiers for this strip - + * 'hold' option should only hold action modifiers if there are + * no other active strips */ + for (strip2=strip->next; strip2; strip2=strip2->next) { + if (strip2 == strip) continue; + + if (scene_cfra>=strip2->start && scene_cfra<=strip2->end) { + if (!(strip2->flag & ACTSTRIP_MUTE)) + do_modif=0; + } + } + + /* if there are any later, activated, strips with 'hold' set, they take precedence, + * so ignore modifiers for this strip */ + for (strip2=strip->next; strip2; strip2=strip2->next) { + if (scene_cfra < strip2->start) continue; + if ((strip2->flag & ACTSTRIP_HOLDLASTFRAME) && !(strip2->flag & ACTSTRIP_MUTE)) { + do_modif=0; + } + } + } + + if (do_modif) { /* temporal solution to prevent 2 strips accumulating */ if(scene_cfra==strip->end && strip->next && strip->next->start==scene_cfra) continue; From 3a8328784e98f7d32406ee9b5dd462476905f54b Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 21 Nov 2007 09:46:08 +0000 Subject: [PATCH 20/29] made twig taper a float rather then a bool, added type conversion when loading settings. --- release/scripts/wizard_curve2tree.py | 181 ++++++++++++++++++++++++--- 1 file changed, 161 insertions(+), 20 deletions(-) diff --git a/release/scripts/wizard_curve2tree.py b/release/scripts/wizard_curve2tree.py index 457b438ddb6..a729494274a 100644 --- a/release/scripts/wizard_curve2tree.py +++ b/release/scripts/wizard_curve2tree.py @@ -102,8 +102,13 @@ def getObFromName(name): except: return None else: return None - - + +def getGroupFromName(name): + if name: + try: return bpy.data.groups[name] + except: return None + else: + return None def closestVecIndex(vec, vecls): best= -1 @@ -271,7 +276,7 @@ class tree: twig_recursive_limit=3,\ twig_ob_bounds=None,\ twig_ob_bounds_prune=True,\ - twig_ob_bounds_prune_taper=True,\ + twig_ob_bounds_prune_taper=1.0,\ twig_placement_maxradius=10.0,\ twig_placement_maxtwig=0,\ twig_follow_parent=0.0,\ @@ -282,7 +287,6 @@ class tree: variation_seed = 1,\ variation_orientation = 0.0,\ variation_scale = 0.0,\ - ): ''' build tree data - fromCurve must run first @@ -507,10 +511,10 @@ class tree: # we would not have been but here if the bounds were outside if twig_ob_bounds_prune: brch_twig.boundsTrim() - if twig_ob_bounds_prune_taper: + if twig_ob_bounds_prune_taper != 1.0: # taper to a point. we could use some nice taper algo here - just linear atm. - brch_twig.taper() + brch_twig.taper(twig_ob_bounds_prune_taper) # Make sure this dosnt mess up anything else @@ -1054,7 +1058,17 @@ class tree: return self.mesh - def toLeafMesh(self, mesh_leaf, leaf_branch_limit = 0.5, leaf_size = 0.5, leaf_fill=True, leaf_fill_count=1000, leaf_fill_ob_bounds=None): + def toLeafMesh(self, mesh_leaf,\ + leaf_branch_limit = 0.5,\ + leaf_size = 0.5,\ + + leaf_fill=True,\ + leaf_fill_count=1000,\ + leaf_fill_ob_bounds=None,\ + + leaf_dupliface=False,\ + leaf_dupliface_fromgroup=None,\ + ): ''' return a mesh with leaves seperate from the tree @@ -1125,7 +1139,6 @@ class tree: vec3 += no_pt vec4 += no_pt ''' - cross faces_extend.append([len(verts_extend), len(verts_extend)+1, len(verts_extend)+2, len(verts_extend)+3]) verts_extend.extend([vec1, vec2, vec3, vec4]) @@ -1133,7 +1146,90 @@ class tree: self.mesh_leaf.verts.extend(verts_extend) self.mesh_leaf.faces.extend(faces_extend) + + + elif leaf_dupliface and leaf_dupliface_fromgroup: + + totpoints = 0 + radius = 0.0 + max_radius = 0.0 + for brch in self.branches_all: + for pt in brch.bpoints: + radius += pt.radius + if pt.radius > max_radius: + max_radius = pt.radius + + #totpoints += len(brch.bpoints) + + radius_max = max_radius * leaf_branch_limit + + + verts_extend = [] + faces_extend = [] + + co1,co2,co3,co4 = Vector(),Vector(),Vector(),Vector() + + for brch in self.branches_all: + + # quick test, do we need leaves on this branch? + if brch.bpoints[-1].radius > radius_max: + continue + + count = 0 + for pt in brch.bpoints: + if pt.childCount == 0 and pt.radius < radius_max: + # Ok we can add a leaf here. set the co's correctly + co1[:] = pt.co + co2[:] = pt.co + co3[:] = pt.co + co4[:] = pt.co + + cross_leafdir = CrossVecs( zup, pt.no ) + cross_leafdir.length = leaf_size + + #cross_leafwidth = CrossVecs(pt.no, cross_leafdir) + + # Facing up + cross_leafwidth_up = CrossVecs(zup, cross_leafdir).normalize() * leaf_size + cross_leafwidth_aligned = pt.no + + #cross_leafwidth = (cross_leafwidth_up + cross_leafwidth_aligned)/2 + cross_leafwidth = cross_leafwidth_aligned + + cross_leafwidth.length = leaf_size/2 + + if count % 2: + cross_leafwidth.negate() + cross_leafdir.negate() + + co1 += cross_leafdir + co2 += cross_leafdir + + co2 += cross_leafwidth + co3 += cross_leafwidth + + co1 -= cross_leafwidth + co4 -= cross_leafwidth + + + i = len(verts_extend) + faces_extend.append( (i,i+1,i+2,i+3) ) + verts_extend.extend([tuple(co1), tuple(co2), tuple(co3), tuple(co4)]) + count += 1 + + # setup dupli's + + leaf_dupliface_fromgroup + + self.mesh_leaf.verts.extend(verts_extend) + self.mesh_leaf.faces.extend(faces_extend) + + + + + + ''' @@ -1860,14 +1956,12 @@ class branch: # Shorten the point list self.bpoints = self.bpoints[:i] - self.bpoints[-1].makeLast() - def taper(self): + def taper(self, twig_ob_bounds_prune_taper = 0.0): l = float(len( self.bpoints )) - for i, pt in enumerate(self.bpoints): - pt.radius *= (l-i)/l + pt.radius *= (((l-i)/l) + (twig_ob_bounds_prune_taper*(i/l)) ) def getParentBranch(self): if not self.parent_pt: @@ -2326,7 +2420,7 @@ PREFS['twig_recursive'] = Draw.Create(1) PREFS['twig_recursive_limit'] = Draw.Create(3) PREFS['twig_ob_bounds'] = Draw.Create('') PREFS['twig_ob_bounds_prune'] = Draw.Create(1) -PREFS['twig_ob_bounds_prune_taper'] = Draw.Create(1) +PREFS['twig_ob_bounds_prune_taper'] = Draw.Create(1.0) PREFS['twig_placement_maxradius'] = Draw.Create(10.0) PREFS['twig_placement_maxtwig'] = Draw.Create(4) PREFS['twig_follow_parent'] = Draw.Create(0.0) @@ -2342,6 +2436,9 @@ PREFS['leaf_fill_ob_bounds'] = Draw.Create('') PREFS['leaf_branch_limit'] = Draw.Create(0.25) PREFS['leaf_size'] = Draw.Create(0.5) +PREFS['leaf_dupliface'] = Draw.Create(0) +PREFS['leaf_dupliface_fromgroup'] = Draw.Create('') + PREFS['do_variation'] = Draw.Create(0) PREFS['variation_seed'] = Draw.Create(1) PREFS['variation_orientation'] = Draw.Create(0.0) @@ -2379,8 +2476,22 @@ def Dict2Prefs(prefs, new_prefs): ''' for key in prefs: # items would be nice for id groups val = prefs[key] - try: new_prefs[key] = Blender.Draw.Create( val ) - except: new_prefs[key] = val + ok = True + + try: + # If we have this setting allredy but its a different type, use the old setting (converting int's to floats for instance) + new_val = new_prefs[key] # this may fail, thats ok + if (type(new_val)==Blender.Types.ButtonType) and (type(new_val.val) != type(val)): + ok = False + except: + pass + + if ok: + try: + new_prefs[key] = Blender.Draw.Create( val ) + except: + new_prefs[key] = val + return new_prefs def Prefs2IDProp(idprop, prefs): @@ -2554,8 +2665,10 @@ def buildTree(ob_curve, single=False): mesh_leaf = ob_leaf.getData(mesh=1) ob_leaf.setMatrix(Matrix()) + leaf_dupliface_fromgroup = getGroupFromName(PREFS['leaf_dupliface_fromgroup'].val) + leaf_fill_ob_bounds = getObFromName(PREFS['leaf_fill_ob_bounds'].val) - print "LEAF!!!" + mesh_leaf = t.toLeafMesh(mesh_leaf,\ leaf_branch_limit = PREFS['leaf_branch_limit'].val,\ leaf_size = PREFS['leaf_size'].val,\ @@ -2563,7 +2676,16 @@ def buildTree(ob_curve, single=False): leaf_fill = PREFS['leaf_fill'].val,\ leaf_fill_count = PREFS['leaf_fill_count'].val,\ leaf_fill_ob_bounds = leaf_fill_ob_bounds,\ + + leaf_dupliface = PREFS['leaf_dupliface'].val,\ + leaf_dupliface_fromgroup = leaf_dupliface_fromgroup,\ ) + + if PREFS['leaf_dupliface'].val and leaf_dupliface_fromgroup: + ob_leaf.enableDupliFaces = True + + parent.makeParent([ob_new]) + mesh.calcNormals() @@ -2726,10 +2848,19 @@ def do_ob_check(e,v): try: bpy.data.objects[v] except: - PREFS['twig_ob_bounds'].val = '' + # PREFS['twig_ob_bounds'].val = '' Draw.PupMenu('Object dosnt exist!') Draw.Redraw() +def do_group_check(e,v): + if not v: return + try: + bpy.data.groups[v] + except: + # PREFS['leaf_dupliface_fromgroup'].val = '' + Draw.PupMenu('dosnt exist!') + Draw.Redraw() + # Button callbacks def do_active_image(e,v): img = bpy.data.images.active @@ -2879,8 +3010,7 @@ def gui(): PREFS['twig_ob_bounds_prune'] = Draw.Toggle('Prune',EVENT_UPDATE_AND_UI, xtmp, y, but_width_tmp, but_height, PREFS['twig_ob_bounds_prune'].val, 'Prune twigs to the mesh object bounds'); xtmp += but_width_tmp; if PREFS['twig_ob_bounds_prune'].val: - PREFS['twig_ob_bounds_prune_taper'] = Draw.Toggle('Taper',EVENT_UPDATE_AND_UI, xtmp, y, but_width, but_height, PREFS['twig_ob_bounds_prune_taper'].val, 'Taper pruned branches to a point'); xtmp += but_width; - + PREFS['twig_ob_bounds_prune_taper'] = Draw.Number('Taper', EVENT_UPDATE_AND_UI, xtmp, y, but_width, but_height, PREFS['twig_ob_bounds_prune_taper'].val, 0.0, 1.0, 'Taper pruned branches to a point'); xtmp += but_width; #PREFS['image_main'] = Draw.String('IM: ', EVENT_UPDATE, xtmp, y, but_width*3, but_height, PREFS['image_main'].val, 64, 'Image to apply to faces'); xtmp += but_width*3; #Draw.PushButton('Use Active', EVENT_UPDATE, xtmp, y, but_width, but_height, 'Get the image from the active image window', do_active_image); xtmp += but_width; @@ -2923,6 +3053,17 @@ def gui(): PREFS['leaf_fill_count'] = Draw.Number('Fill #', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['leaf_fill_count'].val, 10, 100000, 'Number of leaves to fill in'); xtmp += but_width*2; PREFS['leaf_size'] = Draw.Number('Size', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['leaf_size'].val, 0.001, 10.0, 'size of the leaf'); xtmp += but_width*2; + # ---------- ---------- ---------- ---------- + y-=but_height + xtmp = x + + ''' + PREFS['leaf_dupliface'] = Draw.Toggle('DupliLeaf', EVENT_UPDATE_AND_UI, xtmp, y, but_width*2, but_height, PREFS['leaf_dupliface'].val, 'Fill an object with leaves'); xtmp += but_width*2; + + if PREFS['leaf_dupliface'].val: + PREFS['leaf_dupliface_fromgroup'] = Draw.String('group: ', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['leaf_dupliface_fromgroup'].val, 64, 'Pick objects from this group to use as leaves', do_group_check); xtmp += but_width*2; + ''' + Blender.Draw.EndAlign() y-=but_height+MARGIN @@ -3115,6 +3256,6 @@ def gui(): if __name__ == '__main__': # Read the active objects prefs on load. if they exist - do_pref_read(quiet=True) + do_pref_read(quiet=False) Draw.Register(gui, evt, bevt) From 307ad085fcc19cff837064009976e0d92c6a22e9 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 21 Nov 2007 11:53:30 +0000 Subject: [PATCH 21/29] wizard_curve2tree.py - always use active object (local view was messing up the context) Mesh.c - mesh.faces.extend([..., smooth=True]) - smooth keyword argument, in a number of places was looping through all faces just to smooth them. mesh_skin.py - smooth by default --- release/scripts/mesh_skin.py | 2 +- release/scripts/wizard_curve2tree.py | 87 ++++++++++++++++++---------- source/blender/python/api2_2x/Mesh.c | 19 +++++- 3 files changed, 74 insertions(+), 34 deletions(-) diff --git a/release/scripts/mesh_skin.py b/release/scripts/mesh_skin.py index fdb721bc9f3..a554e128b41 100644 --- a/release/scripts/mesh_skin.py +++ b/release/scripts/mesh_skin.py @@ -628,7 +628,7 @@ def main(): try: me.faces.delete(1, [ f for f in me.faces if f.sel ]) except: pass - me.faces.extend(faces) + me.faces.extend(faces, smooth = True) print '\nSkin done in %.4f sec.' % (Blender.sys.time()-time1) diff --git a/release/scripts/wizard_curve2tree.py b/release/scripts/wizard_curve2tree.py index a729494274a..a0781abc21f 100644 --- a/release/scripts/wizard_curve2tree.py +++ b/release/scripts/wizard_curve2tree.py @@ -599,13 +599,14 @@ class tree: for brch in self.branches_all: brch.fixOverlapError(joint_smooth) + # Collapsing for brch in self.branches_all: brch.collapsePoints(seg_density, seg_density_angle, seg_density_radius, joint_smooth) - + ''' for brch in self.branches_all: brch.branchReJoin() - + ''' def buildTwigs(self, twig_ratio, twig_select_mode, twig_select_factor): ratio_int = int(len(self.branches_all) * twig_ratio) @@ -834,7 +835,7 @@ class tree: faces = self.mesh.faces - faces.extend(faces_extend) + faces.extend(faces_extend, smooth=True) if do_uv: # Assign the faces back @@ -843,14 +844,12 @@ class tree: if brch.parent_pt: for i in (0,1,2,3): face = brch.faces[i] = faces[face_index+i] - face.smooth = 1 face_index +=4 for pt in brch.bpoints: for i in (0,1,2,3): if pt.faces[i]: pt.faces[i] = faces[face_index] - pt.faces[i].smooth = True face_index +=1 #if self.mesh.faces: @@ -1028,8 +1027,7 @@ class tree: mesh.activeUVLayer = 'base' # just so people dont get worried the texture is not there - dosnt effect rendering. else: # no UV's - for f in self.mesh.faces: - f.smooth = True + pass if do_cap_ends: # de-select end points for @@ -1199,10 +1197,6 @@ class tree: cross_leafwidth.length = leaf_size/2 - if count % 2: - cross_leafwidth.negate() - cross_leafdir.negate() - co1 += cross_leafdir co2 += cross_leafdir @@ -2209,11 +2203,14 @@ class branch: collapse = False pt = self.bpoints[0] while pt: + # Collapse angles greater then 90. they are useually artifacts + if pt.prev and pt.next and pt.prev.childCount == 0: if abs(pt.radius - pt.prev.radius) / (pt.radius + pt.prev.radius) < seg_density_radius: - if seg_density_angle == 180 or AngleBetweenVecs(pt.no, pt.prev.no) < seg_density_angle: + ang = AngleBetweenVecs(pt.no, pt.prev.no) + if seg_density_angle == 180 or ang > 90 or ang < seg_density_angle: ## if (pt.prev.nextMidCo-pt.co).length < ((pt.radius + pt.prev.radius)/2) * seg_density: - if (pt.prev.nextMidCo-pt.co).length < seg_density: + if (pt.prev.nextMidCo-pt.co).length < seg_density or ang > 90: pt_save = pt.prev if pt.next.collapseUp(): # collapse this point collapse = True @@ -2221,11 +2218,12 @@ class branch: if pt.childCount == 0 and pt.next: #if pt.childrenMidCo == None: if abs(pt.radius - pt.next.radius) / (pt.radius + pt.next.radius) < seg_density_radius: - if seg_density_angle == 180 or AngleBetweenVecs(pt.no, pt.next.no) < seg_density_angle: + ang = AngleBetweenVecs(pt.no, pt.next.no) + if seg_density_angle == 180 or ang > 90 or ang < seg_density_angle: # do here because we only want to run this on points with no children, # Are we closer theto eachother then the radius? ## if (pt.nextMidCo-pt.co).length < ((pt.radius + pt.next.radius)/2) * seg_density: - if (pt.nextMidCo-pt.co).length < seg_density: + if (pt.nextMidCo-pt.co).length < seg_density or ang > 90: if pt.collapseDown(): collapse = True @@ -2451,12 +2449,27 @@ GLOBAL_PREFS['realtime_update'] = Draw.Create(0) def getContextCurveObjects(): sce = bpy.data.scenes.active objects = [] + ob_act = sce.objects.active for ob in sce.objects.context: if ob.type != 'Curve': ob = ob.parent if not ob or ob.type != 'Curve': continue objects.append(ob) + + # Alredy delt with + if ob == ob_act: ob_act = None + + # Add the active, important when using localview or local layers + if ob_act: + ob = ob_act + if ob.type != 'Curve': + ob = ob.parent + if not ob or ob.type != 'Curve': + pass + else: + objects.append(ob) + return objects @@ -2682,10 +2695,14 @@ def buildTree(ob_curve, single=False): ) if PREFS['leaf_dupliface'].val and leaf_dupliface_fromgroup: - ob_leaf.enableDupliFaces = True + ob_leaf.enableDupFaces = True + ob_leaf.enableDupFacesScale = True + for ob_group in leaf_dupliface_fromgroup.objects: + pass - parent.makeParent([ob_new]) - + ob_leaf.makeParent([ob_group]) + else: + ob_leaf.enableDupFaces = False mesh.calcNormals() @@ -3023,16 +3040,11 @@ def gui(): Blender.Draw.BeginAlign() - if PREFS['do_leaf'].val == 0: - but_width_tmp = but_width*2 - else: - but_width_tmp = but_width*4 - PREFS['do_leaf'] = Draw.Toggle('Generate Leaves',EVENT_UPDATE_AND_UI, xtmp, y, but_width_tmp, but_height, PREFS['do_leaf'].val, 'Generate a separate leaf mesh'); xtmp += but_width_tmp; + PREFS['do_leaf'] = Draw.Toggle('Generate Leaves',EVENT_UPDATE_AND_UI, xtmp, y, but_width*2, but_height, PREFS['do_leaf'].val, 'Generate a separate leaf mesh'); xtmp += but_width*2; if PREFS['do_leaf'].val: - # ---------- ---------- ---------- ---------- - y-=but_height - xtmp = x + PREFS['leaf_size'] = Draw.Number('Size', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['leaf_size'].val, 0.001, 10.0, 'size of the leaf'); xtmp += but_width*2; + # Dont use yet # PREFS['leaf_branch_limit'] = Draw.Number('Branch Limit', EVENT_UPDATE, xtmp, y, but_width*4, but_height, PREFS['leaf_branch_limit'].val, 0.1, 2.0, 'Maximum thichness where a branch can bare leaves'); xtmp += but_width*4; @@ -3042,7 +3054,16 @@ def gui(): else: but_width_tmp = but_width*4 - PREFS['leaf_fill'] = Draw.Toggle('Fill Object', EVENT_UPDATE_AND_UI, xtmp, y, but_width*2, but_height, PREFS['leaf_fill'].val, 'Fill an object with leaves'); xtmp += but_width*2; + # ---------- ---------- ---------- ---------- + y-=but_height + xtmp = x + + if PREFS['leaf_fill'].val == 1: + but_width_tmp = but_width*2 + else: + but_width_tmp = but_width*4 + + PREFS['leaf_fill'] = Draw.Toggle('Fill Object', EVENT_UPDATE_AND_UI, xtmp, y, but_width_tmp, but_height, PREFS['leaf_fill'].val, 'Fill an object with leaves'); xtmp += but_width_tmp; if PREFS['leaf_fill'].val: PREFS['leaf_fill_ob_bounds'] = Draw.String('OB Bound: ', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['leaf_fill_ob_bounds'].val, 64, 'Fill this object with leaves', do_ob_check); xtmp += but_width*2; @@ -3050,15 +3071,19 @@ def gui(): y-=but_height xtmp = x - PREFS['leaf_fill_count'] = Draw.Number('Fill #', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['leaf_fill_count'].val, 10, 100000, 'Number of leaves to fill in'); xtmp += but_width*2; - PREFS['leaf_size'] = Draw.Number('Size', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['leaf_size'].val, 0.001, 10.0, 'size of the leaf'); xtmp += but_width*2; + PREFS['leaf_fill_count'] = Draw.Number('Fill #', EVENT_UPDATE, xtmp, y, but_width*4, but_height, PREFS['leaf_fill_count'].val, 10, 100000, 'Number of leaves to fill in'); xtmp += but_width*4; + # ---------- ---------- ---------- ---------- y-=but_height xtmp = x ''' - PREFS['leaf_dupliface'] = Draw.Toggle('DupliLeaf', EVENT_UPDATE_AND_UI, xtmp, y, but_width*2, but_height, PREFS['leaf_dupliface'].val, 'Fill an object with leaves'); xtmp += but_width*2; + if PREFS['leaf_dupliface'].val == 1: + but_width_tmp = but_width*2 + else: + but_width_tmp = but_width*4 + PREFS['leaf_dupliface'] = Draw.Toggle('DupliLeaf', EVENT_UPDATE_AND_UI, xtmp, y, but_width_tmp, but_height, PREFS['leaf_dupliface'].val, 'Create a Dupliface mesh'); xtmp += but_width_tmp; if PREFS['leaf_dupliface'].val: PREFS['leaf_dupliface_fromgroup'] = Draw.String('group: ', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['leaf_dupliface_fromgroup'].val, 64, 'Pick objects from this group to use as leaves', do_group_check); xtmp += but_width*2; @@ -3256,6 +3281,6 @@ def gui(): if __name__ == '__main__': # Read the active objects prefs on load. if they exist - do_pref_read(quiet=False) + do_pref_read(quiet=True) Draw.Register(gui, evt, bevt) diff --git a/source/blender/python/api2_2x/Mesh.c b/source/blender/python/api2_2x/Mesh.c index 5dffb488b3d..8a832d0deeb 100644 --- a/source/blender/python/api2_2x/Mesh.c +++ b/source/blender/python/api2_2x/Mesh.c @@ -5004,7 +5004,8 @@ static PyObject *MFaceSeq_extend( BPy_MEdgeSeq * self, PyObject *args, Mesh *mesh = self->mesh; int ignore_dups = 0; PyObject *return_list = NULL; - + char flag = ME_FACE_SEL; + /* before we try to add faces, add edges; if it fails; exit */ tmp = MEdgeSeq_extend( self, args ); @@ -5034,6 +5035,20 @@ static PyObject *MFaceSeq_extend( BPy_MEdgeSeq * self, PyObject *args, return_list = PyList_New( 0 ); } } + + res = PyDict_GetItemString( keywds, "smooth" ); + if (res) { + switch( PyObject_IsTrue( res ) ) { + case 0: + break; + case -1: + return EXPP_ReturnPyObjError( PyExc_TypeError, + "keyword argument \"smooth\" expected True/False or 0/1" ); + default: + flag |= ME_SMOOTH; + + } + } } /* make sure we get a tuple of sequences of something */ @@ -5319,7 +5334,7 @@ static PyObject *MFaceSeq_extend( BPy_MEdgeSeq * self, PyObject *args, tmpface->v3 = tmppair->v[index[2]]; tmpface->v4 = tmppair->v[index[3]]; - tmpface->flag = ME_FACE_SEL; + tmpface->flag = flag; if( return_list ) { tmp = PyInt_FromLong( mesh->totface ); From 413c24c7467b13155941ea5dddd9a399d1ed912b Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 21 Nov 2007 16:07:47 +0000 Subject: [PATCH 22/29] initial support for leaves as duplifaces as well as some a bugfix for loading settings --- release/scripts/wizard_curve2tree.py | 95 +++++++++++++++++++--------- 1 file changed, 66 insertions(+), 29 deletions(-) diff --git a/release/scripts/wizard_curve2tree.py b/release/scripts/wizard_curve2tree.py index a0781abc21f..4b8a7087a0b 100644 --- a/release/scripts/wizard_curve2tree.py +++ b/release/scripts/wizard_curve2tree.py @@ -123,6 +123,17 @@ def closestVecIndex(vec, vecls): return best +IRATIONAL_NUM = 22.0/7.0 +def next_random_num(rnd): + ''' + return a random number between 0.0 and 1.0 + ''' + rnd[0] += (rnd[0] * IRATIONAL_NUM) % 1 + # prevent + if rnd[0] > 1000000: + rnd[0]-=1000000 + return rnd[0] % 1 + eul = 0.00001 class tree: @@ -353,23 +364,13 @@ class tree: if do_variation: irational_num = 22.0/7.0 # use to make the random number more odd rnd = [variation_seed] - def next_random_num(): - ''' - return a random number between 0.0 and 1.0 - ''' - - rnd[0] += (rnd[0] * irational_num) % 1 - # prevent - if rnd[0] > 1000000: - rnd[0]-=1000000 - return rnd[0] % 1 # Add children temporarily for brch in self.branches_all: if brch.parent_pt: - rnd_rot = ((next_random_num() * variation_orientation) - 0.5) * 720 + rnd_rot = ((next_random_num(rnd) * variation_orientation) - 0.5) * 720 mat_orientation = RotationMatrix(rnd_rot, 3, 'r', brch.parent_pt.no) - rnd_sca = 1 + ((next_random_num()-0.5)* variation_scale ) + rnd_sca = 1 + ((next_random_num(rnd)-0.5)* variation_scale ) mat_scale = Matrix([rnd_sca,0,0],[0,rnd_sca,0],[0,0,rnd_sca]) # mat_orientation = RotationMatrix(0, 3, 'r', brch.parent_pt.no) brch.transformRecursive(self, mat_scale * mat_orientation, brch.parent_pt.co) @@ -1058,6 +1059,7 @@ class tree: def toLeafMesh(self, mesh_leaf,\ leaf_branch_limit = 0.5,\ + leaf_branch_limit_rand = 0.8,\ leaf_size = 0.5,\ leaf_fill=True,\ @@ -1167,39 +1169,59 @@ class tree: co1,co2,co3,co4 = Vector(),Vector(),Vector(),Vector() + rnd_seed = [1.0] # could have seed as an input setting + for brch in self.branches_all: # quick test, do we need leaves on this branch? if brch.bpoints[-1].radius > radius_max: continue + count = 0 for pt in brch.bpoints: - if pt.childCount == 0 and pt.radius < radius_max: + if leaf_branch_limit_rand: + # (-1 : +1) * leaf_branch_limit_rand + rnd = 1 + (((next_random_num(rnd_seed) - 0.5) * 2 ) * leaf_branch_limit_rand) + else: + rnd = 1.0 + + if pt.childCount == 0 and (pt.radius * rnd) < radius_max: # Ok we can add a leaf here. set the co's correctly co1[:] = pt.co co2[:] = pt.co co3[:] = pt.co co4[:] = pt.co + cross_leafdir = CrossVecs( zup, pt.no ) - cross_leafdir.length = leaf_size - + cross_leafdir.length = (leaf_size/2) ### * pt.radius + + + # Rotate the + # Align this with the existing branch + rotate = RotationMatrix( (next_random_num(rnd_seed)-0.5) * 360, 3, 'r', pt.no ) + + cross_leafdir = cross_leafdir * rotate #cross_leafwidth = CrossVecs(pt.no, cross_leafdir) # Facing up - cross_leafwidth_up = CrossVecs(zup, cross_leafdir).normalize() * leaf_size + cross_leafwidth_up = CrossVecs(zup, cross_leafdir).normalize() * leaf_size * pt.radius cross_leafwidth_aligned = pt.no #cross_leafwidth = (cross_leafwidth_up + cross_leafwidth_aligned)/2 cross_leafwidth = cross_leafwidth_aligned - cross_leafwidth.length = leaf_size/2 + cross_leafwidth.length = (leaf_size/2) ### *pt.radius + # base width co1 += cross_leafdir co2 += cross_leafdir + co3 -= cross_leafdir + co4 -= cross_leafdir + # base hight allong the branch co2 += cross_leafwidth co3 += cross_leafwidth @@ -1207,6 +1229,7 @@ class tree: co4 -= cross_leafwidth + i = len(verts_extend) faces_extend.append( (i,i+1,i+2,i+3) ) verts_extend.extend([tuple(co1), tuple(co2), tuple(co3), tuple(co4)]) @@ -2432,6 +2455,7 @@ PREFS['leaf_fill_count'] = Draw.Create(1000) PREFS['leaf_fill_ob_bounds'] = Draw.Create('') PREFS['leaf_branch_limit'] = Draw.Create(0.25) +PREFS['leaf_branch_limit_rand'] = Draw.Create(0.1) PREFS['leaf_size'] = Draw.Create(0.5) PREFS['leaf_dupliface'] = Draw.Create(0) @@ -2451,6 +2475,8 @@ def getContextCurveObjects(): objects = [] ob_act = sce.objects.active for ob in sce.objects.context: + if ob == ob_act: ob_act = None + if ob.type != 'Curve': ob = ob.parent if not ob or ob.type != 'Curve': @@ -2458,7 +2484,7 @@ def getContextCurveObjects(): objects.append(ob) # Alredy delt with - if ob == ob_act: ob_act = None + # Add the active, important when using localview or local layers if ob_act: @@ -2516,12 +2542,14 @@ def Prefs2IDProp(idprop, prefs): idprop[ID_SLOT_NAME] = new_prefs def IDProp2Prefs(idprop, prefs): - try: prefs = idprop[ID_SLOT_NAME] - except: return False + prefs = idprop[ID_SLOT_NAME] + try: + prefs = idprop[ID_SLOT_NAME] + except: + return False Dict2Prefs(prefs, PREFS) return True - def buildTree(ob_curve, single=False): ''' Must be a curve object, write to a child mesh @@ -2530,6 +2558,7 @@ def buildTree(ob_curve, single=False): print 'Curve2Tree, starting...' # if were only doing 1 object, just use the current prefs prefs = {} + if single or not (IDProp2Prefs(ob_curve.properties, prefs)): prefs = PREFS @@ -2684,6 +2713,7 @@ def buildTree(ob_curve, single=False): mesh_leaf = t.toLeafMesh(mesh_leaf,\ leaf_branch_limit = PREFS['leaf_branch_limit'].val,\ + leaf_branch_limit_rand = PREFS['leaf_branch_limit_rand'].val,\ leaf_size = PREFS['leaf_size'].val,\ leaf_fill = PREFS['leaf_fill'].val,\ @@ -2898,8 +2928,10 @@ def do_tree_generate__real(): if is_editmode: Blender.Window.EditMode(0, '', 0) Blender.Window.WaitCursor(1) + for ob in objects: buildTree(ob, len(objects)==1) + Blender.Window.WaitCursor(0) if is_editmode: Blender.Window.EditMode(1, '', 0) @@ -2965,7 +2997,6 @@ def gui(): # ---------- ---------- ---------- ---------- - Blender.Draw.BeginAlign() PREFS['do_twigs'] = Draw.Toggle('Generate Twigs',EVENT_UPDATE_AND_UI, xtmp, y, but_width*2, but_height, PREFS['do_twigs'].val, 'Generate child branches based existing branches'); xtmp += but_width*2; if PREFS['do_twigs'].val: @@ -3002,7 +3033,7 @@ def gui(): # ---------- ---------- ---------- ---------- - PREFS['twig_placement_maxradius'] = Draw.Number('Place Max Radius', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['twig_placement_maxradius'].val, 0.0, 50.0, 'Limit twig placement to branches with this maximum radius'); xtmp += but_width*2; + PREFS['twig_placement_maxradius'] = Draw.Number('Place Max Radius', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['twig_placement_maxradius'].val, 0.0, 50.0, 'Only place twigs on branches below this radius'); xtmp += but_width*2; PREFS['twig_placement_maxtwig'] = Draw.Number('Place Max Count', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['twig_placement_maxtwig'].val, 0.0, 50.0, 'Limit twig placement to this many per branch'); xtmp += but_width*2; y-=but_height @@ -3044,10 +3075,6 @@ def gui(): if PREFS['do_leaf'].val: PREFS['leaf_size'] = Draw.Number('Size', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['leaf_size'].val, 0.001, 10.0, 'size of the leaf'); xtmp += but_width*2; - - - # Dont use yet - # PREFS['leaf_branch_limit'] = Draw.Number('Branch Limit', EVENT_UPDATE, xtmp, y, but_width*4, but_height, PREFS['leaf_branch_limit'].val, 0.1, 2.0, 'Maximum thichness where a branch can bare leaves'); xtmp += but_width*4; if PREFS['leaf_fill'].val == 0: but_width_tmp = but_width*2 @@ -3078,7 +3105,10 @@ def gui(): y-=but_height xtmp = x - ''' + + + + if PREFS['leaf_dupliface'].val == 1: but_width_tmp = but_width*2 else: @@ -3087,7 +3117,14 @@ def gui(): if PREFS['leaf_dupliface'].val: PREFS['leaf_dupliface_fromgroup'] = Draw.String('group: ', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['leaf_dupliface_fromgroup'].val, 64, 'Pick objects from this group to use as leaves', do_group_check); xtmp += but_width*2; - ''' + + # ---------- ---------- ---------- ---------- + y-=but_height + xtmp = x + + # Dont use yet + PREFS['leaf_branch_limit'] = Draw.Number('Branch Limit', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['leaf_branch_limit'].val, 0.0, 1.0, 'Maximum thichness where a branch can bare leaves'); xtmp += but_width*2; + PREFS['leaf_branch_limit_rand'] = Draw.Number('Limit Random', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['leaf_branch_limit_rand'].val, 0.0, 1.0, 'Randomize the starting of leaves'); xtmp += but_width*2; Blender.Draw.EndAlign() From 818bfcca63a145f626e432c8217513610e8aff85 Mon Sep 17 00:00:00 2001 From: Nils Thuerey Date: Wed, 21 Nov 2007 22:12:16 +0000 Subject: [PATCH 23/29] - Added OpenMP code, it is enabled by defining PARALLEL=1 for the elbeem compilation. Currently, it is not yet active by default, but Genscher wanted to do some tests. It can be used to distribute the computation load onto multiple shared- memory CPUs by splitting the domain along the y-axis (assuming a gravity force along z). However, there is no load balancing: so if there's fluid only in one of the y-axis halves you will not get a speedup for 2 CPUs. - Added a fix for the memory allocation bugs #7120 and #6775. In solver_init.cpp there are now several variables max___MemChunk (line 692+), that set upper limits for various systems. The same problem existed for mac & linux, but the limit is higher, so it probably went by undetected. The windows limit is currently 1GB, if the strange 700MB limit problems mentioned in the bug regports the bugs persist, this could be further reduced. For 64bit compilations this problem shouldn't exist anyway. What's still missing is a display of how much the resolution was reduced to fit into memory... - And some minor solver code cleanup. --- intern/elbeem/extern/elbeem.h | 2 +- intern/elbeem/intern/attributes.cpp | 2 +- intern/elbeem/intern/loop_tools.h | 81 ++++++++++++++++++++-- intern/elbeem/intern/ntl_vector3dim.h | 1 + intern/elbeem/intern/particletracer.cpp | 2 +- intern/elbeem/intern/simulation_object.cpp | 6 +- intern/elbeem/intern/solver_class.h | 2 +- intern/elbeem/intern/solver_init.cpp | 55 +++++++++++++-- intern/elbeem/intern/solver_interface.cpp | 6 +- intern/elbeem/intern/solver_interface.h | 6 +- intern/elbeem/intern/solver_main.cpp | 20 ++++-- intern/elbeem/intern/solver_util.cpp | 3 +- intern/elbeem/intern/utilities.cpp | 3 +- intern/elbeem/intern/utilities.h | 5 -- 14 files changed, 159 insertions(+), 35 deletions(-) diff --git a/intern/elbeem/extern/elbeem.h b/intern/elbeem/extern/elbeem.h index b3feda8bbe8..2a594dd07e6 100644 --- a/intern/elbeem/extern/elbeem.h +++ b/intern/elbeem/extern/elbeem.h @@ -154,7 +154,7 @@ typedef struct elbeemMesh { short volumeInitType; /* name of the mesh, mostly for debugging */ - char *name; + const char *name; } elbeemMesh; // API functions diff --git a/intern/elbeem/intern/attributes.cpp b/intern/elbeem/intern/attributes.cpp index 8e337a92a4e..464486f2500 100644 --- a/intern/elbeem/intern/attributes.cpp +++ b/intern/elbeem/intern/attributes.cpp @@ -103,7 +103,7 @@ void AttributeList::readMat4Gfx(string name, ntlMat4Gfx defaultValue, string sou // set that a parameter can be given, and will be ignored... bool AttributeList::ignoreParameter(string name, string source) { - name=source=(""); // remove warning + name = source = (""); return false; } diff --git a/intern/elbeem/intern/loop_tools.h b/intern/elbeem/intern/loop_tools.h index 3c15a609210..70ecb9ce3e0 100644 --- a/intern/elbeem/intern/loop_tools.h +++ b/intern/elbeem/intern/loop_tools.h @@ -54,15 +54,84 @@ -#define unused_GRID_REGION_END() \ - } /* main_region */ \ - // end unusedGRID_REGION_END - // ----------------------------------------------------------------------------------- #else // PARALLEL==1 -#include "paraloop.h" +//#include "paraloop.h" +#define PERFORM_USQRMAXCHECK USQRMAXCHECK(usqr,ux,uy,uz, calcMaxVlen, calcMxvx,calcMxvy,calcMxvz); +#define LIST_EMPTY(x) calcListEmpty.push_back( x ); +#define LIST_FULL(x) calcListFull.push_back( x ); +#define FSGR_ADDPART(x) calcListParts.push_back( x ); + + +// parallel region +//was: # pragma omp parallel default(shared) +#if COMPRESSGRIDS!=1 + // requires compressed grids...! + ERROR! +#endif + +// loop start +#define GRID_REGION_START() \ + { \ + \ + \ + if(mSizez<2) { \ + mPanic = 1; \ + errFatal("ParaLoop::2D","Not valid...!", SIMWORLD_GENERICERROR); \ + } \ + \ + \ + vector calcListFull; \ + vector calcListEmpty; \ + vector calcListParts; \ + LbmFloat calcMxvx, calcMxvy, calcMxvz, calcMaxVlen; \ + calcMxvx = calcMxvy = calcMxvz = calcMaxVlen = 0.0; \ + calcListEmpty.reserve(mListEmpty.capacity() / omp_get_num_threads() ); \ + calcListFull.reserve( mListFull.capacity() / omp_get_num_threads() ); \ + calcListParts.reserve(mSizex); \ + \ + \ + const int id = omp_get_thread_num(); \ + const int Nthrds = omp_get_num_threads(); \ + \ + \ + \ + \ + \ + int kdir = 1; \ + \ + int kstart=getForZMinBnd(), kend=getForZMaxBnd(mMaxRefine); \ + if(gridLoopBound>0){ kstart=getForZMin1(); kend=getForZMax1(mMaxRefine); } \ + LbmFloat *ccel = NULL, *tcel = NULL; \ + CellFlagType *pFlagSrc=NULL, *pFlagDst=NULL; \ + \ + \ + if(mLevel[mMaxRefine].setCurr==1) { \ + kdir = -1; \ + int temp = kend; \ + kend = kstart-1; \ + kstart = temp-1; \ + } \ + \ + const int Nj = mLevel[mMaxRefine].lSizey; \ + int jstart = 0+( id * (Nj / Nthrds) ); \ + int jend = 0+( (id+1) * (Nj / Nthrds) ); \ + if( ((Nj/Nthrds) *Nthrds) != Nj) { \ + errMsg("LbmFsgrSolver","Invalid domain size Nj="< #include #include +#include // hack for MSVC6.0 compiler #ifdef _MSC_VER diff --git a/intern/elbeem/intern/particletracer.cpp b/intern/elbeem/intern/particletracer.cpp index c9da808543a..819fcdd0b9a 100644 --- a/intern/elbeem/intern/particletracer.cpp +++ b/intern/elbeem/intern/particletracer.cpp @@ -325,7 +325,7 @@ void ParticleTracer::getTriangles(double time, vector *triangles, // suppress warnings... vertices = NULL; triangles = NULL; normals = NULL; objectId = 0; - time = 0.0; + time = 0.; #else // ELBEEM_PLUGIN int pcnt = 0; // currently not used in blender diff --git a/intern/elbeem/intern/simulation_object.cpp b/intern/elbeem/intern/simulation_object.cpp index 2ff600a36d4..9b47ae696af 100644 --- a/intern/elbeem/intern/simulation_object.cpp +++ b/intern/elbeem/intern/simulation_object.cpp @@ -15,7 +15,6 @@ #include "solver_interface.h" #include "particletracer.h" #include "elbeem.h" -#include /* exit(3) - also in linux */ #ifdef _WIN32 #else @@ -69,6 +68,7 @@ SimulationObject::~SimulationObject() /*! init tree for certain geometry init */ /*****************************************************************************/ void SimulationObject::initGeoTree() { + // unused!! overriden by solver interface if(mpGlob == NULL) { errFatal("SimulationObject::initGeoTree error","Requires globals!", SIMWORLD_INITERROR); return; @@ -80,7 +80,7 @@ void SimulationObject::initGeoTree() { char treeFlag = (1<<(mGeoInitId+4)); mpGiTree = new ntlTree( 20, 4, // warning - fixed values for depth & maxtriangles here... scene, treeFlag ); - exit(1); // unused!? overriden by solver interface + // unused!! overriden by solver interface } /*****************************************************************************/ @@ -310,7 +310,7 @@ void SimulationObject::step( void ) // dont advance for stopped time mpLbm->step(); mTime += mpParam->getTimestep(); -//if(mTime>0.001) { errMsg("DEBUG!!!!!!!!","quit mlsu..."); exit(1); } // PROFILE DEBUG TEST! + //if(mTime>0.001) { errMsg("DEBUG!!!!!!!!","quit mlsu..."); xit(1); } // PROFILE DEBUG TEST! } if(mpLbm->getPanic()) mPanic = true; diff --git a/intern/elbeem/intern/solver_class.h b/intern/elbeem/intern/solver_class.h index 930c1863aa7..d46f065adfd 100644 --- a/intern/elbeem/intern/solver_class.h +++ b/intern/elbeem/intern/solver_class.h @@ -101,7 +101,7 @@ // sirdude fix for solaris #if !defined(linux) && defined(sun) #ifndef expf -#define expf(a) exp((double)(a)) +#define expf(x) exp((double)(x)) #endif #endif diff --git a/intern/elbeem/intern/solver_init.cpp b/intern/elbeem/intern/solver_init.cpp index abec4a89c89..b0ce130c136 100644 --- a/intern/elbeem/intern/solver_init.cpp +++ b/intern/elbeem/intern/solver_init.cpp @@ -655,6 +655,7 @@ bool LbmFsgrSolver::initializeSolverMemory() int orgSz = mSizez; double sizeReduction = 1.0; double memEstFromFunc = -1.0; + double memEstFine = -1.0; string memreqStr(""); bool firstMInit = true; int minitTries=0; @@ -672,7 +673,7 @@ bool LbmFsgrSolver::initializeSolverMemory() firstMInit=false; calculateMemreqEstimate( mSizex, mSizey, mSizez, - mMaxRefine, mFarFieldSize, &memEstFromFunc, &memreqStr ); + mMaxRefine, mFarFieldSize, &memEstFromFunc, &memEstFine, &memreqStr ); double memLimit; string memLimStr("-"); @@ -685,13 +686,36 @@ bool LbmFsgrSolver::initializeSolverMemory() memLimit = 16.0* 1024.0*1024.0*1024.0; memLimStr = string("16GB"); } - if(memEstFromFunc>memLimit) { + + // restrict max. chunk of 1 mem block to 1GB for windos + bool memBlockAllocProblem = false; + double maxWinMemChunk = 1100.*1024.*1024.; + double maxMacMemChunk = 1200.*1024.*1024.; + double maxDefaultMemChunk = 2.*1024.*1024.*1024.; + //std::cerr<<" memEstFine "<< memEstFine <<" maxWin:" < maxWinMemChunk) { + memBlockAllocProblem = true; + } +#endif // WIN32 +#ifdef __APPLE__ + if(memEstFine> maxMacMemChunk) { + memBlockAllocProblem = true; + } +#endif // Mac + if(sizeof(int)==4 && memEstFine>maxDefaultMemChunk) { + // max memory chunk for 32bit systems 2gig + memBlockAllocProblem = true; + } + + if(memEstFromFunc>memLimit || memBlockAllocProblem) { sizeReduction *= 0.9; mSizex = (int)(orgSx * sizeReduction); mSizey = (int)(orgSy * sizeReduction); mSizez = (int)(orgSz * sizeReduction); debMsgStd("LbmFsgrSolver::initialize",DM_WARNING,"initGridSizes: memory limit exceeded "<< //memEstFromFunc<<"/"<getCellSize(); mLevel[ mMaxRefine ].lcellfactor = 1.0; LONGINT rcellSize = ((mLevel[mMaxRefine].lSizex*mLevel[mMaxRefine].lSizey*mLevel[mMaxRefine].lSizez) *dTotalNum); - // +4 for safety ? - mLevel[ mMaxRefine ].mprsFlags[0] = new CellFlagType[ rcellSize/dTotalNum +4 ]; - mLevel[ mMaxRefine ].mprsFlags[1] = new CellFlagType[ rcellSize/dTotalNum +4 ]; - ownMemCheck += 2 * sizeof(CellFlagType) * (rcellSize/dTotalNum +4); #if COMPRESSGRIDS==0 mLevel[ mMaxRefine ].mprsCells[0] = new LbmFloat[ rcellSize +4 ]; @@ -789,11 +809,34 @@ bool LbmFsgrSolver::initializeSolverMemory() ownMemCheck += 2 * sizeof(LbmFloat) * (rcellSize+4); #else // COMPRESSGRIDS==0 LONGINT compressOffset = (mLevel[mMaxRefine].lSizex*mLevel[mMaxRefine].lSizey*dTotalNum*2); + // D int tmp = ( (rcellSize +compressOffset +4)/(1024*1024) )*4; + // D printf("Debug MEMMMM excee: %d\n", tmp); mLevel[ mMaxRefine ].mprsCells[1] = new LbmFloat[ rcellSize +compressOffset +4 ]; mLevel[ mMaxRefine ].mprsCells[0] = mLevel[ mMaxRefine ].mprsCells[1]+compressOffset; ownMemCheck += sizeof(LbmFloat) * (rcellSize +compressOffset +4); #endif // COMPRESSGRIDS==0 + if(!mLevel[ mMaxRefine ].mprsCells[1] || !mLevel[ mMaxRefine ].mprsCells[0]) { + errFatal("LbmFsgrSolver::initialize","Fatal: Couldnt allocate memory (1)! Aborting...",SIMWORLD_INITERROR); + return false; + } + + // +4 for safety ? + mLevel[ mMaxRefine ].mprsFlags[0] = new CellFlagType[ rcellSize/dTotalNum +4 ]; + mLevel[ mMaxRefine ].mprsFlags[1] = new CellFlagType[ rcellSize/dTotalNum +4 ]; + ownMemCheck += 2 * sizeof(CellFlagType) * (rcellSize/dTotalNum +4); + if(!mLevel[ mMaxRefine ].mprsFlags[1] || !mLevel[ mMaxRefine ].mprsFlags[0]) { + errFatal("LbmFsgrSolver::initialize","Fatal: Couldnt allocate memory (2)! Aborting...",SIMWORLD_INITERROR); + +#if COMPRESSGRIDS==0 + delete[] mLevel[ mMaxRefine ].mprsCells[0]; + delete[] mLevel[ mMaxRefine ].mprsCells[1]; +#else // COMPRESSGRIDS==0 + delete[] mLevel[ mMaxRefine ].mprsCells[1]; +#endif // COMPRESSGRIDS==0 + return false; + } + LbmFloat lcfdimFac = 8.0; if(LBMDIM==2) lcfdimFac = 4.0; for(int i=mMaxRefine-1; i>=0; i--) { diff --git a/intern/elbeem/intern/solver_interface.cpp b/intern/elbeem/intern/solver_interface.cpp index 2539556617b..d25850a003b 100644 --- a/intern/elbeem/intern/solver_interface.cpp +++ b/intern/elbeem/intern/solver_interface.cpp @@ -17,7 +17,6 @@ #include "ntl_world.h" #include "elbeem.h" -#include /* getenv(3) - also in linux */ @@ -142,7 +141,7 @@ void initGridSizes(int &sizex, int &sizey, int &sizez, void calculateMemreqEstimate( int resx,int resy,int resz, int refine, float farfield, - double *reqret, string *reqstr) { + double *reqret, double *reqretFine, string *reqstr) { // debug estimation? const bool debugMemEst = true; // COMPRESSGRIDS define is not available here, make sure it matches @@ -150,6 +149,7 @@ void calculateMemreqEstimate( int resx,int resy,int resz, // make sure we can handle bid numbers here... all double double memCnt = 0.0; double ddTotalNum = (double)dTotalNum; + if(reqretFine) *reqretFine = -1.; double currResx = (double)resx; double currResy = (double)resy; @@ -159,10 +159,12 @@ void calculateMemreqEstimate( int resx,int resy,int resz, if(debugMemEst) debMsgStd("calculateMemreqEstimate",DM_MSG,"res:"<=0; i--) { diff --git a/intern/elbeem/intern/solver_interface.h b/intern/elbeem/intern/solver_interface.h index 1dfdf156ee5..c3dc4983cac 100644 --- a/intern/elbeem/intern/solver_interface.h +++ b/intern/elbeem/intern/solver_interface.h @@ -21,7 +21,7 @@ #if LBM_USE_GUI==1 #define USE_GLUTILITIES // for debug display -#include +//#include #include "../gui/guifuncs.h" #endif @@ -596,8 +596,10 @@ class LbmSolverInterface void initGridSizes(int &mSizex, int &mSizey, int &mSizez, ntlVec3Gfx &mvGeoStart, ntlVec3Gfx &mvGeoEnd, int mMaxRefine, bool parallel); +// return the amount of memory required in total (reqret) +// and for the finest grid only (reqretFine, can be NULL) void calculateMemreqEstimate(int resx,int resy,int resz, int refine, - float farfieldsize, double *reqret, string *reqstr); + float farfieldsize, double *reqret, double *reqretFine, string *reqstr); //! helper function to convert flag to string (for debuggin) string convertCellFlagType2String( CellFlagType flag ); diff --git a/intern/elbeem/intern/solver_main.cpp b/intern/elbeem/intern/solver_main.cpp index 270e8867b3c..afc883972e2 100644 --- a/intern/elbeem/intern/solver_main.cpp +++ b/intern/elbeem/intern/solver_main.cpp @@ -7,11 +7,11 @@ * *****************************************************************************/ -#include /* rand(3) - also in linux */ #include "solver_class.h" #include "solver_relax.h" #include "particletracer.h" #include "loop_tools.h" +#include /*****************************************************************************/ /*! perform a single LBM step */ @@ -375,7 +375,11 @@ LbmFsgrSolver::mainLoop(int lev) const int gridLoopBound=1; GRID_REGION_INIT(); #if PARALLEL==1 -#include "paraloopstart.h" +#pragma omp parallel default(shared) \ + reduction(+: \ + calcCurrentMass,calcCurrentVolume, \ + calcCellsFilled,calcCellsEmptied, \ + calcNumUsedCells ) GRID_REGION_START(); #else // PARALLEL==1 GRID_REGION_START(); @@ -1112,7 +1116,11 @@ LbmFsgrSolver::preinitGrids() GRID_REGION_INIT(); #if PARALLEL==1 -#include "paraloopstart.h" +#pragma omp parallel default(shared) \ + reduction(+: \ + calcCurrentMass,calcCurrentVolume, \ + calcCellsFilled,calcCellsEmptied, \ + calcNumUsedCells ) #endif // PARALLEL==1 GRID_REGION_START(); GRID_LOOP_START(); @@ -1145,7 +1153,11 @@ LbmFsgrSolver::standingFluidPreinit() GRID_REGION_INIT(); #if PARALLEL==1 -#include "paraloopstart.h" +#pragma omp parallel default(shared) \ + reduction(+: \ + calcCurrentMass,calcCurrentVolume, \ + calcCellsFilled,calcCellsEmptied, \ + calcNumUsedCells ) #endif // PARALLEL==1 GRID_REGION_START(); diff --git a/intern/elbeem/intern/solver_util.cpp b/intern/elbeem/intern/solver_util.cpp index 65cc2200d4e..a6685babe68 100644 --- a/intern/elbeem/intern/solver_util.cpp +++ b/intern/elbeem/intern/solver_util.cpp @@ -15,8 +15,7 @@ #include "ntl_world.h" #include "simulation_object.h" -#include /* rand(3) */ - +#include #include #ifndef sqrtf #define sqrtf sqrt diff --git a/intern/elbeem/intern/utilities.cpp b/intern/elbeem/intern/utilities.cpp index 332052e91b6..551c4d0d384 100644 --- a/intern/elbeem/intern/utilities.cpp +++ b/intern/elbeem/intern/utilities.cpp @@ -10,7 +10,6 @@ #include #include -#include /* getenv(3), strtol(3) */ #ifdef WIN32 // for timing #include @@ -482,7 +481,7 @@ double elbeemEstimateMemreq(int res, double memreq = -1.0; string memreqStr(""); // ignore farfield for now... - calculateMemreqEstimate(resx,resy,resz, refine, 0., &memreq, &memreqStr ); + calculateMemreqEstimate(resx,resy,resz, refine, 0., &memreq, NULL, &memreqStr ); if(retstr) { // copy at max. 32 characters diff --git a/intern/elbeem/intern/utilities.h b/intern/elbeem/intern/utilities.h index 0f65408d23c..825e92251fe 100644 --- a/intern/elbeem/intern/utilities.h +++ b/intern/elbeem/intern/utilities.h @@ -9,11 +9,6 @@ #ifndef UTILITIES_H #include "ntl_vector3dim.h" -// Solaris requires ieeefp.h for finite(3C) -#if !defined(linux) && defined(sun) -#include -#endif - /* debugging outputs , debug level 0 (off) to 10 (max) */ #ifdef ELBEEM_PLUGIN From cfb5eb1b8fff5d8a6b9def6504721ea90d4b4ae1 Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Wed, 21 Nov 2007 23:22:56 +0000 Subject: [PATCH 24/29] Patch #7794: X-Axis Mirror Support for Various Operations in Armature EditMode Patch by: Teppo Kansala (teppoka) This patch adds X-Axis Mirror support for the following tools: - Delete Bone (X) - Recalculate Bone Roll Angles... (Ctrl-N) - Duplicate Bone (Shift-D) - Clear Parent... (Alt-P) - Move Bone To Layer (M) --- source/blender/src/editarmature.c | 67 ++++++++++++++++++++++++++----- source/blender/src/poseobject.c | 9 ++++- 2 files changed, 64 insertions(+), 12 deletions(-) diff --git a/source/blender/src/editarmature.c b/source/blender/src/editarmature.c index 3e7e00ef240..24c8382a445 100644 --- a/source/blender/src/editarmature.c +++ b/source/blender/src/editarmature.c @@ -1076,6 +1076,19 @@ void delete_armature(void) TEST_EDITARMATURE; if (okee("Erase selected bone(s)")==0) return; + + /* Select mirrored bones */ + if (arm->flag & ARM_MIRROR_EDIT) { + for (curBone=G.edbo.first; curBone; curBone=curBone->next) { + if (arm->layer & curBone->layer) { + if (curBone->flag & BONE_SELECTED) { + next = armature_bone_get_mirrored(curBone); + if (next) + next->flag |= BONE_SELECTED; + } + } + } + } /* First erase any associated pose channel */ if (G.obedit->pose) { @@ -1321,13 +1334,19 @@ void auto_align_armature(short mode) { bArmature *arm= G.obedit->data; EditBone *ebone; + EditBone *flipbone = NULL; float delta[3]; float curmat[3][3]; float *cursor= give_cursor(); for (ebone = G.edbo.first; ebone; ebone=ebone->next) { - if(arm->layer & ebone->layer) { - if (ebone->flag & BONE_SELECTED) { + if (arm->layer & ebone->layer) { + if (arm->flag & ARM_MIRROR_EDIT) + flipbone = armature_bone_get_mirrored(ebone); + + if ((ebone->flag & BONE_SELECTED) || + (flipbone && flipbone->flag & BONE_SELECTED)) + { /* specific method used to calculate roll depends on mode */ if (mode == 1) { /* Z-Axis point towards cursor */ @@ -1386,7 +1405,7 @@ void auto_align_armature(short mode) Mat3MulMat3(diffmat, imat, curmat); ebone->roll = atan2(diffmat[2][0], diffmat[2][2]); - } + } } } } @@ -1713,11 +1732,24 @@ void adduplicate_armature(void) EditBone *firstDup=NULL; /* The beginning of the duplicated bones in the edbo list */ countall(); // flushes selection! + + /* Select mirrored bones */ + if (arm->flag & ARM_MIRROR_EDIT) { + for (curBone=G.edbo.first; curBone; curBone=curBone->next) { + if (arm->layer & curBone->layer) { + if (curBone->flag & BONE_SELECTED) { + eBone = armature_bone_get_mirrored(curBone); + if (eBone) + eBone->flag |= BONE_SELECTED; + } + } + } + } /* Find the selected bones and duplicate them as needed */ for (curBone=G.edbo.first; curBone && curBone!=firstDup; curBone=curBone->next){ - if(arm->layer & curBone->layer) { - if (curBone->flag & BONE_SELECTED){ + if (arm->layer & curBone->layer) { + if (curBone->flag & BONE_SELECTED) { eBone=MEM_callocN(sizeof(EditBone), "addup_editbone"); eBone->flag |= BONE_SELECTED; @@ -2034,10 +2066,22 @@ void make_bone_parent(void) return; } +static void editbone_clear_parent(EditBone *ebone, int mode) +{ + if (ebone->parent) { + /* for nice selection */ + ebone->parent->flag &= ~(BONE_TIPSEL); + } + + if(mode==1) ebone->parent= NULL; + ebone->flag &= ~BONE_CONNECTED; +} + void clear_bone_parent(void) { bArmature *arm= G.obedit->data; EditBone *ebone; + EditBone *flipbone = NULL; short val; val= pupmenu("Clear Parent%t|Clear Parent%x1|Disconnect Bone%x2"); @@ -2046,13 +2090,13 @@ void clear_bone_parent(void) for (ebone = G.edbo.first; ebone; ebone=ebone->next) { if(arm->layer & ebone->layer) { if(ebone->flag & BONE_SELECTED) { - if(ebone->parent) { - /* for nice selection */ - ebone->parent->flag &= ~(BONE_TIPSEL); + + if(arm->flag & ARM_MIRROR_EDIT) + flipbone = armature_bone_get_mirrored(ebone); - if(val==1) ebone->parent= NULL; - ebone->flag &= ~BONE_CONNECTED; - } + if (flipbone) + editbone_clear_parent(flipbone, val); + editbone_clear_parent(ebone, val); } } } @@ -3179,3 +3223,4 @@ void transform_armature_mirror_update(void) + diff --git a/source/blender/src/poseobject.c b/source/blender/src/poseobject.c index c0835c84e62..68af3d7c64c 100644 --- a/source/blender/src/poseobject.c +++ b/source/blender/src/poseobject.c @@ -917,6 +917,7 @@ void pose_movetolayer(void) else if (G.obedit) { /* the check for editbone layer moving needs to occur before posemode one to work */ EditBone *ebo; + EditBone *flipBone; for (ebo= G.edbo.first; ebo; ebo= ebo->next) { if (arm->layer & ebo->layer) { @@ -931,8 +932,14 @@ void pose_movetolayer(void) for (ebo= G.edbo.first; ebo; ebo= ebo->next) { if (arm->layer & ebo->layer) { - if (ebo->flag & BONE_SELECTED) + if (ebo->flag & BONE_SELECTED) { ebo->layer= lay; + if (arm->flag & ARM_MIRROR_EDIT) { + flipBone = armature_bone_get_mirrored(ebo); + if (flipBone) + flipBone->layer = lay; + } + } } } From 313553b1edb02660361ebc281516fe8b6c122b7f Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Thu, 22 Nov 2007 00:58:57 +0000 Subject: [PATCH 25/29] == Armature Path Drawing Tweak == Peach Request: Bone path lines are now drawn using two colours to show the parts of the path before and after the current frame. Those before the current frame are drawn darker, while those after are drawn in a blue colour. --- source/blender/src/drawarmature.c | 43 ++++++++++++++++++++++++------- 1 file changed, 33 insertions(+), 10 deletions(-) diff --git a/source/blender/src/drawarmature.c b/source/blender/src/drawarmature.c index c424a24718b..c907bab5a23 100644 --- a/source/blender/src/drawarmature.c +++ b/source/blender/src/drawarmature.c @@ -1737,8 +1737,8 @@ static void draw_pose_paths(Object *ob) CfraElem *ce; ListBase ak; float *fp; - int a; - int stepsize, sfra; + int a, stepsize; + int sfra, efra; if(G.vd->zbuf) glDisable(GL_DEPTH_TEST); @@ -1758,16 +1758,39 @@ static void draw_pose_paths(Object *ob) pchan->pathef= EFRA; } - /* get start frame of calculated range */ + /* get frame ranges */ sfra= pchan->pathsf; + efra = sfra + pchan->pathlen; /* draw curve-line of path */ - // TODO: show before/after with slight difference in colour intensity - BIF_ThemeColorBlend(TH_WIRE, TH_BACK, 0.7); - glBegin(GL_LINE_STRIP); - for(a=0, fp= pchan->path; apathlen; a++, fp+=3) - glVertex3fv(fp); - glEnd(); + if ((CFRA > sfra) && (CFRA < efra)) { + /* Show before/after current frame with slight difference in colour intensity + * This is done in two loops, as there seems to be some problems with changing color + * or something during a loop (noted somewhere in the codebase) + */ + + /* before cfra (darker) */ + BIF_ThemeColorBlend(TH_WIRE, TH_BACK, 0.2); + glBegin(GL_LINE_STRIP); + for (a=0, fp=pchan->path; (sfra+a)<=CFRA; a++, fp+=3) + glVertex3fv(fp); + glEnd(); + + /* after cfra (lighter) - backtrack a bit so that we don't have gaps */ + BIF_ThemeColorBlend(TH_WIRE, TH_BONE_POSE, 0.7); + glBegin(GL_LINE_STRIP); + for (--a, fp-=3; apathlen; a++, fp+=3) + glVertex3fv(fp); + glEnd(); + } + else { + /* show both directions with same intensity (cfra somewhere else) */ + BIF_ThemeColorBlend(TH_WIRE, TH_BACK, 0.7); + glBegin(GL_LINE_STRIP); + for (a=0, fp= pchan->path; apathlen; a++, fp+=3) + glVertex3fv(fp); + glEnd(); + } glPointSize(1.0); @@ -1791,7 +1814,7 @@ static void draw_pose_paths(Object *ob) for(a=0, fp= pchan->path; apathlen; a+=stepsize, fp+=(stepsize*3)) { char str[32]; - /* only draw framenum if several consecutive highlighted points occur on same point */ + /* only draw framenum if several consecutive highlighted points don't occur on same point */ if (a == 0) { glRasterPos3fv(fp); sprintf(str, " %d\n", (a+sfra)); From 78ea4f35646927a65c9a703d09f6e766bdd3b4ca Mon Sep 17 00:00:00 2001 From: Geoffrey Bantle Date: Thu, 22 Nov 2007 01:43:24 +0000 Subject: [PATCH 26/29] -> Updated FLT scripts Blender FLT I/O scripts have been updated to have more features.In addition several utility scripts/applets have been added to aid in working with FLT databases within Blender. Documentation can be found here: http://wiki.blender.org/index.php/Scripts/Manual/Import/openflight_flt http://wiki.blender.org/index.php/Scripts/Manual/Export/openflight_flt http://wiki.blender.org/index.php/Scripts/Manual/FLTools --- release/scripts/flt_defaultp.py | 1 + release/scripts/flt_export.py | 1533 +++++++++++++++++++----- release/scripts/flt_filewalker.py | 9 +- release/scripts/flt_import.py | 1597 ++++++++++++++----------- release/scripts/flt_palettemanager.py | 388 ++++++ release/scripts/flt_properties.py | 619 ++++++++++ release/scripts/flt_toolbar.py | 594 +++++++++ 7 files changed, 3742 insertions(+), 999 deletions(-) create mode 100644 release/scripts/flt_defaultp.py create mode 100644 release/scripts/flt_palettemanager.py create mode 100644 release/scripts/flt_properties.py create mode 100644 release/scripts/flt_toolbar.py diff --git a/release/scripts/flt_defaultp.py b/release/scripts/flt_defaultp.py new file mode 100644 index 00000000000..5dca8ba63d7 --- /dev/null +++ b/release/scripts/flt_defaultp.py @@ -0,0 +1 @@ +pal = [-256,0,16711680,-16777216,-19529984,-19726592,-19923200,-20119808,-20316416,-20578560,-20840704,-21102848,-21364992,-21692672,-22020352,-22413568,-22806784,-23200000,-23658752,-24117504,-24641792,-25166080,-25755904,-26411264,-27066624,-27787520,-28573952,-29425920,-30343424,-31326464,-32375040,-33489152,-354550016,-371458304,-388366592,-405274880,-422183168,-439156992,-456130816,-473104640,-506855680,-540672256,-574488832,-608305408,-642121984,-676004096,-709886208,-760611072,-811335936,-862060800,-912851200,-980418816,-1048051968,-1115685120,-1183383808,-1267925248,-1352466688,-1453850880,-1555300608,-1656815872,-1775173888,-1893597440,-2028863744,2130771712,-1010376448,-1043996416,-1077681920,-1111367424,-1145052928,-1178738432,-1229201152,-1279663872,-1330126592,-1380654848,-1431183104,-1498488576,-1565794048,-1633165056,-1700536064,-1784684288,-1868832512,-1969823488,-2070814464,2123096320,2005262592,1887428864,1752752384,1601298688,1449779456,1281417472,1096278272,911073536,709026048,490201344,254533888,2023680,-1380857856,-1397700608,-1431320576,-1464940544,-1498560512,-1532180480,-1565865984,-1599551488,-1650014208,-1700476928,-1750939648,-1801402368,-1851865088,-1919170560,-1986476032,-2053781504,-2121086976,2089797632,2005649408,1904723968,1803798528,1686030336,1568262144,1450493952,1315883008,1164494848,1013041152,844810240,659736576,457885696,239192064,3655680,-1767919872,-1784762624,-1801605376,-1818448128,-1852068096,-1885688064,-1919308032,-1952928000,-1986547968,-2020167936,-2070565120,-2120962304,2123542272,2073079552,2022616832,1955376896,1888136960,1820897024,1736879872,1652797184,1568714496,1467854592,1366994688,1249357568,1131654912,997175040,862695168,711372544,560049920,391950080,207007488,5287680,2139657728,2122880512,2106103296,2089326080,2072548864,2055771648,2022217216,1988662784,1955108352,1921553920,1887933952,1854313984,1803916800,1753519616,1703122432,1652725248,1602328064,1535153664,1467979264,1400804864,1316853248,1232901632,1148950016,1048221184,947426816,846632448,729060864,611489280,477140480,326014464,174888448,6919680,1837268224,1820491008,1803713792,1786936576,1770159360,1753382144,1736604928,1719827712,1686273280,1652718848,1619164416,1585609984,1552055552,1518501120,1468169472,1417837824,1367506176,1317174528,1266842880,1199734016,1132625152,1065516288,998407424,914521344,830635264,729971968,629308672,528645376,411204864,293764352,159546624,8551680,-2086957824,-2103735040,-2120512256,-2137289472,2140900608,2107346176,2073791744,2040237056,2006682368,1973127680,1939572992,1906018304,1855686400,1805354496,1755022592,1704690688,1654358784,1587249664,1520140544,1453031424,1369145088,1285258496,1201371904,1100708096,1000044288,882603264,765162240,630943744,496725248,345729536,177956608,10183680,-1699438080,-1716215552,-1732993024,-1766547712,-1800102400,-1833657088,-1867211776,-1900766464,-1934321152,-1967875840,-2018207744,-2068539904,-2118872064,2125763072,2058653696,1991544320,1924434944,1857325568,1773438720,1689551872,1588887808,1488223744,1387559424,1270117888,1152676352,1018457600,884238592,733242368,565468672,397694976,213144064,11815680,-1311918848,-1345473536,-1379028224,-1412582912,-1446137600,-1479692544,-1513247488,-1546802432,-1597134592,-1647466752,-1697798912,-1748131072,-1798463488,-1865573120,-1932682752,-1999792384,-2083679232,2127400960,2043513856,1942849536,1842184960,1724743168,1607301376,1473082112,1338862848,1187866112,1020092160,852317952,667766528,466437632,248331264,13447680,-924399104,-957954048,-991508992,-1025063936,-1058618880,-1092173824,-1142505984,-1192838144,-1243170560,-1293502976,-1343835392,-1410945024,-1478054656,-1545164544,-1629051648,-1712938752,-1796826112,-1897490688,-1998155264,-2098820096,2078705152,1961262848,1827043328,1676046336,1525049344,1357274880,1172722944,971393792,753287168,518403072,283518720,15079680,-570434304,-603989248,-637544192,-671099136,-704654080,-754986496,-805318912,-855651328,-905983744,-973093632,-1040203520,-1107313408,-1174423296,-1258310656,-1342198016,-1442862848,-1543527680,-1644192512,-1761634816,-1879077120,-2013296896,2147450624,1996453376,1828678656,1660903936,1476351744,1275022080,1056914944,822030336,570368256,301928704,16711680,-503325440,-536880384,-570435328,-603990272,-637545216,-671100416,-721432832,-771765248,-822097664,-872430336,-922763008,-989872896,-1056982784,-1124092928,-1191203072,-1275090688,-1358978304,-1459643136,-1560308224,-1660973312,-1778415872,-1895858432,-2030078464,2113891328,1962893824,1795118848,1610566400,1426013696,1224683520,1006575872,771690752,520028160,-452993792,-469771520,-503326464,-536881408,-570436352,-603991552,-637546752,-671101952,-721434368,-771767040,-822099712,-872432384,-922765056,-989875200,-1056985344,-1124095744,-1191206144,-1275093760,-1358981632,-1459646720,-1560312064,-1677754624,-1795197440,-1912640512,-2046860800,2097108736,1946110720,1778335232,1593782272,1392451840,1174343936,939458560,-419439360,-436217088,-452994816,-469772544,-503327488,-536882688,-570437888,-603993088,-637548288,-671103744,-721436416,-771769088,-822101760,-872434688,-922767616,-989878016,-1056988416,-1124098816,-1207986688,-1291874560,-1375762688,-1476428032,-1577093632,-1694536704,-1811979776,-1946200320,-2080421120,2063547904,1912549376,1744773376,1560219904,1358888960,-385884928,-402662656,-419440384,-436218112,-452995840,-469773824,-503329024,-536884224,-570439424,-603994880,-637550336,-671105792,-721438464,-771771392,-822104320,-872437504,-922770688,-989881088,-1056991744,-1124102400,-1191213312,-1275101440,-1358989824,-1459655680,-1560321536,-1677764864,-1795208448,-1912652288,-2046873600,2097094912,1946095872,1778319360,-335553280,-352331008,-369108736,-385886464,-402664192,-419442176,-436220160,-452998144,-486553344,-520108800,-553664256,-587219712,-620775168,-654330880,-687886592,-738219776,-788552960,-838886144,-889219584,-939553024,-1006663936,-1073774848,-1140886016,-1224774656,-1308663296,-1392552192,-1493218560,-1593885184,-1711329280,-1828773632,-1962995456,-2097217536,-285221632,-301999360,-318777088,-335554816,-352332544,-369110528,-385888512,-402666496,-419444480,-436222720,-453000960,-469779200,-503334656,-536890368,-570446080,-604002048,-637558016,-671113984,-721447424,-771780864,-822114560,-872448256,-922782208,-989893632,-1057005056,-1124116736,-1191228672,-1275118080,-1359007744,-1459674880,-1560342272,-1677787136,-234889984,-234890496,-251668224,-268445952,-285223680,-302001664,-318779648,-335557632,-352335616,-369113856,-385892096,-402670336,-419448576,-436227072,-453005568,-469784320,-503340288,-536896256,-570452480,-604008704,-637565184,-671121664,-704678400,-755012608,-805346816,-855681280,-906016000,-973128192,-1040240640,-1107353344,-1174466304,-1258356736,-234889984,-234890496,-234891008,-234891520,-234892032,-234892800,-234893568,-234894336,-234895104,-251673344,-268451584,-285229824,-302008064,-318786560,-335565056,-352343808,-369122560,-385901312,-402680320,-419459328,-436238592,-453017856,-486574592,-520131584,-553688576,-587245824,-620803328,-654361088,-687919104,-738254592,-788590336,-838926336,-234889984,-234890496,-234891008,-234891520,-234892032,-234892800,-234893568,-234894336,-234895104,-234896128,-234897152,-234898176,-234899200,-234900480,-234901760,-234903296,-234904832,-234906368,-234908160,-234909952,-234912000,-251691264,-268470784,-285250560,-302030336,-318810368,-335590656,-352371200,-369152000,-385933056,-402714368,-419495936,-8960,-9472,-9984,-10496,-11008,-11776,-12544,-13312,-14080,-15104,-16128,-17152,-18176,-19456,-20736,-22272,-23808,-25344,-27136,-28928,-30976,-33024,-35328,-37888,-40448,-43264,-46336,-49664,-53248,-57088,-61184,-65536,-926464,-926976,-927488,-928000,-928512,-929280,-930048,-930816,-931584,-932608,-933632,-934656,-935680,-936960,-938240,-939776,-941312,-1008384,-1075712,-1143040,-1210624,-1278208,-1346048,-1414144,-1482240,-1550592,-1619200,-1688064,-1757184,-1826560,-1896192,-2031616,-926464,-926976,-927488,-928000,-928512,-929280,-930048,-996352,-1062656,-1129216,-1195776,-1262336,-1328896,-1395712,-1462528,-1529600,-1596672,-1663744,-1731072,-1798400,-1865984,-1999104,-2132480,-2266112,-2399744,-2533632,-2667776,-2867712,-3067904,-3268352,-3469056,-3670016,-926464,-992512,-1058560,-1124608,-1190656,-1256960,-1323264,-1389568,-1455872,-1522432,-1588992,-1655552,-1722112,-1788928,-1855744,-1988352,-2120960,-2253568,-2386432,-2519296,-2652416,-2785536,-2984448,-3183616,-3382784,-3582208,-3847424,-4112896,-4378624,-4644608,-4976384,-5308416,-1188608,-1254656,-1320704,-1386752,-1452800,-1519104,-1585408,-1651712,-1718016,-1784576,-1851136,-1983232,-2115328,-2247680,-2380032,-2512640,-2645248,-2777856,-2976256,-3174656,-3373312,-3571968,-3836416,-4101120,-4365824,-4630784,-4961536,-5292544,-5689344,-6086400,-6483712,-6946816,-1385216,-1451264,-1517312,-1583360,-1649408,-1715712,-1782016,-1848320,-1980160,-2112256,-2244352,-2376448,-2508544,-2640896,-2838784,-3036928,-3235072,-3433216,-3631616,-3895552,-4159744,-4423936,-4688384,-5018624,-5348864,-5744896,-6141184,-6537728,-7000064,-7462656,-7991040,-8585216,-1581824,-1647872,-1713920,-1779968,-1846016,-1977856,-2109696,-2241536,-2373376,-2505472,-2637568,-2769664,-2967296,-3165184,-3363072,-3561216,-3759360,-4023040,-4286976,-4550912,-4880640,-5210368,-5540352,-5936128,-6331904,-6793472,-7255296,-7782912,-8310784,-8904448,-9563904,-10223616,-1712896,-1778944,-1844992,-1976576,-2108160,-2240000,-2371840,-2503680,-2635520,-2767616,-2965248,-3162880,-3360512,-3558400,-3821824,-4085504,-4349184,-4612864,-4942336,-5271808,-5667072,-6062336,-6457856,-6919168,-7380480,-7907584,-8434944,-9028096,-9687040,-10346240,-11071232,-11862016,-1843968,-1975552,-2107136,-2238720,-2370304,-2502144,-2633984,-2765824,-2963200,-3160832,-3358464,-3556096,-3753728,-4017152,-4280576,-4544256,-4873472,-5202688,-5532160,-5927168,-6322432,-6783232,-7244288,-7771136,-8297984,-8890624,-9549056,-10207744,-10932224,-11722496,-12578560,-13500416,-1975040,-2106624,-2238208,-2369792,-2501376,-2633216,-2830592,-3027968,-3225344,-3422976,-3620608,-3883776,-4146944,-4410368,-4673792,-5003008,-5332224,-5726976,-6121984,-6582528,-7043328,-7504128,-8030720,-8623104,-9215488,-9873664,-10597632,-11387392,-12242944,-13164288,-14085888,-15138816,-2237184,-2368768,-2500352,-2631936,-2763520,-2960896,-3158272,-3355648,-3553024,-3816192,-4079360,-4342528,-4605696,-4934656,-5263616,-5658368,-6053120,-6447872,-6908416,-7368960,-7895296,-8421632,-9013760,-9671680,-10329600,-11053312,-11842816,-12698112,-13619200,-14606080,-15658752,-16777216] \ No newline at end of file diff --git a/release/scripts/flt_export.py b/release/scripts/flt_export.py index 283c24a3ad0..d2e90bc27b8 100644 --- a/release/scripts/flt_export.py +++ b/release/scripts/flt_export.py @@ -1,45 +1,25 @@ #!BPY """ Registration info for Blender menus: Name: 'OpenFlight (.flt)...' -Blender: 237 +Blender: 245 Group: 'Export' Tip: 'Export to OpenFlight v16.0 (.flt)' """ -__author__ = "Greg MacDonald" -__version__ = "1.2 10/20/05" +__author__ = "Greg MacDonald, Geoffrey Bantle" +__version__ = "2.0 11/21/07" __url__ = ("blender", "elysiun", "Author's homepage, http://sourceforge.net/projects/blight/") __bpydoc__ = """\ This script exports v16.0 OpenFlight files. OpenFlight is a registered trademark of MultiGen-Paradigm, Inc. -Run from "File->Export" menu. - -Options are available from Blender's "Scripts Config Editor," accessible through -the "Scripts->System" menu from the scripts window. - -Features:
-* Heirarchy retained.
-* Normals retained.
-* First texture exported.
-* Diffuse material color is exported as the face color, material color, or both -depending on the option settings.
-* Double sided faces are exported as two faces.
-* Object transforms exported. - -Things To Be Aware Of:
-* Object names are exported, not mesh or data names. -* Material indices that don't have a material associated with them will confuse the -exporter. If a warning appears about this, correct it by deleting the offending -material indices in Blender. - -What's Not Handled:
-* Animations.
-* Vetex colors.
+Feature overview and more availible at: +http://wiki.blender.org/index.php/Scripts/Manual/Export/openflight_flt """ # flt_export.py is an OpenFlight exporter for blender. -# Copyright (C) 2005 Greg MacDonald +# +# Copyright (C) 2005 Greg MacDonald, 2007 Blender Foundation. # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -56,29 +36,87 @@ What's Not Handled:
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. import Blender +from Blender import Modifier +import os.path +import flt_properties +import flt_defaultp as defaultp from flt_filewalker import FltOut +from flt_filewalker import FileFinder +from flt_properties import * +import shutil + +FF = FileFinder() +records = process_recordDefs() class ExporterOptions: def __init__(self): - self.defaults = { 'Diffuse Color To OpenFlight Material': False, - 'Diffuse Color To OpenFlight Face': True} - - d = Blender.Registry.GetKey('flt_export', True) - - if d == None or d.keys() != self.defaults.keys(): - d = self.defaults - Blender.Registry.SetKey('flt_export', d, True) - self.verbose = 1 self.tolerance = 0.001 - self.use_mat_color = d['Diffuse Color To OpenFlight Material'] - self.use_face_color = d['Diffuse Color To OpenFlight Face'] + self.writevcol = True + #new stuff + self.export_shading = 0 + self.shading_default = 45.0 + self.basepath = os.path.dirname(Blender.Get('filename')) + self.scale = 1.0 + + #set externals path + if(os.path.exists(os.path.join(self.basepath,'externals'))): + self.externalspath = os.path.join(self.basepath,'externals') + else: + self.externalspath = self.basepath + + self.doxrefs = 1 + + #texture options + if(os.path.exists(os.path.join(self.basepath,'textures'))): + self.texturespath = os.path.join(self.basepath,'textures') + else: + self.texturespath = self.basepath + + #misc + self.write_attrib_files = 0 + self.copy_textures = 0 + self.export_transform = 0 + self.flattenmesh = False + + self.xapp = 1 + reg = Blender.Registry.GetKey('flt_export',1) + if(reg and 'xappath' in reg.keys()): + self.xappath = reg['xappath'] + else: + self.xappath = '' options = ExporterOptions() +tex_files = dict() #a list of (possibly) modified texture path names + +tex_layers = ['Layer0', 'Layer1', 'Layer2', 'Layer3', 'Layer4', 'Layer5', 'Layer6', 'Layer7'] +mask = 2147483648 +mtexmasks = [] +for i in xrange(7): + mtexmasks.append(mask) + mask = mask / 2 FLOAT_TOLERANCE = options.tolerance +#need to move all this stuff to flt_properties.py. identity_matrix = [[1.0, 0.0, 0.0, 0.0], [0.0, 1.0, 0.0, 0.0], [0.0, 0.0, 1.0, 0.0], [0.0, 0.0, 0.0, 1.0]] +alltypes = [2,4,11,73,63,111] +childtypes = { + 2 : [111,2,73,4,14,63], + 4 : [111], + 73 : [111,2,73,4,14,63], + 63 : [], + 14 : [111,2,73,4,14,63], + 111 : [] +} +recordlen = { + 2: 44, + 4: 28, + 73: 80, + 63: 216, + 14: 384, + 111: 156 +} def is_identity(m): for i in xrange(4): @@ -102,13 +140,47 @@ class MaterialDesc: self.alpha = 1.0 # Range is [0.0, 1.0] class VertexDesc: - def __init__(self, co=None, no=None, uv=None): + def __init__(self, co=None, no=None, uv=None, fltindex=None,cindex=None): if co: self.x, self.y, self.z = tuple(co) else: self.x = self.y = self.z = 0.0 if no: self.nx, self.ny, self.nz = tuple(no) else: self.nx = self.ny = self.nz = 0.0 if uv: self.u, self.v = tuple(uv) else: self.u = self.v = 0.0 + if cindex: self.cindex = cindex + else: self.cindex = 127 + self.fltindex = fltindex + self.accum = 0 + +class shadowVert: + def __init__(self,bvert,object,world,normal): + global options + + self.co = Blender.Mathutils.Vector(bvert.co[0],bvert.co[1],bvert.co[2]) + #if world: + # vec = self.co + # vec = Blender.Mathutils.Vector(vec[0] * options.scale, vec[1] * options.scale, vec[2] * options.scale) #scale + # self.co = Blender.Mathutils.TranslationMatrix(vec) * (self.co * object.getMatrix('worldspace')) + + if normal: + #if world: + # self.no = Blender.Mathutils.Vector(normal * object.getMatrix('worldspace')).normalize() + #else: + self.no = Blender.Mathutils.Vector(normal[0],normal[1],normal[2]) + + else: + #if world: + #self.no = Blender.Mathutils.Vector(bvert.no * object.getMatrix('worldspace')).normalize() + #else: + self.no = Blender.Mathutils.Vector(bvert.no[0],bvert.no[1],bvert.no[2]) + + #do scaling factor + #if options.scale != 1.0: + #self.co[0] = self.co[0] * options.scale + #self.co[1] = self.co[1] * options.scale + #self.co[2] = self.co[2] * options.scale + + self.index = bvert.index class GlobalResourceRepository: def new_face_name(self): @@ -121,44 +193,98 @@ class GlobalResourceRepository: def request_vertex_desc(self, i): return self.vertex_lst[i] - def request_vertex_index(self, desc): - match = None - for i, v in enumerate(self.vertex_lst): - if\ - abs(v.x - desc.x) > FLOAT_TOLERANCE or\ - abs(v.y - desc.y) > FLOAT_TOLERANCE or\ - abs(v.z - desc.z) > FLOAT_TOLERANCE or\ - abs(v.nx - desc.nx) > FLOAT_TOLERANCE or\ - abs(v.ny - desc.ny) > FLOAT_TOLERANCE or\ - abs(v.nz - desc.nz) > FLOAT_TOLERANCE or\ - abs(v.u - desc.u) > FLOAT_TOLERANCE or\ - abs(v.v - desc.v) > FLOAT_TOLERANCE: - pass - else: - match = i - break + def request_vertex_index(self, object, mesh, face, vfindex, uvok,cindex): - if match != None: - return match + flatShadeNorm = None + + if type(face) is list: + vertex = face[vfindex] + elif str(type(face)) == "": + vertex = face + elif str(type(face)) == "": + if vfindex == 1: + vertex = face.v1 + elif vfindex == 2: + vertex = face.v2 + elif str(type(face)) == "": + if not face.smooth: + flatShadeNorm = face.no + vertex = face.v[vfindex] + else: + return None + + if not self.namehash.has_key(object.name): + self.namehash[object.name] = dict() + indexhash = self.namehash[object.name] + + #export in global space? THIS HAS BEEN MADE REDUNDANT... REMOVE ME + if not options.export_transform: + vertex = shadowVert(vertex,object,True,flatShadeNorm) else: - self.vertex_lst.append(desc) - return len(self.vertex_lst) - 1 - - def request_texture_index(self, filename): + vertex = shadowVert(vertex,object,False,flatShadeNorm) + + + #Check to see if this vertex has been visited before. If not, add + if not indexhash.has_key(vertex.index): + if uvok: + newvdesc = VertexDesc(vertex.co, vertex.no, face.uv[vfindex], self.nextvindex,cindex=cindex) + else: + newvdesc = VertexDesc(co=vertex.co, no=vertex.no,fltindex=self.nextvindex,cindex=cindex) + + indexhash[vertex.index] = [newvdesc] + self.vertex_lst.append(newvdesc) + self.nextvindex = self.nextvindex + 1 + return newvdesc.fltindex + + else: + desclist = indexhash[vertex.index] + if uvok: + faceu = face.uv[vfindex][0] + facev = face.uv[vfindex][1] + else: + faceu = 0.0 + facev = 0.0 + for vdesc in desclist: + if\ + abs(vdesc.x - vertex.co[0]) > FLOAT_TOLERANCE or\ + abs(vdesc.y - vertex.co[1]) > FLOAT_TOLERANCE or\ + abs(vdesc.z - vertex.co[2]) > FLOAT_TOLERANCE or\ + abs(vdesc.nx - vertex.no[0]) > FLOAT_TOLERANCE or\ + abs(vdesc.ny - vertex.no[1]) > FLOAT_TOLERANCE or\ + abs(vdesc.nz - vertex.no[2]) > FLOAT_TOLERANCE or\ + vdesc.cindex != cindex or\ + abs(vdesc.u - faceu) > FLOAT_TOLERANCE or\ + abs(vdesc.v - facev) > FLOAT_TOLERANCE: + pass + else: + return vdesc.fltindex + + #if we get this far, we didnt find a match. Add a new one and return + if uvok: + newvdesc = VertexDesc(vertex.co, vertex.no, face.uv[vfindex], self.nextvindex,cindex=cindex) + else: + newvdesc = VertexDesc(co=vertex.co, no=vertex.no,fltindex=self.nextvindex,cindex=cindex) + indexhash[vertex.index].append(newvdesc) + self.vertex_lst.append(newvdesc) + self.nextvindex = self.nextvindex + 1 + return newvdesc.fltindex + + + def request_texture_index(self, image): match = None for i in xrange(len(self.texture_lst)): - if self.texture_lst[i] != filename: + if self.texture_lst[i] != image: continue match = i break if match != None: return match else: - self.texture_lst.append(filename) + self.texture_lst.append(image) return len(self.texture_lst) - 1 def request_texture_filename(self, index): - return self.texture_lst[index] + return Blender.sys.expandpath(self.texture_lst[index].getFilename()) def texture_count(self): return len(self.texture_lst) @@ -239,7 +365,11 @@ class GlobalResourceRepository: return len(self.color_lst) def __init__(self): + #Vertex handling self.vertex_lst = [] + self.nextvindex = 0 + self.namehash = dict() + self.texture_lst = [] self.material_lst = [] self.color_lst = [[255, 255, 255]] @@ -253,7 +383,6 @@ class Node: if self.object: if options.verbose >= 2: print '\t' * level[0], self.name, self.object.type - level[0] += 1 for child in self.children: @@ -288,183 +417,530 @@ class Node: self.header.fw.write_ushort(length+5) # Length of record self.header.fw.write_string(name, length+1) # name + zero terminator + def write_comment(self,comment): + length = len(comment) + if length >= 65535: + comment = comment[:65530] + length = len(comment) + + pad = (length % 4) - 1 + if pad < 0: + pad = None + reclength = length + 5 + else: + reclength = length + 5 + pad + + self.header.fw.write_short(31) # Comment Opcode + self.header.fw.write_ushort(reclength) # Length of record is 4 + comment length + null terminator + pad + self.header.fw.write_string(comment,length+1) # comment + zero terminator + if pad: + self.header.fw.pad(pad) # pad to multiple of 4 bytes + # Initialization sets up basic tree structure. - def __init__(self, parent, header, object, object_lst): + def __init__(self, parent, header, object,props): + global options + self.header = header self.object = object if object: self.name = self.object.name - self.matrix = self.object.getMatrix('localspace') + if not options.export_transform: + oloc = Blender.Mathutils.Vector(object.getLocation('worldspace')) + vec = Blender.Mathutils.Vector(oloc[0] * options.scale, oloc[1] * options.scale, oloc[2] * options.scale) #scale + self.matrix = self.object.getMatrix('worldspace') * Blender.Mathutils.TranslationMatrix(vec - oloc) + else: + self.matrix = self.object.getMatrix('localspace') #do matrix mult here. + self.props = props + self.child_objects = self.header.parenthash[object.name] else: self.name = 'no name' self.matrix = None - + self.props = None + self.child_objects = self.header.child_objects + self.children = [] self.parent = parent if parent: parent.children.append(self) - - left_over = object_lst[:] - self.child_objects = [] - - # Add children to child list and remove from left_over list. - # Pop is faster then remove - i = len(object_lst) - while i: - i-=1 - if object_lst[i].parent == object: - self.child_objects.append(left_over.pop(i)) - # Spawn children. - self.has_object_child = False # For Database class. for child in self.child_objects: - if child.type == 'Mesh': - BlenderMesh(self, header, child, left_over) - self.has_object_child = True - else: # Treat all non meshes as emptys - BlenderEmpty(self, header, child, left_over) - + if(not child.restrictDisplay): + childprops = None + type = None + if not child.properties.has_key('FLT'): + if child.type == 'Empty': + if child.DupGroup: + childprops = FLTXRef.copy() + type = 63 + else: + childprops = FLTGroup.copy() + type = 2 + elif child.type == 'Mesh': + if self.header.childhash[child.name] or not child.parent: + childprops = FLTGroup.copy() + type = 2 + else: + childprops = FLTObject.copy() + type = 4 + + else: + childprops = dict() + for prop in child.properties['FLT']: + childprops[prop] = child.properties['FLT'][prop] + type = child.properties['FLT']['type'] + + if type in self.childtypes and type in alltypes: + Newnode = FLTNode(self,header,child,childprops,type) + if child.type == 'Mesh': + self.header.mnodes.append(Newnode) class FaceDesc: def __init__(self): self.vertex_index_lst = [] + self.mface = None self.texture_index = -1 self.material_index = -1 self.color_index = 127 + self.renderstyle = 0 + self.twoside = 0 + self.name = None #uses next FLT name if not set... fix resolution of conflicts! + + #Multi-Tex info. Dosn't include first UV Layer! + self.uvlayer = list() #list of list of tuples for UV coordinates. + self.images = list() #list of texture indices for seperate UV layers + self.mtex = list() + self.subface = None #can either be 'Push' or 'Pop' + +def edge_get_othervert(vert, edge): + if edge.v1 == vert: + return edge.v2 + elif edge.v2 == vert: + return edge.v1 + return None + +class FLTNode(Node): + def walkLoop(self, targetvert, startvert, startedge, edgelist, visited, vedges, closeloop): + loop = [targetvert] + + curvert = startvert + curedge = startedge + visited[curedge] = True + found = False + + while not found: + loop.append(curvert) + disk = vedges[curvert.index] + if not closeloop: + if len(disk) == 1: + visited[curedge] = True + break + else: + if len(disk) < 2: #what? + visited[curedge] = True + return None + + if disk[0] == curedge: + curedge = disk[1] + else: + curedge = disk[0] + if curedge.v1.index == curvert.index: + curvert = curedge.v2 + else: + curvert = curedge.v1 + + visited[curedge] = True + + if(curvert == targetvert): + found = True + + return loop -class BlenderMesh(Node): - def blender_export(self): - Node.blender_export(self) - - mesh = self.object.getData() - mesh_hasuv = mesh.hasFaceUV() - # Gather materials and textures. - tex_index_lst = [] - mat_index_lst = [] - color_index_lst = [] - materials = mesh.getMaterials() - - if not materials: - materials = [Blender.Material.New()] - - for mat in materials: - # Gather Color. - if options.use_face_color: - color_index_lst.append(self.header.GRR.request_color_index(mat.getRGBCol())) - else: - color_index_lst.append(127) # white - # Gather Texture. - mtex_lst = mat.getTextures() - - index = -1 - mtex = mtex_lst[0] # Not doing multi-texturing at the moment. - if mtex != None: - tex = mtex_lst[0].tex - if tex != None: - image = tex.getImage() - if image != None: - filename = image.getFilename() - index = self.header.GRR.request_texture_index(filename) - - tex_index_lst.append(index) - - # Gather Material - mat_desc = MaterialDesc() - mat_desc.name = mat.name - mat_desc.alpha = mat.getAlpha() - mat_desc.shininess = mat.getSpec() * 64.0 # 2.0 => 128.0 - if options.use_mat_color: - mat_desc.diffuse = mat.getRGBCol() - else: - mat_desc.diffuse = [1.0, 1.0, 1.0] - - mat_desc.specular = mat.getSpecCol() - amb = mat.getAmb() - mat_desc.ambient = [amb, amb, amb] - emit = mat.getEmit() - mat_desc.emissive = [emit, emit, emit] - - mat_index_lst.append(self.header.GRR.request_material_index(mat_desc)) - - # Faces described as lists of indices into the GRR's vertex_lst. - for face in mesh.faces: - - face_v = face.v # Faster access - - # Create vertex description list for each face. - if mesh_hasuv: - vertex_lst = [VertexDesc(v.co, v.no, face.uv[i]) for i, v in enumerate(face_v)] - else: - vertex_lst = [VertexDesc(v.co, v.no) for i, v in enumerate(face_v)] - - index_lst = [] - for vert_desc in vertex_lst: - index_lst.append(self.header.GRR.request_vertex_index(vert_desc)) - - face_desc = FaceDesc() - face_desc.vertex_index_lst = index_lst - - if face.materialIndex < len(materials): - face_desc.color_index = color_index_lst[face.materialIndex] - face_desc.texture_index = tex_index_lst[face.materialIndex] - face_desc.material_index = mat_index_lst[face.materialIndex] - else: - if options.verbose >=1: - print 'Warning: Missing material for material index. Materials will not be imported correctly. Fix by deleting abandoned material indices in Blender.' - - self.face_lst.append(face_desc) - - # Export double sided face as 2 faces with opposite orientations. - if mesh_hasuv and face.mode & Blender.NMesh.FaceModes['TWOSIDE']: - # Create vertex description list for each face. they have a face mode, so we know they have a UV too. - vertex_lst = [VertexDesc(v.co, -v.no, face.uv[i]) for i, v in enumerate(face_v)] - vertex_lst.reverse() # Reversing flips the face. - - index_lst = [] - for vert_desc in vertex_lst: - index_lst.append(self.header.GRR.request_vertex_index(vert_desc)) - + def buildVertFaces(self,vertuse): + for vert in self.exportmesh.verts: + if vertuse[vert.index][0] == False and vertuse[vert.index][1] == 0: face_desc = FaceDesc() - face_desc.vertex_index_lst = index_lst - if face.materialIndex < len(materials): - face_desc.color_index = color_index_lst[face.materialIndex] - face_desc.texture_index = tex_index_lst[face.materialIndex] - face_desc.material_index = mat_index_lst[face.materialIndex] - else: - if options.verbose >=1: - print 'Error: No material for material index. Delete abandoned material indices in Blender.' - + face_desc.vertex_index_lst.append(self.header.GRR.request_vertex_index(self.object, self.exportmesh, vert, 0,0,0)) + face_desc.renderstyle = 3 + face_desc.color_index = 227 self.face_lst.append(face_desc) - def write_faces(self): - for face_desc in self.face_lst: - face_name = self.header.GRR.new_face_name() + def buildEdgeFaces(self,vertuse): + for edge in self.exportmesh.edges: + v1 = vertuse[edge.v1.index] + v2 = vertuse[edge.v2.index] + if v1[0] == False and v2[0] == False: + if v1[1] == 1 and v2[1] == 1: + face_desc = FaceDesc() + face_desc.vertex_index_lst.append(self.header.GRR.request_vertex_index(self.object, self.exportmesh, edge, 1, 0,0)) + face_desc.vertex_index_lst.append(self.header.GRR.request_vertex_index(self.object, self.exportmesh, edge, 2, 0,0)) + face_desc.renderstyle = 3 + face_desc.color_index = 227 + self.face_lst.append(face_desc) + + + def vertwalk(self, startvert, loop, disk, visited): + visited[startvert] = True + for edge in disk[startvert]: + othervert = edge_get_othervert(startvert, edge) + if not visited[othervert]: + loop.append(othervert) + self.vertwalk(othervert,loop,disk,visited) + + def buildOpenFacesNew(self, vertuse): + wireverts = list() + wiredges = list() + visited = dict() + disk = dict() + loops = list() + + for edge in self.exportmesh.edges: + v1 = vertuse[edge.v1.index] + v2 = vertuse[edge.v2.index] + if v1[0] == False and v2[0] == False: + if v1[1] < 3 and v2[1] < 3: + wireverts.append(edge.v1) + wireverts.append(edge.v2) + wiredges.append(edge) + + #build disk data + for vert in wireverts: + visited[vert] = False + disk[vert] = list() + for edge in wiredges: + disk[edge.v1].append(edge) + disk[edge.v2].append(edge) + + #first pass: do open faces + for vert in wireverts: + if not visited[vert] and vertuse[vert.index][1] == 1: + visited[vert] = True + loop = [vert] + othervert = edge_get_othervert(vert, disk[vert][0]) + self.vertwalk(othervert, loop, disk, visited) + if len(loop) > 2: loops.append( ('Open', loop) ) + + for vert in wireverts: + if not visited[vert]: + visited[vert] = True + loop = [vert] + othervert = edge_get_othervert(vert,disk[vert][0]) + self.vertwalk(othervert, loop, disk, visited) + if len(loop) > 2: loops.append( ('closed', loop) ) + + #now go through the loops and append. + for l in loops: + (type, loop) = l + face_desc = FaceDesc() + for i,vert in enumerate(loop): + face_desc.vertex_index_lst.append(self.header.GRR.request_vertex_index(self.object,self.exportmesh,loop,i,0,0)) + if type == 'closed': + face_desc.renderstyle = 2 + else: + face_desc.renderstyle = 3 + face_desc.color_index = 227 + self.face_lst.append(face_desc) + + def sortFLTFaces(self,a,b): + aindex = a.getProperty("FLT_ORIGINDEX") + bindex = b.getProperty("FLT_ORIGINDEX") + + if aindex > bindex: + return 1 + elif aindex < bindex: + return -1 + return 0 + + def buildNormFaces(self): + + global options + meshlayers = self.exportmesh.getUVLayerNames() + oldlayer = self.exportmesh.activeUVLayer + uvok = 0 + subfaceok = 0 + subfacelevel = 0 + + #special case + if self.exportmesh.faceUV and len(meshlayers) == 1: + uvok = 1 + elif self.exportmesh.faceUV and tex_layers[0] in meshlayers: + self.exportmesh.activeUVLayer = tex_layers[0] + uvok = 1 + + #Sort faces according to the subfaces/FLT indices + if "FLT_ORIGINDEX" in self.exportmesh.faces.properties and "FLT_SFLEVEL" in self.exportmesh.faces.properties: + exportfaces = list() + for face in self.exportmesh.faces: + exportfaces.append(face) + exportfaces.sort(self.sortFLTFaces) + subfaceok = 1 + else: + exportfaces = self.exportmesh.faces + # Faces described as lists of indices into the GRR's vertex_lst. + for face in exportfaces: + descs = list() + #first we export the face as normal + index_lst = [] + face_v = face.verts + for i, v in enumerate(face_v): + index_lst.append(self.header.GRR.request_vertex_index(self.object,self.exportmesh,face,i,uvok,0)) + face_desc = FaceDesc() + face_desc.vertex_index_lst = index_lst + face_desc.mface = face + descs.append(face_desc) + + #deal with subfaces + if subfaceok: + fsflevel = face.getProperty("FLT_SFLEVEL") + for face_desc in descs: + if fsflevel > subfacelevel: + face_desc.subface = 'Push' + subfacelevel = fsflevel + elif fsflevel < subfacelevel: + face_desc.subface = 'Pop' + subfacelevel = fsflevel + + + if uvok and (face.mode & Blender.Mesh.FaceModes.TWOSIDE): + face_desc.renderstyle = 1 + for face_desc in descs: + if "FLT_COL" in self.exportmesh.faces.properties: + color_index = face.getProperty("FLT_COL") +# if(color_index < 127): +# color_index = 127 #sanity check for face color indices + if(color_index == 0): + color_index = 127 + face_desc.color_index = color_index + else: + face_desc.color_index = 127 + if "FLT_ID" in self.exportmesh.faces.properties: + face_desc.name = face.getProperty("FLT_ID") #need better solution than this. + + self.face_lst.append(face_desc) + if uvok: + self.exportmesh.activeUVLayer = oldlayer + + def buildTexData(self): + + meshlayers = self.exportmesh.getUVLayerNames() + oldlayer = self.exportmesh.activeUVLayer + uvok = 0 + + if self.exportmesh.faceUV and len(meshlayers) == 1: + uvok = 1 + if self.exportmesh.faceUV and tex_layers[0] in meshlayers: + self.exportmesh.activeUVLayer = tex_layers[0] + uvok = 1 + + if uvok: + #do base layer. UVs have been stored on vertices directly already. + for i, face in enumerate(self.face_lst): + if face.mface: + mface = face.mface + image = mface.image + if image != None and mface.mode & Blender.Mesh.FaceModes["TEX"]: + index = self.header.GRR.request_texture_index(image) + else: + index = -1 + face.texture_index = index + + for i, face in enumerate(self.face_lst): + if face.mface: + mface_v = face.mface.v + for v in mface_v: + face.uvlayer.append([]) + + for layername in tex_layers[1:]: + if layername in meshlayers: + self.exportmesh.activeUVLayer=layername + for i, face in enumerate(self.face_lst): + if face.mface: + + face.mtex.append(layername) + mface = face.mface + mface_v = mface.v + image = mface.image + + if image != None and mface.mode & Blender.Mesh.FaceModes["TEX"]: + index = self.header.GRR.request_texture_index(image) + face.images.append(index) + else: + face.images.append(-1) + + for j, v in enumerate(mface_v): + face.uvlayer[j].append(tuple(mface.uv[j])) + if uvok: + self.exportmesh.activeUVLayer = oldlayer + def blender_export(self): + global options + Node.blender_export(self) + if self.opcode == 111: + self.exportmesh = Blender.Mesh.New() + self.exportmesh.getFromObject(self.object.name) + + for vert in self.exportmesh.verts: + if not options.export_transform: + vec = vert.co + vec = Blender.Mathutils.Vector(vec[0] * options.scale, vec[1] * options.scale, vec[2] * options.scale) #scale + vert.co = Blender.Mathutils.TranslationMatrix(vec) * (vert.co * self.object.getMatrix('worldspace')) + + if options.scale != 1.0: + vert.co = vert.co * options.scale + + if("FLT_VCOL") in self.mesh.verts.properties: + for v in self.exportmesh.verts: + self.vert_lst.append(self.header.GRR.request_vertex_index(self.object,self.exportmesh,v,0,0,v.getProperty("FLT_VCOL"))) + else: + for v in self.mesh.verts: + self.vert_lst.append(self.header.GRR.request_vertex_index(self.object,self.mesh,v,0,0,127)) + + + + elif self.mesh: + orig_mesh = self.object.getData(mesh=True) + self.exportmesh = Blender.Mesh.New() + default = None + + + if options.export_shading: + mods = self.object.modifiers + hasedsplit = False + for mod in mods: + if mod.type == Blender.Modifier.Types.EDGESPLIT: + hasedsplit = True + break + if not hasedsplit: + default = mods.append(Modifier.Types.EDGESPLIT) + default[Modifier.Settings.EDGESPLIT_ANGLE] = options.shading_default + default[Modifier.Settings.EDGESPLIT_FROM_ANGLE] = True + default[Modifier.Settings.EDGESPLIT_FROM_SHARP] = False + self.object.makeDisplayList() + + self.exportmesh.getFromObject(self.object.name) + + #recalculate vertex positions + for vert in self.exportmesh.verts: + if not options.export_transform: + vec = vert.co + vec = Blender.Mathutils.Vector(vec[0] * options.scale, vec[1] * options.scale, vec[2] * options.scale) #scale + vert.co = Blender.Mathutils.TranslationMatrix(vec) * (vert.co * self.object.getMatrix('worldspace')) + + if options.scale != 1.0: + vert.co = vert.co * options.scale + + flipped = self.object.getMatrix('worldspace').determinant() + + if not options.export_transform: + self.exportmesh.calcNormals() + + + if default: + #remove modifier from list + mods.remove(default) + self.object.makeDisplayList() + + #build some adjacency data + vertuse = list() + wiredges = list() + openends = list() + for v in self.exportmesh.verts: + vertuse.append([False,0]) + + #build face incidence data + for face in self.exportmesh.faces: + for i, v in enumerate(face.verts): + vertuse[v.index][0] = True + + for edge in self.exportmesh.edges: #count valance + vertuse[edge.v1.index][1] = vertuse[edge.v1.index][1] + 1 + vertuse[edge.v2.index][1] = vertuse[edge.v2.index][1] + 1 + + #create all face types + self.buildVertFaces(vertuse) + self.buildEdgeFaces(vertuse) + self.buildOpenFacesNew(vertuse) + self.buildNormFaces() + self.buildTexData() + + if not options.export_transform: + if flipped < 0: + for vdesc in self.header.GRR.vertex_lst: + vdesc.accum = 0 + for face in self.face_lst: + face.vertex_index_lst.reverse() + for vert in face.vertex_index_lst: + self.header.GRR.vertex_lst[vert].accum = 1 + + for vdesc in self.header.GRR.vertex_lst: + if vdesc.accum: + vdesc.nx = vdesc.nx * -1 + vdesc.ny = vdesc.ny * -1 + vdesc.nz = vdesc.nz * -1 + + + def write_faces(self): + sublevel = 0 + for face_desc in self.face_lst: + if face_desc.name: + face_name = face_desc.name + else: + face_name = self.header.GRR.new_face_name() + + #grab the alpha value. + alpha = 0 + if face_desc.texture_index > -1: + try: + typestring = os.path.splitext(self.header.GRR.texture_lst[face_desc.texture_index].getFilename())[1] + if typestring == '.inta' or typestring == '.rgba': + alpha = 1 + except: + pass + + if not alpha: + for index in face_desc.images: + try: + typestring = os.path.splitext(self.header.GRR.texture_lst[index].getFilename())[1] + if typestring == '.inta' or typestring == '.rgba': + alpha = 1 + except: + pass + + if face_desc.subface: + if face_desc.subface == 'Push': + self.header.fw.write_short(19) + self.header.fw.write_ushort(4) + sublevel += 1 + else: + self.header.fw.write_short(20) + self.header.fw.write_ushort(4) + sublevel -= 1 self.header.fw.write_short(5) # Face opcode self.header.fw.write_ushort(80) # Length of record self.header.fw.write_string(face_name, 8) # ASCII ID self.header.fw.write_int(-1) # IR color code - self.header.fw.write_short(0) # Relative priority - self.header.fw.write_char(0) # Draw type + self.header.fw.write_short(0) # Relative priority + self.header.fw.write_char(face_desc.renderstyle) # Draw type self.header.fw.write_char(0) # Draw textured white. self.header.fw.write_ushort(0) # Color name index self.header.fw.write_ushort(0) # Alt color name index self.header.fw.write_char(0) # Reserved - self.header.fw.write_char(1) # Template + self.header.fw.write_char(alpha) # Template self.header.fw.write_short(-1) # Detail tex pat index self.header.fw.write_short(face_desc.texture_index) # Tex pattern index self.header.fw.write_short(face_desc.material_index) # material index self.header.fw.write_short(0) # SMC code - self.header.fw.write_short(0) # Feature code + self.header.fw.write_short(0) # Feature code self.header.fw.write_int(0) # IR material code self.header.fw.write_ushort(0) # transparency 0 = opaque self.header.fw.write_uchar(0) # LOD generation control self.header.fw.write_uchar(0) # line style index - self.header.fw.write_int(0x00000000) # Flags + self.header.fw.write_int(0) # Flags self.header.fw.write_uchar(2) # Light mode + #self.header.fw.write_uchar(3) # Light mode + self.header.fw.pad(7) # Reserved - self.header.fw.write_uint(-1) # Packed color - self.header.fw.write_uint(-1) # Packed alt color + self.header.fw.write_uint(0) # Packed color + self.header.fw.write_uint(0) # Packed alt color self.header.fw.write_short(-1) # Tex map index self.header.fw.write_short(0) # Reserved self.header.fw.write_uint(face_desc.color_index) # Color index @@ -473,7 +949,24 @@ class BlenderMesh(Node): self.header.fw.write_short(-1) # Shader index self.write_longid(face_name) - + + + #Write Multitexture field if appropriate + mtex = len(face_desc.mtex) + if mtex: + uvmask = 0 + for layername in face_desc.mtex: + mask = mtexmasks[tex_layers.index(layername)-1] + uvmask |= mask + self.header.fw.write_ushort(52) # MultiTexture Opcode + self.header.fw.write_ushort(8 + (mtex * 8)) # Length + self.header.fw.write_uint(uvmask) # UV mask + for i in xrange(mtex): + self.header.fw.write_ushort(face_desc.images[i]) # Tex pattern index + self.header.fw.write_ushort(0) # Tex effect + self.header.fw.write_ushort(0) # Tex Mapping index + self.header.fw.write_ushort(0) # Tex data. User defined + self.write_push() # Vertex list record @@ -484,72 +977,95 @@ class BlenderMesh(Node): for vert_index in face_desc.vertex_index_lst: # Offset into vertex palette self.header.fw.write_int(vert_index*64+8) - - self.write_pop() - - def write(self): - if self.open_flight_type == 'Object': - self.header.fw.write_short(4) # Object opcode - self.header.fw.write_ushort(28) # Length of record - self.header.fw.write_string(self.name, 8) # ASCII ID - self.header.fw.pad(16) - - self.write_longid(self.name) + #UV list record + if mtex: + #length = 8 + (numverts * multitex * 8) + self.header.fw.write_ushort(53) # UV List Ocode + self.header.fw.write_ushort(8 + (num_verts*mtex*8)) # Record Length + self.header.fw.write_uint(uvmask) # UV mask + for i, vert_index in enumerate(face_desc.vertex_index_lst): + for uv in face_desc.uvlayer[i]: + self.header.fw.write_float(uv[0]) #U coordinate + self.header.fw.write_float(uv[1]) #V coordinate + self.write_pop() + #clean up faces at the end of meshes.... + if sublevel: + self.header.fw.write_short(20) + self.header.fw.write_ushort(4) + + def write_lps(self): + # Vertex list record + self.write_push() + self.header.fw.write_short(72) # Vertex list opcode + num_verts = len(self.vert_lst) + self.header.fw.write_ushort(4*num_verts+4) # Length of record + + for vert_index in self.vert_lst: + # Offset into vertex palette + self.header.fw.write_int(vert_index*64+8) + self.write_pop() + def write(self): + self.header.fw.write_short(self.opcode) + self.header.fw.write_ushort(recordlen[self.opcode]) + exportdict = FLT_Records[self.opcode].copy() + for key in exportdict.keys(): + if self.props.has_key(key): + exportdict[key] = self.props[key] + + if self.opcode == 63 and options.externalspath: + try: + exportdict['3t200!filename'] = os.path.join(options.externalspath,self.object.DupGroup.name+'.flt') + self.header.xrefnames.append(self.object.DupGroup.name) + except: + pass + + for key in records[self.opcode]: + (type,length,propname) = records[self.opcode][key] + write_prop(self.header.fw,type,exportdict[propname],length) + + if self.props.has_key('comment'): + self.write_comment(self.props['comment']) + + self.write_longid(self.name) #fix this! + + if options.export_transform or self.opcode == 63: + #writing transform matrix.... self.write_matrix() - - if self.face_lst != []: - self.write_push() - - self.write_faces() - - self.write_pop() - else: - self.header.fw.write_short(2) # Group opcode - self.header.fw.write_ushort(44) # Length of record - self.header.fw.write_string(self.name, 8) # ASCII ID - self.header.fw.pad(32) - - self.write_longid(self.name) - - # Because a group can contain faces as well as children. - self.write_push() - - self.write_faces() - - for child in self.children: - child.write() - - self.write_pop() - def __init__(self, parent, header, object, object_lst): - Node.__init__(self, parent, header, object, object_lst) - self.face_lst = [] - - if self.children: - self.open_flight_type= 'Group' - else: # Empty list. - self.open_flight_type = 'Object' - - -class BlenderEmpty(Node): - def write(self): - self.header.fw.write_short(2) # Group opcode - self.header.fw.write_ushort(44) # Length of record - self.header.fw.write_string(self.name, 8) # ASCII ID - self.header.fw.pad(32) - - self.write_longid(self.name) - - self.write_matrix() - - if self.children: # != [] + if self.opcode == 111: + self.write_lps() + elif self.face_lst != [] or self.children: self.write_push() - - for child in self.children: - child.write() - + if self.face_lst != []: + #self.write_push() + self.write_faces() + #self.write_pop() + + if self.children: + #self.write_push() + for child in self.children: + child.write() + #self.write_pop() self.write_pop() + + def __init__(self, parent, header, object,props,type): + self.opcode = type #both these next two lines need to be in the node class.... + self.childtypes = childtypes[self.opcode] + Node.__init__(self, parent, header, object,props) + self.face_lst = [] + self.vert_lst = [] #for light points. + self.mesh = None + self.uvlayer = 0 + self.flipx = False + self.flipy = False + self.flipz = False + + + if self.object.type == 'Mesh': + self.mesh = self.object.getData(mesh=True) + if(self.mesh.faceUV): + self.uvLayer = len(self.mesh.getUVLayerNames()) class Database(Node): def write_header(self): @@ -568,8 +1084,19 @@ class Database(Node): self.fw.write_int(0) # projection type, 0 = flat earth self.fw.pad(30) self.fw.write_short(1) # double precision - self.fw.pad(140) + self.fw.write_int(100) # database origin type + self.fw.pad(88) + try: + self.fw.write_double(self.header.scene.properties['FLT']['origin lat']) #database origin lattitude + except: + self.fw.write_double(0) + try: + self.fw.write_double(self.header.scene.properties['FLT']['origin lon']) #database origin longitude + except: + self.fw.write_double(0) + self.fw.pad(32) self.fw.write_int(0) # ellipsoid model, 0 = WSG 1984 + self.fw.pad(52) def write_vert_pal(self): @@ -579,14 +1106,13 @@ class Database(Node): self.fw.write_short(67) # Vertex palette opcode. self.fw.write_short(8) # Length of record self.fw.write_int(self.GRR.vertex_count() * 64 + 8) # Length of everything. - # Write records for individual vertices. for i in xrange(self.GRR.vertex_count()): desc = self.GRR.request_vertex_desc(i) self.fw.write_short(70) # Vertex with color normal and uv opcode. self.fw.write_ushort(64) # Length of record - self.fw.write_ushort(0) # Color name index - self.fw.write_short(0x2000) # Flags set to no color + self.fw.write_ushort(0) # Color name index + self.fw.write_short(0x20000000) # Flags self.fw.write_double(desc.x) self.fw.write_double(desc.y) self.fw.write_double(desc.z) @@ -595,16 +1121,19 @@ class Database(Node): self.fw.write_float(desc.nz) self.fw.write_float(desc.u) self.fw.write_float(desc.v) - self.fw.pad(12) + self.fw.pad(4) + self.fw.write_uint(desc.cindex) + self.fw.pad(4) def write_tex_pal(self): if options.verbose >= 2: print 'Writing texture palette.' # Write record for texture palette - for i in xrange(self.GRR.texture_count()): + for i, img in enumerate(self.GRR.texture_lst): + filename = tex_files[img.name] self.fw.write_short(64) # Texture palette opcode. self.fw.write_short(216) # Length of record - self.fw.write_string(self.GRR.request_texture_filename(i), 200) # Filename + self.fw.write_string(filename, 200) # Filename self.fw.write_int(i) # Texture index self.fw.write_int(0) # X self.fw.write_int(0) # Y @@ -641,13 +1170,17 @@ class Database(Node): self.fw.write_short(32) # Color palette opcode. self.fw.write_short(4228) # Length of record self.fw.pad(128) - count = self.GRR.color_count() + try: + cpalette = self.scene.properties['FLT']['Color Palette'] + except: + cpalette = defaultp.pal + count = len(cpalette) for i in xrange(count): - col = self.GRR.request_max_color(i) - self.fw.write_uchar(255) # alpha - self.fw.write_uchar(col[2]) # b - self.fw.write_uchar(col[1]) # g - self.fw.write_uchar(col[0]) # r + color = struct.unpack('>BBBB',struct.pack('>I',cpalette[i])) + self.fw.write_uchar(color[3]) # alpha + self.fw.write_uchar(color[2]) # b + self.fw.write_uchar(color[1]) # g + self.fw.write_uchar(color[0]) # r self.fw.pad(max(4096-count*4, 0)) def write(self): @@ -657,66 +1190,428 @@ class Database(Node): self.write_mat_pal() self.write_col_pal() - # Wrap everything in a group if it has an object child. - if self.has_object_child: - self.header.fw.write_short(2) # Group opcode - self.header.fw.write_ushort(44) # Length of record - self.header.fw.write_string('g1', 8) # ASCII ID - self.header.fw.pad(32) - self.write_push() - - for child in self.children: - child.write() - + + if options.flattenmesh: + self.mnodes.reverse() + for mnode in self.mnodes: + mnode.write_faces() + else: + for child in self.children: + child.write() self.write_pop() + + def export_textures(self,texturepath): + for i in xrange(self.GRR.texture_count()): + texture = self.GRR.texture_lst[i] + + if options.copy_textures: + filename = os.path.normpath(os.path.join(options.texturespath, os.path.basename(self.GRR.request_texture_filename(i)))) + else: + filename = os.path.normpath(self.GRR.request_texture_filename(i)) + + tex_files[texture.name] = filename + def blender_export(self): + Node.blender_export(self) + self.export_textures(self) + return self.xrefnames def __init__(self, scene, fw): self.fw = fw + self.opcode = 1 + self.childtypes = [73,14,2,63] self.scene = scene - self.all_objects = list(scene.objects) + self.childhash = dict() + self.parenthash = dict() + self.child_objects = list() + self.mnodes = list() + self.xrefnames = list() + for i in self.scene.objects: + self.parenthash[i.name] = list() + self.childhash[i.name] = False + for i in self.scene.objects: + if i.parent: + self.childhash[i.parent.name] = True + self.parenthash[i.parent.name].append(i) + else: + self.child_objects.append(i) + self.GRR = GlobalResourceRepository() + Node.__init__(self, None, self, None,None) - Node.__init__(self, None, self, None, self.all_objects) +def write_attribute_files(): + for imgname in tex_files: + blentex = Blender.Image.Get(imgname) + exportdict = FLT_Records['Image'].copy() + + if blentex.properties.has_key('FLT'): + for key in exportdict.keys(): + if blentex.properties.has_key(key): + exportdict[key] = blentex.properties['FLT'][key] + + # ClampX/Y override + if blentex.clampX: + exportdict['11i!WrapU'] = 1 + if blentex.clampY: + exportdict['12i!WrapV'] = 1 + + exportdict['16i!Enviorment'] = 0 + + # File type + typecode = 0 + try: + typestring = os.path.splitext(blentex.getFilename())[1] + + if typestring == '.rgba': + typecode = 5 + elif typestring == '.rgb': + typecode = 4 + elif typestring == '.inta': + typecode = 3 + elif typestring == '.int': + typecode = 2 + except: + pass + + exportdict['7i!File Format'] = typecode -def fs_callback(filename): + fw = FltOut(tex_files[imgname] + '.attr') + size = blentex.getSize() + fw.write_int(size[0]) + fw.write_int(size[1]) + for key in records['Image']: + (type,length,propname) = records['Image'][key] + write_prop(fw,type,exportdict[propname],length) + fw.close_file() + +#globals used by the scene export function +exportlevel = None +xrefsdone = None + +def dbexport_internal(scene): + global exportlevel + global xrefsdone + global options + + if exportlevel == 0 or not options.externalspath: + fname = os.path.join(options.basepath,scene.name + '.flt') + else: + fname = os.path.join(options.externalspath,scene.name + '.flt') + + fw = FltOut(fname) + db = Database(scene,fw) + + if options.verbose >= 1: + print 'Pass 1: Exporting ', scene.name,'.flt from Blender.\n' + + xreflist = db.blender_export() + if options.verbose >= 1: + print 'Pass 2: Writing %s\n' % fname + db.write() + fw.close_file() + + if options.doxrefs: + for xname in xreflist: + try: + xrefscene = Blender.Scene.Get(xname) + except: + xrefscene = None + if xrefscene and xname not in xrefsdone: + xrefsdone.append(xname) + exportlevel+=1 + dbexport_internal(xrefscene) + exportlevel-=1 + return fname +#main database export function +def dbexport(): + global exportlevel + global xrefsdone + exportlevel = 0 + xrefsdone = list() + Blender.Window.WaitCursor(True) - - if Blender.sys.exists(filename): - r = Blender.Draw.PupMenu('Overwrite ' + filename + '?%t|Yes|No') - if r != 1: - if options.verbose >= 1: - print 'Export cancelled.' - return - time1 = Blender.sys.time() # Start timing - fw = FltOut(filename) - - db = Database(Blender.Scene.GetCurrent(), fw) - if options.verbose >= 1: - print 'Pass 1: Exporting from Blender.\n' + print '\nOpenFlight Exporter' + print 'Version:', __version__ + print 'Author: Greg MacDonald, Geoffrey Bantle' + print __url__[2] + print - db.blender_export() - - if options.verbose >= 1: - print 'Pass 2: Writing %s\n' % filename - - db.write() - - fw.close_file() - if options.verbose >= 1: + fname = dbexport_internal(Blender.Scene.GetCurrent()) + if options.verbose >=1: print 'Done in %.4f sec.\n' % (Blender.sys.time() - time1) - Blender.Window.WaitCursor(False) - -if options.verbose >= 1: - print '\nOpenFlight Exporter' - print 'Version:', __version__ - print 'Author: Greg MacDonald' - print __url__[2] - print -fname = Blender.sys.makename(ext=".flt") -Blender.Window.FileSelector(fs_callback, "Export OpenFlight v16.0", fname) + #optional: Copy textures + if options.copy_textures: + for imgname in tex_files: + #Check to see if texture exists in target directory + if not os.path.exists(tex_files[imgname]): + #Get original Blender file name + origpath = Blender.sys.expandpath(Blender.Image.Get(imgname).getFilename()) + #copy original to new + shutil.copyfile(origpath,tex_files[imgname]) + + #optional: Write attribute files + if options.write_attrib_files: + write_attribute_files() + + if options.xapp: + cmd= options.xappath + " " + fname + status = os.system(cmd) + + +#Begin UI code +FLTExport = None +FLTClose = None +FLTLabel = None + +FLTBaseLabel = None +FLTTextureLabel = None +FLTXRefLabel = None + +FLTBaseString = None +FLTTextureString = None +FLTXRefString = None + +FLTBasePath = None +FLTTexturePath = None +FLTXRefPath = None + +FLTShadeExport = None +FLTShadeDefault = None + +FLTCopyTex = None +FLTDoXRef = None +FLTGlobal = None + +FLTScale = None + +FLTXAPP = None +FLTXAPPath = None +FLTXAPPString = None +FLTXAPPLabel = None +FLTXAPPChooser = None + +FLTAttrib = None + +def setshadingangle(ID,val): + global options + options.shading_default = val +def setBpath(fname): + global options + options.basepath = os.path.dirname(fname) + #update xref and textures path too.... + if(os.path.exists(os.path.join(options.basepath,'externals'))): + options.externalspath = os.path.join(options.basepath,'externals') + if(os.path.exists(os.path.join(options.texturespath,'textures'))): + options.texturespath = os.path.join(options.basepath,'textures') +def setexportscale(ID,val): + global options + options.scale = val + +def setTpath(fname): + global options + options.texturespath = os.path.dirname(fname) +def setXpath(fname): + global options + options.externalspath = os.path.dirname(fname) +def setXApath(fname): + global options + options.xappath = fname + d = dict() + d['xappath'] = options.xappath + Blender.Registry.SetKey('flt_export', d, 1) +def event(evt, val): + x = 1 +def but_event(evt): + global options + + global FLTExport + global FLTClose + global FLTLabel + + global FLTBaseLabel + global FLTTextureLabel + global FLTXRefLabel + + global FLTBaseString + global FLTTextureString + global FLTXRefString + + global FLTBasePath + global FLTTexturePath + global FLTXRefPath + + global FLTShadeExport + global FLTShadeDefault + + global FLTCopyTex + global FLTDoXRef + global FLTGlobal + + global FLTScale + + + global FLTXAPP + global FLTXAPPath + global FLTXAPPString + global FLTXAPPLabel + global FLTXAPPChooser + + global FLTAttrib + + + + #choose base path for export + if evt == 4: + Blender.Window.FileSelector(setBpath, "DB Root", options.basepath) + + #choose XREF path + if evt == 6: + Blender.Window.FileSelector(setXpath,"DB Externals",options.externalspath) + + #choose texture path + if evt == 8: + Blender.Window.FileSelector(setTpath,"DB Textures",options.texturespath) + + #export shading toggle + if evt == 9: + options.export_shading = FLTShadeExport.val + #export Textures + if evt == 11: + options.copy_textures = FLTCopyTex.val + #export XRefs + if evt == 13: + options.doxrefs = FLTDoXRef.val + #export Transforms + if evt == 12: + options.export_transform = FLTGlobal.val + + if evt == 14: + options.xapp = FLTXAPP.val + if evt == 16: + Blender.Window.FileSelector(setXApath,"External Application",options.xappath) + if evt == 20: + options.write_attrib_files = FLTAttrib.val + + #Export DB + if evt == 1: + dbexport() + + #exit + if evt == 2: + Draw.Exit() + +from Blender.BGL import * +from Blender import Draw +def gui(): + + global options + + global FLTExport + global FLTClose + global FLTLabel + + global FLTBaseLabel + global FLTTextureLabel + global FLTXRefLabel + + global FLTBaseString + global FLTTextureString + global FLTXRefString + + global FLTBasePath + global FLTTexturePath + global FLTXRefPath + + global FLTShadeExport + global FLTShadeDefault + + global FLTCopyTex + global FLTDoXRef + global FLTGlobal + + global FLTScale + + global FLTXAPP + global FLTXAPPath + global FLTXAPPString + global FLTXAPPLabel + global FLTXAPPChooser + + global FLTAttrib + + glClearColor(0.880,0.890,0.730,1.0 ) + glClear(GL_COLOR_BUFFER_BIT) + + areas = Blender.Window.GetScreenInfo() + curarea = Blender.Window.GetAreaID() + curRect = None + + for area in areas: + if area['id'] == curarea: + curRect = area['vertices'] + break + + width = curRect[2] - curRect[0] + height = curRect[3] - curRect[1] + #draw from top to bottom.... + cx = 50 + #Draw Title Bar... + #glRasterPos2d(cx, curRect[3]-100) + #FLTLabel = Draw.Text("FLT Exporter V2.0",'large') + cy = height - 80 + + #base path + FLTBaseLabel = Draw.Label("Base Path:",cx,cy,100,20) + FLTBaseString = Draw.String("",3,cx+100,cy,300,20,options.basepath,255,"Folder to export to") + FLTBaseChooser = Draw.PushButton("...",4,cx+400,cy,20,20,"Choose Folder") + + cy = cy-40 + + #externals path + FLTXRefLabel = Draw.Label("XRefs:",cx,cy,100,20) + FLTXRefString = Draw.String("",5,cx+100,cy,300,20,options.externalspath,255,"Folder for external references") + FLTXRefChooser = Draw.PushButton("...",6,cx+400,cy,20,20,"Choose Folder") + cy = cy-40 + #Textures path + FLTTextureLabel = Draw.Label("Textures:",cx,cy,100,20) + FLTTextureString = Draw.String("",7,cx+100,cy,300,20,options.texturespath,255,"Folder for texture files") + FLTTextureChooser = Draw.PushButton("...",8,cx+400,cy,20,20,"Choose Folder") + cy=cy-40 + #External application path + FLTXAPPLabel = Draw.Label("XApp:",cx,cy,100,20) + FLTXAPPString = Draw.String("",15,cx+100,cy,300,20,options.xappath,255,"External application to launch when done") + FLTXAPPChooser = Draw.PushButton("...",16,cx+400, cy,20,20,"Choose Folder") + + cy = cy-60 + #Shading Options + FLTShadeExport = Draw.Toggle("Default Shading",9,cx,cy,100,20,options.export_shading,"Turn on export of custom shading") + FLTShadDefault = Draw.Number("",10,cx + 120,cy,100,20,options.shading_default,0.0,180.0,"Default shading angle for objects with no custom shading assigned",setshadingangle) + + cy = cy-40 + FLTScale = Draw.Number("Export Scale",14,cx,cy,220,20,options.scale,0.0,100.0,"Export scaling factor",setexportscale) + + cy = cy-40 + #misc Options + FLTCopyTex = Draw.Toggle("Copy Textures",11,cx,cy,220,20,options.copy_textures,"Copy textures to folder indicated above") + cy = cy-40 + FLTGlobal = Draw.Toggle("Export Transforms",12,cx,cy,220,20,options.export_transform,"If unchecked, Global coordinates are used (recommended)") + cy = cy-40 + FLTDoXRef = Draw.Toggle("Export XRefs", 13,cx,cy,220,20,options.doxrefs,"Export External references (only those below current scene!)") + cy = cy-40 + FLTXAPP = Draw.Toggle("Launch External App", 14, cx,cy,220,20,options.xapp,"Launch External Application on export") + cy = cy-40 + FLTAttrib = Draw.Toggle("Write Attribute Files", 20, cx, cy, 220,20,options.write_attrib_files, "Write Texture Attribute files") + #FLTXAPPATH = Draw.String("",15,cx,cy,300,20,options.xappath,255,"External application path") + + + #Draw export/close buttons + FLTExport = Draw.PushButton("Export",1,cx,20,100,20,"Export to FLT") + FLTClose = Draw.PushButton("Close", 2, cx+120,20,100,20,"Close window") + + +Draw.Register(gui,event,but_event) \ No newline at end of file diff --git a/release/scripts/flt_filewalker.py b/release/scripts/flt_filewalker.py index 442c9728e91..4a9b86c45d2 100644 --- a/release/scripts/flt_filewalker.py +++ b/release/scripts/flt_filewalker.py @@ -17,6 +17,11 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +__bpydoc__ ="""\ +File read/write module used by OpenFlight I/O and tool scripts. OpenFlight is a +registered trademark of MultiGen-Paradigm, Inc. +""" + import Blender from struct import * import re @@ -199,7 +204,9 @@ class FltOut: self.file.close() def __init__(self, filename): - self.file = open(filename, 'wb') + self.file = open(filename, 'wb') + self.filename = filename + class FileFinder: def add_file_to_search_path(self, filename): diff --git a/release/scripts/flt_import.py b/release/scripts/flt_import.py index ca0db650447..220fc9f355c 100644 --- a/release/scripts/flt_import.py +++ b/release/scripts/flt_import.py @@ -1,72 +1,26 @@ #!BPY """ Registration info for Blender menus: Name: 'OpenFlight (.flt)...' -Blender: 238 +Blender: 245 Group: 'Import' Tip: 'Import OpenFlight (.flt)' """ -__author__ = "Greg MacDonald, Campbell Barton" -__version__ = "1.2 10/20/05" +__author__ = "Greg MacDonald, Campbell Barton, Geoffrey Bantle" +__version__ = "2.0 11/21/07" __url__ = ("blender", "elysiun", "Author's homepage, http://sourceforge.net/projects/blight/") __bpydoc__ = """\ This script imports OpenFlight files into Blender. OpenFlight is a registered trademark of MultiGen-Paradigm, Inc. -Run from "File->Import" menu. +Feature overview and more availible at: +http://wiki.blender.org/index.php/Scripts/Manual/Import/openflight_flt -Options are available from Blender's "Scripts Config Editor," accessible through -the "Scripts->System" menu from the scripts window. - -All global_prefs are toggle switches that let the user choose what is imported. Most -are straight-forward, but one option could be a source of confusion. The -"Diffuse Color From Face" option when set pulls the diffuse color from the face -colors. Otherwise the diffuse color comes from the material. What may be -confusing is that this global_prefs only works if the "Diffuse Color" option is set. - -New Features:
-* Importer is 14 times faster.
-* External triangle module is no longer required, but make sure the importer -has a 3d View screen open while its running or triangulation won't work.
-* Should be able to import all versions of flight files. - -Features:
-* Heirarchy retained.
-* First texture imported.
-* Colors imported from face or material.
-* LOD seperated out into different layers.
-* Asks for location of unfound textures or external references.
-* Searches Blender's texture directory in the user preferences panel.
-* Triangles with more than 4 verts are triangulated if the Triangle python -module is installed.
-* Matrix transforms imported.
-* External references to whole files are imported. - -Things To Be Aware Of:
-* Each new color and face attribute creates a new material and there are only a maximum of 16 -materials per object.
-* For triangulated faces, normals must be recomputed outward manually by typing -CTRL+N in edit mode.
-* You can change global_prefs only after an initial import.
-* External references are imported as geometry and will be exported that way.
-* A work around for not using the Triangle python module is to simply to -triangulate in Creator before importing. This is only necessary if your -model contains 5 or more vertices.
-* You have to manually blend the material color with the texture color. - -What's Not Handled:
-* Special texture repeating modes.
-* Replications and instancing.
-* Comment and attribute fields.
-* Light points.
-* Animations.
-* External references to a node within a file.
-* Multitexturing.
-* Vetex colors.
+Note: This file is a grab-bag of old and new code. It needs some cleanup still. """ # flt_import.py is an OpenFlight importer for blender. -# Copyright (C) 2005 Greg MacDonald +# Copyright (C) 2005 Greg MacDonald, 2007 Blender Foundation # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -87,15 +41,33 @@ import os import BPyMesh import BPyImage import flt_filewalker +import flt_properties +reload(flt_properties) +from flt_properties import * + +#Globals. Should Clean these up and minimize their usage. + +typecodes = ['c','C','s','S','i','I','f','d','t'] +records = dict() + +FLTBaseLabel = None +FLTBaseString = None +FLTBaseChooser = None +FLTExport = None +FLTClose = None +FLTDoXRef = None +FLTScale = None +FLTShadeImport = None +FLTAttrib = None Vector= Blender.Mathutils.Vector +FLOAT_TOLERANCE = 0.01 -def col_to_gray(c): - return 0.3*c[0] + 0.59*c[1] + 0.11*c[2] - +FF = flt_filewalker.FileFinder() +current_layer = 0x01 global_prefs = dict() -global_prefs['verbose']= 1 +global_prefs['verbose']= 4 global_prefs['get_texture'] = True global_prefs['get_diffuse'] = True global_prefs['get_specular'] = False @@ -105,8 +77,41 @@ global_prefs['get_ambient'] = False global_prefs['get_shininess'] = True global_prefs['color_from_face'] = True global_prefs['fltfile']= '' +global_prefs['smoothshading'] = 1 +global_prefs['doxrefs'] = 1 +global_prefs['scale'] = 1.0 +global_prefs['attrib'] = 0 msg_once = False +throw_back_opcodes = [2, 73, 4, 11, 96, 14, 91, 98, 63,111] # Opcodes that indicate its time to return control to parent. +do_not_report_opcodes = [76, 78, 79, 80, 81, 82, 94, 83, 33, 112, 100, 101, 102, 97, 31, 103, 104, 117, 118, 120, 121, 124, 125] + +#Process FLT record definitions +for record in FLT_Records: + props = dict() + for prop in FLT_Records[record]: + position = '' + slice = 0 + (format,name) = prop.split('!') + for i in format: + if i not in typecodes: + position = position + i + slice = slice + 1 + else: + break + type = format[slice:] + length = type[1:] + if len(length) == 0: + length = 1 + else: + type = type[0] + length = int(length) + + props[int(position)] = (type,length,prop) + records[record] = props + +def col_to_gray(c): + return 0.3*c[0] + 0.59*c[1] + 0.11*c[2] class MaterialDesc: # Was going to use int(f*1000.0) instead of round(f,3), but for some reason # round produces better results, as in less dups. @@ -185,16 +190,14 @@ class VertexDesc: self.y = 0.0 self.z = 0.0 - ''' # IGNORE_NORMALS + self.nx = 0.0 - self.ny = 1.0 + self.ny = 0.0 self.nz = 0.0 - ''' + self.uv= Vector(0,0) - self.r = 1.0 - self.g = 1.0 - self.b = 1.0 - self.a = 1.0 + self.cindex = 127 #default/lowest + self.cnorm = False class LightPointAppDesc: def make_key(self): @@ -222,7 +225,7 @@ class LightPointAppDesc: self.props.update({'LOD scale': 0.0}) class GlobalResourceRepository: - def request_lightpoint_app(self, desc): + def request_lightpoint_app(self, desc, scene): match = self.light_point_app.get(desc.make_key()) if match: @@ -231,7 +234,7 @@ class GlobalResourceRepository: # Create empty and fill with properties. name = desc.props['type'] + ': ' + desc.props['id'] object = Blender.Object.New('Empty', name) - scene.link(object) + scene.objects.link(object) object.Layers= current_layer object.sel= 1 @@ -306,6 +309,9 @@ class GlobalResourceRepository: return tex def __init__(self): + + #list of scenes xrefs belong to. + self.xrefs = dict() # material self.mat_dict = dict() mat_lst = Blender.Material.Get() @@ -341,108 +347,6 @@ class GlobalResourceRepository: # light point self.light_point_app = dict() -# Globals -GRR = GlobalResourceRepository() -FF = flt_filewalker.FileFinder() -scene = Blender.Scene.GetCurrent() # just hope they dont chenge scenes once the file selector pops up. -current_layer = 0x01 - - -# Opcodes that indicate its time to return control to parent. -throw_back_opcodes = [2, 73, 4, 11, 96, 14, 91, 98, 63] -do_not_report_opcodes = [76, 78, 79, 80, 81, 82, 94, 83, 33, 112, 100, 101, 102, 97, 31, 103, 104, 117, 118, 120, 121, 124, 125] - -opcode_name = { 0: 'db', - 1: 'head', - 2: 'grp', - 4: 'obj', - 5: 'face', - 10: 'push', - 11: 'pop', - 14: 'dof', - 19: 'push sub', - 20: 'pop sub', - 21: 'push ext', - 22: 'pop ext', - 23: 'cont', - 31: 'comment', - 32: 'color pal', - 33: 'long id', - 49: 'matrix', - 50: 'vector', - 52: 'multi-tex', - 53: 'uv lst', - 55: 'bsp', - 60: 'rep', - 61: 'inst ref', - 62: 'inst def', - 63: 'ext ref', - 64: 'tex pal', - 67: 'vert pal', - 68: 'vert w col', - 69: 'vert w col & norm', - 70: 'vert w col, norm & uv', - 71: 'vert w col & uv', - 72: 'vert lst', - 73: 'lod', - 74: 'bndin box', - 76: 'rot edge', - 78: 'trans', - 79: 'scl', - 80: 'rot pnt', - 81: 'rot and/or scale pnt', - 82: 'put', - 83: 'eyepoint & trackplane pal', - 84: 'mesh', - 85: 'local vert pool', - 86: 'mesh prim', - 87: 'road seg', - 88: 'road zone', - 89: 'morph vert lst', - 90: 'link pal', - 91: 'snd', - 92: 'rd path', - 93: 'snd pal', - 94: 'gen matrix', - 95: 'txt', - 96: 'sw', - 97: 'line styl pal', - 98: 'clip reg', - 100: 'ext', - 101: 'light src', - 102: 'light src pal', - 103: 'reserved', - 104: 'reserved', - 105: 'bndin sph', - 106: 'bndin cyl', - 107: 'bndin hull', - 108: 'bndin vol cntr', - 109: 'bndin vol orient', - 110: 'rsrvd', - 111: 'light pnt', - 112: 'tex map pal', - 113: 'mat pal', - 114: 'name tab', - 115: 'cat', - 116: 'cat dat', - 117: 'rsrvd', - 118: 'rsrvd', - 119: 'bounding hist', - 120: 'rsrvd', - 121: 'rsrvd', - 122: 'push attrib', - 123: 'pop attrib', - 124: 'rsrvd', - 125: 'rsrvd', - 126: 'curv', - 127: 'road const', - 128: 'light pnt appear pal', - 129: 'light pnt anim pal', - 130: 'indexed lp', - 131: 'lp sys', - 132: 'indx str', - 133: 'shdr pal'} - class Handler: def in_throw_back_lst(self, opcode): return opcode in self.throw_back_lst @@ -487,11 +391,11 @@ class Node: print '-', self.props['comment'], print - + for child in self.children: child.blender_import() - - # Import comment. + +# Import comment. # if self.props['comment'] != '': # name = 'COMMENT: ' + self.props['id'] # t = Blender.Text.New(name) @@ -568,8 +472,8 @@ class Node: else: if global_prefs['verbose'] >= 3: print p + ' ignored' - elif global_prefs['verbose'] >= 1 and not opcode in do_not_report_opcodes and opcode in opcode_name: - print opcode_name[opcode], 'not handled' + elif global_prefs['verbose'] >= 1 and not opcode in do_not_report_opcodes and opcode in opcode_name: + print 'not handled' def get_level(self): return self.level @@ -581,7 +485,19 @@ class Node: def parse_comment(self): self.props['comment'] = self.header.fw.read_string(self.header.fw.get_length()-4) return True - + + def parse_record(self): + self.props['type'] = self.opcode + props = records[self.opcode] + propkeys = props.keys() + propkeys.sort() + for position in propkeys: + (type,length,name) = props[position] + self.props[name] = read_prop(self.header.fw,type,length) + try: #remove me! + self.props['id'] = self.props['3t8!id'] + except: + pass def __init__(self, parent, header): self.root_handler = Handler() self.child_handler = Handler() @@ -647,20 +563,16 @@ class VertexPalette(Node): return v def parse_vertex_post_common(self, v): - if not v.flags & 0x2000: # 0x2000 = no color - if v.flags & 0x1000: # 0x1000 = packed color - v.a = self.header.fw.read_uchar() - v.b = self.header.fw.read_uchar() - v.g = self.header.fw.read_uchar() - v.r = self.header.fw.read_uchar() - else: - self.header.fw.read_ahead(4) - - color_index = self.header.fw.read_uint() - v.r, v.g, v.b, v.a= self.header.get_color(color_index) - + #if not v.flags & 0x2000: # 0x2000 = no color + #if v.flags & 0x1000: # 0x1000 = packed color + # v.a = self.header.fw.read_uchar() + # v.b = self.header.fw.read_uchar() + # v.g = self.header.fw.read_uchar() + # v.r = self.header.fw.read_uchar() + #else: + self.header.fw.read_ahead(4) #skip packed color + v.cindex = self.header.fw.read_uint() self.vert_desc_lst.append(v) - return True def parse_vertex_c(self): @@ -672,16 +584,10 @@ class VertexPalette(Node): def parse_vertex_cn(self): v = self.parse_vertex_common() - - ''' + v.cnorm = True v.nx = self.header.fw.read_float() v.ny = self.header.fw.read_float() v.nz = self.header.fw.read_float() - ''' - # Just to advance - self.header.fw.read_float() - self.header.fw.read_float() - self.header.fw.read_float() self.parse_vertex_post_common(v) @@ -698,15 +604,10 @@ class VertexPalette(Node): def parse_vertex_cnuv(self): v = self.parse_vertex_common() - ''' + v.cnorm = True v.nx = self.header.fw.read_float() v.ny = self.header.fw.read_float() v.nz = self.header.fw.read_float() - ''' - # Just to advance - self.header.fw.read_float() - self.header.fw.read_float() - self.header.fw.read_float() v.uv[:] = self.header.fw.read_float(), self.header.fw.read_float() @@ -721,89 +622,370 @@ class InterNode(Node): def __init__(self): self.object = None self.mesh = None - self.isMesh = False + self.hasMesh = False self.faceLs= [] self.matrix = None - - def blender_import_my_faces(self): + self.vis = True + self.hasmtex = False + self.uvlayers = dict() + self.blayernames = dict() + self.subfacelevel = 0 + mask = 2147483648 + for i in xrange(7): + self.uvlayers[mask] = False + mask = mask / 2 + + + def blender_import_my_faces(self): + # Add the verts onto the mesh - mesh = self.mesh blender_verts= self.header.vert_pal.blender_verts vert_desc_lst= self.header.vert_pal.vert_desc_lst - vert_list= [ i for flt_face in self.faceLs for i in flt_face.indices] - - mesh.verts.extend([blender_verts[i] for i in vert_list]) - + vert_list= [ i for flt_face in self.faceLs for i in flt_face.indices] #splitting faces apart. Is this a good thing? + face_edges= [] + face_verts= [] + self.mesh.verts.extend([blender_verts[i] for i in vert_list]) new_faces= [] new_faces_props= [] ngon= BPyMesh.ngon vert_index= 1 + + #add vertex color layer for baked face colors. + self.mesh.addColorLayer("FLT_Fcol") + self.mesh.activeColorLayer = "FLT_Fcol" + + FLT_OrigIndex = 0 for flt_face in self.faceLs: - material_index= flt_face.blen_mat_idx - image= flt_face.blen_image - + if flt_face.tex_index != -1: + try: + image= self.header.tex_pal[flt_face.tex_index][1] + except KeyError: + image= None + else: + image= None face_len= len(flt_face.indices) + #create dummy uvert dicts + if len(flt_face.uverts) == 0: + for i in xrange(face_len): + flt_face.uverts.append(dict()) + #May need to patch up MTex info + if self.hasmtex: + #For every layer in mesh, there should be corresponding layer in the face + for mask in self.uvlayers.keys(): + if self.uvlayers[mask]: + if not flt_face.uvlayers.has_key(mask): #Does the face have this layer? + #Create Layer info for this face + flt_face.uvlayers[mask] = dict() + flt_face.uvlayers[mask]['texture index'] = -1 + flt_face.uvlayers[mask]['texture enviorment'] = 3 + flt_face.uvlayers[mask]['texture mapping'] = 0 + flt_face.uvlayers[mask]['texture data'] = 0 + + #now go through and create dummy uvs for this layer + for uvert in flt_face.uverts: + uv = Vector(0.0,0.0) + uvert[mask] = uv + # Get the indicies in reference to the mesh. - uvs= [vert_desc_lst[j].uv for j in flt_face.indices] - if face_len <=4: # tri or quad + if face_len == 1: + pass + elif face_len == 2: + face_edges.append((vert_index, vert_index+1)) + elif flt_face.props['draw type'] == 2 or flt_face.props['draw type'] == 3: + i = 0 + while i < (face_len-1): + face_edges.append((vert_index + i, vert_index + i + 1)) + i = i + 1 + if flt_face.props['draw type'] == 2: + face_edges.append((vert_index + i,vert_index)) + elif face_len == 3 or face_len == 4: # tri or quad + #if face_len == 1: + # pass + #if face_len == 2: + # face_edges.append((vert_index, vert_index+1)) new_faces.append( [i+vert_index for i in xrange(face_len)] ) - new_faces_props.append((material_index, image, uvs)) + new_faces_props.append((None, image, uvs, flt_face.uverts, flt_face.uvlayers, flt_face.color_index, flt_face.props,FLT_OrigIndex,0, flt_face.subfacelevel)) else: # fgon mesh_face_indicies = [i+vert_index for i in xrange(face_len)] - tri_ngons= ngon(mesh, mesh_face_indicies) + tri_ngons= ngon(self.mesh, mesh_face_indicies) new_faces.extend([ [mesh_face_indicies[t] for t in tri] for tri in tri_ngons]) - new_faces_props.extend( [ (material_index, image, (uvs[tri[0]], uvs[tri[1]], uvs[tri[2]]) ) for tri in tri_ngons ] ) + new_faces_props.extend( [ (None, image, (uvs[tri[0]], uvs[tri[1]], uvs[tri[2]]), [flt_face.uverts[tri[0]], flt_face.uverts[tri[1]], flt_face.uverts[tri[2]]], flt_face.uvlayers, flt_face.color_index, flt_face.props,FLT_OrigIndex,1, flt_face.subfacelevel) for tri in tri_ngons ]) vert_index+= face_len + FLT_OrigIndex+=1 - mesh.faces.extend(new_faces) + self.mesh.faces.extend(new_faces) + self.mesh.edges.extend(face_edges) - try: mesh.faceUV= True - except: pass + #add in the FLT_ORIGINDEX layer + if len(self.mesh.faces): + try: self.mesh.faceUV= True + except: pass - for i, f in enumerate(mesh.faces): - f.mat, f.image, f.uv= new_faces_props[i] - + if self.mesh.faceUV == True: + self.mesh.renameUVLayer(self.mesh.activeUVLayer, 'Layer0') + + #create name layer for faces + self.mesh.faces.addPropertyLayer("FLT_ID",Blender.Mesh.PropertyTypes["STRING"]) + #create layer for face color indices + self.mesh.faces.addPropertyLayer("FLT_COL",Blender.Mesh.PropertyTypes["INT"]) + #create index layer for faces. This is needed by both FGONs and subfaces + self.mesh.faces.addPropertyLayer("FLT_ORIGINDEX",Blender.Mesh.PropertyTypes["INT"]) + #create temporary FGON flag layer. Delete after remove doubles + self.mesh.faces.addPropertyLayer("FLT_FGON",Blender.Mesh.PropertyTypes["INT"]) + self.mesh.faces.addPropertyLayer("FLT_SFLEVEL", Blender.Mesh.PropertyTypes["INT"]) + + for i, f in enumerate(self.mesh.faces): + f.transp |= Blender.Mesh.FaceTranspModes["ALPHA"] #fix this! + f.mode |= Blender.Mesh.FaceModes["LIGHT"] + props = new_faces_props[i] + #f.mat = props[0] + f.image = props[1] + f.uv = props[2] + #set vertex colors + color = self.header.get_color(props[5]) + if not color: + color = [255,255,255,255] + for mcol in f.col: + mcol.a = color[3] + mcol.r = color[0] + mcol.g = color[1] + mcol.b = color[2] + + f.setProperty("FLT_SFLEVEL", props[9]) + f.setProperty("FLT_ORIGINDEX",i) + f.setProperty("FLT_ID",props[6]['id']) + #if props[5] > 13199: + # print "Warning, invalid color index read in! Using default!" + # f.setProperty("FLT_COL",127) + #else: + if(1): #uh oh.... + value = struct.unpack('>i',struct.pack('>I',props[5]))[0] + f.setProperty("FLT_COL",value) + + #if props[8]: + # f.setProperty("FLT_FGON",1) + #else: + # f.setProperty("FLT_FGON",0) + + + #Create multitex layers, if present. + actuvlayer = self.mesh.activeUVLayer + if(self.hasmtex): + #For every multi-tex layer, we have to add a new UV layer to the mesh + for i,mask in enumerate(reversed(sorted(self.uvlayers))): + if self.uvlayers[mask]: + self.blayernames[mask] = "Layer" + str(i+1) + self.mesh.addUVLayer(self.blayernames[mask]) + + #Cycle through availible multi-tex layers and add face UVS + for mask in self.uvlayers: + if self.uvlayers[mask]: + self.mesh.activeUVLayer = self.blayernames[mask] + for j, f in enumerate(self.mesh.faces): + f.transp |= Blender.Mesh.FaceTranspModes["ALPHA"] + f.mode |= Blender.Mesh.FaceModes["LIGHT"] + props = new_faces_props[j] + uvlayers = props[4] + if uvlayers.has_key(mask): #redundant + uverts = props[3] + for k, uv in enumerate(f.uv): + uv[0] = uverts[k][mask][0] + uv[1] = uverts[k][mask][1] + + uvlayer = uvlayers[mask] + tex_index = uvlayer['texture index'] + if tex_index != -1: + try: + f.image = self.header.tex_pal[tex_index][1] + except KeyError: + f.image = None + + if global_prefs['smoothshading'] == True and len(self.mesh.faces): + #We need to store per-face vertex normals in the faces as UV layers and delete them later. + self.mesh.addUVLayer("FLTNorm1") + self.mesh.addUVLayer("FLTNorm2") + self.mesh.activeUVLayer = "FLTNorm1" + for f in self.mesh.faces: + f.smooth = 1 + #grab the X and Y components of normal and store them in UV + for i, uv in enumerate(f.uv): + vert = f.v[i].index + vert_desc = vert_desc_lst[vert_list[vert-1]] + if vert_desc.cnorm: + uv[0] = vert_desc.nx + uv[1] = vert_desc.ny + else: + uv[0] = 0.0 + uv[1] = 0.0 + + #Now go through and populate the second UV Layer with the z component + self.mesh.activeUVLayer = "FLTNorm2" + for f in self.mesh.faces: + for i, uv in enumerate(f.uv): + vert = f.v[i].index + vert_desc = vert_desc_lst[vert_list[vert-1]] + if vert_desc.cnorm: + uv[0] = vert_desc.nz + uv[1] = 0.0 + else: + uv[0] = 0.0 + uv[1] = 0.0 + + + + #Finally, go through, remove dummy vertex, remove doubles and add edgesplit modifier. + Blender.Mesh.Mode(Blender.Mesh.SelectModes['VERTEX']) + self.mesh.verts.delete(0) # remove the dummy vert + self.mesh.sel= 1 + self.header.scene.update(1) #slow! + self.mesh.remDoubles(0.0001) + + edgeHash = dict() + + for edge in self.mesh.edges: + edgeHash[edge.key] = edge.index + + + if global_prefs['smoothshading'] == True and len(self.mesh.faces): + + #rip out the custom vertex normals from the mesh and place them in a face aligned list. Easier to compare this way. + facenorms = [] + self.mesh.activeUVLayer = "FLTNorm1" + for face in self.mesh.faces: + facenorm = [] + for uv in face.uv: + facenorm.append(Vector(uv[0],uv[1],0.0)) + facenorms.append(facenorm) + self.mesh.activeUVLayer = "FLTNorm2" + for i, face in enumerate(self.mesh.faces): + facenorm = facenorms[i] + for j, uv in enumerate(face.uv): + facenorm[j][2] = uv[0] + self.mesh.removeUVLayer("FLTNorm1") + self.mesh.removeUVLayer("FLTNorm2") + + #find hard edges + #store edge data for lookup by faces + #edgeHash = dict() + #for edge in self.mesh.edges: + # edgeHash[edge.key] = edge.index + + edgeNormHash = dict() + #make sure to align the edgenormals to key value! + for i, face in enumerate(self.mesh.faces): + + facenorm = facenorms[i] + faceEdges = [] + faceEdges.append((face.v[0].index,face.v[1].index,facenorm[0],facenorm[1],face.edge_keys[0])) + faceEdges.append((face.v[1].index,face.v[2].index,facenorm[1],facenorm[2],face.edge_keys[1])) + if len(face.v) == 3: + faceEdges.append((face.v[2].index,face.v[0].index,facenorm[2],facenorm[0],face.edge_keys[2])) + elif len(face.v) == 4: + faceEdges.append((face.v[2].index,face.v[3].index,facenorm[2],facenorm[3],face.edge_keys[2])) + faceEdges.append((face.v[3].index,face.v[0].index,facenorm[3],facenorm[0],face.edge_keys[3])) + + #check to see if edgeNormal has been placed in the edgeNormHash yet + #this is a redundant test, and should be optimized to not be called as often as it is. + for j, faceEdge in enumerate(faceEdges): + #the value we are looking for is (faceEdge[2],faceEdge[3]) + hashvalue = (faceEdge[2],faceEdge[3]) + if (faceEdge[0],faceEdge[1]) != faceEdge[4]: + hashvalue = (hashvalue[1],hashvalue[0]) + assert (faceEdge[1],faceEdge[0]) == faceEdge[4] + if edgeNormHash.has_key(faceEdge[4]): + #compare value in the hash, if different, mark as sharp + edgeNorm = edgeNormHash[faceEdge[4]] + if\ + abs(hashvalue[0][0] - edgeNorm[0][0]) > FLOAT_TOLERANCE or\ + abs(hashvalue[0][1] - edgeNorm[0][1]) > FLOAT_TOLERANCE or\ + abs(hashvalue[0][2] - edgeNorm[0][2]) > FLOAT_TOLERANCE or\ + abs(hashvalue[1][0] - edgeNorm[1][0]) > FLOAT_TOLERANCE or\ + abs(hashvalue[1][1] - edgeNorm[1][1]) > FLOAT_TOLERANCE or\ + abs(hashvalue[1][2] - edgeNorm[1][2]) > FLOAT_TOLERANCE: + edge = self.mesh.edges[edgeHash[faceEdge[4]]] + edge.flag |= Blender.Mesh.EdgeFlags.SHARP + + else: + edgeNormHash[faceEdge[4]] = hashvalue + + #add in edgesplit modifier + mod = self.object.modifiers.append(Blender.Modifier.Types.EDGESPLIT) + mod[Blender.Modifier.Settings.EDGESPLIT_FROM_SHARP] = True + mod[Blender.Modifier.Settings.EDGESPLIT_FROM_ANGLE] = False + + if(actuvlayer): + self.mesh.activeUVLayer = actuvlayer + def blender_import(self): -# name = self.props['type'] + ': ' + self.props['id'] + if self.vis and self.parent: + self.vis = self.parent.vis name = self.props['id'] - if self.isMesh: - self.object = Blender.Object.New('Mesh', name) - #self.mesh = self.object.getData() + + if self.hasMesh: self.mesh = Blender.Mesh.New() - self.mesh.verts.extend( Vector() ) # DUMMYVERT - self.object.link(self.mesh) + self.mesh.name = 'FLT_FaceList' + self.mesh.fakeUser = True + self.mesh.verts.extend( Vector()) #DUMMYVERT + self.object = self.header.scene.objects.new(self.mesh) else: - self.object = Blender.Object.New('Empty', name) + self.object = self.header.scene.objects.new('Empty') - if self.parent: - self.parent.object.makeParent([self.object]) + self.object.name = name + self.header.group.objects.link(self.object) - scene.link(self.object) - self.object.Layer = current_layer - self.object.sel = 1 + #id props import + self.object.properties['FLT'] = dict() + for key in self.props: + try: + self.object.properties['FLT'][key] = self.props[key] + except: #horrible... + pass - Node.blender_import(self) # Attach faces to self.faceLs + if self.parent and self.parent.object and (self.header.scene == self.parent.header.scene): + self.parent.object.makeParent([self.object]) + + if self.vis == False: + self.object.restrictDisplay = True + self.object.restrictRender = True - if self.isMesh: - # Add all my faces into the mesh at once - self.blender_import_my_faces() + else: #check for LOD children and set the proper flags + lodlist = list() + for child in self.children: + if child.props.has_key('type') and child.props['type'] == 73: + lodlist.append(child) + def LODmin(a,b): + if a.props['5d!switch in'] < b.props['5d!switch in']: + return a + return b + + min= None + if len(lodlist) > 1: + for lod in lodlist: + lod.vis = False + min = lodlist[0] + for i in xrange(len(lodlist)): + min= LODmin(min,lodlist[i]) + min.vis = True + if self.matrix: self.object.setMatrix(self.matrix) + + Node.blender_import(self) # Attach faces to self.faceLs - # Attach properties - #for name, value in self.props.items(): - # self.object.addProperty(name, value) - + if self.hasMesh: + # Add all my faces into the mesh at once + self.blender_import_my_faces() + def parse_face(self): - child = Face(self) + child = Face(self, self.subfacelevel) child.parse() return True @@ -838,6 +1020,11 @@ class InterNode(Node): child.parse() return True + def parse_dof(self): + child = DOF(self) + child.parse() + return True + def parse_indexed_light_point(self): child = IndexedLightPoint(self) child.parse() @@ -857,32 +1044,42 @@ class InterNode(Node): m[i].append(f) self.matrix = Blender.Mathutils.Matrix(m[0], m[1], m[2], m[3]) -EDGE_FGON= Blender.Mesh.EdgeFlags['FGON'] -FACE_TEX= Blender.Mesh.FaceModes['TEX'] + def parse_subpush(self): + self.parse_push() + self.subfacelevel+= 1 + return True + def parse_subpop(self): + self.parse_pop() + self.subfacelevel -= 1 + return True + + class Face(Node): - def __init__(self, parent): + def __init__(self, parent,subfacelevel): Node.__init__(self, parent, parent.header) self.root_handler.set_handler({31: self.parse_comment, - 10: self.parse_push}) + 10: self.parse_push, + 52: self.parse_multitex}) self.root_handler.set_throw_back_lst(throw_back_opcodes) self.child_handler.set_handler({72: self.parse_vertex_list, 10: self.parse_push, - 11: self.parse_pop}) + 11: self.parse_pop, + 53: self.parse_uvlist}) if parent: - parent.isMesh = True + parent.hasMesh = True - self.indices = list() # face verts here + self.subfacelevel = subfacelevel + self.indices = list() # face verts here + self.uvlayers = dict() # MultiTexture layers keyed to layer bitmask. + self.uverts = list() # Vertex aligned list of dictionaries keyed to layer bitmask. + self.uvmask = 0 # Bitfield read from MTex record self.comment = '' - self.props = dict.fromkeys(['ir color', 'priority', - 'draw type', 'texture white', 'template billboard', - 'smc', 'fid', 'ir material', 'lod generation control', - 'flags', 'light mode']) - - self.header.fw.read_ahead(8) # face id + self.props = dict() + self.props['id'] = self.header.fw.read_string(8) # Load face. self.props['ir color'] = self.header.fw.read_int() self.props['priority'] = self.header.fw.read_short() @@ -919,186 +1116,14 @@ class Face(Node): self.alt_color_index = self.header.fw.read_uint() #self.header.fw.read_ahead(2) #self.shader_index = self.header.fw.read_short() - - - """ - def blender_import_face(self, material_index, image): - - - mesh = self.parent.mesh - face_len= len(self.indices) - - mesh_vert_len_orig= len(mesh.verts) - mesh.verts.extend([ self.header.vert_pal.blender_verts[i] for i in self.indices]) - - # Exception for an edge - if face_len==2: - mesh.edges.extend((mesh.verts[-1], mesh.verts[-2])) - return - - - mesh_face_indicies = range(mesh_vert_len_orig, mesh_vert_len_orig+face_len) - - #print mesh_face_indicies , 'mesh_face_indicies ' - - # First we need to triangulate NGONS - if face_len>4: - tri_indicies = [[i+mesh_vert_len_orig for i in t] for t in BPyMesh.ngon(mesh, mesh_face_indicies) ] # use range because the verts are in order. - else: - tri_indicies= [mesh_face_indicies] # can be a quad but thats ok - - # Extend face or ngon - - mesh.faces.extend(tri_indicies) - #print mesh.faces, 'mesh.faces' - mesh.faceUV= True - - # Now set UVs - for i in xrange(len(mesh.faces)-len(tri_indicies), len(mesh.faces)): - f= mesh.faces[i] - f_v= f.v - for j, uv in enumerate(f.uv): - vertex_index_flt= self.indices[f_v[j].index - mesh_vert_len_orig] - - vert_desc = self.header.vert_pal.vert_desc_lst[vertex_index_flt] - uv.x, uv.y= vert_desc.u, vert_desc.v - - # Only a bug in 2.42, fixed in cvs - for c in f.col: - c.r=c.g=c.b= 255 - - f.mat = material_index - if image: - f.image = image - else: - f.mode &= ~FACE_TEX - - # FGon - - if face_len>4: - # Add edges we know are not fgon - end_index= len(mesh.verts) - start_index= end_index - len(self.indices) - edge_dict= dict([ ((i, i+1), None) for i in xrange(start_index, end_index-1)]) - edge_dict[(start_index, end_index)]= None # wish this was a set - - fgon_edges= {} - for tri in tri_indicies: - for i in (0,1,2): - i1= tri[i] - i2= tri[i-1] - - # Sort - if i1>i2: - i1,i2= i2,i1 - - if not edge_dict.has_key( (i1,i2) ): # if this works its an edge vert - fgon_edges[i1,i2]= None - - - # Now set fgon flags - for ed in mesh.edges: - i1= ed.v1.index - i2= ed.v2.index - if i1>i2: - i1,i2= i2,i1 - - if fgon_edges.has_key( (i1,i2) ): - # This is an edge tagged for fgonning? - fgon_edges[i1, i2] - ed.flag |= EDGE_FGON - del fgon_edges[i1, i2] # make later searches faster? - - if not fgon_edges: - break - """ - + def parse_comment(self): self.comment = self.header.fw.read_string(self.header.fw.get_length()-4) return True - # returns a tuple (material, image) where material is the blender material and - # image is the blender image or None. - def create_blender_material(self): - # Create face material. - mat_desc = MaterialDesc() - - if self.mat_index != -1: - if not self.mat_index in self.header.mat_desc_pal: - if global_prefs['verbose'] >= 1: - #print 'Warning: Material index', self.mat_index, 'not in material palette.' - pass - else: - mat_pal_desc = self.header.mat_desc_pal[self.mat_index] - mat_desc.alpha = mat_pal_desc.alpha * self.alpha # combine face and mat alphas - mat_desc.ambient = mat_pal_desc.ambient - mat_desc.diffuse = mat_pal_desc.diffuse - mat_desc.specular = mat_pal_desc.specular - mat_desc.emissive = mat_pal_desc.emissive - mat_desc.shininess = mat_pal_desc.shininess - else: - # if no material get alpha from just face. - mat_desc.alpha = self.alpha - - # Color. - if global_prefs['color_from_face']: - color = None - if not self.props['flags'] & 0x40000000: - if self.props['flags'] & 0x10000000: # packed color - color = self.packed_color - else: - color = self.header.get_color(self.color_index) - - if color: - r = float(color[0])/255.0 - g = float(color[1])/255.0 - b = float(color[2])/255.0 - mat_desc.diffuse = [r, g, b] - - # Texture - image = None - if self.tex_index != -1 and self.tex_index in self.header.bl_tex_pal: - mat_desc.tex0 = self.header.bl_tex_pal[self.tex_index] - if mat_desc.tex0: - mat_desc.name = FF.strip_path(self.header.tex_pal[self.tex_index]) - image = mat_desc.tex0.image - - # OpenFlight Face Attributes - mat_desc.face_props = self.props - - # Get material. - mat = GRR.request_mat(mat_desc) - - # Add material to mesh. - mesh = self.parent.mesh - - # Return where it is in the mesh for faces. - mesh_materials= mesh.materials - - material_index= -1 - for i,m in enumerate(mesh_materials): - if m.name==mat.name: - material_index= i - break - - if material_index==-1: - material_index= len(mesh_materials) - if material_index==16: - material_index= 15 - if global_prefs['verbose'] >= 1: - print 'Warning: Too many materials per mesh object. Only a maximum of 16 ' + \ - 'allowed. Using 16th material instead.' - - else: - mesh_materials.append(mat) - mesh.materials= mesh_materials - - return (material_index, image) - - def blender_import(self): vert_count = len(self.indices) - if vert_count < 3: + if vert_count < 1: if global_prefs['verbose'] >= 2: print 'Warning: Ignoring face with no vertices.' return @@ -1106,18 +1131,21 @@ class Face(Node): # Assign material and image self.parent.faceLs.append(self) - self.blen_mat_idx, self.blen_image= self.create_blender_material() - - - + #need to store comment in mesh prop layer! # Store comment info in parent. - if self.comment != '': - if self.parent.props['comment'] != '': - self.parent.props['comment'] += '\n\nFrom Face:\n' + self.comment - else: - self.parent.props['comment'] = self.comment + #if self.comment != '': + # if self.parent.props['comment'] != '': + # self.parent.props['comment'] += '\n\nFrom Face:\n' + self.comment + # else: + # self.parent.props['comment'] = self.comment + if self.uvlayers: + #Make sure that the mesh knows about the layers that this face uses + self.parent.hasmtex = True + for mask in self.uvlayers.keys(): + self.parent.uvlayers[mask] = True + def parse_vertex_list(self): length = self.header.fw.get_length() fw = self.header.fw @@ -1138,8 +1166,49 @@ class Face(Node): ' to vertex index.' % byte_offset ''' return True - - + + def parse_multitex(self): + #Parse MultiTex Record. + length = self.header.fw.get_length() + fw = self.header.fw + #num layers == (length - 8) / 4 + uvmask = fw.read_uint() + mask = 2147483648 + for i in xrange(7): + if mask & uvmask: + uvlayer = dict() + self.uvlayers[mask] = uvlayer + mask = mask / 2 + + #read in record for each individual layer. + for key in reversed(sorted(self.uvlayers)): + uvlayer = self.uvlayers[key] + uvlayer['texture index'] = fw.read_ushort() + uvlayer['texture enviorment'] = fw.read_ushort() + uvlayer['texture mapping'] = fw.read_ushort() + uvlayer['texture data'] = fw.read_ushort() + + self.uvmask = uvmask + + def parse_uvlist(self): + #for each uvlayer, add uv vertices + length = self.header.fw.get_length() + fw = self.header.fw + uvmask = fw.read_uint() + if uvmask != self.uvmask: #This should never happen! + fw.read_ahead(self.length - 4) #potentially unnessecary? + else: + #need to store in uvverts dictionary for each vertex. + totverts = len(self.indices) + for i in xrange(totverts): + uvert = dict() + for key in reversed(sorted(self.uvlayers)): + uv = Vector(0.0,0.0) + uv[0] = fw.read_float() + uv[1] = fw.read_float() + uvert[key] = uv + self.uverts.append(uvert) + class Object(InterNode): def __init__(self, parent): Node.__init__(self, parent, parent.header) @@ -1152,15 +1221,15 @@ class Object(InterNode): self.root_handler.set_throw_back_lst(throw_back_opcodes) self.child_handler.set_handler({5: self.parse_face, - #130: self.parse_indexed_light_point, - #111: self.parse_inline_light_point, + 19: self.parse_subpush, + 20: self.parse_subpop, + 111: self.parse_inline_light_point, 10: self.parse_push, 11: self.parse_pop}) - self.props['type'] = 'Object' - self.props['id'] = self.header.fw.read_string(8) - - + self.props = dict() + self.props['comment'] = '' + self.parse_record() class Group(InterNode): def __init__(self, parent): @@ -1174,15 +1243,16 @@ class Group(InterNode): self.root_handler.set_throw_back_lst(throw_back_opcodes) self.child_handler.set_handler({5: self.parse_face, - #130: self.parse_indexed_light_point, - #111: self.parse_inline_light_point, + 19: self.parse_subpush, + 20: self.parse_subpop, + 111: self.parse_inline_light_point, 2: self.parse_group, 73: self.parse_lod, 4: self.parse_object, 10: self.parse_push, 11: self.parse_pop, 96: self.parse_unhandled, - 14: self.parse_unhandled, + 14: self.parse_dof, 91: self.parse_unhandled, 98: self.parse_unhandled, 63: self.parse_xref}) @@ -1190,49 +1260,20 @@ class Group(InterNode): 'special2', 'significance', 'layer code', 'loop count', 'loop duration', 'last frame duration']) - self.props['type'] = 'Group' self.props['comment'] = '' - self.props['id'] = self.header.fw.read_string(8) - self.props['priority'] = self.header.fw.read_short() - self.header.fw.read_ahead(2) - self.props['flags'] = self.header.fw.read_int() - self.props['special1'] = self.header.fw.read_short() - self.props['special2'] = self.header.fw.read_short() - self.props['significance'] = self.header.fw.read_short() - self.props['layer code'] = self.header.fw.read_char() - self.header.fw.read_ahead(5) - self.props['loop count'] = self.header.fw.read_int() - self.props['loop duration'] = self.header.fw.read_float() - self.props['last frame duration'] = self.header.fw.read_float() - -class XRef(InterNode): - def parse(self): - if self.xref: - self.xref.parse() - Node.parse(self) - - def __init__(self, parent): - Node.__init__(self, parent, parent.header) - InterNode.__init__(self) - - self.root_handler.set_handler({49: self.parse_matrix}) - self.root_handler.set_throw_back_lst(throw_back_opcodes) + self.parse_record() - xref_filename = self.header.fw.read_string(200) - filename = FF.find(xref_filename) + #self.props['type'] = str(self.opcode) + ':' + opcode_name[self.opcode] + #props = records[self.opcode] + #propkeys = props.keys() + #propkeys.sort() + #for position in propkeys: + # (type,length,name) = props[position] + # self.props[name] = read_prop(self.header.fw,type,length) + #self.props['id'] = self.props['3t8!id'] - self.props['type'] = 'XRef' - - if filename != None: - self.xref = Database(filename, self) - self.props['id'] = 'X: ' + Blender.sys.splitext(Blender.sys.basename(filename))[0] - else: - self.xref = None - self.props['id'] = 'X: broken' - -class LOD(InterNode): +class DOF(InterNode): def blender_import(self): - self.move_to_next_layer() InterNode.blender_import(self) def __init__(self, parent): @@ -1245,19 +1286,113 @@ class LOD(InterNode): 49: self.parse_matrix}) self.root_handler.set_throw_back_lst(throw_back_opcodes) + self.child_handler.set_handler({#130: self.parse_indexed_light_point, + 111: self.parse_inline_light_point, + 2: self.parse_group, + 73: self.parse_lod, + 4: self.parse_object, + 10: self.parse_push, + 11: self.parse_pop, + 96: self.parse_unhandled, + 14: self.parse_dof, + 91: self.parse_unhandled, + 98: self.parse_unhandled, + 63: self.parse_xref}) + self.props = dict() + self.props['comment'] = '' + self.parse_record() + + +class XRef(InterNode): + def parse(self): + if self.xref: + self.xref.parse() + Node.parse(self) + + def __init__(self, parent): + Node.__init__(self, parent, parent.header) + InterNode.__init__(self) + + self.root_handler.set_handler({49: self.parse_matrix}) + self.root_handler.set_throw_back_lst(throw_back_opcodes) + + self.props = dict() + self.props['comment'] = '' + self.parse_record() + + xref_filename = self.props['3t200!filename'] + self.props['id'] = 'X: ' + Blender.sys.splitext(Blender.sys.basename(xref_filename))[0] #this is really wrong as well.... + + if global_prefs['doxrefs'] and os.path.exists(xref_filename) and not self.header.grr.xrefs.has_key(xref_filename): + self.xref = Database(xref_filename, self.header.grr, self) + self.header.grr.xrefs[xref_filename] = self.xref + else: + self.xref = None + + + def blender_import(self): + #name = self.props['type'] + ': ' + self.props['id'] + name = self.props['id'] + self.object = self.header.scene.objects.new('Empty') + self.object.name = name + self.object.enableDupGroup = True + self.header.group.objects.link(self.object) + + #for broken links its ok to leave this empty! they purely for visual purposes anyway..... + try: + self.object.DupGroup = self.header.grr.xrefs[self.props['3t200!filename']].group + except: + pass + + if self.parent and self.parent.object: + self.parent.object.makeParent([self.object]) + + #id props import + self.object.properties['FLT'] = dict() + for key in self.props: + try: + self.object.properties['FLT'][key] = self.props[key] + except: #horrible... + pass + + self.object.Layer = current_layer + self.object.sel = 1 + if self.matrix: + self.object.setMatrix(self.matrix) + Node.blender_import(self) + + +class LOD(InterNode): + def blender_import(self): + #self.move_to_next_layer() + InterNode.blender_import(self) + #self.object.properties['FLT'] = self.props.copy() + + def __init__(self, parent): + Node.__init__(self, parent, parent.header) + InterNode.__init__(self) + + self.root_handler.set_handler({33: self.parse_long_id, + 31: self.parse_comment, + 10: self.parse_push, + 49: self.parse_matrix}) + self.root_handler.set_throw_back_lst(throw_back_opcodes) + self.child_handler.set_handler({2: self.parse_group, + 111: self.parse_inline_light_point, 73: self.parse_lod, 4: self.parse_object, 10: self.parse_push, 11: self.parse_pop, 96: self.parse_unhandled, # switch - 14: self.parse_unhandled, # DOF + 14: self.parse_dof, # DOF 91: self.parse_unhandled, # sound 98: self.parse_unhandled, # clip 63: self.parse_xref}) - self.props['type'] = 'LOD' - self.props['id'] = self.header.fw.read_string(8) + self.props = dict() + self.props['comment'] = '' + self.parse_record() class InlineLightPoint(InterNode): def __init__(self, parent): @@ -1274,119 +1409,49 @@ class InlineLightPoint(InterNode): 11: self.parse_pop}) self.indices = list() - - self.props = dict.fromkeys(['id', 'type', 'comment', 'draw order', 'appearance']) - self.app_props = dict() - + self.props = dict() self.props['comment'] = '' - self.props['type'] = 'Light Point' - self.props['id'] = self.header.fw.read_string(8) - - self.app_props.update({'smc': self.header.fw.read_short()}) - self.app_props.update({'fid': self.header.fw.read_short()}) - self.app_props.update({'back color: a': self.header.fw.read_uchar()}) - self.app_props.update({'back color: b': self.header.fw.read_uchar()}) - self.app_props.update({'back color: g': self.header.fw.read_uchar()}) - self.app_props.update({'back color: r': self.header.fw.read_uchar()}) - self.app_props.update({'display mode': self.header.fw.read_int()}) - self.app_props.update({'intensity': self.header.fw.read_float()}) - self.app_props.update({'back intensity': self.header.fw.read_float()}) - self.app_props.update({'minimum defocus': self.header.fw.read_float()}) - self.app_props.update({'maximum defocus': self.header.fw.read_float()}) - self.app_props.update({'fading mode': self.header.fw.read_int()}) - self.app_props.update({'fog punch mode': self.header.fw.read_int()}) - self.app_props.update({'directional mode': self.header.fw.read_int()}) - self.app_props.update({'range mode': self.header.fw.read_int()}) - self.app_props.update({'min pixel size': self.header.fw.read_float()}) - self.app_props.update({'max pixel size': self.header.fw.read_float()}) - self.app_props.update({'actual size': self.header.fw.read_float()}) - self.app_props.update({'trans falloff pixel size': self.header.fw.read_float()}) - self.app_props.update({'trans falloff exponent': self.header.fw.read_float()}) - self.app_props.update({'trans falloff scalar': self.header.fw.read_float()}) - self.app_props.update({'trans falloff clamp': self.header.fw.read_float()}) - self.app_props.update({'fog scalar': self.header.fw.read_float()}) - self.app_props.update({'fog intensity': self.header.fw.read_float()}) - self.app_props.update({'size threshold': self.header.fw.read_float()}) - self.app_props.update({'directionality': self.header.fw.read_int()}) - self.app_props.update({'horizontal lobe angle': self.header.fw.read_float()}) - self.app_props.update({'vertical lobe angle': self.header.fw.read_float()}) - self.app_props.update({'lobe roll angle': self.header.fw.read_float()}) - self.app_props.update({'dir falloff exponent': self.header.fw.read_float()}) - self.app_props.update({'dir ambient intensity': self.header.fw.read_float()}) - self.header.fw.read_ahead(12) # Animation settings. - self.app_props.update({'significance': self.header.fw.read_float()}) - self.props['draw order'] = self.header.fw.read_int() - self.app_props.update({'flags': self.header.fw.read_int()}) - #self.fw.read_ahead(12) # More animation settings. - - # return dictionary: lp_app name => index list - def group_points(self, props): - - name_to_indices = {} - - for i in self.indices: - vert_desc = self.header.vert_pal.vert_desc_lst[i] - app_desc = LightPointAppDesc() - app_desc.props.update(props) - # add vertex normal and color - app_desc.props.update({'nx': vert_desc.nx}) - app_desc.props.update({'ny': vert_desc.ny}) - app_desc.props.update({'nz': vert_desc.nz}) - - app_desc.props.update({'r': vert_desc.r}) - app_desc.props.update({'g': vert_desc.g}) - app_desc.props.update({'b': vert_desc.b}) - app_desc.props.update({'a': vert_desc.a}) - - app_name = GRR.request_lightpoint_app(app_desc) + self.parse_record() - if name_to_indices.get(app_name): - name_to_indices[app_name].append(i) - else: - name_to_indices.update({app_name: [i]}) - - return name_to_indices def blender_import(self): - name = '%s: %s' % (self.props['type'], self.props['id']) + - name_to_indices = self.group_points(self.app_props) + name = self.props['id'] + self.mesh= Blender.Mesh.New() + self.mesh.name = 'FLT_LP' + self.object = self.header.scene.objects.new(self.mesh) + self.object.name = name + #self.mesh.verts.extend(Vector() ) # DUMMYVERT + self.object.Layer = current_layer + self.object.sel= 1 + + self.object.properties['FLT'] = dict() + for key in self.props: + try: + self.object.properties['FLT'][key] = self.props[key] + except: #horrible... + pass - for app_name, indices in name_to_indices.iteritems(): - self.object = Blender.Object.New('Mesh', name) - #self.mesh = self.object.getData() - self.mesh= Blender.Mesh.New() - self.mesh.verts.extend( Vector() ) # DUMMYVERT - self.object.link(self.mesh) + if self.parent and self.parent.object and self.header.scene == self.parent.header.scene: + self.parent.object.makeParent([self.object]) - if self.parent: - self.parent.object.makeParent([self.object]) + if self.matrix: + self.object.setMatrix(self.matrix) + + self.mesh.verts.extend([self.header.vert_pal.blender_verts[i] for i in self.indices]) + + #add color index information. + self.mesh.verts.addPropertyLayer("FLT_VCOL",Blender.Mesh.PropertyTypes["INT"]) + for i, vindex in enumerate(self.indices): + vdesc = self.header.vert_pal.vert_desc_lst[vindex] + v = self.mesh.verts[i] + v.setProperty("FLT_VCOL",vdesc.cindex) + #for i, v in enumerate(self.mesh.verts): + # vdesc = self.header.vert_pal.vert_desc_lst[i] + # v.setProperty("FLT_VCOL",vdesc.cindex) + self.mesh.update() - for i in indices: - vert = self.header.vert_pal.blender_verts[i] - self.mesh.verts.append(vert) - - scene.link(self.object) - self.object.Layer = current_layer - self.object.sel= 1 - - if self.matrix: - self.object.setMatrix(self.matrix) - - # Import comment. - if self.props['comment'] != '': - name = 'COMMENT: ' + self.props['id'] - t = Blender.Text.New(name) - t.write(self.props['comment']) - self.props['comment'] = name - - # Attach properties. - self.props.update({'appearance': app_name}) - for name, value in self.props.iteritems(): - self.object.addProperty(name, value) - - self.mesh.update() - def parse_vertex_list(self): length = self.header.fw.get_length() fw = self.header.fw @@ -1432,7 +1497,7 @@ class IndexedLightPoint(InterNode): app_desc.props.update({'b': vert_desc.b}) app_desc.props.update({'a': vert_desc.a}) - app_name = GRR.request_lightpoint_app(app_desc) + app_name = self.header.grr.request_lightpoint_app(app_desc, self.header.scene) if name_to_indices.get(app_name): name_to_indices[app_name].append(i) @@ -1448,7 +1513,6 @@ class IndexedLightPoint(InterNode): for app_name, indices in name_to_indices.iteritems(): self.object = Blender.Object.New('Mesh', name) - #self.mesh = self.object.getData() self.mesh= Blender.Mesh.New() self.mesh.verts.extend( Vector() ) # DUMMYVERT self.object.link(self.mesh) @@ -1460,7 +1524,7 @@ class IndexedLightPoint(InterNode): vert = self.header.vert_pal.blender_verts[i] self.mesh.verts.append(vert) - scene.link(self.object) + self.header.scene.objects.link(self.object) self.object.Layer = current_layer @@ -1543,7 +1607,7 @@ class Unhandled(InterNode): 10: self.parse_push, 11: self.parse_pop, 96: self.parse_unhandled, # switch - 14: self.parse_unhandled, # DOF + 14: self.parse_dof, # DOF 91: self.parse_unhandled, # sound 98: self.parse_unhandled, # clip 63: self.parse_xref}) @@ -1552,30 +1616,31 @@ class Unhandled(InterNode): class Database(InterNode): def blender_import(self): - self.tex_pal = dict(self.tex_pal_lst) - del self.tex_pal_lst - - # Setup Textures - bl_tex_pal_lst = list() - for i in self.tex_pal.iterkeys(): - path_filename = FF.find(self.tex_pal[i]) + for key in self.tex_pal.keys(): + path_filename= FF.find(self.tex_pal[key][0]) if path_filename != None: - img = GRR.request_image(path_filename) + img = self.grr.request_image(path_filename) if img: - tex = GRR.request_texture(img) - tex.setName(FF.strip_path(self.tex_pal[i])) - bl_tex_pal_lst.append( (i, tex) ) - else: - bl_tex_pal_lst.append( (i, None) ) + self.tex_pal[key][1] = img elif global_prefs['verbose'] >= 1: - print 'Warning: Unable to find', self.tex_pal[i] - - self.bl_tex_pal = dict(bl_tex_pal_lst) - - # Setup Materials - self.mat_desc_pal = dict(self.mat_desc_pal_lst) - - InterNode.blender_import(self) + print 'Warning: Unable to find', self.tex_pal[key][0] + + self.scene.properties['FLT'] = dict() + for key in self.props: + try: + self.scene.properties['FLT'][key] = self.props[key] + except: #horrible... + pass + + self.scene.properties['FLT']['Main'] = 0 + self.scene.properties['FLT']['Filename'] = self.bname + + #import color palette + carray = list() + for color in self.col_pal: + carray.append(struct.unpack('>i',struct.pack('>BBBB',color[0],color[1],color[2],color[3]))[0]) + self.scene.properties['FLT']['Color Palette'] = carray + Node.blender_import(self) def parse_appearance_palette(self): props = dict() @@ -1696,9 +1761,10 @@ class Database(InterNode): return True def get_color(self, color_index): + color = None index = color_index / 128 intensity = float(color_index - 128.0 * index) / 127.0 - + if index >= 0 and index <= 1023: brightest = self.col_pal[index] r = int(brightest[0] * intensity) @@ -1707,7 +1773,7 @@ class Database(InterNode): a = int(brightest[3]) color = [r, g, b, a] - + return color def parse_color_palette(self): @@ -1728,15 +1794,56 @@ class Database(InterNode): def parse_texture_palette(self): name = self.fw.read_string(200) index = self.fw.read_int() - self.tex_pal_lst.append( (index, name) ) + self.tex_pal[index]= [name, None] return True - - def __init__(self, filename, parent=None): + + def read_attribute_files(self): + for tex in self.tex_pal.keys(): + [name,image] = self.tex_pal[tex] + basename = os.path.basename(name) + if(image): + basename = basename + ".attr" + dirname = os.path.dirname(Blender.sys.expandpath(image.getFilename())) #can't rely on original info stored in pallette since it might be relative link + newpath = os.path.join(dirname, basename) + if os.path.exists(newpath) and not image.properties.has_key('FLT'): + fw = flt_filewalker.FltIn(newpath) + fw.read_ahead(8) #We dont care what the attribute file says about x/y dimensions + image.properties['FLT']={} + + #need to steal code from parse records.... + props = records['Image'] + propkeys = props.keys() + propkeys.sort() + for position in propkeys: + (type,length,name) = props[position] + image.properties['FLT'][name] = read_prop(fw,type,length) + fw.close_file() + + #copy clamp settings + wrap = image.properties['FLT']['10i!Wrap'] + wrapu = image.properties['FLT']['11i!WrapU'] + wrapv = image.properties['FLT']['12i!WrapV'] + + if wrapu == 3 or wrapv == 3: + wrapuv = (wrap,wrap) + else: + wrapuv = (wrapu, wrapv) + image.clampX = wrapuv[0] + image.clampY = wrapuv[1] + + elif not os.path.exists(newpath): + print "Cannot read attribute file:" + newpath + + def __init__(self, filename, grr, parent=None): if global_prefs['verbose'] >= 1: print 'Parsing:', filename print self.fw = flt_filewalker.FltIn(filename) + self.filename = filename + self.bname = os.path.splitext(os.path.basename(filename))[0] + self.grr = grr + Node.__init__(self, parent, self) InterNode.__init__(self) @@ -1753,23 +1860,26 @@ class Database(InterNode): self.root_handler.set_throw_back_lst(throw_back_opcodes) self.child_handler.set_handler({#130: self.parse_indexed_light_point, - #111: self.parse_inline_light_point, + 111: self.parse_inline_light_point, 2: self.parse_group, 73: self.parse_lod, 4: self.parse_object, 10: self.parse_push, 11: self.parse_pop, 96: self.parse_unhandled, - 14: self.parse_unhandled, + 14: self.parse_dof, 91: self.parse_unhandled, 98: self.parse_unhandled, 63: self.parse_xref}) + self.scene = Blender.Scene.New(self.bname) + self.group = Blender.Group.New(self.bname) + self.vert_pal = None self.lightpoint_appearance_pal = dict() self.tex_pal = dict() - self.tex_pal_lst = list() - self.bl_tex_pal = dict() + #self.tex_pal_lst = list() + #self.bl_tex_pal = dict() self.col_pal = list() self.mat_desc_pal_lst = list() self.mat_desc_pal = dict() @@ -1778,7 +1888,70 @@ class Database(InterNode): 'sw lon', 'ne lat', 'ne lon', 'origin lat', 'origin lon', 'lambert lat1', 'lambert lat2', 'ellipsoid model', 'utm zone', 'radius', 'major axis', 'minor axis']) -def select_file(filename): + +def clearparent(root,childhash): + for child in childhash[root]: + clearparent(child,childhash) + root.clrParent(2,0) + +def fixscale(root,childhash): + for child in childhash[root]: + fixscale(child,childhash) + location = Blender.Mathutils.Vector(root.getLocation('worldspace')) + if location[0] != 0.0 and location[1] != 0.0 and location[2] != 0.0: + #direction = Blender.Mathutils.Vector(0-location[0],0-location[1],0-location[2]) #reverse vector + smat = Blender.Mathutils.ScaleMatrix(global_prefs['scale'],4) + root.setLocation(location * smat) + #if its a mesh, we need to scale all of its vertices too + if root.type == 'Mesh': + smat = Blender.Mathutils.ScaleMatrix(global_prefs['scale'],4) + rmesh = root.getData(mesh=True) + for v in rmesh.verts: + v.co = v.co * smat + + +def reparent(root,childhash,sce): + for child in childhash[root]: + reparent(child,childhash,sce) + + root.makeParent(childhash[root]) + sce.update(1) + +def update_scene(root,sdone): + for object in root.objects: + if object.DupGroup: + try: + child = Blender.Scene.Get(object.DupGroup.name) + except: + child = None + if child and child not in sdone: + update_scene(child,sdone) + root.makeCurrent() + #create a list of children for each object + childhash = dict() + for object in root.objects: + childhash[object] = list() + + for object in root.objects: + if object.parent: + childhash[object.parent].append(object) + + for object in root.objects: + if not object.parent: + #recursivley go through and clear all the children of their transformation, starting at deepest level first. + clearparent(object,childhash) + #now fix the location of everything + fixscale(object,childhash) + #now fix the parenting + reparent(object,childhash,root) + + for object in root.objects: + object.makeDisplayList() + root.update(1) + sdone.append(root) + + +def select_file(filename, grr): if not Blender.sys.exists(filename): msg = 'Error: File ' + filename + ' does not exist.' Blender.Draw.PupMenu(msg) @@ -1801,13 +1974,12 @@ def select_file(filename): global_prefs['get_ambient'] = False global_prefs['get_shininess'] = True global_prefs['color_from_face'] = True + global_prefs['log to blender'] = True + + - # Start loading the file, - # first set the context Blender.Window.WaitCursor(True) Blender.Window.EditMode(0) - for ob in scene.objects: - ob.sel=0 FF.add_file_to_search_path(filename) @@ -1817,7 +1989,7 @@ def select_file(filename): print load_time = Blender.sys.time() - db = Database(filename) + db = Database(filename,grr) db.parse() load_time = Blender.sys.time() - load_time @@ -1828,23 +2000,15 @@ def select_file(filename): import_time = Blender.sys.time() db.blender_import() - import_time = Blender.sys.time() - import_time + + if global_prefs['attrib']: + print "reading attribute files" + db.read_attribute_files() Blender.Window.ViewLayer(range(1,21)) - # FIX UP AFTER DUMMY VERT AND REMOVE DOUBLES - Blender.Mesh.Mode(Blender.Mesh.SelectModes['VERTEX']) - for ob in scene.objects.context: - if ob.type=='Mesh': - me=ob.getData(mesh=1) - me.verts.delete(0) # remove the dummy vert - me.sel= 1 - me.remDoubles(0.0001) - - - - Blender.Window.RedrawAll() - + update_scene(db.scene,[]) + import_time = Blender.sys.time() - import_time if global_prefs['verbose'] >= 1: print 'Done.' print @@ -1854,37 +2018,112 @@ def select_file(filename): Blender.Window.WaitCursor(False) +def setimportscale(ID,val): + global global_prefs + global_prefs['scale'] = val +def setBpath(fname): + global_prefs['fltfile'] = fname -if global_prefs['verbose'] >= 1: - print - print 'OpenFlight Importer' - print 'Version:', __version__ - print 'Author: Greg MacDonald' - print __url__[2] - print +def event(evt,val): + pass +def but_event(evt): + + global FLTBaseLabel + global FLTBaseString + global FLTBaseChooser + global FLTExport + global FLTClose + + global FLTDoXRef + global FLTShadeImport + global FLTAttrib + + #Import DB + if evt == 1: + if global_prefs['verbose'] >= 1: + print + print 'OpenFlight Importer' + print 'Version:', __version__ + print 'Author: Greg MacDonald, Campbell Barton, Geoffrey Bantle' + print __url__[2] + print + + GRR = GlobalResourceRepository() + select_file(global_prefs['fltfile'], GRR) + #choose base path for export + if evt == 4: + Blender.Window.FileSelector(setBpath, "DB Root", global_prefs['fltfile']) + #Import custom shading? + if evt == 9: + global_prefs['smoothshading'] = FLTShadeImport.val + #Import Image attribute files + if evt == 10: + global_prefs['attrib'] = FLTAttrib.val + #export XRefs + if evt == 13: + global_prefs['doxrefs'] = FLTDoXRef.val + + if evt == 2: + Draw.Exit() + -if __name__ == '__main__': - Blender.Window.FileSelector(select_file, "Import OpenFlight", "*.flt") - #select_file('/fe/flt/helnwsflt/helnws.flt') - #select_file('/fe/flt/Container_006.flt') - #select_file('/fe/flt/NaplesORIGINALmesh.flt') - #select_file('/Anti_tank_D30.flt') - #select_file('/metavr/file_examples/flt/cherrypoint/CherryPoint_liter_runway.flt') + +from Blender.BGL import * +from Blender import Draw +def gui(): + + global FLTBaseLabel + global FLTBaseString + global FLTBaseChooser -""" -TIME= Blender.sys.time() -import os -PATH= 'c:\\flt_test' -for FNAME in os.listdir(PATH): - if FNAME.lower().endswith('.flt'): - FPATH= os.path.join(PATH, FNAME) - newScn= Blender.Scene.New(FNAME) - newScn.makeCurrent() - scene= newScn - select_file(FPATH) + global FLTExport + global FLTClose + + global FLTDoXRef + global FLTShadeImport + + global FLTAttrib + + + glClearColor(0.772,0.832,0.847,1.0) + glClear(GL_COLOR_BUFFER_BIT) + + areas = Blender.Window.GetScreenInfo() + curarea = Blender.Window.GetAreaID() + curRect = None + + for area in areas: + if area['id'] == curarea: + curRect = area['vertices'] + break + + width = curRect[2] - curRect[0] + height = curRect[3] - curRect[1] + cx = 50 + cy = height - 80 -print 'TOTAL TIME: %.6f' % (Blender.sys.time() - TIME) -""" - \ No newline at end of file + FLTBaseLabel = Draw.Label("Base file:",cx,cy,100,20) + FLTBaseString = Draw.String("",3,cx+100,cy,300,20,global_prefs['fltfile'],255,"Root DB file") + FLTBaseChooser = Draw.PushButton("...",4,cx+400,cy,20,20,"Choose Folder") + + cy = cy-40 + FLTScale = Draw.Number("Import Scale",14,cx,cy,220,20,global_prefs['scale'],0.0,100.0,"Export scaleing factor",setimportscale) + + cy = cy-40 + FLTDoXRef = Draw.Toggle("Import XRefs", 13,cx,cy,220,20,global_prefs['doxrefs'],"Import External references") + + cy = cy-40 + FLTShadeImport = Draw.Toggle("Import Custom Shading",9,cx,cy,220,20,global_prefs['smoothshading'],"Import custom shading via edgesplit modifiers") + + cy = cy-40 + FLTAttrib = Draw.Toggle("Import Attribute Files", 10,cx,cy,220,20,global_prefs['attrib'],"Import Image Attribute files") + + cy = cy - 40 + FLTExport = Draw.PushButton("Import",1,cx,20,100,20,"Import FLT Database") + FLTClose = Draw.PushButton("Close",2,cx+120,20,100,20,"Close Window") + + + +Draw.Register(gui,event,but_event) \ No newline at end of file diff --git a/release/scripts/flt_palettemanager.py b/release/scripts/flt_palettemanager.py new file mode 100644 index 00000000000..c641a0a4f08 --- /dev/null +++ b/release/scripts/flt_palettemanager.py @@ -0,0 +1,388 @@ +#!BPY + +""" +Name: 'FLT Palette Manager' +Blender: 240 +Group: 'Misc' +Tooltip: 'Manage FLT colors' +""" + +__author__ = "Geoffrey Bantle" +__version__ = "1.0 11/21/2007" +__email__ = ('scripts', 'Author, ') +__url__ = ('blender', 'elysiun') + +__bpydoc__ ="""\ + +This script manages colors in OpenFlight databases. OpenFlight is a +registered trademark of MultiGen-Paradigm, Inc. + +Todo: +-Figure out whats causing the PC speaker to beep when initializing... + +Feature overview and more availible at: +http://wiki.blender.org/index.php/Scripts/Manual/FLTools +""" + +# -------------------------------------------------------------------------- +# flt_palettemanager.py version 0.1 2005/04/08 +# -------------------------------------------------------------------------- +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# Copyright (C) 2007: Blender Foundation +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + +import Blender.Draw as Draw +from Blender.BGL import * +import Blender +import flt_properties +import flt_defaultp as defaultp +from flt_properties import * + + +palette_size = 12 +palette_x = 0 +palette_y = 0 + +colors = list() +curint = 1.0 +curswatch = 0 +#make a default palette, not very useful. +cinc = 1.0 / 1024.0 +cstep = 0.0 +picker = None +ptt = "" +for i in xrange(1024): + colors.append([cstep,cstep,cstep]) + cstep = cstep + cinc +def update_state(): + state = dict() + state["activeScene"] = Blender.Scene.getCurrent() + state["activeObject"] = state["activeScene"].getActiveObject() + state["activeMesh"] = None + if state["activeObject"] and state["activeObject"].type == 'Mesh': + state["activeMesh"] = state["activeObject"].getData(mesh=True) + + state["activeFace"] = None + if state["activeMesh"]: + if state["activeMesh"].faceUV and state["activeMesh"].activeFace != None: + state["activeFace"] = state["activeMesh"].faces[state["activeMesh"].activeFace] + + return state + +def pack_face_index(index, intensity): + return ((127*intensity)+(128*index)) +def unpack_face_index(face_index): + index = face_index / 128 + intensity = float(face_index - 128.0 * index) / 127.0 + return(index,intensity) + +def event(evt,val): + global palette_size + global palette_x + global palette_y + global colors + global curint + global curswatch + + areas = Blender.Window.GetScreenInfo() + curarea = Blender.Window.GetAreaID() + curRect = None + editmode = 0 + + for area in areas: + if area['id'] == curarea: + curRect = area['vertices'] + break + + if evt == Draw.LEFTMOUSE: + mval = Blender.Window.GetMouseCoords() + rastx = mval[0] - curRect[0] + rasty = mval[1] - curRect[1] + + swatchx = (rastx -palette_x) / palette_size #+state["palette_x"] + swatchy = (rasty -palette_y) / palette_size #+state["palette_y"] + if rastx > palette_x and rastx < (palette_x + palette_size * 32) and rasty > palette_y and rasty < (palette_y+ palette_size* 32): + if swatchx < 32 and swatchy < 32: + curswatch = (swatchx * 32) + swatchy + Draw.Redraw(1) + + elif swatchy < 34 and swatchx < 32: + curint = 1.0 - (float(rastx-palette_x)/(palette_size*32.0)) + Draw.Redraw(1) + + #copy current color and intensity to selected faces. + elif evt == Draw.CKEY: + + if Blender.Window.EditMode(): + Blender.Window.EditMode(0) + editmode = 1 + state = update_state() + + #retrieve color from palette + color = struct.unpack('>BBBB',struct.pack('>I',colors[curswatch])) + actmesh = state["activeMesh"] + if actmesh: + if(Blender.Window.GetKeyQualifiers() != Blender.Window.Qual["CTRL"]): + selfaces = list() + for face in actmesh.faces: + if face.sel: + selfaces.append(face) + + if not "FLT_COL" in actmesh.faces.properties: + actmesh.faces.addPropertyLayer("FLT_COL",Blender.Mesh.PropertyTypes["INT"]) + for face in actmesh.faces: + face.setProperty("FLT_COL",127) #default + try: + actmesh.activeColorLayer = "FLT_Fcol" + except: + actmesh.addColorLayer("FLT_Fcol") + actmesh.activeColorLayer = "FLT_Fcol" + + + for face in selfaces: + #First append packed index + color and store in face property + face.setProperty("FLT_COL",int(pack_face_index(curswatch,curint))) + #Save baked color to face vertex colors + for col in face.col: + col.r = int(color[0] * curint) + col.g = int(color[1] * curint) + col.b = int(color[2] * curint) + col.a = int(color[3] * curint) + else: + if Blender.Mesh.Mode() == Blender.Mesh.SelectModes['VERTEX']: + if not 'FLT_VCOL' in actmesh.verts.properties: + actmesh.verts.addPropertyLayer("FLT_VCOL",Blender.Mesh.PropertyTypes["INT"]) + for vert in actmesh.verts: + vert.setProperty("FLT_VCOL",127) + else: + for vert in actmesh.verts: + if vert.sel: + vert.setProperty("FLT_VCOL",int(pack_face_index(curswatch,curint))) + + if editmode: + Blender.Window.EditMode(1) + + Blender.Window.RedrawAll() + + #grab color and intensity from active face + elif evt == Draw.VKEY: + if Blender.Window.EditMode(): + Blender.Window.EditMode(0) + editmode = 1 + state = update_state() + + actmesh = state["activeMesh"] + activeFace = state["activeFace"] + + + if activeFace: + if not "FLT_COL" in actmesh.faces.properties: + actmesh.faces.addPropertyLayer("FLT_COL",Blender.Mesh.PropertyTypes["INT"]) + for face in actmesh.faces: + face.setProperty("FLT_COL",127) #default + try: + actmesh.activeColorLayer = "FLT_Fcol" + except: + actmesh.addColorLayer("FLT_Fcol") + actmesh.activeColorLayer = "FLT_Fcol" + tcol = activeFace.getProperty("FLT_COL") + (index,intensity) = unpack_face_index(tcol) + curswatch = index + curint = intensity + + if editmode: + Blender.Window.EditMode(1) + + Blender.Window.RedrawAll() + + elif evt == Draw.ESCKEY: + Draw.Exit() + + if editmode: + Blender.Window.EditMode(1) + +def update_all(): + global colors + state = update_state() + #update the baked FLT colors for all meshes. + for object in state["activeScene"].objects: + if object.type == "Mesh": + mesh = object.getData(mesh=True) + if 'FLT_COL' in mesh.faces.properties: + mesh.activeColorLayer = "FLT_Fcol" + for face in mesh.faces: + (index,intensity) = unpack_face_index(face.getProperty('FLT_COL')) + color = struct.unpack('>BBBB',struct.pack('>I',colors[index])) + #update the vertex colors for this face + for col in face.col: + col.r = int(color[0] * intensity) + col.g = int(color[1] * intensity) + col.b = int(color[2] * intensity) + col.a = 255 + + +def but_event(evt): + global palette_size + global palette_x + global palette_y + global colors + global curint + global curswatch + global picker + state = update_state() + + if evt == 1: + if picker.val: + rval = (int(picker.val[0]*255),int(picker.val[1]*255),int(picker.val[2]*255),255) + rval = struct.pack('>BBBB',rval[0],rval[1],rval[2],rval[3]) + rval = struct.unpack('>i',rval) + colors[curswatch] = rval[0] + #go cd through all meshes and update their FLT colors + update_all() + + Draw.Redraw(1) +def init_pal(): + global palette_size + global palette_x + global palette_y + global colors + global curint + global curswatch + + state = update_state() + + if not state["activeScene"].properties.has_key('FLT'): + state["activeScene"].properties['FLT'] = dict() + + try: + colors = state["activeScene"].properties['FLT']['Color Palette'] + except: + state["activeScene"].properties['FLT']['Color Palette'] = defaultp.pal + colors = state["activeScene"].properties['FLT']['Color Palette'] + +def draw_palette(): + global palette_size + global palette_x + global palette_y + global colors + global curint + global curswatch + global picker + + state = update_state() + init_pal() + + ssize = palette_size + xpos = palette_x + cid = 0 + + highlight = [(palette_x,palette_y),(palette_x+palette_size,palette_y),(palette_x+palette_size,palette_y+palette_size),(palette_x,palette_y+palette_size)] + for x in xrange(32): + ypos = palette_y + for y in xrange(32): + color = struct.unpack('>BBBB',struct.pack('>I',colors[cid])) + glColor3f(color[0]/255.0,color[1]/255.0,color[2]/255.0) + glBegin(GL_POLYGON) + glVertex2i(xpos,ypos) + glVertex2i(xpos+ssize,ypos) + glVertex2i(xpos+ssize,ypos+ssize) + glVertex2i(xpos,ypos+ssize) + glEnd() + + if curswatch == cid: + highlight[0] = (xpos,ypos) + highlight[1] = (xpos+ssize,ypos) + highlight[2] = (xpos+ssize,ypos+ssize) + highlight[3] = (xpos,ypos+ssize) + + glColor3f(0.0,0.0,0.0) + glBegin(GL_LINE_LOOP) + glVertex2i(xpos,ypos) + glVertex2i(xpos+ssize,ypos) + glVertex2i(xpos+ssize,ypos+ssize) + glVertex2i(xpos,ypos+ssize) + glVertex2i(xpos,ypos) + glEnd() + + + cid = cid + 1 + ypos = ypos + ssize + + xpos = xpos + ssize + + #draw intensity gradient + color = struct.unpack('>BBBB',struct.pack('>I',colors[curswatch])) + color = [color[0]/255.0,color[1]/255.0,color[2]/255.0] + colsteps = [color[0]/255.0,color[1]/255.0,color[2]/255.0] + stripwidth = (palette_size * 32.0) / 256 + strippad = palette_size / 2.0 + + xpos = palette_x + grady = (palette_y + (palette_size * 32.0)) + strippad + for x in xrange(256): + color[0] = color[0] - colsteps[0] + color[1] = color[1] - colsteps[1] + color[2] = color[2] - colsteps[2] + + glColor3f(color[0], color[1] ,color[2]) + glBegin(GL_POLYGON) + glVertex2f(xpos,grady) + glVertex2f(xpos+stripwidth,grady) + glVertex2f(xpos+stripwidth,grady+palette_size) + glVertex2f(xpos,grady+palette_size) + glEnd() + xpos = xpos + stripwidth + + #draw intensity slider bar + #xposition == 512 - ((curint) * 512) + xpos = ((palette_size*32) * (1.0 - curint)) + palette_x + glColor3f(1.0,1.0,1.0) + glBegin(GL_LINE_LOOP) + glVertex2i(xpos-6,grady-1) + glVertex2i(xpos+6,grady-1) + glVertex2i(xpos+6,grady+palette_size+1) + glVertex2i(xpos-6,grady+palette_size+1) + #glVertex2i(xpos-6,grady+7) + glEnd() + + #draw color picker + color = struct.unpack('>BBBB',struct.pack('>I',colors[curswatch])) + pickcol = (color[0]/255.0,color[1]/255.0,color[2]/255.0) + picker = Blender.Draw.ColorPicker(1,highlight[0][0]+1,highlight[0][1]+1,ssize-2,ssize-2,pickcol,ptt) + + #draw highlight swatch + glColor3f(1.0,1.0,1.0) + glBegin(GL_LINE_LOOP) + glVertex2i(highlight[0][0],highlight[0][1]) + glVertex2i(highlight[1][0],highlight[1][1]) + glVertex2i(highlight[2][0],highlight[2][1]) + glVertex2i(highlight[3][0],highlight[3][1]) + glVertex2i(highlight[0][0],highlight[0][1]) + glEnd() + +def gui(): + glClearColor(0.5,0.5,0.5,1.0) + glClear(GL_COLOR_BUFFER_BIT) + draw_palette() + + +init_pal() +Draw.Register(gui,event,but_event) + diff --git a/release/scripts/flt_properties.py b/release/scripts/flt_properties.py new file mode 100644 index 00000000000..07bcc8def1d --- /dev/null +++ b/release/scripts/flt_properties.py @@ -0,0 +1,619 @@ +#!BPY +# flt_properties.py. For setting default OpenFLight ID property types +# Copyright (C) 2007 Blender Foundation +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +__bpydoc__ ="""\ +Utility functions and data defintions used by OpenFlight I/O and tool scripts. OpenFlight is a +registered trademark of MultiGen-Paradigm, Inc. +""" + + +import struct + +bitsLSB = [2147483648] +for i in xrange(31): + bitsLSB.append(bitsLSB[-1]/2) +bitsRSB = bitsLSB[:] +bitsRSB.reverse() + +def pack_color(col): + return struct.pack('>B',col[3]) + struct.pack('>B',col[2]) + struct.pack('>B',col[1]) + struct.pack('>B',col[0]) + +def unpack_color(col): + string = struct.pack('>I', col) + r = struct.unpack('>B',string[3:4]) + g = struct.unpack('>B',string[2:3]) + b = struct.unpack('>B',string[1:2]) + a = struct.unpack('>B',string[0:1]) + return [r,g,b,a] + +def reverse_bits(len,num): + bitbucket = list() + rval = 0 + + for i in xrange(len): + if num & bitsRSB[i]: + bitbucket.append(1) + else: + bitbucket.append(0) + + bitbucket.reverse() + + for i, bit in enumerate(bitbucket): + if bit: + rval |= bitsLSB[i] + + return rval + + +opcode_name = { 0: 'db', + 1: 'head', + 2: 'grp', + 4: 'obj', + 5: 'face', + 10: 'push', + 11: 'pop', + 14: 'dof', + 19: 'push sub', + 20: 'pop sub', + 21: 'push ext', + 22: 'pop ext', + 23: 'cont', + 31: 'comment', + 32: 'color pal', + 33: 'long id', + 49: 'matrix', + 50: 'vector', + 52: 'multi-tex', + 53: 'uv lst', + 55: 'bsp', + 60: 'rep', + 61: 'inst ref', + 62: 'inst def', + 63: 'ext ref', + 64: 'tex pal', + 67: 'vert pal', + 68: 'vert w col', + 69: 'vert w col & norm', + 70: 'vert w col, norm & uv', + 71: 'vert w col & uv', + 72: 'vert lst', + 73: 'lod', + 74: 'bndin box', + 76: 'rot edge', + 78: 'trans', + 79: 'scl', + 80: 'rot pnt', + 81: 'rot and/or scale pnt', + 82: 'put', + 83: 'eyepoint & trackplane pal', + 84: 'mesh', + 85: 'local vert pool', + 86: 'mesh prim', + 87: 'road seg', + 88: 'road zone', + 89: 'morph vert lst', + 90: 'link pal', + 91: 'snd', + 92: 'rd path', + 93: 'snd pal', + 94: 'gen matrix', + 95: 'txt', + 96: 'sw', + 97: 'line styl pal', + 98: 'clip reg', + 100: 'ext', + 101: 'light src', + 102: 'light src pal', + 103: 'reserved', + 104: 'reserved', + 105: 'bndin sph', + 106: 'bndin cyl', + 107: 'bndin hull', + 108: 'bndin vol cntr', + 109: 'bndin vol orient', + 110: 'rsrvd', + 111: 'light pnt', + 112: 'tex map pal', + 113: 'mat pal', + 114: 'name tab', + 115: 'cat', + 116: 'cat dat', + 117: 'rsrvd', + 118: 'rsrvd', + 119: 'bounding hist', + 120: 'rsrvd', + 121: 'rsrvd', + 122: 'push attrib', + 123: 'pop attrib', + 124: 'rsrvd', + 125: 'rsrvd', + 126: 'curv', + 127: 'road const', + 128: 'light pnt appear pal', + 129: 'light pnt anim pal', + 130: 'indexed lp', + 131: 'lp sys', + 132: 'indx str', + 133: 'shdr pal'} + + +typecodes = ['c','C','s','S','i','I','f','d','t'] + +FLT_GRP = 2 +FLT_OBJ = 4 +FLT_LOD = 73 +FLT_XRF = 63 +FLT_DOF = 14 +FLT_ILP = 111 +FLT_DB = 1 +FLT_FCE = 5 + +#not actual opcodes +FLT_NUL = 0 +FLT_EXP = -1 + +#valid childtypes for each FLT node type +FLT_CHILDTYPES = { + FLT_GRP : [111,2,73,4,14,63], + FLT_OBJ : [111], + FLT_LOD : [111,2,73,4,14,63], + FLT_XRF : [], + FLT_DOF : [111,2,73,4,14,63], + FLT_ILP : [] +} + +#List of nodes that can have faces as children +FLT_FACETYPES = [ + FLT_GRP, + FLT_OBJ, + FLT_LOD, + FLT_DOF +] + +def write_prop(fw,type,value,length): + if type == 'c': + fw.write_char(value) + elif type == 'C': + fw.write_uchar(value) + elif type == 's': + fw.write_short(value) + elif type == 'S': + fw.write_ushort(value) + elif type == 'i': + fw.write_int(value) + elif type == 'I': + fw.write_uint(value) + elif type == 'd': + fw.write_double(value) + elif type == 'f': + fw.write_float(value) + elif type == 't': + fw.write_string(value,length) + +def read_prop(fw,type,length): + rval = None + if type == 'c': + rval = fw.read_char() + elif type == 'C': + rval = fw.read_uchar() + elif type == 's': + rval = fw.read_short() + elif type == 'S': + rval = fw.read_ushort() + elif type == 'i': + rval = fw.read_int() + elif type == 'I': + rval = fw.read_uint() + elif type == 'd': + rval = fw.read_double() + elif type == 'f': + rval = fw.read_float() + elif type == 't': + rval = fw.read_string(length) + return rval + +FLTGroup = { + '3t8!id' : 'G', + '4s!priority' : 0, + '5s!reserved1' : 0, + '6i!flags' : 0, + '7s!special1' : 0, + '8s!special2' : 0, + '9s!significance' : 0, + '10c!layer code' : 0, + '11c!reserved2' : 0, + '12i!reserved3' : 0, + '13i!loop count' : 0, + '14f!loop duration' : 0, + '15f!last frame duration' : 0 +} +FLTGroupDisplay = [5,11,12] + +FLTObject = { + '3t8!id' : 'O', + '4I!flags' : 0, + '5s!priority' : 0, + '6S!transp' : 0, + '7s!SFX1' : 0, + '8s!SFX2' : 0, + '9s!significance' : 0, + '10s!reserved' : 0 +} +FLTObjectDisplay = [10] + +FLTLOD = { + '3t8!id' : 'L', + '4i!reserved' : 0, + '5d!switch in' : 0, + '6d!switch out' : 0, + '7s!sfx ID1' : 0, + '8s!sfx ID2' : 0, + '9I!flags' : 0, + '10d!X co' : 0, + '11d!Y co' : 0, + '12d!Z co' : 0, + '13d!Transition' : 0, + '14d!Sig Size' : 0 +} +FLTLODDisplay = [4] + +FLTInlineLP = { + '3t8!id' : 'Lp', + '4s!smc' : 0, + '5s!fid' : 0, + '6C!back color: a' : 255, + '7C!back color: b' : 255, + '8C!back color: g' : 255, + '9C!back color: r' : 255, + '10i!display mode' : 255, + '11f!intensity' : 1.0, + '12f!back intensity' : 0.0, + '13f!minimum defocus' : 0.0, + '14f!maximum defocus' : 1.0, + '15i!fading mode' : 0, + '16i!fog punch mode' : 0, + '17i!directional mode' : 1, + '18i!range mode' : 0, + '19f!min pixel size' : 1.0, + '20f!max pixel size' : 1024, + '21f!actual size' : 0.25, + '22f!trans falloff pixel size' : 0.25, + '23f!trans falloff exponent' : 1.0, + '24f!trans falloff scalar' : 1.0, + '25f!trans falloff clamp' : 1.0, + '26f!fog scalar' : 0.25, + '27f!fog intensity' : 1.0, + '28f!size threshold' : 0.1, + '29i!directionality' : 0, + '30f!horizontal lobe angle' : 180.0, + '31f!vertical lobe angle' : 180.0, + '32f!lobe roll angle' : 0.0, + '33f!dir falloff exponent' : 1.0, + '34f!dir ambient intensity' : 0.1, + '35f!anim period' : 0, + '36f!anim phase' : 0, + '37f!anim enabled' : 0, + '38f!significance' : 0.0, + '39i!draw order' : 0, + '40I!flags' : 813875616, + '41f!roti' : 0, + '42f!rotj' : 0, + '43f!rotk' : 0 +} + +FLTInlineLPDisplay = [35,36,37,41,42,43] + +FLTXRef = { + '3t200!filename' : '', #we dont actually use this value on export + '4i!reserved' : 0, + '5I!flag' : -478150656, + '6s!bbox' : 0, + '7s!reserved' : 0 +} + +FLTXRefDisplay = [4,7,3] + +FLTDOF = { + '3t8!id' : 'D', + '4i!reserved' : 0, + '5d!ORIGX' : 0.0, + '6d!ORIGY' : 0.0, + '7d!ORIGZ' : 0.0, + '8d!XAXIS-X' : 10.0, + '9d!XAXIS-Y' : 0.0, + '10d!XAXIS-Z' : 0.0, + '11d!XYPLANE-X' : 0.0, + '12d!XYPLANE-Y' : 10.0, + '13d!XZPLANE-Z' : 0.0, + '14d!ZMIN' : 0.0, + '15d!ZMAX' : 0.0, + '16d!ZCUR' : 0.0, + '17d!ZSTEP' : 0.0, + '18d!YMIN' : 0.0, + '19d!YMAX' : 0.0, + '20d!YCUR' : 0.0, + '21d!YSTEP' : 0.0, + '22d!XMIN' : 0.0, + '23d!XMAX' : 0.0, + '24d!XCUR' : 0.0, + '25d!XSTEP' : 0.0, + '26d!PITCH-MIN' : 0.0, + '27d!PITCH-MAX' : 0.0, + '28d!PITCH-CUR' : 0.0, + '29d!PITCH-STEP' : 0.0, + '30d!ROLL-MIN' : 0.0, + '31d!ROLL-MAX' : 0.0, + '32d!ROLL-CUR' : 0.0, + '33d!ROLL-STEP' : 0.0, + '34d!YAW-MIN' : 0.0, + '35d!YAW-MAX' : 0.0, + '36d!YAW-CUR' : 0.0, + '37d!YAW-STEP' : 0.0, + '38d!ZSIZE-MIN' : 0.0, + '39d!ZSIZE-MAX' : 0.0, + '40d!ZSIZE-CUR' : 1.0, + '41d!ZSIZE-STEP' : 0.0, + '42d!YSIZE-MIN' : 0.0, + '43d!YSIZE-MAX' : 0.0, + '44d!YSIZE-CUR' : 1.0, + '45d!YSIZE-STEP' : 0.0, + '46d!XSIZE-MIN' : 0.0, + '47d!XSIZE-MAX' : 0.0, + '48d!XSIZE-CUR' : 1.0, + '49d!XSIZE-STEP' : 0.0, + '50I!FLAG' : 1897582, + '51i!reserved2' : 0 +} + +FLTDOFDisplay = [4] + +FLTImage = { + '3i!RealU Direction' : 0, + '4i!RealV Direction' : 0, + '5i!UpX' : 0, + '6i!UpY' : 0, + '7i!File Format' : 0, + '8i!Min Filter' : 1, + '9i!Mag Filter' : 1, + '10i!Wrap' : 0, + '11i!WrapU' : 0, + '12i!WrapV' : 0, + '13i!Modified' : 0, + '14i!PivotX' : 0, + '15i!PivotY' : 0, + '16i!Enviorment' : 0, + '17i!WhiteAlpha' : 0, + '18i!reserved1' : 0, + '19i!reserved2' : 0, + '20i!reserved3' : 0, + '21i!reserved4' : 0, + '22i!reserved5' : 0, + '23i!reserved6' : 0, + '24i!reserved7' : 0, + '25i!reserved8' : 0, + '26i!reserved9' : 0, + '27d!RealU Direction' : 0, + '28d!RealV Direction' : 0, + '29i!Origin' : 0, + '30i!Kernel no.' : 0, + '31i!Internal Format' : 0, + '32i!External Format' : 0, + '33i!MipMap Filter?' : 0, + '34f!MMF1' : 0.0, + '35f!MMF2' : 0.0, + '36f!MMF3' : 0.0, + '37f!MMF4' : 0.0, + '38f!MMF5' : 0.0, + '39f!MMF6' : 0.0, + '40f!MMF7' : 0.0, + '41f!MMF8' : 0.0, + '42i!Tex CPs?' : 0, + '43f!LOD0 CP' : 0.0, + '44f!Scale0 CP' : 0.0, + '45f!LOD1 CP' : 0.0, + '46f!Scale1 CP' : 0.0, + '47f!LOD2 CP' : 0.0, + '48f!Scale2 CP' : 0.0, + '49f!LOD3 CP' : 0.0, + '50f!Scale3 CP' : 0.0, + '51f!LOD4 CP' : 0.0, + '52f!Scale4 CP' : 0.0, + '53f!LOD5 CP' : 0.0, + '54f!Scale5 CP' : 0.0, + '55f!LOD6 CP' : 0.0, + '56f!Scale6 CP' : 0.0, + '57f!LOD7 CP' : 0.0, + '58f!Scale7 CP' : 0.0, + '59f!Control Clamp' : 0.0, + '60i!Mag Alpha Filter' : 0, + '61i!Mag Color Filter' : 0, + '62f!reserved10' : 0, + '63f!reserved11' : 0, + '64f!reserved12' : 0, + '65f!reserved13' : 0, + '66f!reserved14' : 0, + '67f!reserved15' : 0, + '68f!reserved16' : 0, + '69f!reserved17' : 0, + '70f!reserved18' : 0, + '71d!Lambert Central' : 0.0, + '72d!Lambert Upper' : 0.0, + '73d!Lambert Lower' : 0.0, + '74d!reserved19' : 0, + '75f!reserved20' : 0, + '76f!reserved21' : 0, + '77f!reserved22' : 0, + '78f!reserved23' : 0, + '79f!reserved24' : 0, + '80i!Tex Detail?' : 0, + '81i!Tex J' : 0, + '82i!Tex K' : 0, + '83i!Tex M' : 0, + '84i!Tex N' : 0, + '85i!Tex Scramble' : 0, + '86i!Tex Tile?' : 0, + '87f!Tex Tile LLU' : 0.0, + '88f!Tex Tile LLV' : 0.0, + '89f!Tex Tile URU' : 0.0, + '90f!Tex Tile URV' : 0.0, + '91i!Projection' : 0, + '92i!Earth Model' : 0, + '93i!reserved25' : 0, + '94i!UTM Zone' : 0, + '95i!Image Origin' : 0, + '96i!GPU' : 0, + '97i!reserved26' : 0, + '98i!reserved27' : 0, + '99i!GPU Hemi' : 0, + '100i!reserved41' : 0, + '101i!reserved42' : 0, + '102i!reserved43' : 0, + '103i!Cubemap' : 0, + '104t588!reserved44' : '', + '105t512!Comments' : '', + '106i!reserved28' : 0, + '107i!reserved29' : 0, + '108i!reserved30' : 0, + '109i!reserved31' : 0, + '110i!reserved32' : 0, + '111i!reserved33' : 0, + '112i!reserved34' : 0, + '113i!reserved35' : 0, + '114i!reserved36' : 0, + '115i!reserved37' : 0, + '116i!reserved38' : 0, + '117i!reserved39' : 0, + '118i!reserved40' : 0, + '119i!reserved45' : 0, + '120i!Format Version' : 0, + '121i!GPU num' : 0, +} + +FLTImageDisplay = [18,19,29,21,22,23,24,25,26,62,63,64,65,66,67,68,69,70,74,75,76,77,78,79,93,97,98,102,114] + +FLTHeader = { + '3t8!id' : 'db', + '4i!version' : 1620, + '5i!editversion' : 0, + '6t32!date' : 0, + '7s!NGID' : 0, + '8s!NLID' : 0, + '9s!NOID' : 0, + '10s!NFID' : 0, + '11s!UMULT' : 1, + '12c!units' : 0, + '13c!set white' : 0, + '14I!flags' : 0x80000000, + '15i!reserved1' : 0, + '16i!reserved2' : 0, + '17i!reserved3' : 0, + '18i!reserved4' : 0, + '19i!reserved5' : 0, + '20i!reserved6' : 0, + '21i!projection type' : 0, + '22i!reserved7' : 0, + '23i!reserved8' : 0, + '24i!reserved9' : 0, + '25i!reserved10' : 0, + '26i!reserved11' : 0, + '27i!reserved12' : 0, + '28i!reserved13' : 0, + '29s!NDID' : 0, + '30s!vstore' : 1, + '31i!origin' : 0, + '32d!sw x' : 0, + '33d!sw y' : 0, + '34d!dx' : 0, + '35d!dy' : 0, + '36s!NSID' : 0, + '37s!NPID' : 0, + '38i!reserved14' : 0, + '39i!reserved15' : 0, + '40s!NCID' : 0, + '41s!NTID' : 0, + '42s!NBID' : 0, + '43s!NWID' : 0, + '44i!reserved14' : 0, + '45d!sw lat' : 0, + '46d!sw lon' : 0, + '47d!ne lat' : 0, + '48d!ne lon' : 0, + '49d!origin lat' : 0, + '50d!origin lon' : 0, + '51d!lambert lat1' : 0, + '52d!lambert lat2' : 0, + '53s!NLSID' : 0, + '54s!NLPID' : 0, + '55s!NRID' : 0, + '56s!NCATID' : 0, + '57s!reserved15' : 0, + '58s!reserved16' : 0, + '59s!reserved17' : 0, + '60s!reserved18' : 0, + '61i!ellipsoid model' : 1, + '62s!NAID' : 0, + '63s!NCVID' : 0, + '64s!utm zone' : 0, + '65t6!reserved19' : 0, + '66d!dz' : 0, + '67d!radius' : 0, + '68S!NMID' : 0, + '69S!NLPSID' : 0, + '70i!reserved20' : 0, + '71d!major axis' : 0, + '72d!minor axis' : 0, +} + +FLT_Records = { + 2 : FLTGroup, + 4 : FLTObject, + 73 : FLTLOD, + 63 : FLTXRef, + 14 : FLTDOF, + 1 : FLTHeader, + 111 : FLTInlineLP, + 'Image' : FLTImage +} + +def process_recordDefs(): + records = dict() + for record in FLT_Records: + props = dict() + for prop in FLT_Records[record]: + position = '' + slice = 0 + (format,name) = prop.split('!') + for i in format: + if i not in typecodes: + position = position + i + slice = slice + 1 + else: + break + type = format[slice:] + length = type[1:] + if len(length) == 0: + length = 1 + else: + type = type[0] + length = int(length) + + props[int(position)] = (type,length,prop) + records[record] = props + return records + + diff --git a/release/scripts/flt_toolbar.py b/release/scripts/flt_toolbar.py new file mode 100644 index 00000000000..d8a4aa8b4a0 --- /dev/null +++ b/release/scripts/flt_toolbar.py @@ -0,0 +1,594 @@ +#!BPY + +""" +Name: 'FLT Toolbar' +Blender: 240 +Group: 'Misc' +Tooltip: 'Tools for working with FLT databases' +""" + +__author__ = "Geoffrey Bantle" +__version__ = "1.0 11/21/07" +__email__ = ('scripts', 'Author, ') +__url__ = ('blender', 'elysiun') + +__bpydoc__ ="""\ +This script provides tools for working with OpenFlight databases in Blender. OpenFlight is a +registered trademark of MultiGen-Paradigm, Inc. + +Feature overview and more availible at: +http://wiki.blender.org/index.php/Scripts/Manual/FLTools +""" + +# -------------------------------------------------------------------------- +# flt_palettemanager.py version 0.1 2005/04/08 +# -------------------------------------------------------------------------- +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# Copyright (C) 2007: Blender Foundation +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + +import Blender.Draw as Draw +from Blender.BGL import * +import Blender +import flt_properties +reload(flt_properties) +from flt_properties import * + +xrefprefix = "" +xrefstack = list() +vofsstack = list() +vquatstack = list() +prop_w = 256 +prop_h = 256 + + +#event codes +evcode = { + "XREF_MAKE" : 100, + "XREF_EDIT" : 101, + "XREF_FILE" : 102, + "XREF_PICK" : 103, + "XREF_SELECT" : 104, + "XREF_POP" : 105, + "XREF_PREFIX" : 106, + "FACE_NAME" : 200, + "FACE_MAKESUB" : 201, + "FACE_KILLSUB" : 202, + "FACE_SELSUB" : 203, + "SCENE_UPDATE" : 303, + "IDPROP_COPY" : 501, + "IDPROP_KILL" : 502, + "CLIGHT_MAKE" : 700 +} + +XREF_PREFIX = None +XREF_MAKE = None +XREF_EDIT = None +XREF_SELECT = None +XREF_POP = None +FACE_MAKESUB = None +FACE_SELSUB = None +FACE_KILLSUB = None +IDPROP_KILL = None +IDPROP_COPY = None +SCENE_UPDATE = None +CLIGHT_MAKE = None + +def update_state(): + state = dict() + state["activeScene"] = Blender.Scene.getCurrent() + state["activeObject"] = state["activeScene"].getActiveObject() + if state["activeObject"] and not state["activeObject"].sel: + state["activeObject"] = None + state["activeMesh"] = None + if state["activeObject"] and state["activeObject"].type == 'Mesh': + state["activeMesh"] = state["activeObject"].getData(mesh=True) + + state["activeFace"] = None + if state["activeMesh"]: + if state["activeMesh"].faceUV and state["activeMesh"].activeFace != None: + state["activeFace"] = state["activeMesh"].faces[state["activeMesh"].activeFace] + + #update editmode + state["editmode"] = Blender.Window.EditMode() + + return state +def pack_face_index(index, intensity): + return ((127*intensity)+(128*index)) +def unpack_face_index(face_index): + index = face_index / 128 + intensity = float(face_index - 128.0 * index) / 127.0 + return(index,intensity) + +def idprops_append(object, typecode, props): + object.properties["FLT"] = dict() + object.properties["FLT"]['type'] = typecode + for prop in props: + object.properties["FLT"][prop] = props[prop] + object.properties["FLT"]['3t8!id'] = object.name + +def idprops_kill(object): + state = update_state() + if object and object.properties.has_key('FLT'): + object.properties.pop('FLT') + +def idprops_copy(source): + state = update_state() + if source.properties.has_key('FLT'): + for object in state["activeScene"].objects: + if object.sel and object != source and (state["activeScene"].Layers & object.Layers): + idprops_kill(object) + object.properties['FLT'] = dict() + for key in source.properties['FLT']: + object.properties['FLT'][key] = source.properties['FLT'][key] + +def update_all(): + state = update_state() + #update the baked FLT colors for all meshes. + for object in state["activeScene"].objects: + if object.type == "Mesh": + mesh = object.getData(mesh=True) + if 'FLT_COL' in mesh.faces.properties: + mesh.activeColorLayer = "FLT_Fcol" + for face in mesh.faces: + (index,intensity) = unpack_face_index(face.getProperty('FLT_COL')) + color = struct.unpack('>BBBB',struct.pack('>I',state["colors"][index])) + #update the vertex colors for this face + for col in face.col: + col.r = int(color[0] * intensity) + col.g = int(color[1] * intensity) + col.b = int(color[2] * intensity) + col.a = 255 + + +#Change this to find the deep parent +def xref_create(): + global xrefprefix + global xrefstack + global vofsstack + global vquatstack + global prop_w + global prop_h + + state = update_state() + + def findchildren(object): + children = list() + for candidate in state["activeScene"].objects: + if candidate.parent == object: + children.append(candidate) + retlist = list(children) + for child in children: + retlist = retlist + findchildren(child) + return retlist + + actObject = state["activeObject"] + if actObject and xrefprefix: + scenenames = list() + for scene in Blender.Scene.Get(): + scenenames.append(scene.name) + + if xrefprefix in scenenames: + #build a unique name for the xref... + suffix = 1 + found = False + while not found: + candidate = xrefprefix + str(suffix) + if not candidate in scenenames: + xrefname = candidate + found = True + suffix+=1 + else: + xrefname = xrefprefix + #create our XRef node + xnode = state["activeScene"].objects.new('Empty') + xnode.name = 'X:' + xrefname + xnode.properties['FLT'] = dict() + for prop in FLTXRef: + xnode.properties['FLT'][prop] = FLTXRef[prop] + xnode.properties['FLT']['3t200!filename'] = xrefname + '.flt' + xnode.properties['FLT']['type'] = 63 + xnode.enableDupGroup = True + xnode.DupGroup = Blender.Group.New(xrefname) #this is dangerous... be careful! + + #copy rot and loc of actObject + xnode.setLocation(actObject.getLocation()) + xnode.setEuler(actObject.getEuler()) + + #build the new scene + xrefscene = Blender.Scene.New(xrefname) + xrefscene.properties['FLT'] = dict() + xrefscene.properties['FLT']['Filename'] = xrefname + xrefscene.properties['FLT']['Main'] = 0 + + #find the children of actObject so that we can add them to the group + linkobjects = findchildren(actObject) + linkobjects.append(actObject) + for object in linkobjects: + xrefscene.objects.link(object) + state["activeScene"].objects.unlink(object) + xnode.DupGroup.objects.link(object) + #clear rotation of actObject and location + actObject.setLocation(0.0,0.0,0.0) + actObject.setEuler(0.0,0.0,0.0) + + xrefscene.update(1) + state["activeScene"].update(1) + +def xref_edit(): + global xrefprefix + global xrefstack + global vofsstack + global vquatstack + global prop_w + global prop_h + + state = update_state() + + actObject = state["activeObject"] + + if actObject and actObject.type == 'Empty' and actObject.DupGroup: +# if actObject.properties.has_key('FLT') and actObject.properties['FLT']['type'] == 63: + for FLTscene in Blender.Scene.Get(): + if FLTscene.properties.has_key('FLT') and FLTscene.name == actObject.DupGroup.name: + actObject.sel = 0 + xrefstack.append(state["activeScene"]) + vofsstack.append(Blender.Window.GetViewOffset()) + vquatstack.append(Blender.Window.GetViewQuat()) + FLTscene.makeCurrent() + Blender.Window.SetViewOffset(0.0,0.0,0.0) + +def xref_finish(): + global xrefprefix + global xrefstack + global vofsstack + global vquatstack + global prop_w + global prop_h + + state = update_state() + if xrefstack: + scene = xrefstack.pop() + Blender.Window.SetViewQuat(vquatstack.pop()) + Blender.Window.SetViewOffset(vofsstack.pop()) + scene.makeCurrent() + + +def sortSub(a,b): + aindex = a.getProperty("FLT_ORIGINDEX") + bindex = b.getProperty("FLT_ORIGINDEX") + + if aindex > bindex: + return 1 + elif aindex < bindex: + return -1 + return 0 + +def subface_make(): + global xrefprefix + global xrefstack + global vofsstack + global vquatstack + global prop_w + global prop_h + + editmode = 0 + if Blender.Window.EditMode(): + Blender.Window.EditMode(0) + editmode = 1 + + state = update_state() + + actmesh = state["activeMesh"] + activeFace = state["activeFace"] + if actmesh: + if not "FLT_ORIGINDEX" in actmesh.faces.properties: + actmesh.faces.addPropertyLayer("FLT_ORIGINDEX",Blender.Mesh.PropertyTypes["INT"]) + for i, face in enumerate(actmesh.faces): + face.setProperty("FLT_ORIGINDEX",i) + if not "FLT_SFLEVEL" in actmesh.faces.properties: + actmesh.faces.addPropertyLayer("FLT_SFLEVEL",Blender.Mesh.PropertyTypes["INT"]) + + #attach the subfaces to the active face. Note, this doesnt really work 100 percent properly yet, just enough for one level! + if activeFace: + #steps: + #remove actface and selected faces from the facelist + #quicksort facelist + #append actface and subfaces to end of facelist. + #generate new indices + facelist = list() + sublist = list() + for face in actmesh.faces: + facelist.append(face) + for face in facelist: + if face == activeFace: + face.setProperty("FLT_SFLEVEL",0) + sublist.insert(0,face) + elif face.sel: + face.setProperty("FLT_SFLEVEL",1) + sublist.append(face) + for face in sublist: + facelist.remove(face) + facelist.sort(sortSub) + for face in sublist: + facelist.append(face) + for i, face in enumerate(facelist): + face.setProperty("FLT_ORIGINDEX",i) + else: + pass + + if editmode: + Blender.Window.EditMode(1) + +def subface_kill(): + global xrefprefix + global xrefstack + global vofsstack + global vquatstack + global prop_w + global prop_h + + editmode = 0 + if Blender.Window.EditMode(): + Blender.Window.EditMode(0) + editmode = 1 + state = update_state() + + actmesh = state["activeMesh"] + if actmesh: + if "FLT_ORIGINDEX" in actmesh.faces.properties and "FLT_SFLEVEL" in actmesh.faces.properties: + for i,face in enumerate(actmesh.faces): + face.setProperty("FLT_ORIGINDEX",i) + face.setProperty("FLT_SFLEVEL",0) + if editmode: + Blender.Window.EditMode(1) + +def subface_select(): + global xrefprefix + global xrefstack + global vofsstack + global vquatstack + global prop_w + global prop_h + + editmode = 0 + if Blender.Window.EditMode(): + Blender.Window.EditMode(0) + editmode = 1 + state = update_state() + + actmesh = state["activeMesh"] + activeFace = state["activeFace"] + if actmesh and activeFace: + if "FLT_ORIGINDEX" in actmesh.faces.properties and "FLT_SFLEVEL" in actmesh.faces.properties: + facelist = list() + actIndex = None + sublevel = None + for face in actmesh.faces: + facelist.append(face) + facelist.sort(sortSub) + for i, face in enumerate(facelist): + if face == activeFace: + actIndex = i + sublevel = face.getProperty("FLT_SFLEVEL")+1 + break + leftover = facelist[actIndex+1:] + for face in leftover: + if face.getProperty("FLT_SFLEVEL") == sublevel: + face.sel = 1 + else: + break + if editmode: + Blender.Window.EditMode(1) + +def select_by_typecode(typecode): + global xrefprefix + global xrefstack + global vofsstack + global vquatstack + global prop_w + global prop_h + + state = update_state() + + for object in state["activeScene"].objects: + if object.properties.has_key('FLT') and object.properties['FLT']['type'] == typecode and state["activeScene"].Layers & object.Layers: + object.select(1) +def clight_make(): + state = update_state() + actmesh = state["activeMesh"] + actobj = state["activeObject"] + + if actobj and actmesh: + actobj.properties['FLT'] = dict() + actobj.properties['FLT']['type'] = 111 + for prop in FLTInlineLP: + actobj.properties['FLT'][prop] = FLTInlineLP[prop] + + actmesh.verts.addPropertyLayer("FLT_VCOL", Blender.Mesh.PropertyTypes["INT"]) + for v in actmesh.verts: + v.setProperty("FLT_VCOL", 67295) + +def event(evt,val): + if evt == Draw.ESCKEY: + Draw.Exit() + +def but_event(evt): + global xrefprefix + global xrefstack + global vofsstack + global vquatstack + global prop_w + global prop_h + global evcode + + state = update_state() + + #do Xref buttons + if evt == evcode["XREF_PREFIX"]: + xrefprefix = XREF_PREFIX.val + if evt == evcode["XREF_EDIT"]: + xref_edit() + if evt == evcode["XREF_SELECT"]: + select_by_typecode(63) + if evt == evcode["XREF_MAKE"]: + xref_create() + #do scene buttons + if evt == evcode["SCENE_UPDATE"]: + update_all() + #do face buttons + if evt == evcode["FACE_MAKESUB"]: + subface_make() + if evt== evcode["FACE_KILLSUB"]: + subface_kill() + if evt== evcode["FACE_SELSUB"]: + subface_select() + #common buttons + if evt == evcode["IDPROP_KILL"]: + if state["activeObject"]: + idprops_kill(state["activeObject"]) + if evt == evcode["IDPROP_COPY"]: + if state["activeObject"]: + idprops_copy(state["activeObject"]) + if evt == evcode["XREF_POP"]: + xref_finish() + if evt == evcode["CLIGHT_MAKE"]: + clight_make() + Draw.Redraw(1) + Blender.Window.RedrawAll() + + +def box(x,y,w,h,c,mode): + glColor3f(c[0],c[1],c[2]) + if mode == "outline": + glBegin(GL_LINE_LOOP) + else: + glBegin(GL_POLYGON) + glVertex2i(x,y) + glVertex2i(x+w,y) + glVertex2i(x+w,y+h) + glVertex2i(x,y+h) + glEnd() + +def draw_postcommon(x,y,finaly): + global sheetlabel + global xrefprefix + global xrefstack + global vofsstack + global vquatstack + global prop_w + global prop_h + global evcode + + state = update_state() + + width = prop_w + height = prop_h + + #draw the header + glColor3f(0.15,0.15,0.15) + glBegin(GL_POLYGON) + glVertex2i(x-1,y) + glVertex2i(x+width+1,y) + glVertex2i(x+width+1,y-25) + glVertex2i(x-1,y-25) + glEnd() + glColor3f(1,1,1) + glRasterPos2i(x,y-20) + sheetlabel = Blender.Draw.Text("FLT Tools Panel") + #draw the box outline + glColor3f(0,0,0) + glBegin(GL_LINE_LOOP) + glVertex2i(x-1,y) + glVertex2i(x+1+width,y) + glVertex2i(x+1+width,finaly-1) + glVertex2i(x-1,finaly-1) + glEnd() + return finaly + + +def draw_propsheet(x,y): + global XREF_PREFIX + global XREF_MAKE + global XREF_EDIT + global XREF_SELECT + global XREF_POP + global FACE_MAKESUB + global FACE_SELSUB + global FACE_KILLSUB + global IDPROP_KILL + global IDPROP_COPY + global SCENE_UPDATE + global CLIGHT_MAKE + global xrefprefix + global xrefstack + global vofsstack + global vquatstack + global prop_w + global prop_h + global evcode + + state = update_state() + + width = prop_w + height = prop_h + origx = x + origy = y + + #draw Xref tools + y = y-20 + XREF_PREFIX = Blender.Draw.String("XRef Name:",evcode["XREF_PREFIX"],x,y,width,20,xrefprefix,18,"Xref prefix name, Actual name is generated from this") + y = y-20 + XREF_MAKE = Blender.Draw.PushButton("Make XRef",evcode["XREF_MAKE"],x,y,width,20,"Make External Reference") + y = y-20 + XREF_EDIT = Blender.Draw.PushButton("Edit XRef",evcode["XREF_EDIT"],x,y,width,20,"Edit External Reference") + y = y-20 + XREF_SELECT = Blender.Draw.PushButton("Select XRefs",evcode["XREF_SELECT"],x,y,width,20,"Select External References") + y = y - 20 + XREF_POP = Blender.Draw.PushButton("Return to previous scene",evcode["XREF_POP"],x,y,width,20,"Go up one level in xref hierarchy") + + #Draw facetools + y = y-20 + FACE_MAKESUB = Blender.Draw.PushButton("Make Subfaces",evcode["FACE_MAKESUB"],x,y,width,20,"Make subfaces") + y = y-20 + FACE_SELSUB = Blender.Draw.PushButton("Select Subfaces",evcode["FACE_SELSUB"],x,y,width,20,"Select subfaces") + y = y-20 + FACE_KILLSUB = Blender.Draw.PushButton("Kill Subfaces",evcode["FACE_KILLSUB"],x,y,width,20,"Kill subfaces") + + #Draw ID Property tools + y = y - 20 + IDPROP_KILL = Blender.Draw.PushButton("Delete ID props",evcode["IDPROP_KILL"],x,y,width,20,"Delete ID props") + y = y - 20 + IDPROP_COPY = Blender.Draw.PushButton("Copy to selected",evcode["IDPROP_COPY"],x,y,width,20, "Copy from active to all selected") + + y= y - 20 + CLIGHT_MAKE = Blender.Draw.PushButton("Make Light Point", evcode["CLIGHT_MAKE"],x,y,width,20,"Create inline light points from current mesh") + #General tools + y = y-20 + SCENE_UPDATE = Blender.Draw.PushButton("Update All",evcode["SCENE_UPDATE"],x,y,width,20,"Update all vertex colors") + draw_postcommon(origx, origy,y) + +def gui(): + #draw the propsheet/toolbox. + psheety = 256 + #psheetx = psheety + 10 + draw_propsheet(0,psheety) +Draw.Register(gui,event,but_event) + From e64a44266ccba44a7e0482eb059e82d90920b3db Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 22 Nov 2007 10:10:57 +0000 Subject: [PATCH 27/29] SetPivot, patch from malefico, #7785 also added GetPivot --- source/blender/python/api2_2x/Window.c | 72 ++++++++++++++++++++- source/blender/python/api2_2x/doc/Window.py | 14 ++++ 2 files changed, 85 insertions(+), 1 deletion(-) diff --git a/source/blender/python/api2_2x/Window.c b/source/blender/python/api2_2x/Window.c index 323f209651a..c5c0860a921 100644 --- a/source/blender/python/api2_2x/Window.c +++ b/source/blender/python/api2_2x/Window.c @@ -61,6 +61,19 @@ #include "gen_utils.h" #include "Armature.h" +/* Pivot Types +-0 for Bounding Box Center; \n\ +-1 for 3D Cursor\n\ +-2 for Individual Centers\n\ +-3 for Median Point\n\ +-4 for Active Object"; */ + +#define PIVOT_BOUNDBOX 0 +#define PIVOT_CURSOR 1 +#define PIVOT_INDIVIDUAL 2 +#define PIVOT_MEDIAN 3 +#define PIVOT_ACTIVE 4 + /* See Draw.c */ extern int EXPP_disable_force_draw; extern void setcameratoview3d(void); @@ -106,6 +119,9 @@ static PyObject *M_Window_GetScreens( PyObject * self ); static PyObject *M_Window_SetScreen( PyObject * self, PyObject * value ); static PyObject *M_Window_GetScreenInfo( PyObject * self, PyObject * args, PyObject * kwords ); +static PyObject *M_Window_GetPivot( PyObject * self ); +static PyObject *M_Window_SetPivot( PyObject * self, PyObject * value ); + PyObject *Window_Init( void ); @@ -287,6 +303,18 @@ Each dictionary has keys:\n\ 'win': window type, see Blender.Window.Types dict;\n\ 'id': area's id."; +static char M_Window_SetPivot_doc[] = + "(Pivot) - Set Pivot Mode for 3D Viewport:\n\ +Options are: \n\ +-PivotTypes.BOUNDBOX for Bounding Box Center; \n\ +-PivotTypes.CURSOR for 3D Cursor\n\ +-PivotTypes.INDIVIDUAL for Individual Centers\n\ +-PivotTypes.MEDIAN for Median Point\n\ +-PivotTypes.ACTIVE for Active Object"; + +static char M_Window_GetPivot_doc[] = + "Return the pivot for the active 3d window"; + /*****************************************************************************/ /* Python method structure definition for Blender.Window module: */ /*****************************************************************************/ @@ -374,6 +402,10 @@ struct PyMethodDef M_Window_methods[] = { M_Window_SetScreen_doc}, {"GetScreenInfo", ( PyCFunction ) M_Window_GetScreenInfo, METH_VARARGS | METH_KEYWORDS, M_Window_GetScreenInfo_doc}, + {"GetPivot", ( PyCFunction ) M_Window_GetPivot, METH_NOARGS, + M_Window_GetPivot_doc}, + {"SetPivot", ( PyCFunction ) M_Window_SetPivot, METH_O, + M_Window_SetPivot_doc}, {NULL, NULL, 0, NULL} }; @@ -1454,12 +1486,38 @@ static PyObject *M_Window_GetScreenInfo( PyObject * self, PyObject * args, return list; } +static PyObject *M_Window_GetPivot( PyObject * self ) +{ + if (G.vd) { + return PyInt_FromLong( G.vd->around ); + } + Py_RETURN_NONE; +} + +static PyObject *M_Window_SetPivot( PyObject * self, PyObject * value) + +{ + short pivot; + if (G.vd) { + pivot = (short)PyInt_AsLong( value ); + + if ( pivot > 4 || pivot < 0 ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "Expected a constant from Window.PivotTypes" ); + + G.vd->around = pivot; + } + Py_RETURN_NONE; +} + + + /*****************************************************************************/ /* Function: Window_Init */ /*****************************************************************************/ PyObject *Window_Init( void ) { - PyObject *submodule, *Types, *Qual, *MButs, *dict; + PyObject *submodule, *Types, *Qual, *MButs, *PivotTypes, *dict; submodule = Py_InitModule3( "Blender.Window", M_Window_methods, @@ -1472,6 +1530,7 @@ PyObject *Window_Init( void ) Types = PyConstant_New( ); Qual = PyConstant_New( ); MButs = PyConstant_New( ); + PivotTypes = PyConstant_New( ); if( Types ) { BPy_constant *d = ( BPy_constant * ) Types; @@ -1522,5 +1581,16 @@ PyObject *Window_Init( void ) PyModule_AddObject( submodule, "MButs", MButs ); } + if( PivotTypes ) { + BPy_constant *d = ( BPy_constant * ) PivotTypes; + + PyConstant_Insert(d, "BOUNDBOX", PyInt_FromLong( PIVOT_BOUNDBOX ) ); + PyConstant_Insert(d, "CURSOR", PyInt_FromLong( PIVOT_CURSOR ) ); + PyConstant_Insert(d, "MEDIAN", PyInt_FromLong( PIVOT_MEDIAN ) ); + PyConstant_Insert(d, "ACTIVE", PyInt_FromLong( PIVOT_ACTIVE ) ); + PyConstant_Insert(d, "INDIVIDUAL", PyInt_FromLong( PIVOT_INDIVIDUAL ) ); + + PyModule_AddObject( submodule, "PivotTypes", PivotTypes ); + } return submodule; } diff --git a/source/blender/python/api2_2x/doc/Window.py b/source/blender/python/api2_2x/doc/Window.py index b5145d34ca2..7fceeb757de 100644 --- a/source/blender/python/api2_2x/doc/Window.py +++ b/source/blender/python/api2_2x/doc/Window.py @@ -210,6 +210,20 @@ def SetCursorPos (coords): can be done with L{Redraw}. """ +def GetPivot (): + """ + Get the pivot for the active 3D view. + @rtype: int + @return: constant - Window.PivotTypes + """ + +def SetPivot (pivot): + """ + Set the pivot on the active 3D view. + @type pivot: int + @param pivot: constant - Window.PivotTypes + """ + def WaitCursor (bool): """ Set cursor to wait or back to normal mode. From 0d6d89a27bba554409fd26253a99487558daf80d Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 22 Nov 2007 14:10:51 +0000 Subject: [PATCH 28/29] wizard_curve2tree - mistake while debugging. buttons_shading.c - short names for world settings were not needed. --- release/scripts/wizard_curve2tree.py | 1 - source/blender/src/buttons_shading.c | 8 ++++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/release/scripts/wizard_curve2tree.py b/release/scripts/wizard_curve2tree.py index 4b8a7087a0b..041fe72f6f0 100644 --- a/release/scripts/wizard_curve2tree.py +++ b/release/scripts/wizard_curve2tree.py @@ -2542,7 +2542,6 @@ def Prefs2IDProp(idprop, prefs): idprop[ID_SLOT_NAME] = new_prefs def IDProp2Prefs(idprop, prefs): - prefs = idprop[ID_SLOT_NAME] try: prefs = idprop[ID_SLOT_NAME] except: diff --git a/source/blender/src/buttons_shading.c b/source/blender/src/buttons_shading.c index e42a0570fe7..258afa1175e 100644 --- a/source/blender/src/buttons_shading.c +++ b/source/blender/src/buttons_shading.c @@ -2098,13 +2098,13 @@ static void world_panel_mistaph(World *wrld) uiBlockSetCol(block, TH_AUTO); uiBlockBeginAlign(block); - uiDefButS(block, ROW, B_WORLDPRV2, "Qua", 10, 90, 40, 19, &wrld->mistype, 1.0, 0.0, 0, 0, "Mist uses quadratic progression"); + uiDefButS(block, ROW, B_WORLDPRV2, "Quad", 10, 90, 40, 19, &wrld->mistype, 1.0, 0.0, 0, 0, "Mist uses quadratic progression"); uiDefButS(block, ROW, B_WORLDPRV2, "Lin", 50, 90, 50, 19, &wrld->mistype, 1.0, 1.0, 0, 0, "Mist uses linear progression"); uiDefButS(block, ROW, B_WORLDPRV2, "Sqr", 100, 90, 50, 19, &wrld->mistype, 1.0, 2.0, 0, 0, "Mist uses inverse quadratic progression"); uiBlockBeginAlign(block); - uiDefButF(block, NUM,B_WORLDPRV2, "Sta:",10,70,140,19, &wrld->miststa, 0.0, 10000.0, 10, 0, "Specifies the starting distance of the mist"); - uiDefButF(block, NUM,B_WORLDPRV2, "Di:",10,50,140,19, &wrld->mistdist, 0.0,10000.0, 10, 00, "Specifies the depth of the mist"); - uiDefButF(block, NUM,B_WORLDPRV2,"Hi:", 10,30,140,19, &wrld->misthi,0.0,100.0, 10, 0, "Specifies the factor for a less dense mist with increasing height"); + uiDefButF(block, NUM,B_WORLDPRV2, "Start:",10,70,140,19, &wrld->miststa, 0.0, 10000.0, 10, 0, "Specifies the starting distance of the mist"); + uiDefButF(block, NUM,B_WORLDPRV2, "Dist:",10,50,140,19, &wrld->mistdist, 0.0,10000.0, 10, 00, "Specifies the depth of the mist"); + uiDefButF(block, NUM,B_WORLDPRV2,"Height:", 10,30,140,19, &wrld->misthi,0.0,100.0, 10, 0, "Specifies the factor for a less dense mist with increasing height"); uiDefButF(block, NUMSLI, B_WORLDPRV2, "Misi ", 10,10,140,19, &(wrld->misi), 0., 1.0, 0, 0, "Sets the mist intensity"); uiBlockEndAlign(block); From a03836312463813e366f1043093625dafd3ebd2b Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 22 Nov 2007 16:30:14 +0000 Subject: [PATCH 29/29] mesh_wire.py - gave an error with no faces, wizard_curve2tree.py - didnt work with no bevel object Curve.py - ext1, ext2 didnt reference the interface names. --- release/scripts/bpymodules/BPyMessages.py | 2 ++ release/scripts/mesh_wire.py | 27 +++++++++++++--------- release/scripts/wizard_curve2tree.py | 4 +++- source/blender/python/api2_2x/doc/Curve.py | 4 ++-- 4 files changed, 23 insertions(+), 14 deletions(-) diff --git a/release/scripts/bpymodules/BPyMessages.py b/release/scripts/bpymodules/BPyMessages.py index 0ff8e178ac1..8ee1aa6c707 100644 --- a/release/scripts/bpymodules/BPyMessages.py +++ b/release/scripts/bpymodules/BPyMessages.py @@ -11,6 +11,8 @@ def Error_NoMeshUvActive(): Draw.PupMenu('Error%t|Active object is not a mesh with texface') def Error_NoMeshMultiresEdit(): Draw.PupMenu('Error%t|Unable to complete action with multires enabled') +def Error_NoMeshFaces(): + Draw.PupMenu('Error%t|Mesh has no faces') # File I/O messages def Error_NoFile(path): diff --git a/release/scripts/mesh_wire.py b/release/scripts/mesh_wire.py index 35cfa325497..bd38c47a9b9 100644 --- a/release/scripts/mesh_wire.py +++ b/release/scripts/mesh_wire.py @@ -44,6 +44,7 @@ from BPyMathutils import angleToLength import mesh_solidify import BPyMessages +reload(BPyMessages) import bpy @@ -219,9 +220,7 @@ def solid_wire(ob_orig, me_orig, sce, PREF_THICKNESS, PREF_SOLID, PREF_SHARP, PR for ii in vusers: co += me.verts[ii].co co /= len(vusers) - - - + me.faces.delete(1, range(len(me.faces))) me.faces.extend(new_faces) @@ -245,6 +244,18 @@ def main(): BPyMessages.Error_NoMeshActive() return + # Saves the editmode state and go's out of + # editmode if its enabled, we cant make + # changes to the mesh data while in editmode. + is_editmode = Window.EditMode() + Window.EditMode(0) + + me = ob_act.getData(mesh=1) # old NMesh api is default + if len(me.faces)==0: + BPyMessages.Error_NoMeshFaces() + if is_editmode: Window.EditMode(1) + return + # Create the variables. PREF_THICK = Blender.Draw.Create(0.005) PREF_SOLID = Blender.Draw.Create(1) @@ -259,16 +270,10 @@ def main(): ] if not Blender.Draw.PupBlock('Solid Wireframe', pup_block): + if is_editmode: Window.EditMode(1) return - # Saves the editmode state and go's out of - # editmode if its enabled, we cant make - # changes to the mesh data while in editmode. - is_editmode = Window.EditMode() - Window.EditMode(0) - Window.WaitCursor(1) - me = ob_act.getData(mesh=1) # old NMesh api is default t = sys.time() # Run the mesh editing function @@ -282,4 +287,4 @@ def main(): # This lets you can import the script without running it if __name__ == '__main__': - main() \ No newline at end of file + main() diff --git a/release/scripts/wizard_curve2tree.py b/release/scripts/wizard_curve2tree.py index 041fe72f6f0..9b23d9e7b11 100644 --- a/release/scripts/wizard_curve2tree.py +++ b/release/scripts/wizard_curve2tree.py @@ -183,7 +183,9 @@ class tree: bb = curve.bevob.boundingBox # self.limbScale = (bb[0] - bb[7]).length / 2.825 # THIS IS GOOD WHEN NON SUBSURRFED self.limbScale = (bb[0] - bb[7]).length / 1.8 - + elif curve.ext2 != 0.0: + self.limbScale = curve.ext2 * 1.5 + # forward_diff_bezier will fill in the blanks # nice we can reuse these for every curve segment :) pointlist = [[None, None, None] for i in xrange(steps+1)] diff --git a/source/blender/python/api2_2x/doc/Curve.py b/source/blender/python/api2_2x/doc/Curve.py index 5e6df688953..5ccf5834ebd 100644 --- a/source/blender/python/api2_2x/doc/Curve.py +++ b/source/blender/python/api2_2x/doc/Curve.py @@ -115,9 +115,9 @@ class Curve: @type resolv: int @ivar width: The Curve Data width [0 - 2]. @type width: float - @ivar ext1: The Curve Data extent1 (for bevels). + @ivar ext1: The Curve Data extent1 Called "Extrude" in the user interface (for bevels only). @type ext1: float - @ivar ext2: The Curve Data extent2 (for bevels). + @ivar ext2: The Curve Data extent2 - Called "Bevel Depth" in the user interface (for bevels only). @type ext2: float @ivar loc: The Curve Data location(from the center). @type loc: list of 3 floats