From 75385297521cf6a195dede60793583b70bcb1ac7 Mon Sep 17 00:00:00 2001 From: Nathan Letwory Date: Sat, 11 Sep 2010 10:12:56 +0000 Subject: Remove for retag [[Split portion of a mixed commit.]] --- add_curve_aceous_galore.py | 1120 ----------------- add_curve_torus_knots.py | 320 ----- add_mesh_3d_function_surface.py | 636 ---------- add_mesh_BoltFactory/Boltfactory.py | 306 ----- add_mesh_BoltFactory/__init__.py | 59 - add_mesh_BoltFactory/createMesh.py | 2111 -------------------------------- add_mesh_BoltFactory/preset_utils.py | 53 - add_mesh_BoltFactory/presets/M10.py | 22 - add_mesh_BoltFactory/presets/M12.py | 22 - add_mesh_BoltFactory/presets/M3.py | 22 - add_mesh_BoltFactory/presets/M4.py | 22 - add_mesh_BoltFactory/presets/M5.py | 22 - add_mesh_BoltFactory/presets/M6.py | 22 - add_mesh_BoltFactory/presets/M8.py | 22 - add_mesh_ant_landscape.py | 913 -------------- add_mesh_extras.py | 776 ------------ add_mesh_gears.py | 937 -------------- add_mesh_gemstones.py | 472 ------- add_mesh_pipe_joint.py | 1306 -------------------- add_mesh_solid.py | 902 -------------- add_mesh_twisted_torus.py | 363 ------ curve_simplify.py | 597 --------- io_anim_camera.py | 164 --- io_export_directx_x.py | 1154 ----------------- io_export_unreal_psk_psa.py | 1593 ------------------------ io_import_images_as_planes.py | 525 -------- io_import_scene_lwo.py | 1247 ------------------- io_import_scene_mhx.py | 2245 ---------------------------------- io_import_scene_unreal_psk.py | 602 --------- io_mesh_raw/__init__.py | 69 -- io_mesh_raw/export_raw.py | 112 -- io_mesh_raw/import_raw.py | 143 --- io_mesh_stl/__init__.py | 163 --- io_mesh_stl/blender_utils.py | 53 - io_mesh_stl/stl_utils.py | 228 ---- mesh_relax.py | 128 -- mesh_surface_sketch.py | 819 ------------- object_add_chain.py | 150 --- object_cloud_gen.py | 674 ---------- object_fracture/__init__.py | 80 -- object_fracture/data.blend | Bin 232271 -> 0 bytes object_fracture/fracture_ops.py | 490 -------- object_fracture/fracture_setup.py | 74 -- render_povray/__init__.py | 131 -- render_povray/render.py | 790 ------------ render_povray/ui.py | 136 -- render_renderfarmfi.py | 820 ------------- space_view3d_align_tools.py | 338 ----- space_view3d_materials_utils.py | 689 ----------- space_view3d_panel_measure.py | 1065 ---------------- space_view3d_property_chart.py | 230 ---- space_view3d_spacebar_menu.py | 1471 ---------------------- system_blend_info.py | 207 ---- 53 files changed, 27615 deletions(-) delete mode 100644 add_curve_aceous_galore.py delete mode 100644 add_curve_torus_knots.py delete mode 100644 add_mesh_3d_function_surface.py delete mode 100644 add_mesh_BoltFactory/Boltfactory.py delete mode 100644 add_mesh_BoltFactory/__init__.py delete mode 100644 add_mesh_BoltFactory/createMesh.py delete mode 100644 add_mesh_BoltFactory/preset_utils.py delete mode 100644 add_mesh_BoltFactory/presets/M10.py delete mode 100644 add_mesh_BoltFactory/presets/M12.py delete mode 100644 add_mesh_BoltFactory/presets/M3.py delete mode 100644 add_mesh_BoltFactory/presets/M4.py delete mode 100644 add_mesh_BoltFactory/presets/M5.py delete mode 100644 add_mesh_BoltFactory/presets/M6.py delete mode 100644 add_mesh_BoltFactory/presets/M8.py delete mode 100644 add_mesh_ant_landscape.py delete mode 100644 add_mesh_extras.py delete mode 100644 add_mesh_gears.py delete mode 100644 add_mesh_gemstones.py delete mode 100644 add_mesh_pipe_joint.py delete mode 100644 add_mesh_solid.py delete mode 100644 add_mesh_twisted_torus.py delete mode 100644 curve_simplify.py delete mode 100644 io_anim_camera.py delete mode 100644 io_export_directx_x.py delete mode 100644 io_export_unreal_psk_psa.py delete mode 100644 io_import_images_as_planes.py delete mode 100644 io_import_scene_lwo.py delete mode 100644 io_import_scene_mhx.py delete mode 100644 io_import_scene_unreal_psk.py delete mode 100644 io_mesh_raw/__init__.py delete mode 100644 io_mesh_raw/export_raw.py delete mode 100644 io_mesh_raw/import_raw.py delete mode 100644 io_mesh_stl/__init__.py delete mode 100644 io_mesh_stl/blender_utils.py delete mode 100644 io_mesh_stl/stl_utils.py delete mode 100644 mesh_relax.py delete mode 100644 mesh_surface_sketch.py delete mode 100644 object_add_chain.py delete mode 100644 object_cloud_gen.py delete mode 100644 object_fracture/__init__.py delete mode 100644 object_fracture/data.blend delete mode 100644 object_fracture/fracture_ops.py delete mode 100644 object_fracture/fracture_setup.py delete mode 100644 render_povray/__init__.py delete mode 100644 render_povray/render.py delete mode 100644 render_povray/ui.py delete mode 100644 render_renderfarmfi.py delete mode 100644 space_view3d_align_tools.py delete mode 100644 space_view3d_materials_utils.py delete mode 100644 space_view3d_panel_measure.py delete mode 100644 space_view3d_property_chart.py delete mode 100644 space_view3d_spacebar_menu.py delete mode 100644 system_blend_info.py diff --git a/add_curve_aceous_galore.py b/add_curve_aceous_galore.py deleted file mode 100644 index 9de8c015..00000000 --- a/add_curve_aceous_galore.py +++ /dev/null @@ -1,1120 +0,0 @@ -# ##### 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -# ##### END GPL LICENSE BLOCK ##### - -bl_addon_info = { - 'name': 'Curveaceous Galore!', - 'author': 'Jimmy Hazevoet, testscreenings', - 'version': (0,1), - 'blender': (2, 5, 3), - 'api': 31667, - 'location': 'Add Curve menu', - 'description': 'adds many types of curves', - 'warning': '', # used for warning icon and text in addons panel - 'wiki_url': 'http://wiki.blender.org/index.php/Extensions:2.5/Py/' \ - 'Scripts/Curve/Curves_Galore', - 'tracker_url': 'https://projects.blender.org/tracker/index.php?'\ - 'func=detail&aid=22404&group_id=153&atid=469', - 'category': 'Add Curve'} - - -##------------------------------------------------------------ -#### import modules -import bpy -from bpy.props import * -from mathutils import * -from math import * -###------------------------------------------------------------ -#### Some functions to use with others: -###------------------------------------------------------------ -''' -#------------------------------------------------------------ -# Generate random number: -def randnum( low=0.0, high=1.0, seed=0 ): - """ - randnum( low=0.0, high=1.0, seed=0 ) - - Create random number - - Parameters: - low - lower range - (type=float) - high - higher range - (type=float) - seed - the random seed number, if seed is 0, the current time will be used instead - (type=int) - Returns: - a random number - (type=float) - """ - - s = Noise.setRandomSeed( seed ) - rnum = Noise.random() - rnum = rnum*(high-low) - rnum = rnum+low - return rnum - - - -#------------------------------------------------------------ -# Make some noise: -def vTurbNoise((x,y,z), iScale=0.25, Size=1.0, Depth=6, Hard=0, Basis=0, Seed=0 ): - """ - vTurbNoise((x,y,z), iScale=0.25, Size=1.0, Depth=6, Hard=0, Basis=0, Seed=0 ) - - Create randomised vTurbulence noise - - Parameters: - xyz - (x,y,z) float values. - (type=3-float tuple) - iScale - noise intensity scale - (type=float) - Size - noise size - (type=float) - Depth - number of noise values added. - (type=int) - Hard - noise hardness: 0 - soft noise; 1 - hard noise - (type=int) - basis - type of noise used for turbulence - (type=int) - Seed - the random seed number, if seed is 0, the current time will be used instead - (type=int) - Returns: - the generated turbulence vector. - (type=3-float list) - """ - - rand = randnum(-100,100,Seed) - if Basis ==9: Basis = 14 - vTurb = Noise.vTurbulence(( x/Size+rand, y/Size+rand, z/Size+rand ), Depth, Hard, Basis ) - tx = vTurb[0]*iScale - ty = vTurb[1]*iScale - tz = vTurb[2]*iScale - return tx,ty,tz - - - -#------------------------------------------------------------ -# Axis: ( used in 3DCurve Turbulence ) -def AxisFlip((x,y,z), x_axis=1, y_axis=1, z_axis=1, flip=0 ): - if flip != 0: - flip *= -1 - else: flip = 1 - x *= x_axis*flip - y *= y_axis*flip - z *= z_axis*flip - return x,y,z -''' - -###------------------------------------------------------------------- -#### 2D Curve shape functions: -###------------------------------------------------------------------- - -##------------------------------------------------------------ -# 2DCurve: Profile: L, H, T, U, Z -def ProfileCurve(type=0, a=0.25, b=0.25): - """ - ProfileCurve( type=0, a=0.25, b=0.25 ) - - Create profile curve - - Parameters: - type - select profile type, L, H, T, U, Z - (type=int) - a - a scaling parameter - (type=float) - b - b scaling parameter - (type=float) - Returns: - a list with lists of x,y,z coordinates for curve points, [[x,y,z],[x,y,z],...n] - (type=list) - """ - - newpoints = [] - if type ==1: - ## H: - a*=0.5 - b*=0.5 - newpoints = [ [ -1.0, 1.0, 0.0 ], [ -1.0+a, 1.0, 0.0 ], - [ -1.0+a, b, 0.0 ], [ 1.0-a, b, 0.0 ], [ 1.0-a, 1.0, 0.0 ], - [ 1.0, 1.0, 0.0 ], [ 1.0, -1.0, 0.0 ], [ 1.0-a, -1.0, 0.0 ], - [ 1.0-a, -b, 0.0 ], [ -1.0+a, -b, 0.0 ], [ -1.0+a, -1.0, 0.0 ], - [ -1.0, -1.0, 0.0 ] ] - elif type ==2: - ## T: - a*=0.5 - newpoints = [ [ -1.0, 1.0, 0.0 ], [ 1.0, 1.0, 0.0 ], - [ 1.0, 1.0-b, 0.0 ], [ a, 1.0-b, 0.0 ], [ a, -1.0, 0.0 ], - [ -a, -1.0, 0.0 ], [ -a, 1.0-b, 0.0 ], [ -1.0, 1.0-b, 0.0 ] ] - elif type ==3: - ## U: - a*=0.5 - newpoints = [ [ -1.0, 1.0, 0.0 ], [ -1.0+a, 1.0, 0.0 ], - [ -1.0+a, -1.0+b, 0.0 ], [ 1.0-a, -1.0+b, 0.0 ], [ 1.0-a, 1.0, 0.0 ], - [ 1.0, 1.0, 0.0 ], [ 1.0, -1.0, 0.0 ], [ -1.0, -1.0, 0.0 ] ] - elif type ==4: - ## Z: - a*=0.5 - newpoints = [ [ -0.5, 1.0, 0.0 ], [ a, 1.0, 0.0 ], - [ a, -1.0+b, 0.0 ], [ 1.0, -1.0+b, 0.0 ], [ 1.0, -1.0, 0.0 ], - [ -a, -1.0, 0.0 ], [ -a, 1.0-b, 0.0 ], [ -1.0, 1.0-b, 0.0 ], - [ -1.0, 1.0, 0.0 ] ] - else: - ## L: - newpoints = [ [ -1.0, 1.0, 0.0 ], [ -1.0+a, 1.0, 0.0 ], - [ -1.0+a, -1.0+b, 0.0 ], [ 1.0, -1.0+b, 0.0 ], - [ 1.0, -1.0, 0.0 ], [ -1.0, -1.0, 0.0 ] ] - return newpoints - -##------------------------------------------------------------ -# 2DCurve: Miscellaneous.: Diamond, Arrow1, Arrow2, Square, .... -def MiscCurve(type=1, a=1.0, b=0.5, c=90.0): - """ - MiscCurve( type=1, a=1.0, b=0.5, c=90.0 ) - - Create miscellaneous curves - - Parameters: - type - select type, Diamond, Arrow1, Arrow2, Square - (type=int) - a - a scaling parameter - (type=float) - b - b scaling parameter - (type=float) - c - c scaling parameter - (type=float) - doesn't seem to do anything - Returns: - a list with lists of x,y,z coordinates for curve points, [[x,y,z],[x,y,z],...n] - (type=list) - """ - - newpoints = [] - a*=0.5 - b*=0.5 - if type ==1: - ## diamond: - newpoints = [ [ 0.0, b, 0.0 ], [ a, 0.0, 0.0 ], [ 0.0, -b, 0.0 ], [ -a, 0.0, 0.0 ] ] - elif type ==2: - ## Arrow1: - newpoints = [ [ -a, b, 0.0 ], [ a, 0.0, 0.0 ], [ -a, -b, 0.0 ], [ 0.0, 0.0, 0.0 ] ] - elif type ==3: - ## Arrow2: - newpoints = [ [ -1.0, b, 0.0 ], [ -1.0+a, b, 0.0 ], - [ -1.0+a, 1.0, 0.0 ], [ 1.0, 0.0, 0.0 ], - [ -1.0+a, -1.0, 0.0 ], [ -1.0+a, -b, 0.0 ], - [ -1.0, -b, 0.0 ] ] - elif type ==4: - ## Rounded square: - newpoints = [ [ -a, b-b*0.2, 0.0 ], [ -a+a*0.05, b-b*0.05, 0.0 ], [ -a+a*0.2, b, 0.0 ], - [ a-a*0.2, b, 0.0 ], [ a-a*0.05, b-b*0.05, 0.0 ], [ a, b-b*0.2, 0.0 ], - [ a, -b+b*0.2, 0.0 ], [ a-a*0.05, -b+b*0.05, 0.0 ], [ a-a*0.2, -b, 0.0 ], - [ -a+a*0.2, -b, 0.0 ], [ -a+a*0.05, -b+b*0.05, 0.0 ], [ -a, -b+b*0.2, 0.0 ] ] - - #elif type ==15: - ## : - #newpoints = [ [ x,y,z ] ] - else: - ## Square: - newpoints = [ [ -a, b, 0.0 ], [ a, b, 0.0 ], [ a, -b, 0.0 ], [ -a, -b, 0.0 ] ] - return newpoints - -##------------------------------------------------------------ -# 2DCurve: Star: -def StarCurve(starpoints=8, innerradius=0.5, outerradius=1.0, twist=0.0): - """ - StarCurve( starpoints=8, innerradius=0.5, outerradius=1.0, twist=0.0 ) - - Create star shaped curve - - Parameters: - starpoints - the number of points - (type=int) - innerradius - innerradius - (type=float) - outerradius - outerradius - (type=float) - twist - twist amount - (type=float) - Returns: - a list with lists of x,y,z coordinates for curve points, [[x,y,z],[x,y,z],...n] - (type=list) - """ - - newpoints = [] - step = (2.0/(starpoints)) - i = 0 - while i < starpoints: - t = (i*step) - x1 = cos(t*pi)*outerradius - y1 = sin(t*pi)*outerradius - newpoints.append([x1,y1,0]) - x2 = cos(t*pi+(pi/starpoints+twist))*innerradius - y2 = sin(t*pi+(pi/starpoints+twist))*innerradius - newpoints.append([x2,y2,0]) - i+=1 - return newpoints - -##------------------------------------------------------------ -# 2DCurve: Flower: -def FlowerCurve(petals=8, innerradius=0.5, outerradius=1.0, petalwidth=2.0): - """ - FlowerCurve( petals=8, innerradius=0.5, outerradius=1.0, petalwidth=2.0 ) - - Create flower shaped curve - - Parameters: - petals - the number of petals - (type=int) - innerradius - innerradius - (type=float) - outerradius - outerradius - (type=float) - petalwidth - width of petals - (type=float) - Returns: - a list with lists of x,y,z coordinates for curve points, [[x,y,z],[x,y,z],...n] - (type=list) - """ - - newpoints = [] - step = (2.0/(petals)) - pet = (step/pi*2)*petalwidth - i = 0 - while i < petals: - t = (i*step) - x1 = cos(t*pi-(pi/petals))*innerradius - y1 = sin(t*pi-(pi/petals))*innerradius - newpoints.append([x1,y1,0]) - x2 = cos(t*pi-pet)*outerradius - y2 = sin(t*pi-pet)*outerradius - newpoints.append([x2,y2,0]) - x3 = cos(t*pi+pet)*outerradius - y3 = sin(t*pi+pet)*outerradius - newpoints.append([x3,y3,0]) - i+=1 - return newpoints - -##------------------------------------------------------------ -# 2DCurve: Arc,Sector,Segment,Ring: -def ArcCurve(sides=6, startangle=0.0, endangle=90.0, innerradius=0.5, outerradius=1.0, type=3): - """ - ArcCurve( sides=6, startangle=0.0, endangle=90.0, innerradius=0.5, outerradius=1.0, type=3 ) - - Create arc shaped curve - - Parameters: - sides - number of sides - (type=int) - startangle - startangle - (type=float) - endangle - endangle - (type=float) - innerradius - innerradius - (type=float) - outerradius - outerradius - (type=float) - type - select type Arc,Sector,Segment,Ring - (type=int) - Returns: - a list with lists of x,y,z coordinates for curve points, [[x,y,z],[x,y,z],...n] - (type=list) - """ - - newpoints = [] - sides += 1 - angle = (2.0*(1.0/360.0)) - endangle-=startangle - step = ((angle*endangle)/(sides-1)) - i = 0 - while i < sides: - t = (i*step) + angle*startangle - x1 = sin(t*pi)*outerradius - y1 = cos(t*pi)*outerradius - newpoints.append([x1,y1,0]) - i+=1 - - #if type ==0: - # Arc: turn cyclic curve flag off! - - # Segment: - if type ==2: - newpoints.append([0,0,0]) - # Ring: - elif type ==3: - j=sides-1 - while j > -1: - t = (j*step) + angle*startangle - x2 = sin(t*pi)*innerradius - y2 = cos(t*pi)*innerradius - newpoints.append([x2,y2,0]) - j-=1 - return newpoints - -##------------------------------------------------------------ -# 2DCurve: Cog wheel: -def CogCurve(theeth=8, innerradius=0.8, middleradius=0.95, outerradius=1.0, bevel=0.5): - """ - CogCurve( theeth=8, innerradius=0.8, middleradius=0.95, outerradius=1.0, bevel=0.5 ) - - Create cog wheel shaped curve - - Parameters: - theeth - number of theeth - (type=int) - innerradius - innerradius - (type=float) - middleradius - middleradius - (type=float) - outerradius - outerradius - (type=float) - bevel - bevel amount - (type=float) - Returns: - a list with lists of x,y,z coordinates for curve points, [[x,y,z],[x,y,z],...n] - (type=list) - """ - - newpoints = [] - step = (2.0/(theeth)) - pet = (step/pi*2) - bevel = 1.0-bevel - i = 0 - while i < theeth: - t = (i*step) - x1 = cos(t*pi-(pi/theeth)-pet)*innerradius - y1 = sin(t*pi-(pi/theeth)-pet)*innerradius - newpoints.append([x1,y1,0]) - x2 = cos(t*pi-(pi/theeth)+pet)*innerradius - y2 = sin(t*pi-(pi/theeth)+pet)*innerradius - newpoints.append([x2,y2,0]) - x3 = cos(t*pi-pet)*middleradius - y3 = sin(t*pi-pet)*middleradius - newpoints.append([x3,y3,0]) - x4 = cos(t*pi-(pet*bevel))*outerradius - y4 = sin(t*pi-(pet*bevel))*outerradius - newpoints.append([x4,y4,0]) - x5 = cos(t*pi+(pet*bevel))*outerradius - y5 = sin(t*pi+(pet*bevel))*outerradius - newpoints.append([x5,y5,0]) - x6 = cos(t*pi+pet)*middleradius - y6 = sin(t*pi+pet)*middleradius - newpoints.append([x6,y6,0]) - i+=1 - return newpoints - -##------------------------------------------------------------ -# 2DCurve: nSide: -def nSideCurve(sides=6, radius=1.0): - """ - nSideCurve( sides=6, radius=1.0 ) - - Create n-sided curve - - Parameters: - sides - number of sides - (type=int) - radius - radius - (type=float) - Returns: - a list with lists of x,y,z coordinates for curve points, [[x,y,z],[x,y,z],...n] - (type=list) - """ - - newpoints = [] - step = (2.0/(sides)) - i = 0 - while i < sides: - t = (i*step) - x = sin(t*pi)*radius - y = cos(t*pi)*radius - newpoints.append([x,y,0]) - i+=1 - return newpoints - -''' -##------------------------------------------------------------ -# 2DCurve: Splat: -def SplatCurve(sides=24, scale=1.0, seed=0, basis=0, radius=1.0): - """ - SplatCurve( sides=24, scale=1.0, seed=0, basis=0, radius=1.0 ) - - Create splat curve - - Parameters: - sides - number of sides - (type=int) - scale - noise size - (type=float) - seed - noise random seed - (type=int) - basis - noise basis - (type=int) - radius - radius - (type=float) - Returns: - a list with lists of x,y,z coordinates for curve points, [[x,y,z],[x,y,z],...n] - (type=list) - """ - - newpoints = [] - step = (2.0/(sides)) - i = 0 - while i < sides: - t = (i*step) - turb = vTurbNoise(t, 1.0, scale, 6, 0, basis, seed ) - turb = turb[2] * 0.5 + 0.5 - x = sin(t*pi)*radius * turb - y = cos(t*pi)*radius * turb - newpoints.append([x,y,0]) - i+=1 - return newpoints -''' -###----------------------------------------------------------- -#### 3D curve shape functions: -###----------------------------------------------------------- - -###------------------------------------------------------------ -# 3DCurve: Helix: -def HelixCurve( number=100, height=2.0, startangle=0.0, endangle=360.0, width=1.0, a=0.0, b=0.0 ): - """ - HelixCurve( number=100, height=2.0, startangle=0.0, endangle=360.0, width=1.0, a=0.0, b=0.0 ) - - Create helix curve - - Parameters: - number - the number of points - (type=int) - height - height - (type=float) - startangle - startangle - (type=float) - endangle - endangle - (type=float) - width - width - (type=float) - a - a - (type=float) - b - b - (type=float) - Returns: - a list with lists of x,y,z coordinates for curve points, [[x,y,z],[x,y,z],...n] - (type=list) - """ - - newpoints = [] - angle = (2.0/360.0)*(endangle-startangle) - step = angle/(number-1) - h = height/angle - start = (startangle*2.0/360.0) - a/=angle - i = 0 - while i < number: - t = ( i*step+start ) - x = sin( (t*pi) ) * ( 1.0 + cos( t * pi * a - ( b * pi ) ) ) * ( 0.25 * width ) - y = cos( (t*pi) ) * ( 1.0 + cos( t * pi * a - ( b * pi ) ) ) * ( 0.25 * width ) - z = ( t * h ) -h*start - newpoints.append([x,y,z]) - i+=1 - return newpoints - -###------------------------------------------------------------ ? -# 3DCurve: Cycloid: Cycloid, Epicycloid, Hypocycloid -def CycloidCurve( number=24, length=2.0, type=0, a=1.0, b=1.0, startangle=0.0, endangle=360.0 ): - """ - CycloidCurve( number=24, length=2.0, type=0, a=1.0, b=1.0, startangle=0.0, endangle=360.0 ) - - Create a Cycloid, Epicycloid or Hypocycloid curve - - Parameters: - number - the number of points - (type=int) - length - length of curve - (type=float) - type - types: Cycloid, Epicycloid, Hypocycloid - (type=int) - Returns: - a list with lists of x,y,z coordinates for curve points, [[x,y,z],[x,y,z],...n] - (type=list) - """ - - newpoints = [] - angle = (2.0/360.0)*(endangle-startangle) - step = angle/(number-1) - #h = height/angle - d = length - start = (startangle*2.0/360.0) - a/=angle - i = 0 - if type == 0: # Epitrochoid - while i < number: - t = ( i*step+start ) - x = ((a + b) * cos(t*pi)) - (d * cos(((a+b)/b)*t*pi)) - y = ((a + b) * sin(t*pi)) - (d * sin(((a+b)/b)*t*pi)) - z = 0 # ( t * h ) -h*start - newpoints.append([x,y,z]) - i+=1 - - else: - newpoints = [[-1,-1,0], [-1,1,0], [1,1,0], [1,-1,0]] - return newpoints - -##------------------------------------------------------------ -# calculates the matrix for the new object -# depending on user pref -def align_matrix(context): - loc = Matrix.Translation(context.scene.cursor_location) - obj_align = context.user_preferences.edit.object_align - if (context.space_data.type == 'VIEW_3D' - and obj_align == 'VIEW'): - rot = context.space_data.region_3d.view_matrix.rotation_part().invert().resize4x4() - else: - rot = Matrix() - align_matrix = loc * rot - return align_matrix - -##------------------------------------------------------------ -#### Curve creation functions -# sets bezierhandles to auto -def setBezierHandles(obj, mode = 'AUTOMATIC'): - scene = bpy.context.scene - if obj.type != 'CURVE': - return - scene.objects.active = obj - bpy.ops.object.mode_set(mode='EDIT', toggle=True) - bpy.ops.curve.select_all(action='SELECT') - bpy.ops.curve.handle_type_set(type=mode) - bpy.ops.object.mode_set(mode='OBJECT', toggle=True) - -# get array of vertcoordinates acording to splinetype -def vertsToPoints(Verts, splineType): - # main vars - vertArray = [] - - # array for BEZIER spline output (V3) - if splineType == 'BEZIER': - for v in Verts: - vertArray += v - - # array for nonBEZIER output (V4) - else: - for v in Verts: - vertArray += v - if splineType == 'NURBS': - vertArray.append(1) #for nurbs w=1 - else: #for poly w=0 - vertArray.append(0) - return vertArray - -# create new CurveObject from vertarray and splineType -def createCurve(vertArray, props, align_matrix): - # options to vars - splineType = props.outputType # output splineType 'POLY' 'NURBS' 'BEZIER' - name = props.GalloreType # GalloreType as name - - # create curve - scene = bpy.context.scene - newCurve = bpy.data.curves.new(name, type = 'CURVE') # curvedatablock - newSpline = newCurve.splines.new(type = splineType) # spline - - # create spline from vertarray - if splineType == 'BEZIER': - newSpline.bezier_points.add(int(len(vertArray)*0.33)) - newSpline.bezier_points.foreach_set('co', vertArray) - else: - newSpline.points.add(int(len(vertArray)*0.25 - 1)) - newSpline.points.foreach_set('co', vertArray) - newSpline.use_endpoint_u = True - - # set curveOptions - newCurve.dimensions = props.shape - newSpline.use_cyclic_u = props.use_cyclic_u - newSpline.use_endpoint_u = props.endp_u - newSpline.order_u = props.order_u - - # create object with newCurve - new_obj = bpy.data.objects.new(name, newCurve) # object - scene.objects.link(new_obj) # place in active scene - new_obj.select = True # set as selected - scene.objects.active = new_obj # set as active - new_obj.matrix_world = align_matrix # apply matrix - - # set bezierhandles - if splineType == 'BEZIER': - setBezierHandles(new_obj, props.handleType) - - return - -##------------------------------------------------------------ -# Main Function -def main(context, props, align_matrix): - # deselect all objects - bpy.ops.object.select_all(action='DESELECT') - - # options - galType = props.GalloreType - splineType = props.outputType - innerRadius = props.innerRadius - middleRadius = props.middleRadius - outerRadius = props.outerRadius - - # get verts - if galType == 'Profile': - verts = ProfileCurve(props.ProfileCurveType, - props.ProfileCurvevar1, - props.ProfileCurvevar2) - if galType == 'Miscellaneous': - verts = MiscCurve(props.MiscCurveType, - props.MiscCurvevar1, - props.MiscCurvevar2, - props.MiscCurvevar3) - if galType == 'Flower': - verts = FlowerCurve(props.petals, - innerRadius, - outerRadius, - props.petalWidth) - if galType == 'Star': - verts = StarCurve(props.starPoints, - innerRadius, - outerRadius, - props.starTwist) - if galType == 'Arc': - verts = ArcCurve(props.arcSides, - props.startAngle, - props.endAngle, - innerRadius, - outerRadius, - props.arcType) - if galType == 'Cogwheel': - verts = CogCurve(props.teeth, - innerRadius, - middleRadius, - outerRadius, - props.bevel) - if galType == 'Nsided': - verts = nSideCurve(props.Nsides, - outerRadius) - ''' - if galType == 'Splat': - verts = SplatCurve(props.splatSides, - props.splatScale, - props.seed, - props.basis, - outerRadius) - ''' - if galType == 'Helix': - verts = HelixCurve(props.helixPoints, - props.helixHeight, - props.helixStart, - props.helixEnd, - props.helixWidth, - props.helix_a, - props.helix_b) - if galType == 'Cycloid': - verts = CycloidCurve(props.cycloPoints, - props.cyclo_d, - props.cycloType, - props.cyclo_a, - props.cyclo_b, - props.cycloStart, - props.cycloEnd) - - # turn verts into array - vertArray = vertsToPoints(verts, splineType) - - # create object - createCurve(vertArray, props, align_matrix) - - return - -class Curveaceous_galore(bpy.types.Operator): - '''''' - bl_idname = "curveaceous_galore" - bl_label = "Curveaceous galore" - bl_options = {'REGISTER', 'UNDO'} - bl_description = "adds many types of curves" - - # align_matrix for the invoke - align_matrix = Matrix() - - #### general properties - GalloreTypes = [ - ('Profile', 'Profile', 'Profile'), - ('Miscellaneous', 'Miscellaneous', 'Miscellaneous'), - ('Flower', 'Flower', 'Flower'), - ('Star', 'Star', 'Star'), - ('Arc', 'Arc', 'Arc'), - ('Cogwheel', 'Cogwheel', 'Cogwheel'), - ('Nsided', 'Nsided', 'Nsided'), -# ('Splat', 'Splat', 'Splat'), - ('Cycloid', 'Cycloid', 'Cycloid'), - ('Helix', 'Helix (3D)', 'Helix')] - GalloreType = EnumProperty(name="Type", - description="Form of Curve to create", - items=GalloreTypes) - SplineTypes = [ - ('POLY', 'Poly', 'POLY'), - ('NURBS', 'Nurbs', 'NURBS'), - ('BEZIER', 'Bezier', 'BEZIER')] - outputType = EnumProperty(name="Output splines", - description="Type of splines to output", - items=SplineTypes) - - #### Curve Options - shapeItems = [ - ('2D', '2D', '2D'), - ('3D', '3D', '3D')] - shape = EnumProperty(name="2D / 3D", - items=shapeItems, - description="2D or 3D Curve") - use_cyclic_u = BoolProperty(name="Cyclic", - default=True, - description="make curve closed") - endp_u = BoolProperty(name="use_endpoint_u", - default=True, - description="stretch to endpoints") - order_u = IntProperty(name="order_u", - default=4, - min=2, soft_min=2, - max=6, soft_max=6, - description="Order of nurbs spline") - bezHandles = [ - ('VECTOR', 'Vector', 'VECTOR'), - ('AUTOMATIC', 'Auto', 'AUTOMATIC')] - handleType = EnumProperty(name="Handle type", - description="bezier handles type", - items=bezHandles) - - #### ProfileCurve properties - ProfileCurveType = IntProperty(name="Type", - min=1, soft_min=1, - max=5, soft_max=5, - default=1, - description="Type of ProfileCurve") - ProfileCurvevar1 = FloatProperty(name="var_1", - default=0.25, - description="var1 of ProfileCurve") - ProfileCurvevar2 = FloatProperty(name="var_2", - default=0.25, - description="var2 of ProfileCurve") - - #### MiscCurve properties - MiscCurveType = IntProperty(name="Type", - min=1, soft_min=1, - max=5, soft_max=5, - default=1, - description="Type of ProfileCurve") - MiscCurvevar1 = FloatProperty(name="var_1", - default=1.0, - description="var1 of ProfileCurve") - MiscCurvevar2 = FloatProperty(name="var_2", - default=0.5, - description="var2 of ProfileCurve") - MiscCurvevar3 = FloatProperty(name="var_3", # doesn't seem to do anything - default=90.0, - description="var3 of ProfileCurve") - - #### Common properties - innerRadius = FloatProperty(name="Inner radius", - default=0.5, - min=0, soft_min=0, - description="Inner radius") - middleRadius = FloatProperty(name="Middle radius", - default=0.95, - min=0, soft_min=0, - description="Middle radius") - outerRadius = FloatProperty(name="Outer radius", - default=1.0, - min=0, soft_min=0, - description="Outer radius") - - #### Flower properties - petals = IntProperty(name="Petals", - default=8, - min=2, soft_min=2, - description="Number of petals") - petalWidth = FloatProperty(name="Petal width", - default=2.0, - min=0.01, soft_min=0.01, - description="Petal width") - - #### Star properties - starPoints = IntProperty(name="Star points", - default=8, - min=2, soft_min=2, - description="Number of star points") - starTwist = FloatProperty(name="Twist", - default=0.0, - description="Twist") - - #### Arc properties - arcSides = IntProperty(name="Arc sides", - default=6, - min=1, soft_min=1, - description="Sides of arc") - startAngle = FloatProperty(name="Start angle", - default=0.0, - description="Start angle") - endAngle = FloatProperty(name="End angle", - default=90.0, - description="End angle") - arcType = IntProperty(name="Arc type", - default=3, - min=1, soft_min=1, - max=3, soft_max=3, - description="Sides of arc") - - #### Cogwheel properties - teeth = IntProperty(name="Teeth", - default=8, - min=2, soft_min=2, - description="number of teeth") - bevel = FloatProperty(name="Bevel", - default=0.5, - min=0, soft_min=0, - max=1, soft_max=1, - description="Bevel") - - #### Nsided property - Nsides = IntProperty(name="Sides", - default=8, - min=3, soft_min=3, - description="Number of sides") - - #### Splat properties - splatSides = IntProperty(name="Splat sides", - default=24, - min=3, soft_min=3, - description="Splat sides") - splatScale = FloatProperty(name="Splat scale", - default=1.0, - min=0, soft_min=0, - description="Splat scale") - seed = IntProperty(name="Seed", - default=0, - min=0, soft_min=0, - description="Seed") - basis = IntProperty(name="Basis", - default=0, - min=0, soft_min=0, - description="Basis") - - #### Helix properties - helixPoints = IntProperty(name="resolution", - default=100, - min=3, soft_min=3, - description="resolution") - helixHeight = FloatProperty(name="Height", - default=2.0, - min=0, soft_min=0, - description="Helix height") - helixStart = FloatProperty(name="Start angle", - default=0.0, - description="Helix start angle") - helixEnd = FloatProperty(name="Endangle", - default=360.0, - description="Helix end angle") - helixWidth = FloatProperty(name="Width", - default=1.0, - description="Helix width") - helix_a = FloatProperty(name="var_1", - default=0.0, - description="Helix var1") - helix_b = FloatProperty(name="var_2", - default=0.0, - description="Helix var2") - - #### Cycloid properties - cycloPoints = IntProperty(name="Resolution", - default=100, - min=3, soft_min=3, - description="Resolution") - cyclo_d = FloatProperty(name="var_3", - default=1.5, - description="Cycloid var3") - cycloType = IntProperty(name="Type", - default=0, - min=0, soft_min=0, - max=0, soft_max=0, - description="resolution") - cyclo_a = FloatProperty(name="var_1", - default=5.0, - min=0.01, soft_min=0.01, - description="Cycloid var1") - cyclo_b = FloatProperty(name="var_2", - default=0.5, - min=0.01, soft_min=0.01, - description="Cycloid var2") - cycloStart = FloatProperty(name="Start angle", - default=0.0, - description="Cycloid start angle") - cycloEnd = FloatProperty(name="End angle", - default=360.0, - description="Cycloid end angle") - - ##### DRAW ##### - def draw(self, context): - props = self.properties - layout = self.layout - - # general options - col = layout.column() - col.prop(props, 'GalloreType') - col.label(text=props.GalloreType+" Options") - - # options per GalloreType - box = layout.box() - if props.GalloreType == 'Profile': - box.prop(props, 'ProfileCurveType') - box.prop(props, 'ProfileCurvevar1') - box.prop(props, 'ProfileCurvevar2') - if props.GalloreType == 'Miscellaneous': - box.prop(props, 'MiscCurveType') - box.prop(props, 'MiscCurvevar1') - box.prop(props, 'MiscCurvevar2') - #box.prop(props, 'MiscCurvevar3') # doesn't seem to do anything - if props.GalloreType == 'Flower': - box.prop(props, 'petals') - box.prop(props, 'petalWidth') - box.prop(props, 'innerRadius') - box.prop(props, 'outerRadius') - if props.GalloreType == 'Star': - box.prop(props, 'starPoints') - box.prop(props, 'starTwist') - box.prop(props, 'innerRadius') - box.prop(props, 'outerRadius') - if props.GalloreType == 'Arc': - box.prop(props, 'arcSides') - box.prop(props, 'arcType') # has only one Type? - box.prop(props, 'startAngle') - box.prop(props, 'endAngle') - box.prop(props, 'innerRadius') # doesn't seem to do anything - box.prop(props, 'outerRadius') - if props.GalloreType == 'Cogwheel': - box.prop(props, 'teeth') - box.prop(props, 'bevel') - box.prop(props, 'innerRadius') - box.prop(props, 'middleRadius') - box.prop(props, 'outerRadius') - if props.GalloreType == 'Nsided': - box.prop(props, 'Nsides') - box.prop(props, 'outerRadius', text='Radius') - ''' - if props.GalloreType == 'Splat': - box.prop(props, 'splatSides') - box.prop(props, 'outerRadius') - box.prop(props, 'splatScale') - box.prop(props, 'seed') - box.prop(props, 'basis') - ''' - if props.GalloreType == 'Helix': - box.prop(props, 'helixPoints') - box.prop(props, 'helixHeight') - box.prop(props, 'helixWidth') - box.prop(props, 'helixStart') - box.prop(props, 'helixEnd') - box.prop(props, 'helix_a') - box.prop(props, 'helix_b') - if props.GalloreType == 'Cycloid': - box.prop(props, 'cycloPoints') - #box.prop(props, 'cycloType') # needs the other types first - box.prop(props, 'cycloStart') - box.prop(props, 'cycloEnd') - box.prop(props, 'cyclo_a') - box.prop(props, 'cyclo_b') - box.prop(props, 'cyclo_d') - - col = layout.column() - col.label(text="Output Curve Type") - row = layout.row() - row.prop(props, 'outputType', expand=True) - col = layout.column() - col.label(text="Curve Options") - - # output options - box = layout.box() - if props.outputType == 'NURBS': - box.row().prop(props, 'shape', expand=True) - #box.prop(props, 'use_cyclic_u') - #box.prop(props, 'endp_u') - box.prop(props, 'order_u') - - if props.outputType == 'POLY': - box.row().prop(props, 'shape', expand=True) - #box.prop(props, 'use_cyclic_u') - - if props.outputType == 'BEZIER': - box.row().prop(props, 'shape', expand=True) - box.row().prop(props, 'handleType', expand=True) - #box.prop(props, 'use_cyclic_u') - - - ##### POLL ##### - @classmethod - def poll(cls, context): - return context.scene != None - - ##### EXECUTE ##### - def execute(self, context): - # turn off undo - undo = bpy.context.user_preferences.edit.use_global_undo - bpy.context.user_preferences.edit.use_global_undo = False - - # deal with 2D - 3D curve differences - props = self.properties - if props.GalloreType in ['Helix', 'Cycloid']: - props.shape = '3D' - #else: - #props.shape = '2D' # someone decide if we want this - - if props.GalloreType in ['Helix']: - props.use_cyclic_u = False - else: - props.use_cyclic_u = True - - - # main function - main(context, props, self.align_matrix) - - # restore pre operator undo state - bpy.context.user_preferences.edit.use_global_undo = undo - - return {'FINISHED'} - - ##### INVOKE ##### - def invoke(self, context, event): - # store creation_matrix - self.align_matrix = align_matrix(context) - self.execute(context) - - return {'FINISHED'} - -################################################################################ -##### REGISTER ##### - -def Curveaceous_galore_button(self, context): - self.layout.operator(Curveaceous_galore.bl_idname, text="curvatures gallore", icon="PLUGIN") - - -def register(): - bpy.types.INFO_MT_curve_add.append(Curveaceous_galore_button) - -def unregister(): - bpy.types.INFO_MT_curve_add.remove(Curveaceous_galore_button) - -if __name__ == "__main__": - register() diff --git a/add_curve_torus_knots.py b/add_curve_torus_knots.py deleted file mode 100644 index 2f13ac84..00000000 --- a/add_curve_torus_knots.py +++ /dev/null @@ -1,320 +0,0 @@ -# ##### 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -# ##### END GPL LICENSE BLOCK ##### - - -bl_addon_info = { - "name": "Torus Knots", - "author": "testscreenings", - "version": (0,1), - "blender": (2, 5, 3), - "api": 31667, - "location": "View3D > Add > Curve", - "description": "Adds many types of knots", - "warning": "", - "wiki_url": "http://wiki.blender.org/index.php/Extensions:2.5/Py/"\ - "Scripts/Curve/Torus_Knot", - "tracker_url": "https://projects.blender.org/tracker/index.php?"\ - "func=detail&aid=22403&group_id=153&atid=469", - "category": "Add Curve"} - - -##------------------------------------------------------------ -#### import modules -import bpy -from bpy.props import * -from mathutils import * -from math import * - -##------------------------------------------------------------ -# calculates the matrix for the new object -# depending on user pref -def align_matrix(context): - loc = Matrix.Translation(context.scene.cursor_location) - obj_align = context.user_preferences.edit.object_align - if (context.space_data.type == 'VIEW_3D' - and obj_align == 'VIEW'): - rot = context.space_data.region_3d.view_matrix.rotation_part().invert().resize4x4() - else: - rot = Matrix() - align_matrix = loc * rot - return align_matrix - -##------------------------------------------------------------ -#### Curve creation functions - -# get array of vertcoordinates acording to splinetype -def vertsToPoints(Verts): - vertArray = [] - - for v in Verts: - vertArray += v - vertArray.append(1) #for nurbs w=1 - - return vertArray - -# create new CurveObject from vertarray and splineType -def createCurve(vertArray, props, align_matrix): - # options to vars - splineType = 'NURBS' - name = 'Torus_Knot' - - # create curve - scene = bpy.context.scene - newCurve = bpy.data.curves.new(name, type = 'CURVE') # curvedatablock - newSpline = newCurve.splines.new(type = splineType) # spline - - # create spline from vertarray - newSpline.points.add(int(len(vertArray)*0.25 - 1)) - newSpline.points.foreach_set('co', vertArray) - newSpline.use_endpoint_u = True - - # Curve settings - newCurve.dimensions = '3D' - newSpline.use_cyclic_u = True - newSpline.use_endpoint_u = True - newSpline.order_u = 4 - - if props.geo_surf: - newCurve.bevel_depth = props.geo_bDepth - newCurve.bevel_resolution = props.geo_bRes - newCurve.use_fill_front = False - newCurve.use_fill_back = False - newCurve.extrude = props.geo_extrude - newCurve.offset = props.geo_width - newCurve.resolution_u = props.geo_res - - # create object with newCurve - new_obj = bpy.data.objects.new(name, newCurve) # object - scene.objects.link(new_obj) # place in active scene - new_obj.select = True # set as selected - scene.objects.active = new_obj # set as active - new_obj.matrix_world = align_matrix # apply matrix - - return - -######################################################################## -####################### Knot Definitions ############################### -######################################################################## - -#### TORUS KNOT -def Torus_Knot_Curve(p=2, q=3, w=1, res=24, formula=0, h=1, u=1 ,v=1, rounds=2): - newPoints = [] - angle = 2*rounds - step = angle/(res-1) - scale = h - height = w - - for i in range(res-1): - t = ( i*step*pi) - - x = (2 * scale + cos((q*t)/p*v)) * cos(t * u) - y = (2 * scale + cos((q*t)/p*v)) * sin(t * u) - z = sin(q*t/p) * height - - newPoints.append([x,y,z]) - - return newPoints - -##------------------------------------------------------------ -# Main Function -def main(context, props, align_matrix): - # deselect all objects - bpy.ops.object.select_all(action='DESELECT') - - # get verts - verts = Torus_Knot_Curve(props.torus_p, - props.torus_q, - props.torus_w, - props.torus_res, - props.torus_formula, - props.torus_h, - props.torus_u, - props.torus_v, - props.torus_rounds) - - # turn verts into array - vertArray = vertsToPoints(verts) - - # create object - createCurve(vertArray, props, align_matrix) - - return - -class torus_knot_plus(bpy.types.Operator): - '''''' - bl_idname = "torus_knot_plus" - bl_label = "Torus Knot +" - bl_options = {'REGISTER', 'UNDO'} - bl_description = "adds many types of knots" - - # align_matrix for the invoke - align_matrix = Matrix() - - #### general options - options_plus = BoolProperty(name="plus options", - default=False, - description="Show more options (the plus part).") - - #### GEO Options - geo_surf = BoolProperty(name="Surface", - default=True) - geo_bDepth = FloatProperty(name="bevel", - default=0.08, - min=0, soft_min=0) - geo_bRes = IntProperty(name="bevel res", - default=2, - min=0, soft_min=0, - max=4, soft_max=4) - geo_extrude = FloatProperty(name="extrude", - default=0.0, - min=0, soft_min=0) - geo_width = FloatProperty(name="width", - default=1.0, - min=0, soft_min=0) - geo_res = IntProperty(name="resolution", - default=12, - min=1, soft_min=1) - - - #### Parameters - torus_res = IntProperty(name="Resoulution", - default=200, - min=3, soft_min=3, - description='Resolution, Number of controlverticies.') - torus_p = IntProperty(name="p", - default=2, - min=1, soft_min=1, - #max=1, soft_max=1, - description="p") - torus_q = IntProperty(name="q", - default=3, - min=1, soft_min=1, - #max=1, soft_max=1, - description="q") - torus_w = FloatProperty(name="Height", - default=1, - #min=0, soft_min=0, - #max=1, soft_max=1, - description="Height in Z") - torus_h = FloatProperty(name="Scale", - default=1, - #min=0, soft_min=0, - #max=1, soft_max=1, - description="Scale, in XY") - torus_u = IntProperty(name="u", - default=1, - min=1, soft_min=1, - #max=1, soft_max=1, - description="u") - torus_v = IntProperty(name="v", - default=1, - min=1, soft_min=1, - #max=1, soft_max=1, - description="v") - torus_formula = IntProperty(name="Variation", - default=0, - min=0, soft_min=0, - max=10, soft_max=10) - torus_rounds = IntProperty(name="Rounds", - default=2, - min=1, soft_min=1, - #max=1, soft_max=1, - description="Rounds") - - ##### DRAW ##### - def draw(self, context): - props = self.properties - layout = self.layout - - # general options - col = layout.column() - #col.prop(props, 'KnotType') waits for more knottypes - col.label(text="Torus Knot Parameters") - - # Parameters - box = layout.box() - box.prop(props, 'torus_res') - box.prop(props, 'torus_w') - box.prop(props, 'torus_h') - box.prop(props, 'torus_p') - box.prop(props, 'torus_q') - box.prop(props, 'options_plus') - if props.options_plus: - box.prop(props, 'torus_u') - box.prop(props, 'torus_v') - box.prop(props, 'torus_rounds') - - # surface Options - col = layout.column() - col.label(text="Geometry Options") - box = layout.box() - box.prop(props, 'geo_surf') - if props.geo_surf: - box.prop(props, 'geo_bDepth') - box.prop(props, 'geo_bRes') - box.prop(props, 'geo_extrude') - #box.prop(props, 'geo_width') # not really good - box.prop(props, 'geo_res') - - ##### POLL ##### - @classmethod - def poll(cls, context): - return context.scene != None - - ##### EXECUTE ##### - def execute(self, context): - # turn off undo - undo = bpy.context.user_preferences.edit.use_global_undo - bpy.context.user_preferences.edit.use_global_undo = False - - props = self.properties - - if not props.options_plus: - props.torus_rounds = props.torus_p - - # main function - main(context, props, self.align_matrix) - - # restore pre operator undo state - bpy.context.user_preferences.edit.use_global_undo = undo - - return {'FINISHED'} - - ##### INVOKE ##### - def invoke(self, context, event): - # store creation_matrix - self.align_matrix = align_matrix(context) - self.execute(context) - - return {'FINISHED'} - -################################################################################ -##### REGISTER ##### - -def torus_knot_plus_button(self, context): - self.layout.operator(torus_knot_plus.bl_idname, text="Torus Knot +", icon="PLUGIN") - - -def register(): - bpy.types.INFO_MT_curve_add.append(torus_knot_plus_button) - -def unregister(): - bpy.types.INFO_MT_curve_add.remove(torus_knot_plus_button) - -if __name__ == "__main__": - register() diff --git a/add_mesh_3d_function_surface.py b/add_mesh_3d_function_surface.py deleted file mode 100644 index 0b1db521..00000000 --- a/add_mesh_3d_function_surface.py +++ /dev/null @@ -1,636 +0,0 @@ -# ##### 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -# ##### END GPL LICENSE BLOCK ##### - -bl_addon_info = { - "name": "3D Function Surfaces", - "author": "Buerbaum Martin (Pontiac)", - "version": (0,3,5), - "blender": (2, 5, 3), - "api": 31854, - "location": "View3D > Add > Mesh > Z Function Surface & XYZ Function Surface", - "description": "Create Objects using Math Formulas", - "warning": "", - "wiki_url": "http://wiki.blender.org/index.php/Extensions:2.5/Py/"\ - "Scripts/Add_Mesh/Add_3d_Function_Surface", - "tracker_url": "https://projects.blender.org/tracker/index.php?"\ - "func=detail&aid=21444&group_id=153&atid=469", - "category": "Add Mesh"} - -""" -Z Function Surface - -This script lets the user create a surface where the z coordinate -is a function of the x and y coordinates. - - z = f(x,y) - -X,Y,Z Function Surface - -This script lets the user create a surface where the x, y and z -coordinates are defiend by a function. - - x = f(u,v) - y = f(u,v) - z = f(u,v) - -Usage: -You have to activated the script in the "Add-Ons" tab (user preferences). -The functionality can then be accessed via the -"Add Mesh" -> "Z Function Surface" -and -"Add Mesh" -> "X,Y,Z Function Surface" -menu. - -Version history: -v0.3.5 - createFaces can now "Flip" faces and create fan/star like faces. -v0.3.4 - Updated store_recall_properties, apply_object_align - and create_mesh_object. - Changed how recall data is stored. -v0.3.3 - API change Mathutils -> mathutils (r557) -v0.3.2 - Various fixes&streamlining by ideasman42/Campbell Barton. - r544 Compile expressions for faster execution - r544 Use operator reports for errors too - r544 Avoid type checks by converting to a float, errors - converting to a float are reported too. - Fixed an error Campbell overlooked (appending tuples to an - array, not single values) Thamnks for the report wild_doogy. - Added 'description' field, updated 'wiki_url'. - Made the script PEP8 compatible again. -v0.3.1 - Use hidden "edit" property for "recall" operator. - Bugfix: Z Function was mixing up div_x and div_y -v0.3 - X,Y,Z Function Surface (by Ed Mackey & tuga3d). - Renamed old function to "Z Function Surface". - Align the geometry to the view if the user preference says so. - Store recall properties in newly created object. -v0.2.3 - Use bl_addon_info for Add-On information. -v0.2.2 - Fixed Add-On registration text. -v0.2.1 - Fixed some new API stuff. - Mainly we now have the register/unregister functions. - Also the new() function for objects now accepts a mesh object. - Changed the script so it can be managed from the "Add-Ons" tab - in the user preferences. - Added dummy "PLUGIN" icon. - Corrected FSF address. - Clean up of tooltips. -v0.2 - Added security check for eval() function - Check return value of eval() for complex numbers. -v0.1.1 - Use 'CANCELLED' return value when failing. - Updated web links. -v0.1 - Initial revision. - -More Links: -http://gitorious.org/blender-scripts/blender-3d-function-surface -http://blenderartists.org/forum/showthread.php?t=179043 -""" - - -import bpy -from mathutils import * -from math import * -from bpy.props import * - -# List of safe functions for eval() -safe_list = ['math', 'acos', 'asin', 'atan', 'atan2', 'ceil', 'cos', 'cosh', - 'degrees', 'e', 'exp', 'fabs', 'floor', 'fmod', 'frexp', 'hypot', - 'ldexp', 'log', 'log10', 'modf', 'pi', 'pow', 'radians', - 'sin', 'sinh', 'sqrt', 'tan', 'tanh'] - -# Use the list to filter the local namespace -safe_dict = dict([(k, globals().get(k, None)) for k in safe_list]) - - -# Stores the values of a list of properties and the -# operator id in a property group ('recall_op') inside the object. -# Could (in theory) be used for non-objects. -# Note: Replaces any existing property group with the same name! -# ob ... Object to store the properties in. -# op ... The operator that should be used. -# op_args ... A dictionary with valid Blender -# properties (operator arguments/parameters). - - -# calculates the matrix for the new object -# depending on user pref -def align_matrix(context): - loc = Matrix.Translation(context.scene.cursor_location) - obj_align = context.user_preferences.edit.object_align - if (context.space_data.type == 'VIEW_3D' - and obj_align == 'VIEW'): - rot = context.space_data.region_3d.view_matrix.rotation_part().invert().resize4x4() - else: - rot = Matrix() - align_matrix = loc * rot - return align_matrix - - -# Create a new mesh (object) from verts/edges/faces. -# verts/edges/faces ... List of vertices/edges/faces for the -# new mesh (as used in from_pydata). -# name ... Name of the new mesh (& object). -# edit ... Replace existing mesh data. -# Note: Using "edit" will destroy/delete existing mesh data. -def create_mesh_object(context, verts, edges, faces, name, edit, align_matrix): - scene = context.scene - obj_act = scene.objects.active - - # Can't edit anything, unless we have an active obj. - if edit and not obj_act: - return None - - # Create new mesh - mesh = bpy.data.meshes.new(name) - - # Make a mesh from a list of verts/edges/faces. - mesh.from_pydata(verts, edges, faces) - - # Update mesh geometry after adding stuff. - mesh.update() - - # Deselect all objects. - bpy.ops.object.select_all(action='DESELECT') - - if edit: - # Replace geometry of existing object - - # Use the active obj and select it. - ob_new = obj_act - ob_new.select = True - - if obj_act.mode == 'OBJECT': - # Get existing mesh datablock. - old_mesh = ob_new.data - - # Set object data to nothing - ob_new.data = None - - # Clear users of existing mesh datablock. - old_mesh.user_clear() - - # Remove old mesh datablock if no users are left. - if (old_mesh.users == 0): - bpy.data.meshes.remove(old_mesh) - - # Assign new mesh datablock. - ob_new.data = mesh - - else: - # Create new object - ob_new = bpy.data.objects.new(name, mesh) - - # Link new object to the given scene and select it. - scene.objects.link(ob_new) - ob_new.select = True - - # Place the object at the 3D cursor location. - # apply viewRotaion - ob_new.matrix_world = align_matrix - - if obj_act and obj_act.mode == 'EDIT': - if not edit: - # We are in EditMode, switch to ObjectMode. - bpy.ops.object.mode_set(mode='OBJECT') - - # Select the active object as well. - obj_act.select = True - - # Apply location of new object. - scene.update() - - # Join new object into the active. - bpy.ops.object.join() - - # Switching back to EditMode. - bpy.ops.object.mode_set(mode='EDIT') - - ob_new = obj_act - - else: - # We are in ObjectMode. - # Make the new object the active one. - scene.objects.active = ob_new - - return ob_new - - -# A very simple "bridge" tool. -# Connects two equally long vertex rows with faces. -# Returns a list of the new faces (list of lists) -# -# vertIdx1 ... First vertex list (list of vertex indices). -# vertIdx2 ... Second vertex list (list of vertex indices). -# closed ... Creates a loop (first & last are closed). -# flipped ... Invert the normal of the face(s). -# -# Note: You can set vertIdx1 to a single vertex index to create -# a fan/star of faces. -# Note: If both vertex idx list are the same length they have -# to have at least 2 vertices. -def createFaces(vertIdx1, vertIdx2, closed=False, flipped=False): - faces = [] - - if not vertIdx1 or not vertIdx2: - return None - - if len(vertIdx1) < 2 and len(vertIdx2) < 2: - return None - - fan = False - if (len(vertIdx1) != len(vertIdx2)): - if (len(vertIdx1) == 1 and len(vertIdx2) > 1): - fan = True - else: - return None - - total = len(vertIdx2) - - if closed: - # Bridge the start with the end. - if flipped: - face = [ - vertIdx1[0], - vertIdx2[0], - vertIdx2[total - 1]] - if not fan: - face.append(vertIdx1[total - 1]) - faces.append(face) - - else: - face = [vertIdx2[0], vertIdx1[0]] - if not fan: - face.append(vertIdx1[total - 1]) - face.append(vertIdx2[total - 1]) - faces.append(face) - - # Bridge the rest of the faces. - for num in range(total - 1): - if flipped: - if fan: - face = [vertIdx2[num], vertIdx1[0], vertIdx2[num + 1]] - else: - face = [vertIdx2[num], vertIdx1[num], - vertIdx1[num + 1], vertIdx2[num + 1]] - faces.append(face) - else: - if fan: - face = [vertIdx1[0], vertIdx2[num], vertIdx2[num + 1]] - else: - face = [vertIdx1[num], vertIdx2[num], - vertIdx2[num + 1], vertIdx1[num + 1]] - faces.append(face) - - return faces - - -class AddZFunctionSurface(bpy.types.Operator): - '''Add a surface defined defined by a function z=f(x,y)''' - bl_idname = "mesh.primitive_z_function_surface" - bl_label = "Add Z Function Surface" - bl_options = {'REGISTER', 'UNDO'} - - # edit - Whether to add or update. - edit = BoolProperty(name="", - description="", - default=False, - options={'HIDDEN'}) - - equation = StringProperty(name="Z Equation", - description="Equation for z=f(x,y)", - default="1 - ( x**2 + y**2 )") - - div_x = IntProperty(name="X Subdivisions", - description="Number of vertices in x direction.", - default=16, - min=3, - max=256) - div_y = IntProperty(name="Y Subdivisions", - description="Number of vertices in y direction.", - default=16, - min=3, - max=256) - - size_x = FloatProperty(name="X Size", - description="Size of the x axis.", - default=2.0, - min=0.01, - max=100.0, - unit="LENGTH") - size_y = FloatProperty(name="Y Size", - description="Size of the y axis.", - default=2.0, - min=0.01, - max=100.0, - unit="LENGTH") - align_matrix = Matrix() - - def execute(self, context): - edit = self.properties.edit - equation = self.properties.equation - div_x = self.properties.div_x - div_y = self.properties.div_y - size_x = self.properties.size_x - size_y = self.properties.size_y - - verts = [] - faces = [] - - delta_x = size_x / float(div_x - 1) - delta_y = size_y / float(div_y - 1) - start_x = -(size_x / 2.0) - start_y = -(size_y / 2.0) - - edgeloop_prev = [] - - try: - expr_args = ( - compile(equation, __file__, 'eval'), - {"__builtins__": None}, - safe_dict) - except: - import traceback - self.report({'ERROR'}, "Error parsing expression: " - + traceback.format_exc(limit=1)) - return {'CANCELLED'} - - for row_x in range(div_x): - edgeloop_cur = [] - x = start_x + row_x * delta_x - - for row_y in range(div_y): - y = start_y + row_y * delta_y - z = 0.0 - - safe_dict['x'] = x - safe_dict['y'] = y - - # Try to evaluate the equation. - try: - z = float(eval(*expr_args)) - except: - import traceback - self.report({'ERROR'}, "Error evaluating expression: " - + traceback.format_exc(limit=1)) - return {'CANCELLED'} - - edgeloop_cur.append(len(verts)) - verts.append((x, y, z)) - - if len(edgeloop_prev) > 0: - faces_row = createFaces(edgeloop_prev, edgeloop_cur) - faces.extend(faces_row) - - edgeloop_prev = edgeloop_cur - - obj = create_mesh_object(context, verts, [], faces, "Z Function", edit, self.align_matrix) - - return {'FINISHED'} - - def invoke(self, context, event): - self.align_matrix = align_matrix(context) - self.execute(context) - return {'FINISHED'} - -def xyz_function_surface_faces(self, x_eq, y_eq, z_eq, - range_u_min, range_u_max, range_u_step, wrap_u, - range_v_min, range_v_max, range_v_step, wrap_v): - - verts = [] - faces = [] - - uStep = (range_u_max - range_u_min) / range_u_step - vStep = (range_v_max - range_v_min) / range_v_step - - uRange = range_u_step - if range_u_step == 0: - uRange = uRange + 1 - - vRange = range_v_step - if range_v_step == 0: - vRange = vRange + 1 - - try: - expr_args_x = ( - compile(x_eq, __file__.replace(".py", "_x.py"), 'eval'), - {"__builtins__": None}, - safe_dict) - expr_args_y = ( - compile(y_eq, __file__.replace(".py", "_y.py"), 'eval'), - {"__builtins__": None}, - safe_dict) - expr_args_z = ( - compile(z_eq, __file__.replace(".py", "_z.py"), 'eval'), - {"__builtins__": None}, - safe_dict) - except: - import traceback - self.report({'ERROR'}, "Error parsing expression: " - + traceback.format_exc(limit=1)) - return [], [] - - for vN in range(vRange): - v = range_v_min + (vN * vStep) - - for uN in range(uRange): - u = range_u_min + (uN * uStep) - - safe_dict['u'] = u - safe_dict['v'] = v - - # Try to evaluate the equation. - try: - verts.append(( - float(eval(*expr_args_x)), - float(eval(*expr_args_y)), - float(eval(*expr_args_z)))) - - except: - import traceback - self.report({'ERROR'}, "Error evaluating expression: " - + traceback.format_exc(limit=1)) - return [], [] - - for vN in range(1, range_v_step + 1): - vThis = vN - - if (vThis >= vRange): - if wrap_v: - vThis = 0 - else: - continue - - for uN in range(1, range_u_step + 1): - uThis = uN - - if (uThis >= uRange): - if wrap_u: - uThis = 0 - else: - continue - - faces.append([(vThis * uRange) + uThis, - (vThis * uRange) + uN - 1, - ((vN - 1) * uRange) + uN - 1, - ((vN - 1) * uRange) + uThis]) - - return verts, faces - - -# Original Script "Parametric.py" by Ed Mackey. -# -> http://www.blinken.com/blender-plugins.php -# Partly converted for Blender 2.5 by tuga3d. -# -# Sphere: -# x = sin(2*pi*u)*sin(pi*v) -# y = cos(2*pi*u)*sin(pi*v) -# z = cos(pi*v) -# u_min = v_min = 0 -# u_max = v_max = 1 -# -# "Snail shell" -# x = 1.2**v*(sin(u)**2 *sin(v)) -# y = 1.2**v*(sin(u)*cos(u)) -# z = 1.2**v*(sin(u)**2 *cos(v)) -# u_min = 0 -# u_max = pi -# v_min = -pi/4, -# v max = 5*pi/2 -class AddXYZFunctionSurface(bpy.types.Operator): - '''Add a surface defined defined by 3 functions:''' \ - + ''' x=f(u,v), y=f(u,v) and z=f(u,v)''' - bl_idname = "mesh.primitive_xyz_function_surface" - bl_label = "Add X,Y,Z Function Surface" - bl_options = {'REGISTER', 'UNDO'} - - # edit - Whether to add or update. - edit = BoolProperty(name="", - description="", - default=False, - options={'HIDDEN'}) - - x_eq = StringProperty(name="X Equation", - description="Equation for x=f(u,v)", - default="1.2**v*(sin(u)**2 *sin(v))") - - y_eq = StringProperty(name="Y Equation", - description="Equation for y=f(u,v)", - default="1.2**v*(sin(u)*cos(u))") - - z_eq = StringProperty(name="Z Equation", - description="Equation for z=f(u,v)", - default="1.2**v*(sin(u)**2 *cos(v))") - - range_u_min = FloatProperty(name="U min", - description="Minimum U value. Lower boundary of U range.", - min=-100.00, - max=0.00, - default=0.00) - - range_u_max = FloatProperty(name="U max", - description="Maximum U value. Upper boundary of U range.", - min=0.00, - max=100.00, - default=pi) - - range_u_step = IntProperty(name="U step", - description="U Subdivisions", - min=1, - max=1024, - default=32) - - wrap_u = BoolProperty(name="U wrap", - description="U Wrap around", - default=True) - - range_v_min = FloatProperty(name="V min", - description="Minimum V value. Lower boundary of V range.", - min=-100.00, - max=0.00, - default=-pi / 4) - - range_v_max = FloatProperty(name="V max", - description="Maximum V value. Upper boundary of V range.", - min=0.00, - max=100.00, - default=5 * pi / 2) - - range_v_step = IntProperty(name="V step", - description="V Subdivisions", - min=1, - max=1024, - default=32) - - wrap_v = BoolProperty(name="V wrap", - description="V Wrap around", - default=False) - - align_matrix = Matrix() - - def execute(self, context): - props = self.properties - - verts, faces = xyz_function_surface_faces( - self, - props.x_eq, - props.y_eq, - props.z_eq, - props.range_u_min, - props.range_u_max, - props.range_u_step, - props.wrap_u, - props.range_v_min, - props.range_v_max, - props.range_v_step, - props.wrap_v) - - if not verts: - return {'CANCELLED'} - - obj = create_mesh_object(context, verts, [], faces, - "XYZ Function", props.edit, self.align_matrix) - - return {'FINISHED'} - - def invoke(self, context, event): - self.align_matrix = align_matrix(context) - self.execute(context) - return {'FINISHED'} - - -################################ -import space_info - -# Define "3D Function Surface" menu -def menu_func_z(self, context): - self.layout.operator(AddZFunctionSurface.bl_idname, text="Z Function Surface", icon="PLUGIN") - -def menu_func_xyz(self, context): - self.layout.operator(AddXYZFunctionSurface.bl_idname, text="X,Y,Z Function Surface", icon="PLUGIN") - - -def register(): - # Add menus to the "Add Mesh" menu - space_info.INFO_MT_mesh_add.append(menu_func_z) - space_info.INFO_MT_mesh_add.append(menu_func_xyz) - - -def unregister(): - # Remove menus from the "Add Mesh" menu. - space_info.INFO_MT_mesh_add.remove(menu_func_z) - space_info.INFO_MT_mesh_add.remove(menu_func_xyz) - -if __name__ == "__main__": - register() diff --git a/add_mesh_BoltFactory/Boltfactory.py b/add_mesh_BoltFactory/Boltfactory.py deleted file mode 100644 index 27c0d8cc..00000000 --- a/add_mesh_BoltFactory/Boltfactory.py +++ /dev/null @@ -1,306 +0,0 @@ -# ##### 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -# ##### END GPL LICENSE BLOCK ##### - - -import bpy -import mathutils -from bpy.props import * -from add_mesh_BoltFactory.createMesh import * -from add_mesh_BoltFactory.preset_utils import * - - - -##------------------------------------------------------------ -# calculates the matrix for the new object -# depending on user pref -def align_matrix(context): - loc = mathutils.Matrix.Translation(context.scene.cursor_location) - obj_align = context.user_preferences.edit.object_align - if (context.space_data.type == 'VIEW_3D' - and obj_align == 'VIEW'): - rot = context.space_data.region_3d.view_matrix.rotation_part().invert().resize4x4() - else: - rot = mathutils.Matrix() - align_matrix = loc * rot - return align_matrix - - - -class add_mesh_bolt(bpy.types.Operator): - '''''' - bl_idname = 'add_mesh_bolt' - bl_label = "Add Bolt" - bl_options = {'REGISTER', 'UNDO'} - bl_description = "adds many types of Bolts" - - align_matrix = mathutils.Matrix() - MAX_INPUT_NUMBER = 50 - - #Model Types - Model_Type_List = [('bf_Model_Bolt','BOLT','Bolt Model'), - ('bf_Model_Nut','NUT','Nut Model')] - bf_Model_Type = EnumProperty( attr='bf_Model_Type', - name='Model', - description='Choose the type off model you would like', - items = Model_Type_List, default = 'bf_Model_Bolt') - - #Head Types - Model_Type_List = [('bf_Head_Hex','HEX','Hex Head'), - ('bf_Head_Cap','CAP','Cap Head'), - ('bf_Head_Dome','DOME','Dome Head'), - ('bf_Head_Pan','PAN','Pan Head'), - ('bf_Head_CounterSink','COUNTER SINK','Counter Sink Head')] - bf_Head_Type = EnumProperty( attr='bf_Head_Type', - name='Head', - description='Choose the type off Head you would like', - items = Model_Type_List, default = 'bf_Head_Hex') - - #Bit Types - Bit_Type_List = [('bf_Bit_None','NONE','No Bit Type'), - ('bf_Bit_Allen','ALLEN','Allen Bit Type'), - ('bf_Bit_Philips','PHILLIPS','Phillips Bit Type')] - bf_Bit_Type = EnumProperty( attr='bf_Bit_Type', - name='Bit Type', - description='Choose the type of bit to you would like', - items = Bit_Type_List, default = 'bf_Bit_None') - - #Nut Types - Nut_Type_List = [('bf_Nut_Hex','HEX','Hex Nut'), - ('bf_Nut_Lock','LOCK','Lock Nut')] - bf_Nut_Type = EnumProperty( attr='bf_Nut_Type', - name='Nut Type', - description='Choose the type of nut you would like', - items = Nut_Type_List, default = 'bf_Nut_Hex') - - #Shank Types - bf_Shank_Length = FloatProperty(attr='bf_Shank_Length', - name='Shank Length', default = 0, - min = 0, soft_min = 0, max = MAX_INPUT_NUMBER, - description='Length of the unthreaded shank') - - bf_Shank_Dia = FloatProperty(attr='bf_Shank_Dia', - name='Shank Dia', default = 3, - min = 0, soft_min = 0,max = MAX_INPUT_NUMBER, - description='Diameter of the shank') - - bf_Phillips_Bit_Depth = FloatProperty(attr='bf_Phillips_Bit_Depth', - name='Bit Depth', default = 0, #set in execute - options = {'HIDDEN'}, #gets calculated in execute - min = 0, soft_min = 0,max = MAX_INPUT_NUMBER, - description='Depth of the Phillips Bit') - - bf_Allen_Bit_Depth = FloatProperty(attr='bf_Allen_Bit_Depth', - name='Bit Depth', default = 1.5, - min = 0, soft_min = 0,max = MAX_INPUT_NUMBER, - description='Depth of the Allen Bit') - - bf_Allen_Bit_Flat_Distance = FloatProperty( attr='bf_Allen_Bit_Flat_Distance', - name='Flat Dist', default = 2.5, - min = 0, soft_min = 0, max = MAX_INPUT_NUMBER, - description='Flat Distance of the Allen Bit') - - bf_Hex_Head_Height = FloatProperty( attr='bf_Hex_Head_Height', - name='Head Height', default = 2, - min = 0, soft_min = 0, max = MAX_INPUT_NUMBER, - description='Height of the Hex Head') - - bf_Hex_Head_Flat_Distance = FloatProperty( attr='bf_Hex_Head_Flat_Distance', - name='Flat Dist', default = 5.5, - min = 0, soft_min = 0, max = MAX_INPUT_NUMBER, - description='Flat Distance of the Hex Head') - - bf_CounterSink_Head_Dia = FloatProperty( attr='bf_CounterSink_Head_Dia', - name='Head Dia', default = 5.5, - min = 0, soft_min = 0, max = MAX_INPUT_NUMBER, - description='Diameter of the Counter Sink Head') - - bf_Cap_Head_Height = FloatProperty( attr='bf_Cap_Head_Height', - name='Head Height', default = 5.5, - min = 0, soft_min = 0, max = MAX_INPUT_NUMBER, - description='Height of the Cap Head') - - bf_Cap_Head_Dia = FloatProperty( attr='bf_Cap_Head_Dia', - name='Head Dia', default = 3, - min = 0, soft_min = 0, max = MAX_INPUT_NUMBER, - description='Diameter of the Cap Head') - - bf_Dome_Head_Dia = FloatProperty( attr='bf_Dome_Head_Dia', - name='Dome Head Dia', default = 5.6, - min = 0, soft_min = 0, max = MAX_INPUT_NUMBER, - description='Length of the unthreaded shank') - - bf_Pan_Head_Dia = FloatProperty( attr='bf_Pan_Head_Dia', - name='Pan Head Dia', default = 5.6, - min = 0, soft_min = 0, max = MAX_INPUT_NUMBER, - description='Diameter of the Pan Head') - - bf_Philips_Bit_Dia = FloatProperty(attr='bf_Philips_Bit_Dia', - name='Bit Dia', default = 0, #set in execute - options = {'HIDDEN'}, #gets calculated in execute - min = 0, soft_min = 0,max = MAX_INPUT_NUMBER, - description='Diameter of the Philips Bit') - - bf_Thread_Length = FloatProperty( attr='bf_Thread_Length', - name='Thread Length', default = 6, - min = 0, soft_min = 0, max = MAX_INPUT_NUMBER, - description='Length of the Thread') - - bf_Major_Dia = FloatProperty( attr='bf_Major_Dia', - name='Major Dia', default = 3, - min = 0, soft_min = 0, max = MAX_INPUT_NUMBER, - description='Outside diameter of the Thread') - - bf_Pitch = FloatProperty( attr='bf_Pitch', - name='Pitch', default = 0.35, - min = 0.1, soft_min = 0.1, max = 7.0, - description='Pitch if the thread') - - bf_Minor_Dia = FloatProperty( attr='bf_Minor_Dia', - name='Minor Dia', default = 0, #set in execute - options = {'HIDDEN'}, #gets calculated in execute - min = 0, soft_min = 0, max = MAX_INPUT_NUMBER, - description='Inside diameter of the Thread') - - bf_Crest_Percent = IntProperty( attr='bf_Crest_Percent', - name='Crest Percent', default = 10, - min = 1, soft_min = 1, max = 90, - description='Percent of the pitch that makes up the Crest') - - bf_Root_Percent = IntProperty( attr='bf_Root_Percent', - name='Root Percent', default = 10, - min = 1, soft_min = 1, max = 90, - description='Percent of the pitch that makes up the Root') - - bf_Hex_Nut_Height = FloatProperty( attr='bf_Hex_Nut_Height', - name='Hex Nut Height', default = 2.4, - min = 0, soft_min = 0, max = MAX_INPUT_NUMBER, - description='Height of the Hex Nut') - - bf_Hex_Nut_Flat_Distance = FloatProperty( attr='bf_Hex_Nut_Flat_Distance', - name='Hex Nut Flat Dist', default = 5.5, - min = 0, soft_min = 0, max = MAX_INPUT_NUMBER, - description='Flat distance of the Hex Nut') - - presets, presetsPath = getPresets() - - bf_presets = EnumProperty(attr='bf_presets', - name='Preset', - description="Use Preset from File", - default='M3.py', - items=presets) - - last_preset = None - - - def draw(self, context): - props = self.properties - layout = self.layout - col = layout.column() - - #ENUMS - col.prop(props, 'bf_Model_Type') - col.prop(props, 'bf_presets') - col.separator() - - #Bit - if props.bf_Model_Type == 'bf_Model_Bolt': - col.prop(props, 'bf_Bit_Type') - if props.bf_Bit_Type == 'bf_Bit_None': - DoNothing = 1; - elif props.bf_Bit_Type == 'bf_Bit_Allen': - col.prop(props,'bf_Allen_Bit_Depth') - col.prop(props,'bf_Allen_Bit_Flat_Distance') - elif props.bf_Bit_Type == 'bf_Bit_Philips': - col.prop(props,'bf_Phillips_Bit_Depth') - col.prop(props,'bf_Philips_Bit_Dia') - col.separator() - - #Head - if props.bf_Model_Type == 'bf_Model_Bolt': - col.prop(props, 'bf_Head_Type') - if props.bf_Head_Type == 'bf_Head_Hex': - col.prop(props, 'bf_Hex_Head_Height') - col.prop(props, 'bf_Hex_Head_Flat_Distance') - elif props.bf_Head_Type == 'bf_Head_Cap': - col.prop(props,'bf_Cap_Head_Height') - col.prop(props,'bf_Cap_Head_Dia') - elif props.bf_Head_Type == 'bf_Head_Dome': - col.prop(props,'bf_Dome_Head_Dia') - elif props.bf_Head_Type == 'bf_Head_Pan': - col.prop(props,'bf_Pan_Head_Dia') - elif props.bf_Head_Type == 'bf_Head_CounterSink': - col.prop(props,'bf_CounterSink_Head_Dia') - col.separator() - #Shank - if props.bf_Model_Type == 'bf_Model_Bolt': - col.label(text='Shank') - col.prop(props, 'bf_Shank_Length') - col.prop(props, 'bf_Shank_Dia') - col.separator() - #Nut - if props.bf_Model_Type == 'bf_Model_Nut': - col.prop(props, 'bf_Nut_Type') - col.prop(props,'bf_Hex_Nut_Height') - col.prop(props,'bf_Hex_Nut_Flat_Distance') - #Thread - col.label(text='Thread') - if props.bf_Model_Type == 'bf_Model_Bolt': - col.prop(props,'bf_Thread_Length') - col.prop(props,'bf_Major_Dia') - col.prop(props,'bf_Minor_Dia') - col.prop(props,'bf_Pitch') - col.prop(props,'bf_Crest_Percent') - col.prop(props,'bf_Root_Percent') - - - - ##### POLL ##### - @classmethod - def poll(cls, context): - return context.scene != None - - ##### EXECUTE ##### - def execute(self, context): - - #print('EXECUTING...') - props = self.properties - - if not self.last_preset or props.bf_presets != self.last_preset: - #print('setting Preset', props.bf_presets) - setProps(props, props.bf_presets, self.presetsPath) - props.bf_Phillips_Bit_Depth = float(Get_Phillips_Bit_Height(props.bf_Philips_Bit_Dia)) - - self.last_preset = props.bf_presets - - - #props.bf_Phillips_Bit_Depth = float(Get_Phillips_Bit_Height(props.bf_Philips_Bit_Dia)) - #props.bf_Philips_Bit_Dia = props.bf_Pan_Head_Dia*(1.82/5.6) - #props.bf_Minor_Dia = props.bf_Major_Dia - (1.082532 * props.bf_Pitch) - - Create_New_Mesh(props, context, self.align_matrix) - - return {'FINISHED'} - - ##### INVOKE ##### - def invoke(self, context, event): - #print('\n___________START_____________') - # store creation_matrix - self.align_matrix = align_matrix(context) - self.execute(context) - - return {'FINISHED'} diff --git a/add_mesh_BoltFactory/__init__.py b/add_mesh_BoltFactory/__init__.py deleted file mode 100644 index 6e8e1ef1..00000000 --- a/add_mesh_BoltFactory/__init__.py +++ /dev/null @@ -1,59 +0,0 @@ -# ##### 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -# ##### END GPL LICENSE BLOCK ##### - -bl_addon_info = { - "name": "BoltFactory", - "author": "Aaron Keith", - "version": (3,9), - "blender": (2, 5, 3), - "api": 31854, - "location": "add Mesh", - "wiki_url": "http://wiki.blender.org/index.php/Extensions:2.5/Py/"\ - "Scripts/Add_Mesh/BoltFactory", - "tracker_url": "https://projects.blender.org/tracker/index.php?"\ - "func=detail&aid=22842&group_id=153&atid=468", - "category": "Add Mesh"} - -import bpy - -try: - init_data - - reload(Boltfactory) -except: - from add_mesh_BoltFactory import Boltfactory - -init_data = True - -################################################################################ -##### REGISTER ##### - -def add_mesh_bolt_button(self, context): - self.layout.operator(Boltfactory.add_mesh_bolt.bl_idname, text="BOLT", icon="PLUGIN") - - -def register(): - bpy.types.INFO_MT_mesh_add.append(add_mesh_bolt_button) - #bpy.types.VIEW3D_PT_tools_objectmode.prepend(add_mesh_bolt_button) #just for testing - -def unregister(): - bpy.types.INFO_MT_mesh_add.remove(add_mesh_bolt_button) - #bpy.types.VIEW3D_PT_tools_objectmode.remove(add_mesh_bolt_button) #just for testing - -if __name__ == "__main__": - register() diff --git a/add_mesh_BoltFactory/createMesh.py b/add_mesh_BoltFactory/createMesh.py deleted file mode 100644 index f6562072..00000000 --- a/add_mesh_BoltFactory/createMesh.py +++ /dev/null @@ -1,2111 +0,0 @@ -# ##### 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -# ##### END GPL LICENSE BLOCK ##### - - -import os #remove this -import bpy - -try: - import mathutils - MATHUTILS = mathutils -except: - import Mathutils - MATHUTILS = Mathutils - - - -from math import * -from bpy.props import IntProperty, FloatProperty ,EnumProperty -from itertools import * - -NARROW_UI = 180 -MAX_INPUT_NUMBER = 50 - -#Global_Scale = 0.001 #1 blender unit = X mm -GLOBAL_SCALE = 0.1 #1 blender unit = X mm -#Global_Scale = 1.0 #1 blender unit = X mm - - - - -# next two utility functions are stolen from import_obj.py - -def unpack_list(list_of_tuples): - l = [] - for t in list_of_tuples: - l.extend(t) - return l - -def unpack_face_list(list_of_tuples): - l = [] - for t in list_of_tuples: - face = [i for i in t] - - if len(face) != 3 and len(face) != 4: - raise RuntimeError("{0} vertices in face.".format(len(face))) - - # rotate indices if the 4th is 0 - if len(face) == 4 and face[3] == 0: - face = [face[3], face[0], face[1], face[2]] - - if len(face) == 3: - face.append(0) - - l.extend(face) - - return l - -''' -Remove Doubles takes a list on Verts and a list of Faces and -removes the doubles, much like Blender does in edit mode. -It doesn’t have the range function but it will round the corrdinates -and remove verts that are very close togther. The function -is useful because you can perform a “Remove Doubles” with out -having to enter Edit Mode. Having to enter edit mode has the -disadvantage of not being able to interactively change the properties. -''' - - -def RemoveDoubles(verts,faces,Decimal_Places = 4): - - new_verts = [] - new_faces = [] - dict_verts = {} - Rounded_Verts = [] - - for v in verts: - Rounded_Verts.append([round(v[0],Decimal_Places),round(v[1],Decimal_Places),round(v[2],Decimal_Places)]) - - for face in faces: - new_face = [] - for vert_index in face: - Real_co = tuple(verts[vert_index]) - Rounded_co = tuple(Rounded_Verts[vert_index]) - - if Rounded_co not in dict_verts: - dict_verts[Rounded_co] = len(dict_verts) - new_verts.append(Real_co) - if dict_verts[Rounded_co] not in new_face: - new_face.append(dict_verts[Rounded_co]) - if len(new_face) == 3 or len(new_face) == 4: - new_faces.append(new_face) - - return new_verts,new_faces - - - - -def Scale_Mesh_Verts(verts,scale_factor): - Ret_verts = [] - for v in verts: - Ret_verts.append([v[0]*scale_factor,v[1]*scale_factor,v[2]*scale_factor]) - return Ret_verts - - - - - -#Create a matrix representing a rotation. -# -#Parameters: -# -# * angle (float) - The angle of rotation desired. -# * matSize (int) - The size of the rotation matrix to construct. Can be 2d, 3d, or 4d. -# * axisFlag (string (optional)) - Possible values: -# o "x - x-axis rotation" -# o "y - y-axis rotation" -# o "z - z-axis rotation" -# o "r - arbitrary rotation around vector" -# * axis (Vector object. (optional)) - The arbitrary axis of rotation used with "R" -# -#Returns: Matrix object. -# A new rotation matrix. -def Simple_RotationMatrix(angle, matSize, axisFlag): - if matSize != 4 : - print ("Simple_RotationMatrix can only do 4x4") - - q = radians(angle) #make the rotation go clockwise - - if axisFlag == 'x': - matrix = MATHUTILS.Matrix([1,0,0,0],[0,cos(q),sin(q),0],[0,-sin(q),cos(q),0],[0,0,0,1]) - elif axisFlag == 'y': - matrix = MATHUTILS.Matrix([cos(q),0,-sin(q),0],[0,1,0,0],[sin(q),0,cos(q),0],[0,0,0,1]) - elif axisFlag == 'z': - matrix = MATHUTILS.Matrix([cos(q),sin(q),0,0],[-sin(q),cos(q),0,0],[0,0,1,0],[0,0,0,1]) - else: - print ("Simple_RotationMatrix can only do x y z axis") - return matrix - - -########################################################################################## -########################################################################################## -## Converter Functions For Bolt Factory -########################################################################################## -########################################################################################## - - -def Flat_To_Radius(FLAT): - h = (float(FLAT)/2)/cos(radians(30)) - return h - -def Get_Phillips_Bit_Height(Bit_Dia): - Flat_Width_half = (Bit_Dia*(0.5/1.82))/2.0 - Bit_Rad = Bit_Dia / 2.0 - x = Bit_Rad - Flat_Width_half - y = tan(radians(60))*x - return float(y) - - -########################################################################################## -########################################################################################## -## Miscellaneous Utilities -########################################################################################## -########################################################################################## - -# Returns a list of verts rotated by the given matrix. Used by SpinDup -def Rot_Mesh(verts,matrix): - ret = [] - #print ("rot mat",matrix) - for v in verts: - vec = MATHUTILS.Vector(v) * matrix - ret.append([vec.x,vec.y,vec.z]) - return ret - -# Returns a list of faces that has there index incremented by offset -def Copy_Faces(faces,offset): - ret = [] - for f in faces: - fsub = [] - for i in range(len(f)): - fsub.append(f[i]+ offset) - ret.append(fsub) - return ret - - -# Much like Blenders built in SpinDup. -def SpinDup(VERTS,FACES,DEGREE,DIVISIONS,AXIS): - verts=[] - faces=[] - - if DIVISIONS == 0: - DIVISIONS = 1 - - step = DEGREE/DIVISIONS # set step so pieces * step = degrees in arc - - for i in range(int(DIVISIONS)): - rotmat = Simple_RotationMatrix(step*i, 4, AXIS) # 4x4 rotation matrix, 30d about the x axis. - Rot = Rot_Mesh(VERTS,rotmat) - faces.extend(Copy_Faces(FACES,len(verts))) - verts.extend(Rot) - return verts,faces - - - -# Returns a list of verts that have been moved up the z axis by DISTANCE -def Move_Verts_Up_Z(VERTS,DISTANCE): - ret = [] - for v in VERTS: - ret.append([v[0],v[1],v[2]+DISTANCE]) - return ret - - -# Returns a list of verts and faces that has been mirrored in the AXIS -def Mirror_Verts_Faces(VERTS,FACES,AXIS,FLIP_POINT =0): - ret_vert = [] - ret_face = [] - offset = len(VERTS) - if AXIS == 'y': - for v in VERTS: - Delta = v[0] - FLIP_POINT - ret_vert.append([FLIP_POINT-Delta,v[1],v[2]]) - if AXIS == 'x': - for v in VERTS: - Delta = v[1] - FLIP_POINT - ret_vert.append([v[0],FLIP_POINT-Delta,v[2]]) - if AXIS == 'z': - for v in VERTS: - Delta = v[2] - FLIP_POINT - ret_vert.append([v[0],v[1],FLIP_POINT-Delta]) - - for f in FACES: - fsub = [] - for i in range(len(f)): - fsub.append(f[i]+ offset) - fsub.reverse() # flip the order to make norm point out - ret_face.append(fsub) - - return ret_vert,ret_face - - - -# Returns a list of faces that -# make up an array of 4 point polygon. -def Build_Face_List_Quads(OFFSET,COLUM,ROW,FLIP = 0): - Ret =[] - RowStart = 0; - for j in range(ROW): - for i in range(COLUM): - Res1 = RowStart + i; - Res2 = RowStart + i + (COLUM +1) - Res3 = RowStart + i + (COLUM +1) +1 - Res4 = RowStart+i+1 - if FLIP: - Ret.append([OFFSET+Res1,OFFSET+Res2,OFFSET+Res3,OFFSET+Res4]) - else: - Ret.append([OFFSET+Res4,OFFSET+Res3,OFFSET+Res2,OFFSET+Res1]) - RowStart += COLUM+1 - return Ret - - -# Returns a list of faces that makes up a fill pattern for a -# circle -def Fill_Ring_Face(OFFSET,NUM,FACE_DOWN = 0): - Ret =[] - Face = [1,2,0] - TempFace = [0,0,0] - A = 0 - B = 1 - C = 2 - if NUM < 3: - return None - for i in range(NUM-2): - if (i%2): - TempFace[0] = Face[C]; - TempFace[1] = Face[C] + 1; - TempFace[2] = Face[B]; - if FACE_DOWN: - Ret.append([OFFSET+Face[2],OFFSET+Face[1],OFFSET+Face[0]]) - else: - Ret.append([OFFSET+Face[0],OFFSET+Face[1],OFFSET+Face[2]]) - else: - TempFace[0] =Face[C]; - if Face[C] == 0: - TempFace[1] = NUM-1; - else: - TempFace[1] = Face[C] - 1; - TempFace[2] = Face[B]; - if FACE_DOWN: - Ret.append([OFFSET+Face[0],OFFSET+Face[1],OFFSET+Face[2]]) - else: - Ret.append([OFFSET+Face[2],OFFSET+Face[1],OFFSET+Face[0]]) - - Face[0] = TempFace[0] - Face[1] = TempFace[1] - Face[2] = TempFace[2] - return Ret - -###################################################################################### -########################################################################################## -########################################################################################## -## Create Allen Bit -########################################################################################## -########################################################################################## - - -def Allen_Fill(OFFSET,FLIP= 0): - faces = [] - Lookup = [[19,1,0], - [19,2,1], - [19,3,2], - [19,20,3], - [20,4,3], - [20,5,4], - [20,6,5], - [20,7,6], - [20,8,7], - [20,9,8], - - [20,21,9], - - [21,10,9], - [21,11,10], - [21,12,11], - [21,13,12], - [21,14,13], - [21,15,14], - - [21,22,15], - [22,16,15], - [22,17,16], - [22,18,17] - ] - for i in Lookup: - if FLIP: - faces.append([OFFSET+i[2],OFFSET+i[1],OFFSET+i[0]]) - else: - faces.append([OFFSET+i[0],OFFSET+i[1],OFFSET+i[2]]) - - return faces - -def Allen_Bit_Dia(FLAT_DISTANCE): - Flat_Radius = (float(FLAT_DISTANCE)/2.0)/cos(radians(30)) - return (Flat_Radius * 1.05) * 2.0 - -def Allen_Bit_Dia_To_Flat(DIA): - Flat_Radius = (DIA/2.0)/1.05 - return (Flat_Radius * cos (radians(30)))* 2.0 - - - -def Create_Allen_Bit(FLAT_DISTANCE,HEIGHT): - Div = 36 - verts = [] - faces = [] - - Flat_Radius = (float(FLAT_DISTANCE)/2.0)/cos(radians(30)) - OUTTER_RADIUS = Flat_Radius * 1.05 - Outter_Radius_Height = Flat_Radius * (0.1/5.77) - FaceStart_Outside = len(verts) - Deg_Step = 360.0 /float(Div) - - for i in range(int(Div/2)+1): # only do half and mirror later - x = sin(radians(i*Deg_Step))*OUTTER_RADIUS - y = cos(radians(i*Deg_Step))*OUTTER_RADIUS - verts.append([x,y,0]) - - FaceStart_Inside = len(verts) - - Deg_Step = 360.0 /float(6) - for i in range(int(6/2)+1): - x = sin(radians(i*Deg_Step))* Flat_Radius - y = cos(radians(i*Deg_Step))* Flat_Radius - verts.append([x,y,0-Outter_Radius_Height]) - - faces.extend(Allen_Fill(FaceStart_Outside,0)) - - - FaceStart_Bottom = len(verts) - - Deg_Step = 360.0 /float(6) - for i in range(int(6/2)+1): - x = sin(radians(i*Deg_Step))* Flat_Radius - y = cos(radians(i*Deg_Step))* Flat_Radius - verts.append([x,y,0-HEIGHT]) - - faces.extend(Build_Face_List_Quads(FaceStart_Inside,3,1,True)) - faces.extend(Fill_Ring_Face(FaceStart_Bottom,4)) - - - M_Verts,M_Faces = Mirror_Verts_Faces(verts,faces,'y') - verts.extend(M_Verts) - faces.extend(M_Faces) - - return verts,faces,OUTTER_RADIUS * 2.0 - - -########################################################################################## -########################################################################################## -## Create Phillips Bit -########################################################################################## -########################################################################################## - - -def Phillips_Fill(OFFSET,FLIP= 0): - faces = [] - Lookup = [[0,1,10], - [1,11,10], - [1,2,11], - [2,12,11], - - [2,3,12], - [3,4,12], - [4,5,12], - [5,6,12], - [6,7,12], - - [7,13,12], - [7,8,13], - [8,14,13], - [8,9,14], - - - [10,11,16,15], - [11,12,16], - [12,13,16], - [13,14,17,16], - [15,16,17,18] - - - ] - for i in Lookup: - if FLIP: - if len(i) == 3: - faces.append([OFFSET+i[2],OFFSET+i[1],OFFSET+i[0]]) - else: - faces.append([OFFSET+i[3],OFFSET+i[2],OFFSET+i[1],OFFSET+i[0]]) - else: - if len(i) == 3: - faces.append([OFFSET+i[0],OFFSET+i[1],OFFSET+i[2]]) - else: - faces.append([OFFSET+i[0],OFFSET+i[1],OFFSET+i[2],OFFSET+i[3]]) - return faces - - - -def Create_Phillips_Bit(FLAT_DIA,FLAT_WIDTH,HEIGHT): - Div = 36 - verts = [] - faces = [] - - FLAT_RADIUS = FLAT_DIA * 0.5 - OUTTER_RADIUS = FLAT_RADIUS * 1.05 - - Flat_Half = float(FLAT_WIDTH)/2.0 - - FaceStart_Outside = len(verts) - Deg_Step = 360.0 /float(Div) - for i in range(int(Div/4)+1): # only do half and mirror later - x = sin(radians(i*Deg_Step))*OUTTER_RADIUS - y = cos(radians(i*Deg_Step))*OUTTER_RADIUS - verts.append([x,y,0]) - - - FaceStart_Inside = len(verts) - verts.append([0,FLAT_RADIUS,0]) #10 - verts.append([Flat_Half,FLAT_RADIUS,0]) #11 - verts.append([Flat_Half,Flat_Half,0]) #12 - verts.append([FLAT_RADIUS,Flat_Half,0]) #13 - verts.append([FLAT_RADIUS,0,0]) #14 - - - verts.append([0,Flat_Half,0-HEIGHT]) #15 - verts.append([Flat_Half,Flat_Half,0-HEIGHT]) #16 - verts.append([Flat_Half,0,0-HEIGHT]) #17 - - verts.append([0,0,0-HEIGHT]) #18 - - faces.extend(Phillips_Fill(FaceStart_Outside,True)) - - Spin_Verts,Spin_Face = SpinDup(verts,faces,360,4,'z') - - return Spin_Verts,Spin_Face,OUTTER_RADIUS * 2 - - -########################################################################################## -########################################################################################## -## Create Head Types -########################################################################################## -########################################################################################## - -def Max_Pan_Bit_Dia(HEAD_DIA): - HEAD_RADIUS = HEAD_DIA * 0.5 - XRad = HEAD_RADIUS * 1.976 - return (sin(radians(10))*XRad) * 2.0 - - -def Create_Pan_Head(HOLE_DIA,HEAD_DIA,SHANK_DIA,HEIGHT,RAD1,RAD2,FACE_OFFSET): - - DIV = 36 - HOLE_RADIUS = HOLE_DIA * 0.5 - HEAD_RADIUS = HEAD_DIA * 0.5 - SHANK_RADIUS = SHANK_DIA * 0.5 - - verts = [] - faces = [] - Row = 0 - BEVEL = HEIGHT * 0.01 - #Dome_Rad = HEAD_RADIUS * (1.0/1.75) - - Dome_Rad = HEAD_RADIUS * 1.12 - RAD_Offset = HEAD_RADIUS * 0.96 - OtherRad = HEAD_RADIUS * 0.16 - OtherRad_X_Offset = HEAD_RADIUS * 0.84 - OtherRad_Z_Offset = HEAD_RADIUS * 0.504 - XRad = HEAD_RADIUS * 1.976 - ZRad = HEAD_RADIUS * 1.768 - EndRad = HEAD_RADIUS * 0.284 - EndZOffset = HEAD_RADIUS * 0.432 - HEIGHT = HEAD_RADIUS * 0.59 - -# Dome_Rad = 5.6 -# RAD_Offset = 4.9 -# OtherRad = 0.8 -# OtherRad_X_Offset = 4.2 -# OtherRad_Z_Offset = 2.52 -# XRad = 9.88 -# ZRad = 8.84 -# EndRad = 1.42 -# EndZOffset = 2.16 -# HEIGHT = 2.95 - - FaceStart = FACE_OFFSET - - z = cos(radians(10))*ZRad - verts.append([HOLE_RADIUS,0.0,(0.0-ZRad)+z]) - Start_Height = 0 - ((0.0-ZRad)+z) - Row += 1 - - #for i in range(0,30,10): was 0 to 30 more work needed to make this look good. - for i in range(10,30,10): - x = sin(radians(i))*XRad - z = cos(radians(i))*ZRad - verts.append([x,0.0,(0.0-ZRad)+z]) - Row += 1 - - for i in range(20,140,10): - x = sin(radians(i))*EndRad - z = cos(radians(i))*EndRad - if ((0.0 - EndZOffset)+z) < (0.0-HEIGHT): - verts.append([(HEAD_RADIUS -EndRad)+x,0.0,0.0 - HEIGHT]) - else: - verts.append([(HEAD_RADIUS -EndRad)+x,0.0,(0.0 - EndZOffset)+z]) - Row += 1 - - - verts.append([SHANK_RADIUS,0.0,(0.0-HEIGHT)]) - Row += 1 - - verts.append([SHANK_RADIUS,0.0,(0.0-HEIGHT)-Start_Height]) - Row += 1 - - - sVerts,sFaces = SpinDup(verts,faces,360,DIV,'z') - sVerts.extend(verts) #add the start verts to the Spin verts to complete the loop - - faces.extend(Build_Face_List_Quads(FaceStart,Row-1,DIV)) - - Global_Head_Height = HEIGHT ; - - - return Move_Verts_Up_Z(sVerts,Start_Height),faces,HEIGHT - - - -def Create_Dome_Head(HOLE_DIA,HEAD_DIA,SHANK_DIA,HEIGHT,RAD1,RAD2,FACE_OFFSET): - DIV = 36 - HOLE_RADIUS = HOLE_DIA * 0.5 - HEAD_RADIUS = HEAD_DIA * 0.5 - SHANK_RADIUS = SHANK_DIA * 0.5 - - verts = [] - faces = [] - Row = 0 - BEVEL = HEIGHT * 0.01 - #Dome_Rad = HEAD_RADIUS * (1.0/1.75) - - Dome_Rad = HEAD_RADIUS * 1.12 - #Head_Height = HEAD_RADIUS * 0.78 - RAD_Offset = HEAD_RADIUS * 0.98 - Dome_Height = HEAD_RADIUS * 0.64 - OtherRad = HEAD_RADIUS * 0.16 - OtherRad_X_Offset = HEAD_RADIUS * 0.84 - OtherRad_Z_Offset = HEAD_RADIUS * 0.504 - - -# Dome_Rad = 5.6 -# RAD_Offset = 4.9 -# Dome_Height = 3.2 -# OtherRad = 0.8 -# OtherRad_X_Offset = 4.2 -# OtherRad_Z_Offset = 2.52 -# - - FaceStart = FACE_OFFSET - - verts.append([HOLE_RADIUS,0.0,0.0]) - Row += 1 - - - for i in range(0,60,10): - x = sin(radians(i))*Dome_Rad - z = cos(radians(i))*Dome_Rad - if ((0.0-RAD_Offset)+z) <= 0: - verts.append([x,0.0,(0.0-RAD_Offset)+z]) - Row += 1 - - - for i in range(60,160,10): - x = sin(radians(i))*OtherRad - z = cos(radians(i))*OtherRad - z = (0.0-OtherRad_Z_Offset)+z - if z < (0.0-Dome_Height): - z = (0.0-Dome_Height) - verts.append([OtherRad_X_Offset+x,0.0,z]) - Row += 1 - - verts.append([SHANK_RADIUS,0.0,(0.0-Dome_Height)]) - Row += 1 - - - sVerts,sFaces = SpinDup(verts,faces,360,DIV,'z') - sVerts.extend(verts) #add the start verts to the Spin verts to complete the loop - - faces.extend(Build_Face_List_Quads(FaceStart,Row-1,DIV)) - - return sVerts,faces,Dome_Height - - - -def Create_CounterSink_Head(HOLE_DIA,HEAD_DIA,SHANK_DIA,HEIGHT,RAD1): - DIV = 36 - - HOLE_RADIUS = HOLE_DIA * 0.5 - HEAD_RADIUS = HEAD_DIA * 0.5 - SHANK_RADIUS = SHANK_DIA * 0.5 - - - verts = [] - faces = [] - Row = 0 - BEVEL = HEIGHT * 0.01 - - - -# HEAD_RADIUS = (HEIGHT/tan(radians(60))) + SHANK_RADIUS - HEIGHT = tan(radians(60)) * (HEAD_RADIUS - SHANK_RADIUS) - #print (RAD1) - - FaceStart = len(verts) - - verts.append([HOLE_RADIUS,0.0,0.0]) - Row += 1 - - #rad - - for i in range(0,100,10): - x = sin(radians(i))*RAD1 - z = cos(radians(i))*RAD1 - verts.append([(HEAD_RADIUS-RAD1)+x,0.0,(0.0-RAD1)+z]) - Row += 1 - - - verts.append([SHANK_RADIUS,0.0,0.0-HEIGHT]) - Row += 1 - - - sVerts,sFaces = SpinDup(verts,faces,360,DIV,'z') - sVerts.extend(verts) #add the start verts to the Spin verts to complete the loop - - - faces.extend(Build_Face_List_Quads(FaceStart,Row-1,DIV,1)) - - return sVerts,faces,HEIGHT - - - - -def Create_Cap_Head(HOLE_DIA,HEAD_DIA,SHANK_DIA,HEIGHT,RAD1,RAD2): - DIV = 36 - - HOLE_RADIUS = HOLE_DIA * 0.5 - HEAD_RADIUS = HEAD_DIA * 0.5 - SHANK_RADIUS = SHANK_DIA * 0.5 - - verts = [] - faces = [] - Row = 0 - BEVEL = HEIGHT * 0.01 - - - FaceStart = len(verts) - - verts.append([HOLE_RADIUS,0.0,0.0]) - Row += 1 - - #rad - - for i in range(0,100,10): - x = sin(radians(i))*RAD1 - z = cos(radians(i))*RAD1 - verts.append([(HEAD_RADIUS-RAD1)+x,0.0,(0.0-RAD1)+z]) - Row += 1 - - - verts.append([HEAD_RADIUS,0.0,0.0-HEIGHT+BEVEL]) - Row += 1 - - verts.append([HEAD_RADIUS-BEVEL,0.0,0.0-HEIGHT]) - Row += 1 - - #rad2 - - for i in range(0,100,10): - x = sin(radians(i))*RAD2 - z = cos(radians(i))*RAD2 - verts.append([(SHANK_RADIUS+RAD2)-x,0.0,(0.0-HEIGHT-RAD2)+z]) - Row += 1 - - - sVerts,sFaces = SpinDup(verts,faces,360,DIV,'z') - sVerts.extend(verts) #add the start verts to the Spin verts to complete the loop - - - faces.extend(Build_Face_List_Quads(FaceStart,Row-1,DIV)) - - return sVerts,faces,HEIGHT+RAD2 - - -def Create_Hex_Head(FLAT,HOLE_DIA,SHANK_DIA,HEIGHT): - - verts = [] - faces = [] - HOLE_RADIUS = HOLE_DIA * 0.5 - Half_Flat = FLAT/2 - TopBevelRadius = Half_Flat - (Half_Flat* (0.05/8)) - Undercut_Height = (Half_Flat* (0.05/8)) - Shank_Bevel = (Half_Flat* (0.05/8)) - Flat_Height = HEIGHT - Undercut_Height - Shank_Bevel - #Undercut_Height = 5 - SHANK_RADIUS = SHANK_DIA/2 - Row = 0; - - verts.append([0.0,0.0,0.0]) - - - FaceStart = len(verts) - #inner hole - - x = sin(radians(0))*HOLE_RADIUS - y = cos(radians(0))*HOLE_RADIUS - verts.append([x,y,0.0]) - - - x = sin(radians(60/6))*HOLE_RADIUS - y = cos(radians(60/6))*HOLE_RADIUS - verts.append([x,y,0.0]) - - - x = sin(radians(60/3))*HOLE_RADIUS - y = cos(radians(60/3))*HOLE_RADIUS - verts.append([x,y,0.0]) - - - x = sin(radians(60/2))*HOLE_RADIUS - y = cos(radians(60/2))*HOLE_RADIUS - verts.append([x,y,0.0]) - Row += 1 - - #bevel - - x = sin(radians(0))*TopBevelRadius - y = cos(radians(0))*TopBevelRadius - vec1 = MATHUTILS.Vector([x,y,0.0]) - verts.append([x,y,0.0]) - - - x = sin(radians(60/6))*TopBevelRadius - y = cos(radians(60/6))*TopBevelRadius - vec2 = MATHUTILS.Vector([x,y,0.0]) - verts.append([x,y,0.0]) - - - x = sin(radians(60/3))*TopBevelRadius - y = cos(radians(60/3))*TopBevelRadius - vec3 = MATHUTILS.Vector([x,y,0.0]) - verts.append([x,y,0.0]) - - - x = sin(radians(60/2))*TopBevelRadius - y = cos(radians(60/2))*TopBevelRadius - vec4 = MATHUTILS.Vector([x,y,0.0]) - verts.append([x,y,0.0]) - Row += 1 - - #Flats - - x = tan(radians(0))*Half_Flat - dvec = vec1 - MATHUTILS.Vector([x,Half_Flat,0.0]) - verts.append([x,Half_Flat,-dvec.length]) - - - x = tan(radians(60/6))*Half_Flat - dvec = vec2 - MATHUTILS.Vector([x,Half_Flat,0.0]) - verts.append([x,Half_Flat,-dvec.length]) - - - x = tan(radians(60/3))*Half_Flat - dvec = vec3 - MATHUTILS.Vector([x,Half_Flat,0.0]) - Lowest_Point = -dvec.length - verts.append([x,Half_Flat,-dvec.length]) - - - x = tan(radians(60/2))*Half_Flat - dvec = vec4 - MATHUTILS.Vector([x,Half_Flat,0.0]) - Lowest_Point = -dvec.length - verts.append([x,Half_Flat,-dvec.length]) - Row += 1 - - #down Bits Tri - x = tan(radians(0))*Half_Flat - verts.append([x,Half_Flat,Lowest_Point]) - - x = tan(radians(60/6))*Half_Flat - verts.append([x,Half_Flat,Lowest_Point]) - - x = tan(radians(60/3))*Half_Flat - verts.append([x,Half_Flat,Lowest_Point]) - - x = tan(radians(60/2))*Half_Flat - verts.append([x,Half_Flat,Lowest_Point]) - Row += 1 - - #down Bits - - x = tan(radians(0))*Half_Flat - verts.append([x,Half_Flat,-Flat_Height]) - - x = tan(radians(60/6))*Half_Flat - verts.append([x,Half_Flat,-Flat_Height]) - - x = tan(radians(60/3))*Half_Flat - verts.append([x,Half_Flat,-Flat_Height]) - - x = tan(radians(60/2))*Half_Flat - verts.append([x,Half_Flat,-Flat_Height]) - Row += 1 - - - #under cut - - x = sin(radians(0))*Half_Flat - y = cos(radians(0))*Half_Flat - vec1 = MATHUTILS.Vector([x,y,0.0]) - verts.append([x,y,-Flat_Height]) - - x = sin(radians(60/6))*Half_Flat - y = cos(radians(60/6))*Half_Flat - vec2 = MATHUTILS.Vector([x,y,0.0]) - verts.append([x,y,-Flat_Height]) - - x = sin(radians(60/3))*Half_Flat - y = cos(radians(60/3))*Half_Flat - vec3 = MATHUTILS.Vector([x,y,0.0]) - verts.append([x,y,-Flat_Height]) - - x = sin(radians(60/2))*Half_Flat - y = cos(radians(60/2))*Half_Flat - vec3 = MATHUTILS.Vector([x,y,0.0]) - verts.append([x,y,-Flat_Height]) - Row += 1 - - #under cut down bit - x = sin(radians(0))*Half_Flat - y = cos(radians(0))*Half_Flat - vec1 = MATHUTILS.Vector([x,y,0.0]) - verts.append([x,y,-Flat_Height-Undercut_Height]) - - x = sin(radians(60/6))*Half_Flat - y = cos(radians(60/6))*Half_Flat - vec2 = MATHUTILS.Vector([x,y,0.0]) - verts.append([x,y,-Flat_Height-Undercut_Height]) - - x = sin(radians(60/3))*Half_Flat - y = cos(radians(60/3))*Half_Flat - vec3 = MATHUTILS.Vector([x,y,0.0]) - verts.append([x,y,-Flat_Height-Undercut_Height]) - - x = sin(radians(60/2))*Half_Flat - y = cos(radians(60/2))*Half_Flat - vec3 = MATHUTILS.Vector([x,y,0.0]) - verts.append([x,y,-Flat_Height-Undercut_Height]) - Row += 1 - - #under cut to Shank BEVEAL - x = sin(radians(0))*(SHANK_RADIUS+Shank_Bevel) - y = cos(radians(0))*(SHANK_RADIUS+Shank_Bevel) - vec1 = MATHUTILS.Vector([x,y,0.0]) - verts.append([x,y,-Flat_Height-Undercut_Height]) - - x = sin(radians(60/6))*(SHANK_RADIUS+Shank_Bevel) - y = cos(radians(60/6))*(SHANK_RADIUS+Shank_Bevel) - vec2 = MATHUTILS.Vector([x,y,0.0]) - verts.append([x,y,-Flat_Height-Undercut_Height]) - - x = sin(radians(60/3))*(SHANK_RADIUS+Shank_Bevel) - y = cos(radians(60/3))*(SHANK_RADIUS+Shank_Bevel) - vec3 = MATHUTILS.Vector([x,y,0.0]) - verts.append([x,y,-Flat_Height-Undercut_Height]) - - x = sin(radians(60/2))*(SHANK_RADIUS+Shank_Bevel) - y = cos(radians(60/2))*(SHANK_RADIUS+Shank_Bevel) - vec3 = MATHUTILS.Vector([x,y,0.0]) - verts.append([x,y,-Flat_Height-Undercut_Height]) - Row += 1 - - #under cut to Shank BEVEAL - x = sin(radians(0))*SHANK_RADIUS - y = cos(radians(0))*SHANK_RADIUS - vec1 = MATHUTILS.Vector([x,y,0.0]) - verts.append([x,y,-Flat_Height-Undercut_Height-Shank_Bevel]) - - x = sin(radians(60/6))*SHANK_RADIUS - y = cos(radians(60/6))*SHANK_RADIUS - vec2 = MATHUTILS.Vector([x,y,0.0]) - verts.append([x,y,-Flat_Height-Undercut_Height-Shank_Bevel]) - - x = sin(radians(60/3))*SHANK_RADIUS - y = cos(radians(60/3))*SHANK_RADIUS - vec3 = MATHUTILS.Vector([x,y,0.0]) - verts.append([x,y,-Flat_Height-Undercut_Height-Shank_Bevel]) - - x = sin(radians(60/2))*SHANK_RADIUS - y = cos(radians(60/2))*SHANK_RADIUS - vec3 = MATHUTILS.Vector([x,y,0.0]) - verts.append([x,y,-Flat_Height-Undercut_Height-Shank_Bevel]) - Row += 1 - - - #Global_Head_Height = 0 - (-HEIGHT-0.1) - faces.extend(Build_Face_List_Quads(FaceStart,3,Row - 1)) - - - Mirror_Verts,Mirror_Faces = Mirror_Verts_Faces(verts,faces,'y') - verts.extend(Mirror_Verts) - faces.extend(Mirror_Faces) - - Spin_Verts,Spin_Faces = SpinDup(verts,faces,360,6,'z') - - - return Spin_Verts,Spin_Faces,0 - (-HEIGHT) - - -########################################################################################## -########################################################################################## -## Create External Thread -########################################################################################## -########################################################################################## - - - -def Thread_Start3(verts,INNER_RADIUS,OUTTER_RADIUS,PITCH,DIV,CREST_PERCENT,ROOT_PERCENT,Height_Offset): - - - Ret_Row = 0; - - Half_Pitch = float(PITCH)/2 - Height_Start = Height_Offset - PITCH - Height_Step = float(PITCH)/float(DIV) - Deg_Step = 360.0 /float(DIV) - - Crest_Height = float(PITCH) * float(CREST_PERCENT)/float(100) - Root_Height = float(PITCH) * float(ROOT_PERCENT)/float(100) - Root_to_Crest_Height = Crest_to_Root_Height = (float(PITCH) - (Crest_Height + Root_Height))/2.0 - -#theard start - - Rank = float(OUTTER_RADIUS - INNER_RADIUS)/float(DIV) - for j in range(4): - - for i in range(DIV+1): - z = Height_Offset - (Height_Step*i) - if z > Height_Start: - z = Height_Start - x = sin(radians(i*Deg_Step))*OUTTER_RADIUS - y = cos(radians(i*Deg_Step))*OUTTER_RADIUS - verts.append([x,y,z]) - Height_Offset -= Crest_Height - Ret_Row += 1 - - for i in range(DIV+1): - z = Height_Offset - (Height_Step*i) - if z > Height_Start: - z = Height_Start - - x = sin(radians(i*Deg_Step))*OUTTER_RADIUS - y = cos(radians(i*Deg_Step))*OUTTER_RADIUS - verts.append([x,y,z ]) - Height_Offset -= Crest_to_Root_Height - Ret_Row += 1 - - - for i in range(DIV+1): - z = Height_Offset - (Height_Step*i) - if z > Height_Start: - z = Height_Start - - x = sin(radians(i*Deg_Step))*INNER_RADIUS - y = cos(radians(i*Deg_Step))*INNER_RADIUS - if j == 0: - x = sin(radians(i*Deg_Step))*(OUTTER_RADIUS - (i*Rank)) - y = cos(radians(i*Deg_Step))*(OUTTER_RADIUS - (i*Rank)) - verts.append([x,y,z ]) - Height_Offset -= Root_Height - Ret_Row += 1 - - for i in range(DIV+1): - z = Height_Offset - (Height_Step*i) - if z > Height_Start: - z = Height_Start - - x = sin(radians(i*Deg_Step))*INNER_RADIUS - y = cos(radians(i*Deg_Step))*INNER_RADIUS - - if j == 0: - x = sin(radians(i*Deg_Step))*(OUTTER_RADIUS - (i*Rank)) - y = cos(radians(i*Deg_Step))*(OUTTER_RADIUS - (i*Rank)) - verts.append([x,y,z ]) - Height_Offset -= Root_to_Crest_Height - Ret_Row += 1 - - return Ret_Row,Height_Offset - - -def Create_Shank_Verts(START_DIA,OUTTER_DIA,LENGTH,Z_LOCATION = 0): - - verts = [] - DIV = 36 - - START_RADIUS = START_DIA/2 - OUTTER_RADIUS = OUTTER_DIA/2 - - Opp = abs(START_RADIUS - OUTTER_RADIUS) - Taper_Lentgh = Opp/tan(radians(31)); - - if Taper_Lentgh > LENGTH: - Taper_Lentgh = 0 - - Stright_Length = LENGTH - Taper_Lentgh - - Deg_Step = 360.0 /float(DIV) - - Row = 0 - - Lowest_Z_Vert = 0; - - Height_Offset = Z_LOCATION - - - #ring - for i in range(DIV+1): - x = sin(radians(i*Deg_Step))*START_RADIUS - y = cos(radians(i*Deg_Step))*START_RADIUS - z = Height_Offset - 0 - verts.append([x,y,z]) - Lowest_Z_Vert = min(Lowest_Z_Vert,z) - Height_Offset -= Stright_Length - Row += 1 - - for i in range(DIV+1): - x = sin(radians(i*Deg_Step))*START_RADIUS - y = cos(radians(i*Deg_Step))*START_RADIUS - z = Height_Offset - 0 - verts.append([x,y,z]) - Lowest_Z_Vert = min(Lowest_Z_Vert,z) - Height_Offset -= Taper_Lentgh - Row += 1 - - - return verts,Row,Height_Offset - - -def Create_Thread_Start_Verts(INNER_DIA,OUTTER_DIA,PITCH,CREST_PERCENT,ROOT_PERCENT,Z_LOCATION = 0): - - verts = [] - DIV = 36 - - INNER_RADIUS = INNER_DIA/2 - OUTTER_RADIUS = OUTTER_DIA/2 - - Half_Pitch = float(PITCH)/2 - Deg_Step = 360.0 /float(DIV) - Height_Step = float(PITCH)/float(DIV) - - Row = 0 - - Lowest_Z_Vert = 0; - - Height_Offset = Z_LOCATION - - Height_Start = Height_Offset - - Crest_Height = float(PITCH) * float(CREST_PERCENT)/float(100) - Root_Height = float(PITCH) * float(ROOT_PERCENT)/float(100) - Root_to_Crest_Height = Crest_to_Root_Height = (float(PITCH) - (Crest_Height + Root_Height))/2.0 - - Rank = float(OUTTER_RADIUS - INNER_RADIUS)/float(DIV) - - Height_Offset = Z_LOCATION + PITCH - Cut_off = Z_LOCATION - - - for j in range(1): - - for i in range(DIV+1): - x = sin(radians(i*Deg_Step))*OUTTER_RADIUS - y = cos(radians(i*Deg_Step))*OUTTER_RADIUS - z = Height_Offset - (Height_Step*i) - if z > Cut_off : z = Cut_off - verts.append([x,y,z]) - Lowest_Z_Vert = min(Lowest_Z_Vert,z) - Height_Offset -= Crest_Height - Row += 1 - - for i in range(DIV+1): - x = sin(radians(i*Deg_Step))*OUTTER_RADIUS - y = cos(radians(i*Deg_Step))*OUTTER_RADIUS - z = Height_Offset - (Height_Step*i) - if z > Cut_off : z = Cut_off - verts.append([x,y,z]) - Lowest_Z_Vert = min(Lowest_Z_Vert,z) - Height_Offset -= Crest_to_Root_Height - Row += 1 - - for i in range(DIV+1): - x = sin(radians(i*Deg_Step))*OUTTER_RADIUS - y = cos(radians(i*Deg_Step))*OUTTER_RADIUS - z = Height_Offset - (Height_Step*i) - if z > Cut_off : z = Cut_off - verts.append([x,y,z]) - Lowest_Z_Vert = min(Lowest_Z_Vert,z) - Height_Offset -= Root_Height - Row += 1 - - for i in range(DIV+1): - x = sin(radians(i*Deg_Step))*OUTTER_RADIUS - y = cos(radians(i*Deg_Step))*OUTTER_RADIUS - z = Height_Offset - (Height_Step*i) - if z > Cut_off : z = Cut_off - verts.append([x,y,z]) - Lowest_Z_Vert = min(Lowest_Z_Vert,z) - Height_Offset -= Root_to_Crest_Height - Row += 1 - - - for j in range(2): - for i in range(DIV+1): - z = Height_Offset - (Height_Step*i) - if z > Height_Start: - z = Height_Start - x = sin(radians(i*Deg_Step))*OUTTER_RADIUS - y = cos(radians(i*Deg_Step))*OUTTER_RADIUS - verts.append([x,y,z]) - Lowest_Z_Vert = min(Lowest_Z_Vert,z) - Height_Offset -= Crest_Height - Row += 1 - - for i in range(DIV+1): - z = Height_Offset - (Height_Step*i) - if z > Height_Start: - z = Height_Start - - x = sin(radians(i*Deg_Step))*OUTTER_RADIUS - y = cos(radians(i*Deg_Step))*OUTTER_RADIUS - verts.append([x,y,z ]) - Lowest_Z_Vert = min(Lowest_Z_Vert,z) - Height_Offset -= Crest_to_Root_Height - Row += 1 - - - for i in range(DIV+1): - z = Height_Offset - (Height_Step*i) - if z > Height_Start: - z = Height_Start - - x = sin(radians(i*Deg_Step))*INNER_RADIUS - y = cos(radians(i*Deg_Step))*INNER_RADIUS - if j == 0: - x = sin(radians(i*Deg_Step))*(OUTTER_RADIUS - (i*Rank)) - y = cos(radians(i*Deg_Step))*(OUTTER_RADIUS - (i*Rank)) - verts.append([x,y,z ]) - Lowest_Z_Vert = min(Lowest_Z_Vert,z) - Height_Offset -= Root_Height - Row += 1 - - for i in range(DIV+1): - z = Height_Offset - (Height_Step*i) - if z > Height_Start: - z = Height_Start - - x = sin(radians(i*Deg_Step))*INNER_RADIUS - y = cos(radians(i*Deg_Step))*INNER_RADIUS - - if j == 0: - x = sin(radians(i*Deg_Step))*(OUTTER_RADIUS - (i*Rank)) - y = cos(radians(i*Deg_Step))*(OUTTER_RADIUS - (i*Rank)) - verts.append([x,y,z ]) - Lowest_Z_Vert = min(Lowest_Z_Vert,z) - Height_Offset -= Root_to_Crest_Height - Row += 1 - - - return verts,Row,Height_Offset - - - -def Create_Thread_Verts(INNER_DIA,OUTTER_DIA,PITCH,HEIGHT,CREST_PERCENT,ROOT_PERCENT,Z_LOCATION = 0): - verts = [] - - DIV = 36 - - INNER_RADIUS = INNER_DIA/2 - OUTTER_RADIUS = OUTTER_DIA/2 - - Half_Pitch = float(PITCH)/2 - Deg_Step = 360.0 /float(DIV) - Height_Step = float(PITCH)/float(DIV) - - NUM_OF_START_THREADS = 4.0 - NUM_OF_END_THREADS = 3.0 - Num = int((HEIGHT- ((NUM_OF_START_THREADS*PITCH) + (NUM_OF_END_THREADS*PITCH) ))/PITCH) - Row = 0 - - - Crest_Height = float(PITCH) * float(CREST_PERCENT)/float(100) - Root_Height = float(PITCH) * float(ROOT_PERCENT)/float(100) - Root_to_Crest_Height = Crest_to_Root_Height = (float(PITCH) - (Crest_Height + Root_Height))/2.0 - - - Height_Offset = Z_LOCATION - - Lowest_Z_Vert = 0; - FaceStart = len(verts) - - - for j in range(Num): - - for i in range(DIV+1): - x = sin(radians(i*Deg_Step))*OUTTER_RADIUS - y = cos(radians(i*Deg_Step))*OUTTER_RADIUS - z = Height_Offset - (Height_Step*i) - verts.append([x,y,z]) - Lowest_Z_Vert = min(Lowest_Z_Vert,z) - Height_Offset -= Crest_Height - Row += 1 - - for i in range(DIV+1): - x = sin(radians(i*Deg_Step))*OUTTER_RADIUS - y = cos(radians(i*Deg_Step))*OUTTER_RADIUS - z = Height_Offset - (Height_Step*i) - verts.append([x,y,z]) - Lowest_Z_Vert = min(Lowest_Z_Vert,z) - Height_Offset -= Crest_to_Root_Height - Row += 1 - - - for i in range(DIV+1): - x = sin(radians(i*Deg_Step))*INNER_RADIUS - y = cos(radians(i*Deg_Step))*INNER_RADIUS - z = Height_Offset - (Height_Step*i) - verts.append([x,y,z]) - Lowest_Z_Vert = min(Lowest_Z_Vert,z) - Height_Offset -= Root_Height - Row += 1 - - for i in range(DIV+1): - x = sin(radians(i*Deg_Step))*INNER_RADIUS - y = cos(radians(i*Deg_Step))*INNER_RADIUS - z = Height_Offset - (Height_Step*i) - verts.append([x,y,z]) - Lowest_Z_Vert = min(Lowest_Z_Vert,z) - Height_Offset -= Root_to_Crest_Height - Row += 1 - - return verts,Row,Height_Offset - - - -def Create_Thread_End_Verts(INNER_DIA,OUTTER_DIA,PITCH,CREST_PERCENT,ROOT_PERCENT,Z_LOCATION = 0): - verts = [] - - DIV = 36 - - INNER_RADIUS = INNER_DIA/2 - OUTTER_RADIUS = OUTTER_DIA/2 - - Half_Pitch = float(PITCH)/2 - Deg_Step = 360.0 /float(DIV) - Height_Step = float(PITCH)/float(DIV) - - Crest_Height = float(PITCH) * float(CREST_PERCENT)/float(100) - Root_Height = float(PITCH) * float(ROOT_PERCENT)/float(100) - Root_to_Crest_Height = Crest_to_Root_Height = (float(PITCH) - (Crest_Height + Root_Height))/2.0 - - Col = 0 - Row = 0 - - Height_Offset = Z_LOCATION - - Tapper_Height_Start = Height_Offset - PITCH - PITCH - - Max_Height = Tapper_Height_Start - PITCH - - Lowest_Z_Vert = 0; - - FaceStart = len(verts) - for j in range(4): - - for i in range(DIV+1): - z = Height_Offset - (Height_Step*i) - z = max(z,Max_Height) - Tapper_Radius = OUTTER_RADIUS - if z < Tapper_Height_Start: - Tapper_Radius = OUTTER_RADIUS - (Tapper_Height_Start - z) - - x = sin(radians(i*Deg_Step))*(Tapper_Radius) - y = cos(radians(i*Deg_Step))*(Tapper_Radius) - verts.append([x,y,z]) - Lowest_Z_Vert = min(Lowest_Z_Vert,z) - Height_Offset -= Crest_Height - Row += 1 - - for i in range(DIV+1): - z = Height_Offset - (Height_Step*i) - z = max(z,Max_Height) - Tapper_Radius = OUTTER_RADIUS - if z < Tapper_Height_Start: - Tapper_Radius = OUTTER_RADIUS - (Tapper_Height_Start - z) - - x = sin(radians(i*Deg_Step))*(Tapper_Radius) - y = cos(radians(i*Deg_Step))*(Tapper_Radius) - verts.append([x,y,z]) - Lowest_Z_Vert = min(Lowest_Z_Vert,z) - Height_Offset -= Crest_to_Root_Height - Row += 1 - - - for i in range(DIV+1): - z = Height_Offset - (Height_Step*i) - z = max(z,Max_Height) - Tapper_Radius = OUTTER_RADIUS - (Tapper_Height_Start - z) - if Tapper_Radius > INNER_RADIUS: - Tapper_Radius = INNER_RADIUS - - x = sin(radians(i*Deg_Step))*(Tapper_Radius) - y = cos(radians(i*Deg_Step))*(Tapper_Radius) - verts.append([x,y,z]) - Lowest_Z_Vert = min(Lowest_Z_Vert,z) - Height_Offset -= Root_Height - Row += 1 - - for i in range(DIV+1): - z = Height_Offset - (Height_Step*i) - z = max(z,Max_Height) - Tapper_Radius = OUTTER_RADIUS - (Tapper_Height_Start - z) - if Tapper_Radius > INNER_RADIUS: - Tapper_Radius = INNER_RADIUS - - x = sin(radians(i*Deg_Step))*(Tapper_Radius) - y = cos(radians(i*Deg_Step))*(Tapper_Radius) - verts.append([x,y,z]) - Lowest_Z_Vert = min(Lowest_Z_Vert,z) - Height_Offset -= Root_to_Crest_Height - Row += 1 - - return verts,Row,Height_Offset,Lowest_Z_Vert - - - - -def Create_External_Thread(SHANK_DIA,SHANK_LENGTH,INNER_DIA,OUTTER_DIA,PITCH,LENGTH,CREST_PERCENT,ROOT_PERCENT): - - verts = [] - faces = [] - - DIV = 36 - - Total_Row = 0 - Thread_Len = 0; - - Face_Start = len(verts) - Offset = 0.0; - - - Shank_Verts,Shank_Row,Offset = Create_Shank_Verts(SHANK_DIA,OUTTER_DIA,SHANK_LENGTH,Offset) - Total_Row += Shank_Row - - Thread_Start_Verts,Thread_Start_Row,Offset = Create_Thread_Start_Verts(INNER_DIA,OUTTER_DIA,PITCH,CREST_PERCENT,ROOT_PERCENT,Offset) - Total_Row += Thread_Start_Row - - - Thread_Verts,Thread_Row,Offset = Create_Thread_Verts(INNER_DIA,OUTTER_DIA,PITCH,LENGTH,CREST_PERCENT,ROOT_PERCENT,Offset) - Total_Row += Thread_Row - - - Thread_End_Verts,Thread_End_Row,Offset,Lowest_Z_Vert = Create_Thread_End_Verts(INNER_DIA,OUTTER_DIA,PITCH,CREST_PERCENT,ROOT_PERCENT,Offset ) - Total_Row += Thread_End_Row - - - verts.extend(Shank_Verts) - verts.extend(Thread_Start_Verts) - verts.extend(Thread_Verts) - verts.extend(Thread_End_Verts) - - faces.extend(Build_Face_List_Quads(Face_Start,DIV,Total_Row -1,0)) - faces.extend(Fill_Ring_Face(len(verts)-DIV,DIV,1)) - - return verts,faces,0.0 - Lowest_Z_Vert - - -########################################################################################## -########################################################################################## -## Create Nut -########################################################################################## -########################################################################################## - -def add_Hex_Nut(FLAT,HOLE_DIA,HEIGHT): - global Global_Head_Height - global Global_NutRad - - verts = [] - faces = [] - HOLE_RADIUS = HOLE_DIA * 0.5 - Half_Flat = FLAT/2 - Half_Height = HEIGHT/2 - TopBevelRadius = Half_Flat - 0.05 - - Global_NutRad = TopBevelRadius - - Row = 0; - Lowest_Z_Vert = 0.0; - - verts.append([0.0,0.0,0.0]) - - - FaceStart = len(verts) - #inner hole - - x = sin(radians(0))*HOLE_RADIUS - y = cos(radians(0))*HOLE_RADIUS - #print ("rad 0 x;", x, "y:" ,y ) - verts.append([x,y,0.0]) - - - x = sin(radians(60/6))*HOLE_RADIUS - y = cos(radians(60/6))*HOLE_RADIUS - #print ("rad 60/6x;", x, "y:" ,y ) - verts.append([x,y,0.0]) - - - x = sin(radians(60/3))*HOLE_RADIUS - y = cos(radians(60/3))*HOLE_RADIUS - #print ("rad 60/3x;", x, "y:" ,y ) - verts.append([x,y,0.0]) - - - x = sin(radians(60/2))*HOLE_RADIUS - y = cos(radians(60/2))*HOLE_RADIUS - #print ("rad 60/2x;", x, "y:" ,y ) - verts.append([x,y,0.0]) - Row += 1 - - - #bevel - - x = sin(radians(0))*TopBevelRadius - y = cos(radians(0))*TopBevelRadius - vec1 = MATHUTILS.Vector([x,y,0.0]) - verts.append([x,y,0.0]) - - - x = sin(radians(60/6))*TopBevelRadius - y = cos(radians(60/6))*TopBevelRadius - vec2 = MATHUTILS.Vector([x,y,0.0]) - verts.append([x,y,0.0]) - - - x = sin(radians(60/3))*TopBevelRadius - y = cos(radians(60/3))*TopBevelRadius - vec3 = MATHUTILS.Vector([x,y,0.0]) - verts.append([x,y,0.0]) - - - x = sin(radians(60/2))*TopBevelRadius - y = cos(radians(60/2))*TopBevelRadius - vec4 = MATHUTILS.Vector([x,y,0.0]) - verts.append([x,y,0.0]) - Row += 1 - - #Flats - - x = tan(radians(0))*Half_Flat - dvec = vec1 - MATHUTILS.Vector([x,Half_Flat,0.0]) - verts.append([x,Half_Flat,-dvec.length]) - Lowest_Z_Vert = min(Lowest_Z_Vert,-dvec.length) - - - x = tan(radians(60/6))*Half_Flat - dvec = vec2 - MATHUTILS.Vector([x,Half_Flat,0.0]) - verts.append([x,Half_Flat,-dvec.length]) - Lowest_Z_Vert = min(Lowest_Z_Vert,-dvec.length) - - - x = tan(radians(60/3))*Half_Flat - dvec = vec3 - MATHUTILS.Vector([x,Half_Flat,0.0]) - Lowest_Point = -dvec.length - verts.append([x,Half_Flat,-dvec.length]) - Lowest_Z_Vert = min(Lowest_Z_Vert,-dvec.length) - - x = tan(radians(60/2))*Half_Flat - dvec = vec4 - MATHUTILS.Vector([x,Half_Flat,0.0]) - Lowest_Point = -dvec.length - verts.append([x,Half_Flat,-dvec.length]) - Lowest_Z_Vert = min(Lowest_Z_Vert,-dvec.length) - Row += 1 - - #down Bits Tri - x = tan(radians(0))*Half_Flat - verts.append([x,Half_Flat,Lowest_Point]) - - - x = tan(radians(60/6))*Half_Flat - verts.append([x,Half_Flat,Lowest_Point]) - x = tan(radians(60/3))*Half_Flat - verts.append([x,Half_Flat,Lowest_Point]) - - x = tan(radians(60/2))*Half_Flat - verts.append([x,Half_Flat,Lowest_Point]) - Lowest_Z_Vert = min(Lowest_Z_Vert,Lowest_Point) - Row += 1 - - #down Bits - - x = tan(radians(0))*Half_Flat - verts.append([x,Half_Flat,-Half_Height]) - - x = tan(radians(60/6))*Half_Flat - verts.append([x,Half_Flat,-Half_Height]) - - x = tan(radians(60/3))*Half_Flat - verts.append([x,Half_Flat,-Half_Height]) - - x = tan(radians(60/2))*Half_Flat - verts.append([x,Half_Flat,-Half_Height]) - Lowest_Z_Vert = min(Lowest_Z_Vert,-Half_Height) - Row += 1 - - faces.extend(Build_Face_List_Quads(FaceStart,3,Row - 1)) - - Global_Head_Height = HEIGHT - - Tvert,tface = Mirror_Verts_Faces(verts,faces,'z',Lowest_Z_Vert) - verts.extend(Tvert) - faces.extend(tface) - - - Tvert,tface = Mirror_Verts_Faces(verts,faces,'y') - verts.extend(Tvert) - faces.extend(tface) - - S_verts,S_faces = SpinDup(verts,faces,360,6,'z') - - #return verts,faces,TopBevelRadius - return S_verts,S_faces,TopBevelRadius - - - -def add_Nylon_Head(OUTSIDE_RADIUS,Z_LOCATION = 0): - DIV = 36 - verts = [] - faces = [] - Row = 0 - - INNER_HOLE = OUTSIDE_RADIUS - (OUTSIDE_RADIUS * (1.25/4.75)) - EDGE_THICKNESS = (OUTSIDE_RADIUS * (0.4/4.75)) - RAD1 = (OUTSIDE_RADIUS * (0.5/4.75)) - OVER_ALL_HEIGTH = (OUTSIDE_RADIUS * (2.0/4.75)) - - - FaceStart = len(verts) - - Start_Height = 0 - 3 - Height_Offset = Z_LOCATION - Lowest_Z_Vert = 0 - - x = INNER_HOLE - z = (Height_Offset - OVER_ALL_HEIGTH) + EDGE_THICKNESS - verts.append([x,0.0,z]) - Lowest_Z_Vert = min(Lowest_Z_Vert,z) - Row += 1 - - x = INNER_HOLE - z = (Height_Offset - OVER_ALL_HEIGTH) - verts.append([x,0.0,z]) - Lowest_Z_Vert = min(Lowest_Z_Vert,z) - Row += 1 - - - for i in range(180,80,-10): - x = sin(radians(i))*RAD1 - z = cos(radians(i))*RAD1 - verts.append([(OUTSIDE_RADIUS-RAD1)+x,0.0,((Height_Offset - OVER_ALL_HEIGTH)+RAD1)+z]) - Lowest_Z_Vert = min(Lowest_Z_Vert,z) - Row += 1 - - - x = OUTSIDE_RADIUS - 0 - z = Height_Offset - verts.append([x,0.0,z]) - Lowest_Z_Vert = min(Lowest_Z_Vert,z) - Row += 1 - - sVerts,sFaces = SpinDup(verts,faces,360,DIV,'z') - sVerts.extend(verts) #add the start verts to the Spin verts to complete the loop - - faces.extend(Build_Face_List_Quads(FaceStart,Row-1,DIV)) - - return Move_Verts_Up_Z(sVerts,0),faces,Lowest_Z_Vert - - - -def add_Nylon_Part(OUTSIDE_RADIUS,Z_LOCATION = 0): - DIV = 36 - verts = [] - faces = [] - Row = 0 - - INNER_HOLE = OUTSIDE_RADIUS - (OUTSIDE_RADIUS * (1.5/4.75)) - EDGE_THICKNESS = (OUTSIDE_RADIUS * (0.4/4.75)) - RAD1 = (OUTSIDE_RADIUS * (0.5/4.75)) - OVER_ALL_HEIGTH = (OUTSIDE_RADIUS * (2.0/4.75)) - PART_THICKNESS = OVER_ALL_HEIGTH - EDGE_THICKNESS - PART_INNER_HOLE = (OUTSIDE_RADIUS * (2.5/4.75)) - - FaceStart = len(verts) - - Start_Height = 0 - 3 - Height_Offset = Z_LOCATION - Lowest_Z_Vert = 0 - - - x = INNER_HOLE + EDGE_THICKNESS - z = Height_Offset - verts.append([x,0.0,z]) - Lowest_Z_Vert = min(Lowest_Z_Vert,z) - Row += 1 - - x = PART_INNER_HOLE - z = Height_Offset - verts.append([x,0.0,z]) - Lowest_Z_Vert = min(Lowest_Z_Vert,z) - Row += 1 - - x = PART_INNER_HOLE - z = Height_Offset - PART_THICKNESS - verts.append([x,0.0,z]) - Lowest_Z_Vert = min(Lowest_Z_Vert,z) - Row += 1 - - x = INNER_HOLE + EDGE_THICKNESS - z = Height_Offset - PART_THICKNESS - verts.append([x,0.0,z]) - Lowest_Z_Vert = min(Lowest_Z_Vert,z) - Row += 1 - - - sVerts,sFaces = SpinDup(verts,faces,360,DIV,'z') - sVerts.extend(verts) #add the start verts to the Spin verts to complete the loop - - faces.extend(Build_Face_List_Quads(FaceStart,Row-1,DIV,1)) - - return sVerts,faces,0 - Lowest_Z_Vert - - -########################################################################################## -########################################################################################## -## Create Internal Thread -########################################################################################## -########################################################################################## - - -def Create_Internal_Thread_Start_Verts(verts,INNER_RADIUS,OUTTER_RADIUS,PITCH,DIV,CREST_PERCENT,ROOT_PERCENT,Height_Offset): - - - Ret_Row = 0; - - Height_Offset = Height_Offset + PITCH #Move the offset up so that the verts start at - #at the correct place (Height_Start) - - Half_Pitch = float(PITCH)/2 - Height_Start = Height_Offset - PITCH - Height_Step = float(PITCH)/float(DIV) - Deg_Step = 360.0 /float(DIV) - - Crest_Height = float(PITCH) * float(CREST_PERCENT)/float(100) - Root_Height = float(PITCH) * float(ROOT_PERCENT)/float(100) - Root_to_Crest_Height = Crest_to_Root_Height = (float(PITCH) - (Crest_Height + Root_Height))/2.0 - - - Rank = float(OUTTER_RADIUS - INNER_RADIUS)/float(DIV) - for j in range(1): - - for i in range(DIV+1): - z = Height_Offset - (Height_Step*i) - if z > Height_Start: - z = Height_Start - x = sin(radians(i*Deg_Step))*OUTTER_RADIUS - y = cos(radians(i*Deg_Step))*OUTTER_RADIUS - verts.append([x,y,z]) - Height_Offset -= Crest_Height - Ret_Row += 1 - - for i in range(DIV+1): - z = Height_Offset - (Height_Step*i) - if z > Height_Start: - z = Height_Start - - x = sin(radians(i*Deg_Step))*OUTTER_RADIUS - y = cos(radians(i*Deg_Step))*OUTTER_RADIUS - verts.append([x,y,z ]) - Height_Offset -= Crest_to_Root_Height - Ret_Row += 1 - - - for i in range(DIV+1): - z = Height_Offset - (Height_Step*i) - if z > Height_Start: - z = Height_Start - - x = sin(radians(i*Deg_Step))*INNER_RADIUS - y = cos(radians(i*Deg_Step))*INNER_RADIUS - if j == 0: - x = sin(radians(i*Deg_Step))*(OUTTER_RADIUS - (i*Rank)) - y = cos(radians(i*Deg_Step))*(OUTTER_RADIUS - (i*Rank)) - verts.append([x,y,z ]) - Height_Offset -= Root_Height - Ret_Row += 1 - - for i in range(DIV+1): - z = Height_Offset - (Height_Step*i) - if z > Height_Start: - z = Height_Start - - x = sin(radians(i*Deg_Step))*INNER_RADIUS - y = cos(radians(i*Deg_Step))*INNER_RADIUS - - if j == 0: - x = sin(radians(i*Deg_Step))*(OUTTER_RADIUS - (i*Rank)) - y = cos(radians(i*Deg_Step))*(OUTTER_RADIUS - (i*Rank)) - verts.append([x,y,z ]) - Height_Offset -= Root_to_Crest_Height - Ret_Row += 1 - - return Ret_Row,Height_Offset - - -def Create_Internal_Thread_End_Verts(verts,INNER_RADIUS,OUTTER_RADIUS,PITCH,DIV,CREST_PERCENT,ROOT_PERCENT,Height_Offset): - - - Ret_Row = 0; - - Half_Pitch = float(PITCH)/2 - #Height_End = Height_Offset - PITCH - PITCH - PITCH- PITCH - PITCH- PITCH - Height_End = Height_Offset - PITCH - #Height_End = -2.1 - Height_Step = float(PITCH)/float(DIV) - Deg_Step = 360.0 /float(DIV) - - Crest_Height = float(PITCH) * float(CREST_PERCENT)/float(100) - Root_Height = float(PITCH) * float(ROOT_PERCENT)/float(100) - Root_to_Crest_Height = Crest_to_Root_Height = (float(PITCH) - (Crest_Height + Root_Height))/2.0 - - - Rank = float(OUTTER_RADIUS - INNER_RADIUS)/float(DIV) - - Num = 0 - - for j in range(2): - - for i in range(DIV+1): - z = Height_Offset - (Height_Step*i) - if z < Height_End: - z = Height_End - x = sin(radians(i*Deg_Step))*OUTTER_RADIUS - y = cos(radians(i*Deg_Step))*OUTTER_RADIUS - verts.append([x,y,z]) - Height_Offset -= Crest_Height - Ret_Row += 1 - - - for i in range(DIV+1): - z = Height_Offset - (Height_Step*i) - if z < Height_End: - z = Height_End - - x = sin(radians(i*Deg_Step))*OUTTER_RADIUS - y = cos(radians(i*Deg_Step))*OUTTER_RADIUS - verts.append([x,y,z ]) - Height_Offset -= Crest_to_Root_Height - Ret_Row += 1 - - - for i in range(DIV+1): - z = Height_Offset - (Height_Step*i) - if z < Height_End: - z = Height_End - - x = sin(radians(i*Deg_Step))*INNER_RADIUS - y = cos(radians(i*Deg_Step))*INNER_RADIUS - if j == Num: - x = sin(radians(i*Deg_Step))*(INNER_RADIUS + (i*Rank)) - y = cos(radians(i*Deg_Step))*(INNER_RADIUS + (i*Rank)) - if j > Num: - x = sin(radians(i*Deg_Step))*(OUTTER_RADIUS) - y = cos(radians(i*Deg_Step))*(OUTTER_RADIUS ) - - verts.append([x,y,z ]) - Height_Offset -= Root_Height - Ret_Row += 1 - - - for i in range(DIV+1): - z = Height_Offset - (Height_Step*i) - if z < Height_End: - z = Height_End - - x = sin(radians(i*Deg_Step))*INNER_RADIUS - y = cos(radians(i*Deg_Step))*INNER_RADIUS - - if j == Num: - x = sin(radians(i*Deg_Step))*(INNER_RADIUS + (i*Rank)) - y = cos(radians(i*Deg_Step))*(INNER_RADIUS + (i*Rank)) - if j > Num: - x = sin(radians(i*Deg_Step))*(OUTTER_RADIUS ) - y = cos(radians(i*Deg_Step))*(OUTTER_RADIUS ) - - verts.append([x,y,z ]) - Height_Offset -= Root_to_Crest_Height - Ret_Row += 1 - - - return Ret_Row,Height_End # send back Height End as this is the lowest point - - -def Create_Internal_Thread(INNER_DIA,OUTTER_DIA,PITCH,HEIGHT,CREST_PERCENT,ROOT_PERCENT,INTERNAL = 1): - verts = [] - faces = [] - - DIV = 36 - - INNER_RADIUS = INNER_DIA/2 - OUTTER_RADIUS = OUTTER_DIA/2 - - Half_Pitch = float(PITCH)/2 - Deg_Step = 360.0 /float(DIV) - Height_Step = float(PITCH)/float(DIV) - - Num = int(round((HEIGHT- PITCH)/PITCH)) # less one pitch for the start and end that is 1/2 pitch high - - Col = 0 - Row = 0 - - - Crest_Height = float(PITCH) * float(CREST_PERCENT)/float(100) - Root_Height = float(PITCH) * float(ROOT_PERCENT)/float(100) - Root_to_Crest_Height = Crest_to_Root_Height = (float(PITCH) - (Crest_Height + Root_Height))/2.0 - - Height_Offset = 0 - FaceStart = len(verts) - - Row_Inc,Height_Offset = Create_Internal_Thread_Start_Verts(verts,INNER_RADIUS,OUTTER_RADIUS,PITCH,DIV,CREST_PERCENT,ROOT_PERCENT,Height_Offset) - Row += Row_Inc - - for j in range(Num): - - for i in range(DIV+1): - x = sin(radians(i*Deg_Step))*OUTTER_RADIUS - y = cos(radians(i*Deg_Step))*OUTTER_RADIUS - verts.append([x,y,Height_Offset - (Height_Step*i) ]) - Height_Offset -= Crest_Height - Row += 1 - - for i in range(DIV+1): - x = sin(radians(i*Deg_Step))*OUTTER_RADIUS - y = cos(radians(i*Deg_Step))*OUTTER_RADIUS - verts.append([x,y,Height_Offset - (Height_Step*i) ]) - Height_Offset -= Crest_to_Root_Height - Row += 1 - - for i in range(DIV+1): - x = sin(radians(i*Deg_Step))*INNER_RADIUS - y = cos(radians(i*Deg_Step))*INNER_RADIUS - verts.append([x,y,Height_Offset - (Height_Step*i) ]) - Height_Offset -= Root_Height - Row += 1 - - for i in range(DIV+1): - x = sin(radians(i*Deg_Step))*INNER_RADIUS - y = cos(radians(i*Deg_Step))*INNER_RADIUS - verts.append([x,y,Height_Offset - (Height_Step*i) ]) - Height_Offset -= Root_to_Crest_Height - Row += 1 - - - Row_Inc,Height_Offset = Create_Internal_Thread_End_Verts(verts,INNER_RADIUS,OUTTER_RADIUS,PITCH,DIV,CREST_PERCENT,ROOT_PERCENT,Height_Offset) - Row += Row_Inc - - faces.extend(Build_Face_List_Quads(FaceStart,DIV,Row -1,INTERNAL)) - - return verts,faces,0 - Height_Offset - - -def Nut_Mesh(props, context): - - verts = [] - faces = [] - Head_Verts = [] - Head_Faces= [] - #sc = context.scene - - New_Nut_Height = 5 - - Face_Start = len(verts) - Thread_Verts,Thread_Faces,New_Nut_Height = Create_Internal_Thread(props.bf_Minor_Dia,props.bf_Major_Dia,props.bf_Pitch,props.bf_Hex_Nut_Height,props.bf_Crest_Percent,props.bf_Root_Percent,1) - verts.extend(Thread_Verts) - faces.extend(Copy_Faces(Thread_Faces,Face_Start)) - - Face_Start = len(verts) - Head_Verts,Head_Faces,Lock_Nut_Rad = add_Hex_Nut(props.bf_Hex_Nut_Flat_Distance,props.bf_Major_Dia,New_Nut_Height) - verts.extend((Head_Verts)) - faces.extend(Copy_Faces(Head_Faces,Face_Start)) - - LowZ = 0 - New_Nut_Height - - if props.bf_Nut_Type == 'bf_Nut_Lock': - Face_Start = len(verts) - Nylon_Head_Verts,Nylon_Head_faces,LowZ = add_Nylon_Head(Lock_Nut_Rad,0-New_Nut_Height) - verts.extend((Nylon_Head_Verts)) - faces.extend(Copy_Faces(Nylon_Head_faces,Face_Start)) - - Face_Start = len(verts) - Nylon_Verts,Nylon_faces,Temp_LowZ = add_Nylon_Part(Lock_Nut_Rad,0-New_Nut_Height) - verts.extend((Nylon_Verts)) - faces.extend(Copy_Faces(Nylon_faces,Face_Start)) - - - return Move_Verts_Up_Z(verts,0 - LowZ),faces - - - -########################################################################################## -########################################################################################## -########################################################################################## -## Create Bolt -########################################################################################## -########################################################################################## - - - -def Bolt_Mesh(props, context): - - - verts = [] - faces = [] - Bit_Verts = [] - Bit_Faces = [] - Bit_Dia = 0.001 - Head_Verts = [] - Head_Faces= [] - Head_Height = 0.0 - #sc = context.scene - - ReSized_Allen_Bit_Flat_Distance = props.bf_Allen_Bit_Flat_Distance # set default - - - Head_Height = props.bf_Hex_Head_Height # will be changed by the Head Functions - - - if props.bf_Bit_Type == 'bf_Bit_Allen' and props.bf_Head_Type == 'bf_Head_Pan': - #need to size Allen bit if it is too big. - if Allen_Bit_Dia(props.bf_Allen_Bit_Flat_Distance) > Max_Pan_Bit_Dia(props.bf_Pan_Head_Dia): - ReSized_Allen_Bit_Flat_Distance = Allen_Bit_Dia_To_Flat(Max_Pan_Bit_Dia(props.bf_Pan_Head_Dia)) * 1.05 - #print ("Resized Allen Bit Flat Distance to ",ReSized_Allen_Bit_Flat_Distance) - - #bit Mesh - if props.bf_Bit_Type == 'bf_Bit_Allen': - Bit_Verts,Bit_Faces,Bit_Dia = Create_Allen_Bit(ReSized_Allen_Bit_Flat_Distance,props.bf_Allen_Bit_Depth) - - if props.bf_Bit_Type == 'bf_Bit_Philips': - Bit_Verts,Bit_Faces,Bit_Dia = Create_Phillips_Bit(props.bf_Philips_Bit_Dia,props.bf_Philips_Bit_Dia*(0.5/1.82),props.bf_Phillips_Bit_Depth) - - - #Head Mesh - - if props.bf_Head_Type =='bf_Head_Hex': - Head_Verts,Head_Faces,Head_Height = Create_Hex_Head(props.bf_Hex_Head_Flat_Distance,Bit_Dia,props.bf_Shank_Dia,props.bf_Hex_Head_Height) - - elif props.bf_Head_Type == 'bf_Head_Cap': - Head_Verts,Head_Faces,Head_Height = Create_Cap_Head(Bit_Dia,props.bf_Cap_Head_Dia,props.bf_Shank_Dia,props.bf_Cap_Head_Height,props.bf_Cap_Head_Dia*(1.0/19.0),props.bf_Cap_Head_Dia*(1.0/19.0)) - - elif props.bf_Head_Type =='bf_Head_Dome': - Head_Verts,Head_Faces,Head_Height = Create_Dome_Head(Bit_Dia,props.bf_Dome_Head_Dia,props.bf_Shank_Dia,props.bf_Hex_Head_Height,1,1,0) - - elif props.bf_Head_Type == 'bf_Head_Pan': - Head_Verts,Head_Faces,Head_Height = Create_Pan_Head(Bit_Dia,props.bf_Pan_Head_Dia,props.bf_Shank_Dia,props.bf_Hex_Head_Height,1,1,0) - - elif props.bf_Head_Type == 'bf_Head_CounterSink': - Head_Verts,Head_Faces,Head_Height = Create_CounterSink_Head(Bit_Dia,props.bf_CounterSink_Head_Dia,props.bf_Shank_Dia,props.bf_CounterSink_Head_Dia,props.bf_CounterSink_Head_Dia*(0.09/6.31)) -#Head_Verts,Head_Faces,Head_Height = Create_CounterSink_Head(Bit_Dia,props.bf_CounterSink_Head_Dia,props.bf_Shank_Dia,props.bf_CounterSink_Head_Dia,props.bf_CounterSink_Head_Dia*(1.0/19.0)) - - Face_Start = len(verts) - verts.extend(Move_Verts_Up_Z(Bit_Verts,Head_Height)) - faces.extend(Copy_Faces(Bit_Faces,Face_Start)) - - Face_Start = len(verts) - verts.extend(Move_Verts_Up_Z(Head_Verts,Head_Height)) - faces.extend(Copy_Faces(Head_Faces,Face_Start)) - - Face_Start = len(verts) - Thread_Verts,Thread_Faces,Thread_Height = Create_External_Thread(props.bf_Shank_Dia,props.bf_Shank_Length,props.bf_Minor_Dia,props.bf_Major_Dia,props.bf_Pitch,props.bf_Thread_Length,props.bf_Crest_Percent,props.bf_Root_Percent) - - verts.extend(Move_Verts_Up_Z(Thread_Verts,00)) - faces.extend(Copy_Faces(Thread_Faces,Face_Start)) - - return Move_Verts_Up_Z(verts,Thread_Height),faces - - -def Create_New_Mesh(props, context, align_matrix): - - verts = [] - faces = [] - sMeshName ='' - sObjName ='' - - if props.bf_Model_Type == 'bf_Model_Bolt': - #print('Create Bolt') - verts, faces = Bolt_Mesh(props, context) - sMeshName = 'Bolt' - sObjName = 'Bolt' - - if props.bf_Model_Type == 'bf_Model_Nut': - #print('Create Nut') - verts, faces = Nut_Mesh(props, context) - sMeshName = 'Nut' - sObjName = 'Nut' - - - verts, faces = RemoveDoubles(verts, faces) - - verts = Scale_Mesh_Verts(verts,GLOBAL_SCALE) - - - mesh = bpy.data.meshes.new(sMeshName) - - mesh.vertices.add(len(verts)) - mesh.faces.add(len(faces)) - - mesh.vertices.foreach_set("co", unpack_list(verts)) - mesh.faces.foreach_set("vertices_raw", unpack_face_list(faces)) - - - scene = context.scene - - bpy.ops.object.select_all(action='DESELECT') - - mesh.update() - ob_new = bpy.data.objects.new(sObjName, mesh) - scene.objects.link(ob_new) - ob_new.select = True - scene.objects.active = ob_new - - #ob_new.location = scene.cursor_location - ob_new.matrix_world = align_matrix - - #print("Created_Object") - return - - diff --git a/add_mesh_BoltFactory/preset_utils.py b/add_mesh_BoltFactory/preset_utils.py deleted file mode 100644 index d477b94a..00000000 --- a/add_mesh_BoltFactory/preset_utils.py +++ /dev/null @@ -1,53 +0,0 @@ -# ##### 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -# ##### END GPL LICENSE BLOCK ##### - - -import bpy -import os, sys - - -def getPresets(): - - scriptPath = os.path.join(bpy.utils.script_paths()[0], "addons" , "add_mesh_BoltFactory") - presetPath = os.path.join(scriptPath, "presets") - presetFiles = os.listdir(presetPath) - #presetFiles.sort() - - presets = [(presetFile, presetFile.rpartition(".")[0], presetFile) - for i, presetFile in enumerate(presetFiles)] - - #print(presets) - return presets, presetPath - - -#presets = getPresets() - - - -def setProps(props, preset, presetsPath): - - #bpy.ops.script.python_file_run(filepath=presetsPath + '\\' + preset) - - file = open(os.path.join(presetsPath, preset)) - - for line in file: - exec(line) - - file.close() - - return diff --git a/add_mesh_BoltFactory/presets/M10.py b/add_mesh_BoltFactory/presets/M10.py deleted file mode 100644 index f2ea9c8d..00000000 --- a/add_mesh_BoltFactory/presets/M10.py +++ /dev/null @@ -1,22 +0,0 @@ -props.bf_Shank_Dia = 10.0 -#props.bf_Pitch = 1.5 #Coarse -props.bf_Pitch = 1.25 #Fine -props.bf_Crest_Percent = 10 -props.bf_Root_Percent = 10 -props.bf_Major_Dia = 10.0 -props.bf_Minor_Dia = props.bf_Major_Dia - (1.082532 * props.bf_Pitch) -props.bf_Hex_Head_Flat_Distance = 17.0 -props.bf_Hex_Head_Height = 6.4 -props.bf_Cap_Head_Dia = 16.0 -props.bf_Cap_Head_Height = 10.0 -props.bf_CounterSink_Head_Dia = 20.0 -props.bf_Allen_Bit_Flat_Distance = 8.0 -props.bf_Allen_Bit_Depth = 5.0 -props.bf_Pan_Head_Dia = 20.0 -props.bf_Dome_Head_Dia = 20.0 -props.bf_Philips_Bit_Dia = props.bf_Pan_Head_Dia*(1.82/5.6) -#props.bf_Phillips_Bit_Depth = Get_Phillips_Bit_Height(props.bf_Philips_Bit_Dia) -props.bf_Hex_Nut_Height = 8.0 -props.bf_Hex_Nut_Flat_Distance = 17.0 -props.bf_Thread_Length = 20 -props.bf_Shank_Length = 0.0 diff --git a/add_mesh_BoltFactory/presets/M12.py b/add_mesh_BoltFactory/presets/M12.py deleted file mode 100644 index 44f3876f..00000000 --- a/add_mesh_BoltFactory/presets/M12.py +++ /dev/null @@ -1,22 +0,0 @@ -#props.bf_Pitch = 1.75 #Coarse -props.bf_Pitch = 1.50 #Fine -props.bf_Crest_Percent = 10 -props.bf_Root_Percent = 10 -props.bf_Major_Dia = 12.0 -props.bf_Minor_Dia = props.bf_Major_Dia - (1.082532 * props.bf_Pitch) -props.bf_Hex_Head_Flat_Distance = 19.0 -props.bf_Hex_Head_Height = 7.5 -props.bf_Cap_Head_Dia = 18.5 -props.bf_Cap_Head_Height = 12.0 -props.bf_CounterSink_Head_Dia = 22.0 -props.bf_Allen_Bit_Flat_Distance = 10.0 -props.bf_Allen_Bit_Depth = 6.0 -props.bf_Pan_Head_Dia = 24.0 -props.bf_Dome_Head_Dia = 24.0 -props.bf_Philips_Bit_Dia = props.bf_Pan_Head_Dia*(1.82/5.6) -#props.bf_Phillips_Bit_Depth = Get_Phillips_Bit_Height(props.bf_Philips_Bit_Dia) -props.bf_Hex_Nut_Height = 10.0 -props.bf_Hex_Nut_Flat_Distance = 19.0 -props.bf_Shank_Dia = 12.0 -props.bf_Shank_Length = 33.0 -props.bf_Thread_Length = 32.0 diff --git a/add_mesh_BoltFactory/presets/M3.py b/add_mesh_BoltFactory/presets/M3.py deleted file mode 100644 index 3e970468..00000000 --- a/add_mesh_BoltFactory/presets/M3.py +++ /dev/null @@ -1,22 +0,0 @@ -props.bf_Shank_Dia = 3.0 -#props.bf_Pitch = 0.5 #Coarse -props.bf_Pitch = 0.35 #Fine -props.bf_Crest_Percent = 10 -props.bf_Root_Percent = 10 -props.bf_Major_Dia = 3.0 -props.bf_Minor_Dia = props.bf_Major_Dia - (1.082532 * props.bf_Pitch) -props.bf_Hex_Head_Flat_Distance = 5.5 -props.bf_Hex_Head_Height = 2.0 -props.bf_Cap_Head_Dia = 5.5 -props.bf_Cap_Head_Height = 3.0 -props.bf_CounterSink_Head_Dia = 6.3 -props.bf_Allen_Bit_Flat_Distance = 2.5 -props.bf_Allen_Bit_Depth = 1.5 -props.bf_Pan_Head_Dia = 5.6 -props.bf_Dome_Head_Dia = 5.6 -props.bf_Philips_Bit_Dia = props.bf_Pan_Head_Dia*(1.82/5.6) -#props.bf_Phillips_Bit_Depth = Get_Phillips_Bit_Height(props.bf_Philips_Bit_Dia) -props.bf_Hex_Nut_Height = 2.4 -props.bf_Hex_Nut_Flat_Distance = 5.5 -props.bf_Thread_Length = 6 -props.bf_Shank_Length = 0.0 diff --git a/add_mesh_BoltFactory/presets/M4.py b/add_mesh_BoltFactory/presets/M4.py deleted file mode 100644 index 5682b442..00000000 --- a/add_mesh_BoltFactory/presets/M4.py +++ /dev/null @@ -1,22 +0,0 @@ -props.bf_Shank_Dia = 4.0 -#props.bf_Pitch = 0.7 #Coarse -props.bf_Pitch = 0.5 #Fine -props.bf_Crest_Percent = 10 -props.bf_Root_Percent = 10 -props.bf_Major_Dia = 4.0 -props.bf_Minor_Dia = props.bf_Major_Dia - (1.082532 * props.bf_Pitch) -props.bf_Hex_Head_Flat_Distance = 7.0 -props.bf_Hex_Head_Height = 2.8 -props.bf_Cap_Head_Dia = 7.0 -props.bf_Cap_Head_Height = 4.0 -props.bf_CounterSink_Head_Dia = 9.4 -props.bf_Allen_Bit_Flat_Distance = 3.0 -props.bf_Allen_Bit_Depth = 2.0 -props.bf_Pan_Head_Dia = 8.0 -props.bf_Dome_Head_Dia = 8.0 -props.bf_Philips_Bit_Dia = props.bf_Pan_Head_Dia*(1.82/5.6) -#props.bf_Phillips_Bit_Depth = Get_Phillips_Bit_Height(props.bf_Philips_Bit_Dia) -props.bf_Hex_Nut_Height = 3.2 -props.bf_Hex_Nut_Flat_Distance = 7.0 -props.bf_Thread_Length = 8 -props.bf_Shank_Length = 0.0 diff --git a/add_mesh_BoltFactory/presets/M5.py b/add_mesh_BoltFactory/presets/M5.py deleted file mode 100644 index b889f349..00000000 --- a/add_mesh_BoltFactory/presets/M5.py +++ /dev/null @@ -1,22 +0,0 @@ -props.bf_Shank_Dia = 5.0 -#props.bf_Pitch = 0.8 #Coarse -props.bf_Pitch = 0.5 #Fine -props.bf_Crest_Percent = 10 -props.bf_Root_Percent = 10 -props.bf_Major_Dia = 5.0 -props.bf_Minor_Dia = props.bf_Major_Dia - (1.082532 * props.bf_Pitch) -props.bf_Hex_Head_Flat_Distance = 8.0 -props.bf_Hex_Head_Height = 3.5 -props.bf_Cap_Head_Dia = 8.5 -props.bf_Cap_Head_Height = 5.0 -props.bf_CounterSink_Head_Dia = 10.4 -props.bf_Allen_Bit_Flat_Distance = 4.0 -props.bf_Allen_Bit_Depth = 2.5 -props.bf_Pan_Head_Dia = 9.5 -props.bf_Dome_Head_Dia = 9.5 -props.bf_Philips_Bit_Dia = props.bf_Pan_Head_Dia*(1.82/5.6) -#props.bf_Phillips_Bit_Depth = Get_Phillips_Bit_Height(props.bf_Philips_Bit_Dia) -props.bf_Hex_Nut_Height = 4.0 -props.bf_Hex_Nut_Flat_Distance = 8.0 -props.bf_Thread_Length = 10 -props.bf_Shank_Length = 0.0 diff --git a/add_mesh_BoltFactory/presets/M6.py b/add_mesh_BoltFactory/presets/M6.py deleted file mode 100644 index 2b11a43d..00000000 --- a/add_mesh_BoltFactory/presets/M6.py +++ /dev/null @@ -1,22 +0,0 @@ -props.bf_Shank_Dia = 6.0 -#bf_Pitch = 1.0 #Coarse -props.bf_Pitch = 0.75 #Fine -props.bf_Crest_Percent = 10 -props.bf_Root_Percent = 10 -props.bf_Major_Dia = 6.0 -props.bf_Minor_Dia = props.bf_Major_Dia - (1.082532 * props.bf_Pitch) -props.bf_Hex_Head_Flat_Distance = 10.0 -props.bf_Hex_Head_Height = 4.0 -props.bf_Cap_Head_Dia = 10.0 -props.bf_Cap_Head_Height = 6.0 -props.bf_CounterSink_Head_Dia = 12.6 -props.bf_Allen_Bit_Flat_Distance = 5.0 -props.bf_Allen_Bit_Depth = 3.0 -props.bf_Pan_Head_Dia = 12.0 -props.bf_Dome_Head_Dia = 12.0 -props.bf_Philips_Bit_Dia = props.bf_Pan_Head_Dia*(1.82/5.6) -#props.bf_Phillips_Bit_Depth = Get_Phillips_Bit_Height(props.bf_Philips_Bit_Dia) -props.bf_Hex_Nut_Height = 5.0 -props.bf_Hex_Nut_Flat_Distance = 10.0 -props.bf_Thread_Length = 12 -props.bf_Shank_Length = 0.0 diff --git a/add_mesh_BoltFactory/presets/M8.py b/add_mesh_BoltFactory/presets/M8.py deleted file mode 100644 index 77cbb497..00000000 --- a/add_mesh_BoltFactory/presets/M8.py +++ /dev/null @@ -1,22 +0,0 @@ -props.bf_Shank_Dia = 8.0 -#props.bf_Pitch = 1.25 #Coarse -props.bf_Pitch = 1.00 #Fine -props.bf_Crest_Percent = 10 -props.bf_Root_Percent = 10 -props.bf_Major_Dia = 8.0 -props.bf_Minor_Dia = props.bf_Major_Dia - (1.082532 * props.bf_Pitch) -props.bf_Hex_Head_Flat_Distance = 13.0 -props.bf_Hex_Head_Height = 5.3 -props.bf_Cap_Head_Dia = 13.5 -props.bf_Cap_Head_Height = 8.0 -props.bf_CounterSink_Head_Dia = 17.3 -props.bf_Allen_Bit_Flat_Distance = 6.0 -props.bf_Allen_Bit_Depth = 4.0 -props.bf_Pan_Head_Dia = 16.0 -props.bf_Dome_Head_Dia = 16.0 -props.bf_Philips_Bit_Dia = props.bf_Pan_Head_Dia*(1.82/5.6) -#props.bf_Phillips_Bit_Depth = Get_Phillips_Bit_Height(props.bf_Philips_Bit_Dia) -props.bf_Hex_Nut_Height = 6.5 -props.bf_Hex_Nut_Flat_Distance = 13.0 -props.bf_Thread_Length = 16 -props.bf_Shank_Length = 0.0 diff --git a/add_mesh_ant_landscape.py b/add_mesh_ant_landscape.py deleted file mode 100644 index b1b42612..00000000 --- a/add_mesh_ant_landscape.py +++ /dev/null @@ -1,913 +0,0 @@ -# ##### 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -# ##### END GPL LICENSE BLOCK ##### - -bl_addon_info = { - "name": "ANT Landscape", - "author": "Jimmy Hazevoet", - "version": (0,1,0), - "blender": (2, 5, 3), - "api": 31854, - "location": "Add Mesh menu", - "description": "Adds a landscape primitive", - "warning": "", # used for warning icon and text in addons panel - "wiki_url": "http://wiki.blender.org/index.php/Extensions:2.5/Py/"\ - "Scripts/Add_Mesh/ANT_Landscape", - "tracker_url": "https://projects.blender.org/tracker/index.php?"\ - "func=detail&aid=23130&group_id=153&atid=469", - "category": "Add Mesh"} - -''' -Another Noise Tool: Landscape mesh generator - -MESH OPTIONS: -Mesh update: Turn this on for interactive mesh update. -Sphere: Generate sphere or a grid mesh. (Turn height falloff off for sphere mesh) -Smooth: Generate smooth shaded mesh. -Subdivision: Number of mesh subdivisions, higher numbers gives more detail but also slows down the script. -Mesh size: X,Y size of the grid mesh (in blender units). - -NOISE OPTIONS: ( Most of these options are the same as in blender textures. ) -Random seed: Use this to randomise the origin of the noise function. -Noise size: Size of the noise. -Noise type: Available noise types: multiFractal, ridgedMFractal, hybridMFractal, heteroTerrain, Turbulence, Distorted Noise, Cellnoise, Shattered_hTerrain, Marble -Noise basis: Blender, Perlin, NewPerlin, Voronoi_F1, Voronoi_F2, Voronoi_F3, Voronoi_F4, Voronoi_F2-F1, Voronoi Crackle, Cellnoise -VLNoise basis: Blender, Perlin, NewPerlin, Voronoi_F1, Voronoi_F2, Voronoi_F3, Voronoi_F4, Voronoi_F2-F1, Voronoi Crackle, Cellnoise -Distortion: Distortion amount. -Hard: Hard/Soft turbulence noise. -Depth: Noise depth, number of frequencies in the fBm. -Dimension: Musgrave: Fractal dimension of the roughest areas. -Lacunarity: Musgrave: Gap between successive frequencies. -Offset: Musgrave: Raises the terrain from sea level. -Gain: Musgrave: Scale factor. -Marble Bias: Sin, Tri, Saw -Marble Sharpnes: Soft, Sharp, Sharper -Marble Shape: Shape of the marble function: Default, Ring, Swirl, X, Y - -HEIGHT OPTIONS: -Invert: Invert terrain height. -Height: Scale terrain height. -Offset: Terrain height offset. -Falloff: Terrain height falloff: Type 1, Type 2, X, Y -Sealevel: Flattens terrain below sealevel. -Platlevel: Flattens terrain above plateau level. -Strata: Strata amount, number of strata/terrace layers. -Strata type: Strata types, Smooth, Sharp-sub, Sharp-add -''' - -# import modules -import bpy -from bpy.props import * -from mathutils import * -from noise import * -from math import * - - -###------------------------------------------------------------ -# calculates the matrix for the new object depending on user pref -def align_matrix(context): - loc = Matrix.Translation(context.scene.cursor_location) - obj_align = context.user_preferences.edit.object_align - if (context.space_data.type == 'VIEW_3D' - and obj_align == 'VIEW'): - rot = context.space_data.region_3d.view_matrix.rotation_part().invert().resize4x4() - else: - rot = Matrix() - align_matrix = loc * rot - return align_matrix - -# Create a new mesh (object) from verts/edges/faces. -# verts/edges/faces ... List of vertices/edges/faces for the -# new mesh (as used in from_pydata). -# name ... Name of the new mesh (& object). -# edit ... Replace existing mesh data. -# Note: Using "edit" will destroy/delete existing mesh data. -def create_mesh_object(context, verts, edges, faces, name, edit, align_matrix): - scene = context.scene - obj_act = scene.objects.active - - # Can't edit anything, unless we have an active obj. - if edit and not obj_act: - return None - - # Create new mesh - mesh = bpy.data.meshes.new(name) - - # Make a mesh from a list of verts/edges/faces. - mesh.from_pydata(verts, edges, faces) - - # Update mesh geometry after adding stuff. - mesh.update() - - # Deselect all objects. - bpy.ops.object.select_all(action='DESELECT') - - if edit: - # Replace geometry of existing object - - # Use the active obj and select it. - ob_new = obj_act - ob_new.select = True - - if obj_act.mode == 'OBJECT': - # Get existing mesh datablock. - old_mesh = ob_new.data - - # Set object data to nothing - ob_new.data = None - - # Clear users of existing mesh datablock. - old_mesh.user_clear() - - # Remove old mesh datablock if no users are left. - if (old_mesh.users == 0): - bpy.data.meshes.remove(old_mesh) - - # Assign new mesh datablock. - ob_new.data = mesh - - else: - # Create new object - ob_new = bpy.data.objects.new(name, mesh) - - # Link new object to the given scene and select it. - scene.objects.link(ob_new) - ob_new.select = True - - # Place the object at the 3D cursor location. - # apply viewRotaion - ob_new.matrix_world = align_matrix - - if obj_act and obj_act.mode == 'EDIT': - if not edit: - # We are in EditMode, switch to ObjectMode. - bpy.ops.object.mode_set(mode='OBJECT') - - # Select the active object as well. - obj_act.select = True - - # Apply location of new object. - scene.update() - - # Join new object into the active. - bpy.ops.object.join() - - # Switching back to EditMode. - bpy.ops.object.mode_set(mode='EDIT') - - ob_new = obj_act - - else: - # We are in ObjectMode. - # Make the new object the active one. - scene.objects.active = ob_new - - return ob_new - -# A very simple "bridge" tool. -# Connects two equally long vertex rows with faces. -# Returns a list of the new faces (list of lists) -# -# vertIdx1 ... First vertex list (list of vertex indices). -# vertIdx2 ... Second vertex list (list of vertex indices). -# closed ... Creates a loop (first & last are closed). -# flipped ... Invert the normal of the face(s). -# -# Note: You can set vertIdx1 to a single vertex index to create -# a fan/star of faces. -# Note: If both vertex idx list are the same length they have -# to have at least 2 vertices. -def createFaces(vertIdx1, vertIdx2, closed=False, flipped=False): - faces = [] - - if not vertIdx1 or not vertIdx2: - return None - - if len(vertIdx1) < 2 and len(vertIdx2) < 2: - return None - - fan = False - if (len(vertIdx1) != len(vertIdx2)): - if (len(vertIdx1) == 1 and len(vertIdx2) > 1): - fan = True - else: - return None - - total = len(vertIdx2) - - if closed: - # Bridge the start with the end. - if flipped: - face = [ - vertIdx1[0], - vertIdx2[0], - vertIdx2[total - 1]] - if not fan: - face.append(vertIdx1[total - 1]) - faces.append(face) - - else: - face = [vertIdx2[0], vertIdx1[0]] - if not fan: - face.append(vertIdx1[total - 1]) - face.append(vertIdx2[total - 1]) - faces.append(face) - - # Bridge the rest of the faces. - for num in range(total - 1): - if flipped: - if fan: - face = [vertIdx2[num], vertIdx1[0], vertIdx2[num + 1]] - else: - face = [vertIdx2[num], vertIdx1[num], - vertIdx1[num + 1], vertIdx2[num + 1]] - faces.append(face) - else: - if fan: - face = [vertIdx1[0], vertIdx2[num], vertIdx2[num + 1]] - else: - face = [vertIdx1[num], vertIdx2[num], - vertIdx2[num + 1], vertIdx1[num + 1]] - faces.append(face) - - return faces - - -###------------------------------------------------------------ -###------------------------------------------------------------ -# some functions for marble_noise -def sin_bias(a): - return 0.5 + 0.5 * sin(a) - -def tri_bias(a): - b = 2 * pi - a = 1 - 2 * abs(floor((a * (1/b))+0.5) - (a*(1/b))) - return a - -def saw_bias(a): - b = 2 * pi - n = int(a/b) - a -= n * b - if a < 0: a += b - return a / b - -def soft(a): - return a - -def sharp(a): - return a**0.5 - -def sharper(a): - return sharp(sharp(a)) - -def shapes(x,y,shape=0): - if shape == 1: - # ring - x = x*2 - y = y*2 - s = (-cos(x**2+y**2)/(x**2+y**2+0.5)) - elif shape == 2: - # swirl - x = x*2 - y = y*2 - s = (( x*sin( x*x+y*y ) + y*cos( x*x+y*y ) ) / (x**2+y**2+0.5)) - elif shape == 3: - # bumps - x = x*2 - y = y*2 - s = ((cos( x*pi ) + cos( y*pi ))-0.5) - elif shape == 4: - # y grad. - s = (y*pi) - elif shape == 5: - # x grad. - s = (x*pi) - else: - # marble - s = ((x+y)*5) - return s - -# marble_noise -def marble_noise(x,y,z, origin, size, shape, bias, sharpnes, turb, depth, hard, basis ): - x = x / size - y = y / size - z = z / size - s = shapes(x,y,shape) - - x += origin[0] - y += origin[1] - z += origin[2] - value = s + turb * turbulence_vector((x,y,z), depth, hard, basis )[0] - - if bias == 1: - value = tri_bias( value ) - elif bias == 2: - value = saw_bias( value ) - else: - value = sin_bias( value ) - - if sharpnes == 1: - value = sharp( value ) - elif sharpnes == 2: - value = sharper( value ) - else: - value = soft( value ) - - return value - -###------------------------------------------------------------ -# custom noise types - -# shattered_hterrain: -def shattered_hterrain( x,y,z, H, lacunarity, octaves, offset, distort, basis ): - d = ( turbulence_vector( ( x, y, z ), 6, 0, 0 )[0] * 0.5 + 0.5 )*distort*0.5 - t1 = ( turbulence_vector( ( x+d, y+d, z ), 0, 0, 7 )[0] + 0.5 ) - t2 = ( hetero_terrain(( x*2, y*2, z*2 ), H, lacunarity, octaves, offset, basis )*0.5 ) - return (( t1*t2 )+t2*0.5) * 0.5 - -# strata_hterrain -def strata_hterrain( x,y,z, H, lacunarity, octaves, offset, distort, basis ): - value = hetero_terrain(( x, y, z ), H, lacunarity, octaves, offset, basis )*0.5 - steps = ( sin( value*(distort*5)*pi ) * ( 0.1/(distort*5)*pi ) ) - return ( value * (1.0-0.5) + steps*0.5 ) - -###------------------------------------------------------------ -# landscape_gen -def landscape_gen(x,y,z,falloffsize,options=[0,1.0,1, 0,0,1.0,0,6,1.0,2.0,1.0,2.0,0,0,0, 1.0,0.0,1,0.0,1.0,0,0,0]): - - # options - rseed = options[0] - nsize = options[1] - ntype = int( options[2][0] ) - nbasis = int( options[3][0] ) - vlbasis = int( options[4][0] ) - distortion = options[5] - hardnoise = options[6] - depth = options[7] - dimension = options[8] - lacunarity = options[9] - offset = options[10] - gain = options[11] - marblebias = int( options[12][0] ) - marblesharpnes = int( options[13][0] ) - marbleshape = int( options[14][0] ) - invert = options[15] - height = options[16] - heightoffset = options[17] - falloff = int( options[18][0] ) - sealevel = options[19] - platlevel = options[20] - strata = options[21] - stratatype = options[22] - sphere = options[23] - - # origin - if rseed == 0: - origin = 0.0,0.0,0.0 - origin_x = 0.0 - origin_y = 0.0 - origin_z = 0.0 - else: - # randomise origin - seed_set( rseed ) - origin = random_unit_vector() - origin_x = ( 0.5 - origin[0] ) * 1000.0 - origin_y = ( 0.5 - origin[1] ) * 1000.0 - origin_z = ( 0.5 - origin[2] ) * 1000.0 - - # adjust noise size and origin - ncoords = ( x / nsize + origin_x, y / nsize + origin_y, z / nsize + origin_z ) - - # noise basis type's - if nbasis == 9: nbasis = 14 # to get cellnoise basis you must set 14 instead of 9 - if vlbasis ==9: vlbasis = 14 - # noise type's - if ntype == 0: value = multi_fractal( ncoords, dimension, lacunarity, depth, nbasis ) * 0.5 - elif ntype == 1: value = ridged_multi_fractal( ncoords, dimension, lacunarity, depth, offset, gain, nbasis ) * 0.5 - elif ntype == 2: value = hybrid_multi_fractal( ncoords, dimension, lacunarity, depth, offset, gain, nbasis ) * 0.5 - elif ntype == 3: value = hetero_terrain( ncoords, dimension, lacunarity, depth, offset, nbasis ) * 0.25 - elif ntype == 4: value = fractal( ncoords, dimension, lacunarity, depth, nbasis ) - elif ntype == 5: value = turbulence_vector( ncoords, depth, hardnoise, nbasis )[0] - elif ntype == 6: value = vl_vector( ncoords, distortion, nbasis, vlbasis ) + 0.5 - elif ntype == 7: value = marble_noise( x*2.0/falloffsize,y*2.0/falloffsize,z*2/falloffsize, origin, nsize, marbleshape, marblebias, marblesharpnes, distortion, depth, hardnoise, nbasis ) - elif ntype == 8: value = shattered_hterrain( ncoords[0], ncoords[1], ncoords[2], dimension, lacunarity, depth, offset, distortion, nbasis ) - elif ntype == 9: value = strata_hterrain( ncoords[0], ncoords[1], ncoords[2], dimension, lacunarity, depth, offset, distortion, nbasis ) - else: - value = 0.0 - - # adjust height - if invert !=0: - value = (1-value) * height + heightoffset - else: - value = value * height + heightoffset - - # edge falloff - if sphere == 0: # no edge falloff if spherical - if falloff != 0: - fallofftypes = [ 0, sqrt((x*x)**2+(y*y)**2), sqrt(x*x+y*y), sqrt(y*y), sqrt(x*x) ] - dist = fallofftypes[ falloff] - if falloff ==1: - radius = (falloffsize/2)**2 - else: - radius = falloffsize/2 - value = value - sealevel - if( dist < radius ): - dist = dist / radius - dist = ( (dist) * (dist) * ( 3-2*(dist) ) ) - value = ( value - value * dist ) + sealevel - else: - value = sealevel - - # strata / terrace / layered - if stratatype !='0': - strata = strata / height - if stratatype == '1': - strata *= 2 - steps = ( sin( value*strata*pi ) * ( 0.1/strata*pi ) ) - value = ( value * (1.0-0.5) + steps*0.5 ) * 2.0 - elif stratatype == '2': - steps = -abs( sin( value*(strata)*pi ) * ( 0.1/(strata)*pi ) ) - value =( value * (1.0-0.5) + steps*0.5 ) * 2.0 - elif stratatype == '3': - steps = abs( sin( value*(strata)*pi ) * ( 0.1/(strata)*pi ) ) - value =( value * (1.0-0.5) + steps*0.5 ) * 2.0 - else: - value = value - - # clamp height - if ( value < sealevel ): value = sealevel - if ( value > platlevel ): value = platlevel - - return value - - -# generate grid -def grid_gen( sub_d, size_me, options ): - - verts = [] - faces = [] - edgeloop_prev = [] - - delta = size_me / float(sub_d - 1) - start = -(size_me / 2.0) - - for row_x in range(sub_d): - edgeloop_cur = [] - x = start + row_x * delta - for row_y in range(sub_d): - y = start + row_y * delta - z = landscape_gen(x,y,0.0,size_me,options) - - edgeloop_cur.append(len(verts)) - verts.append((x,y,z)) - - if len(edgeloop_prev) > 0: - faces_row = createFaces(edgeloop_prev, edgeloop_cur) - faces.extend(faces_row) - - edgeloop_prev = edgeloop_cur - - return verts, faces - - -# generate sphere -def sphere_gen( sub_d, size_me, options ): - - verts = [] - faces = [] - edgeloop_prev = [] - - for row_x in range(sub_d): - edgeloop_cur = [] - for row_y in range(sub_d): - u = sin(row_y*pi*2/(sub_d-1)) * cos(-pi/2+row_x*pi/(sub_d-1)) * size_me/2 - v = cos(row_y*pi*2/(sub_d-1)) * cos(-pi/2+row_x*pi/(sub_d-1)) * size_me/2 - w = sin(-pi/2+row_x*pi/(sub_d-1)) * size_me/2 - h = landscape_gen(u,v,w,size_me,options) / size_me - u,v,w = u+u*h, v+v*h, w+w*h - - edgeloop_cur.append(len(verts)) - verts.append((u, v, w)) - - if len(edgeloop_prev) > 0: - faces_row = createFaces(edgeloop_prev, edgeloop_cur) - faces.extend(faces_row) - - edgeloop_prev = edgeloop_cur - - return verts, faces - - -###------------------------------------------------------------ -# Add landscape -class landscape_add(bpy.types.Operator): - '''Add a landscape mesh''' - bl_idname = "Add_landscape" - bl_label = "Landscape" - bl_options = {'REGISTER', 'UNDO'} - bl_description = "Add landscape mesh" - - # edit - Whether to add or update. - edit = BoolProperty(name="", - description="", - default=False, - options={'HIDDEN'}) - - # align_matrix for the invoke - align_matrix = Matrix() - - # properties - AutoUpdate = BoolProperty(name="Mesh update", - default=True, - description="Update mesh") - - SphereMesh = BoolProperty(name="Sphere", - default=False, - description="Generate Sphere mesh") - - SmoothMesh = BoolProperty(name="Smooth", - default=True, - description="Shade smooth") - - Subdivision = IntProperty(name="Subdivisions", - min=4, - max=6400, - default=64, - description="Mesh x y subdivisions") - - MeshSize = FloatProperty(name="Mesh Size", - min=0.01, - max=100000.0, - default=2.0, - description="Mesh size") - - RandomSeed = IntProperty(name="Random Seed", - min=0, - max=9999, - default=0, - description="Randomize noise origin") - - NoiseSize = FloatProperty(name="Noise Size", - min=0.01, - max=10000.0, - default=1.0, - description="Noise size") - - NoiseTypes = [ - ("0","multiFractal","multiFractal"), - ("1","ridgedMFractal","ridgedMFractal"), - ("2","hybridMFractal","hybridMFractal"), - ("3","heteroTerrain","heteroTerrain"), - ("4","fBm","fBm"), - ("5","Turbulence","Turbulence"), - ("6","Distorted Noise","Distorted Noise"), - ("7","Marble","Marble"), - ("8","Shattered_hTerrain","Shattered_hTerrain"), - ("9","Strata_hTerrain","Strata_hTerrain")] - - NoiseType = EnumProperty(name="Type", - description="Noise type", - items=NoiseTypes) - - BasisTypes = [ - ("0","Blender","Blender"), - ("1","Perlin","Perlin"), - ("2","NewPerlin","NewPerlin"), - ("3","Voronoi_F1","Voronoi_F1"), - ("4","Voronoi_F2","Voronoi_F2"), - ("5","Voronoi_F3","Voronoi_F3"), - ("6","Voronoi_F4","Voronoi_F4"), - ("7","Voronoi_F2-F1","Voronoi_F2-F1"), - ("8","Voronoi Crackle","Voronoi Crackle"), - ("9","Cellnoise","Cellnoise")] - BasisType = EnumProperty(name="Basis", - description="Noise basis", - items=BasisTypes) - - VLBasisTypes = [ - ("0","Blender","Blender"), - ("1","Perlin","Perlin"), - ("2","NewPerlin","NewPerlin"), - ("3","Voronoi_F1","Voronoi_F1"), - ("4","Voronoi_F2","Voronoi_F2"), - ("5","Voronoi_F3","Voronoi_F3"), - ("6","Voronoi_F4","Voronoi_F4"), - ("7","Voronoi_F2-F1","Voronoi_F2-F1"), - ("8","Voronoi Crackle","Voronoi Crackle"), - ("9","Cellnoise","Cellnoise")] - VLBasisType = EnumProperty(name="VLBasis", - description="VLNoise basis", - items=VLBasisTypes) - - Distortion = FloatProperty(name="Distortion", - min=0.01, - max=1000.0, - default=1.0, - description="Distortion amount") - - HardNoise = BoolProperty(name="Hard", - default=True, - description="Hard noise") - - NoiseDepth = IntProperty(name="Depth", - min=1, - max=16, - default=6, - description="Noise Depth - number of frequencies in the fBm.") - - mDimension = FloatProperty(name="Dimension", - min=0.01, - max=2.0, - default=1.0, - description="H - fractal dimension of the roughest areas.") - - mLacunarity = FloatProperty(name="Lacunarity", - min=0.01, - max=6.0, - default=2.0, - description="Lacunarity - gap between successive frequencies.") - - mOffset = FloatProperty(name="Offset", - min=0.01, - max=6.0, - default=1.0, - description="Offset - raises the terrain from sea level.") - - mGain = FloatProperty(name="Gain", - min=0.01, - max=6.0, - default=1.0, - description="Gain - scale factor.") - - BiasTypes = [ - ("0","Sin","Sin"), - ("1","Tri","Tri"), - ("2","Saw","Saw")] - MarbleBias = EnumProperty(name="Bias", - description="Marble bias", - items=BiasTypes) - - SharpTypes = [ - ("0","Soft","Soft"), - ("1","Sharp","Sharp"), - ("2","Sharper","Sharper")] - MarbleSharp = EnumProperty(name="Sharp", - description="Marble sharp", - items=SharpTypes) - - ShapeTypes = [ - ("0","Default","Default"), - ("1","Ring","Ring"), - ("2","Swirl","Swirl"), - ("3","Bump","Bump"), - ("4","Y","Y"), - ("5","X","X")] - MarbleShape = EnumProperty(name="Shape", - description="Marble shape", - items=ShapeTypes) - - Invert = BoolProperty(name="Invert", - default=False, - description="Invert noise input") - - Height = FloatProperty(name="Height", - min=0.01, - max=10000.0, - default=0.5, - description="Height scale") - - Offset = FloatProperty(name="Offset", - min=-10000.0, - max=10000.0, - default=0.0, - description="Height offset") - - fallTypes = [ - ("0","None","None"), - ("1","Type 1","Type 1"), - ("2","Type 2","Type 2"), - ("3","Y","Y"), - ("4","X","X")] - Falloff = EnumProperty(name="Falloff", - description="Edge falloff", - default="1", - items=fallTypes) - - Sealevel = FloatProperty(name="Sealevel", - min=-10000.0, - max=10000.0, - default=0.0, - description="Sealevel") - - Plateaulevel = FloatProperty(name="Plateau", - min=-10000.0, - max=10000.0, - default=1.0, - description="Plateau level") - - Strata = FloatProperty(name="Strata", - min=0.01, - max=1000.0, - default=3.0, - description="Strata amount") - - StrataTypes = [ - ("0","None","None"), - ("1","Type 1","Type 1"), - ("2","Type 2","Type 2"), - ("3","Type 3","Type 3")] - StrataType = EnumProperty(name="Strata", - description="Strata type", - default="0", - items=StrataTypes) - - ###------------------------------------------------------------ - # Draw - def draw(self, context): - props = self.properties - layout = self.layout - - box = layout.box() - box.prop(props, 'AutoUpdate') - box.prop(props, 'SphereMesh') - box.prop(props, 'SmoothMesh') - box.prop(props, 'Subdivision') - box.prop(props, 'MeshSize') - - box = layout.box() - box.prop(props, 'NoiseType') - if props.NoiseType != '7': - box.prop(props, 'BasisType') - box.prop(props, 'RandomSeed') - box.prop(props, 'NoiseSize') - if props.NoiseType == '0': - box.prop(props, 'NoiseDepth') - box.prop(props, 'mDimension') - box.prop(props, 'mLacunarity') - if props.NoiseType == '1': - box.prop(props, 'NoiseDepth') - box.prop(props, 'mDimension') - box.prop(props, 'mLacunarity') - box.prop(props, 'mOffset') - box.prop(props, 'mGain') - if props.NoiseType == '2': - box.prop(props, 'NoiseDepth') - box.prop(props, 'mDimension') - box.prop(props, 'mLacunarity') - box.prop(props, 'mOffset') - box.prop(props, 'mGain') - if props.NoiseType == '3': - box.prop(props, 'NoiseDepth') - box.prop(props, 'mDimension') - box.prop(props, 'mLacunarity') - box.prop(props, 'mOffset') - if props.NoiseType == '4': - box.prop(props, 'NoiseDepth') - box.prop(props, 'mDimension') - box.prop(props, 'mLacunarity') - if props.NoiseType == '5': - box.prop(props, 'NoiseDepth') - box.prop(props, 'HardNoise') - if props.NoiseType == '6': - box.prop(props, 'VLBasisType') - box.prop(props, 'Distortion') - if props.NoiseType == '7': - box.prop(props, 'MarbleShape') - box.prop(props, 'MarbleBias') - box.prop(props, 'MarbleSharp') - box.prop(props, 'Distortion') - box.prop(props, 'NoiseDepth') - box.prop(props, 'HardNoise') - if props.NoiseType == '8': - box.prop(props, 'NoiseDepth') - box.prop(props, 'mDimension') - box.prop(props, 'mLacunarity') - box.prop(props, 'mOffset') - box.prop(props, 'Distortion') - if props.NoiseType == '9': - box.prop(props, 'NoiseDepth') - box.prop(props, 'mDimension') - box.prop(props, 'mLacunarity') - box.prop(props, 'mOffset') - box.prop(props, 'Distortion') - - box = layout.box() - box.prop(props, 'Invert') - box.prop(props, 'Height') - box.prop(props, 'Offset') - box.prop(props, 'Plateaulevel') - box.prop(props, 'Sealevel') - if props.SphereMesh == False: - box.prop(props, 'Falloff') - box.prop(props, 'StrataType') - if props.StrataType != '0': - box.prop(props, 'Strata') - - ###------------------------------------------------------------ - # Execute - def execute(self, context): - - props = self.properties - edit = props.edit - - #mesh update - if props.AutoUpdate != 0: - - # turn off undo - undo = bpy.context.user_preferences.edit.use_global_undo - bpy.context.user_preferences.edit.use_global_undo = False - - # deselect all objects - bpy.ops.object.select_all(action='DESELECT') - - # options - options = [ - props.RandomSeed, #0 - props.NoiseSize, #1 - props.NoiseType, #2 - props.BasisType, #3 - props.VLBasisType, #4 - props.Distortion, #5 - props.HardNoise, #6 - props.NoiseDepth, #7 - props.mDimension, #8 - props.mLacunarity, #9 - props.mOffset, #10 - props.mGain, #11 - props.MarbleBias, #12 - props.MarbleSharp, #13 - props.MarbleShape, #14 - props.Invert, #15 - props.Height, #16 - props.Offset, #17 - props.Falloff, #18 - props.Sealevel, #19 - props.Plateaulevel, #20 - props.Strata, #21 - props.StrataType, #22 - props.SphereMesh #23 - ] - - # Main function - if props.SphereMesh !=0: - # sphere - verts, faces = sphere_gen( props.Subdivision, props.MeshSize, options ) - else: - # grid - verts, faces = grid_gen( props.Subdivision, props.MeshSize, options ) - - # create mesh object - obj = create_mesh_object(context, verts, [], faces, "Landscape", edit, self.align_matrix) - - # sphere, remove doubles - if props.SphereMesh !=0: - bpy.ops.object.mode_set(mode='EDIT') - bpy.ops.mesh.remove_doubles(limit=0.0001) - bpy.ops.object.mode_set(mode='OBJECT') - - # Shade smooth - if props.SmoothMesh !=0: - bpy.ops.object.shade_smooth() - - # restore pre operator undo state - bpy.context.user_preferences.edit.use_global_undo = undo - - return {'FINISHED'} - else: - return {'PASS_THROUGH'} - - def invoke(self, context, event): - self.align_matrix = align_matrix(context) - self.execute(context) - return {'FINISHED'} - -###------------------------------------------------------------ -# Register -import space_info - - # Define "Landscape" menu -def menu_func_landscape(self, context): - self.layout.operator(landscape_add.bl_idname, text="Landscape", icon="PLUGIN") - -def register(): - space_info.INFO_MT_mesh_add.append(menu_func_landscape) - -def unregister(): - space_info.INFO_MT_mesh_add.remove(menu_func_landscape) - -if __name__ == "__main__": - register() diff --git a/add_mesh_extras.py b/add_mesh_extras.py deleted file mode 100644 index 1df801b2..00000000 --- a/add_mesh_extras.py +++ /dev/null @@ -1,776 +0,0 @@ -# ##### 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -# ##### END GPL LICENSE BLOCK ##### - -bl_addon_info = { - "name": "Extras", - "author": "Pontiac, Fourmadmen, meta-androcto", - "version": (0,3), - "blender": (2, 5, 3), - "api": 31854, - "location": "View3D > Add > Mesh > Extras", - "description": "Adds Star, Wedge, Sqorus & Spindle objects.", - "warning": "", - "wiki_url": "http://wiki.blender.org/index.php/Extensions:2.5/Py/"\ - "Scripts/Add_Mesh/Add_Extra", - "tracker_url": "https://projects.blender.org/tracker/index.php?"\ - "func=detail&aid=22457&group_id=153&atid=469", - "category": "Add Mesh"} - -import bpy -from mathutils import * -from math import * -from bpy.props import * - -# calculates the matrix for the new object -# depending on user pref -def align_matrix(context): - loc = Matrix.Translation(context.scene.cursor_location) - obj_align = context.user_preferences.edit.object_align - if (context.space_data.type == 'VIEW_3D' - and obj_align == 'VIEW'): - rot = context.space_data.region_3d.view_matrix.rotation_part().invert().resize4x4() - else: - rot = Matrix() - align_matrix = loc * rot - return align_matrix - -# Create a new mesh (object) from verts/edges/faces. -# verts/edges/faces ... List of vertices/edges/faces for the -# new mesh (as used in from_pydata). -# name ... Name of the new mesh (& object). -# edit ... Replace existing mesh data. -# Note: Using "edit" will destroy/delete existing mesh data. -def create_mesh_object(context, verts, edges, faces, name, edit, align_matrix): - scene = context.scene - obj_act = scene.objects.active - - # Can't edit anything, unless we have an active obj. - if edit and not obj_act: - return None - - # Create new mesh - mesh = bpy.data.meshes.new(name) - - # Make a mesh from a list of verts/edges/faces. - mesh.from_pydata(verts, edges, faces) - - # Update mesh geometry after adding stuff. - mesh.update() - - # Deselect all objects. - bpy.ops.object.select_all(action='DESELECT') - - if edit: - # Replace geometry of existing object - - # Use the active obj and select it. - ob_new = obj_act - ob_new.select = True - - if obj_act.mode == 'OBJECT': - # Get existing mesh datablock. - old_mesh = ob_new.data - - # Set object data to nothing - ob_new.data = None - - # Clear users of existing mesh datablock. - old_mesh.user_clear() - - # Remove old mesh datablock if no users are left. - if (old_mesh.users == 0): - bpy.data.meshes.remove(old_mesh) - - # Assign new mesh datablock. - ob_new.data = mesh - - else: - # Create new object - ob_new = bpy.data.objects.new(name, mesh) - - # Link new object to the given scene and select it. - scene.objects.link(ob_new) - ob_new.select = True - - # Place the object at the 3D cursor location. - # apply viewRotaion - ob_new.matrix_world = align_matrix - - if obj_act and obj_act.mode == 'EDIT': - if not edit: - # We are in EditMode, switch to ObjectMode. - bpy.ops.object.mode_set(mode='OBJECT') - - # Select the active object as well. - obj_act.select = True - - # Apply location of new object. - scene.update() - - # Join new object into the active. - bpy.ops.object.join() - - # Switching back to EditMode. - bpy.ops.object.mode_set(mode='EDIT') - - ob_new = obj_act - - else: - # We are in ObjectMode. - # Make the new object the active one. - scene.objects.active = ob_new - - return ob_new - - -# A very simple "bridge" tool. -# Connects two equally long vertex rows with faces. -# Returns a list of the new faces (list of lists) -# -# vertIdx1 ... First vertex list (list of vertex indices). -# vertIdx2 ... Second vertex list (list of vertex indices). -# closed ... Creates a loop (first & last are closed). -# flipped ... Invert the normal of the face(s). -# -# Note: You can set vertIdx1 to a single vertex index to create -# a fan/star of faces. -# Note: If both vertex idx list are the same length they have -# to have at least 2 vertices. -def createFaces(vertIdx1, vertIdx2, closed=False, flipped=False): - faces = [] - - if not vertIdx1 or not vertIdx2: - return None - - if len(vertIdx1) < 2 and len(vertIdx2) < 2: - return None - - fan = False - if (len(vertIdx1) != len(vertIdx2)): - if (len(vertIdx1) == 1 and len(vertIdx2) > 1): - fan = True - else: - return None - - total = len(vertIdx2) - - if closed: - # Bridge the start with the end. - if flipped: - face = [ - vertIdx1[0], - vertIdx2[0], - vertIdx2[total - 1]] - if not fan: - face.append(vertIdx1[total - 1]) - faces.append(face) - - else: - face = [vertIdx2[0], vertIdx1[0]] - if not fan: - face.append(vertIdx1[total - 1]) - face.append(vertIdx2[total - 1]) - faces.append(face) - - # Bridge the rest of the faces. - for num in range(total - 1): - if flipped: - if fan: - face = [vertIdx2[num], vertIdx1[0], vertIdx2[num + 1]] - else: - face = [vertIdx2[num], vertIdx1[num], - vertIdx1[num + 1], vertIdx2[num + 1]] - faces.append(face) - else: - if fan: - face = [vertIdx1[0], vertIdx2[num], vertIdx2[num + 1]] - else: - face = [vertIdx1[num], vertIdx2[num], - vertIdx2[num + 1], vertIdx1[num + 1]] - faces.append(face) - - return faces - - -# @todo Clean up vertex&face creation process a bit. -def add_sqorus(hole_size, subdivide): - verts = [] - faces = [] - - size = 2.0 - - thickness = (size - hole_size) / 2.0 - distances = [ - -size / 2.0, - -size / 2.0 + thickness, - size / 2.0 - thickness, - size / 2.0] - - if subdivide: - for i in range(4): - y = distances[i] - - for j in range(4): - x = distances[j] - - verts.append(Vector((x, y, size / 2.0))) - verts.append(Vector((x, y, -size / 2.0))) - - # Top outer loop (vertex indices) - vIdx_out_up = [0, 2, 4, 6, 14, 22, 30, 28, 26, 24, 16, 8] - # Lower outer loop (vertex indices) - vIdx_out_low = [i + 1 for i in vIdx_out_up] - - faces_outside = createFaces(vIdx_out_up, vIdx_out_low, closed=True) - faces.extend(faces_outside) - - # Top inner loop (vertex indices) - vIdx_inner_up = [10, 12, 20, 18] - - # Lower inner loop (vertex indices) - vIdx_inner_low = [i + 1 for i in vIdx_inner_up] - - faces_inside = createFaces(vIdx_inner_up, vIdx_inner_low, - closed=True, flipped=True) - faces.extend(faces_inside) - - row1_top = [0, 8, 16, 24] - row2_top = [i + 2 for i in row1_top] - row3_top = [i + 2 for i in row2_top] - row4_top = [i + 2 for i in row3_top] - - faces_top1 = createFaces(row1_top, row2_top) - faces.extend(faces_top1) - faces_top2_side1 = createFaces(row2_top[:2], row3_top[:2]) - faces.extend(faces_top2_side1) - faces_top2_side2 = createFaces(row2_top[2:], row3_top[2:]) - faces.extend(faces_top2_side2) - faces_top3 = createFaces(row3_top, row4_top) - faces.extend(faces_top3) - - row1_bot = [1, 9, 17, 25] - row2_bot = [i + 2 for i in row1_bot] - row3_bot = [i + 2 for i in row2_bot] - row4_bot = [i + 2 for i in row3_bot] - - faces_bot1 = createFaces(row1_bot, row2_bot, flipped=True) - faces.extend(faces_bot1) - faces_bot2_side1 = createFaces(row2_bot[:2], row3_bot[:2], - flipped=True) - faces.extend(faces_bot2_side1) - faces_bot2_side2 = createFaces(row2_bot[2:], row3_bot[2:], - flipped=True) - faces.extend(faces_bot2_side2) - faces_bot3 = createFaces(row3_bot, row4_bot, flipped=True) - faces.extend(faces_bot3) - - else: - # Do not subdivde outer faces - - vIdx_out_up = [] - vIdx_out_low = [] - vIdx_in_up = [] - vIdx_in_low = [] - - for i in range(4): - y = distances[i] - - for j in range(4): - x = distances[j] - - append = False - inner = False - # Outer - if (i in [0, 3] and j in [0, 3]): - append = True - - # Inner - if (i in [1, 2] and j in [1, 2]): - append = True - inner = True - - if append: - vert_up = len(verts) - verts.append(Vector((x, y, size / 2.0))) - vert_low = len(verts) - verts.append(Vector((x, y, -size / 2.0))) - - if inner: - vIdx_in_up.append(vert_up) - vIdx_in_low.append(vert_low) - - else: - vIdx_out_up.append(vert_up) - vIdx_out_low.append(vert_low) - - # Flip last two vertices - vIdx_out_up = vIdx_out_up[:2] + list(reversed(vIdx_out_up[2:])) - vIdx_out_low = vIdx_out_low[:2] + list(reversed(vIdx_out_low[2:])) - vIdx_in_up = vIdx_in_up[:2] + list(reversed(vIdx_in_up[2:])) - vIdx_in_low = vIdx_in_low[:2] + list(reversed(vIdx_in_low[2:])) - - # Create faces - faces_top = createFaces(vIdx_in_up, vIdx_out_up, closed=True) - faces.extend(faces_top) - faces_bottom = createFaces(vIdx_out_low, vIdx_in_low, closed=True) - faces.extend(faces_bottom) - faces_inside = createFaces(vIdx_in_low, vIdx_in_up, closed=True) - faces.extend(faces_inside) - faces_outside = createFaces(vIdx_out_up, vIdx_out_low, closed=True) - faces.extend(faces_outside) - - return verts, faces - - -def add_wedge(size_x, size_y, size_z): - verts = [] - faces = [] - - size_x /= 2.0 - size_y /= 2.0 - size_z /= 2.0 - - vIdx_top = [] - vIdx_bot = [] - - vIdx_top.append(len(verts)) - verts.append(Vector((-size_x, -size_y, size_z))) - vIdx_bot.append(len(verts)) - verts.append(Vector((-size_x, -size_y, -size_z))) - - vIdx_top.append(len(verts)) - verts.append(Vector((size_x, -size_y, size_z))) - vIdx_bot.append(len(verts)) - verts.append(Vector((size_x, -size_y, -size_z))) - - vIdx_top.append(len(verts)) - verts.append(Vector((-size_x, size_y, size_z))) - vIdx_bot.append(len(verts)) - verts.append(Vector((-size_x, size_y, -size_z))) - - faces.append(vIdx_top) - faces.append(vIdx_bot) - faces_outside = createFaces(vIdx_top, vIdx_bot, closed=True) - faces.extend(faces_outside) - - return verts, faces - -def add_spindle(segments, radius, height, cap_height): - verts = [] - faces = [] - - tot_verts = segments * 2 + 2 - - half_height = height / 2.0 - - # Upper tip - idx_upper_tip = len(verts) - verts.append(Vector((0, 0, half_height + cap_height))) - - # Lower tip - idx_lower_tip = len(verts) - verts.append(Vector((0.0, 0.0, -half_height - cap_height))) - - upper_edgeloop = [] - lower_edgeloop = [] - for index in range(segments): - mtx = Matrix.Rotation(2.0 * pi * float(index) / segments, 3, 'Z') - - # Calculate index & location of upper verte4x tip. - idx_up = len(verts) - upper_edgeloop.append(idx_up) - verts.append(Vector((radius, 0.0, half_height)) * mtx) - - if height > 0: - idx_low = len(verts) - lower_edgeloop.append(idx_low) - verts.append(Vector((radius, 0.0, -half_height)) * mtx) - - # Create faces for the upper tip. - tip_up_faces = createFaces([idx_upper_tip], upper_edgeloop, - closed=True, flipped=True) - faces.extend(tip_up_faces) - - if height > 0: - # Create faces for the middle cylinder. - cyl_faces = createFaces(lower_edgeloop, upper_edgeloop, closed=True) - faces.extend(cyl_faces) - - # Create faces for the lower tip. - tip_low_faces = createFaces([idx_lower_tip], lower_edgeloop, - closed=True) - faces.extend(tip_low_faces) - - else: - # Skipping middle part/cylinder (height=0). - - # Create faces for the lower tip. - tip_low_faces = createFaces([idx_lower_tip], upper_edgeloop, - closed=True) - faces.extend(tip_low_faces) - - return verts, faces - -def add_star(points, outer_radius, inner_radius, height): - PI_2 = pi * 2 - z_axis = (0, 0, 1) - - verts = [] - faces = [] - - segments = points * 2 - - half_height = height / 2.0 - - vert_idx_top = len(verts) - verts.append(Vector((0.0, 0.0, half_height))) - - vert_idx_bottom = len(verts) - verts.append(Vector((0.0, 0.0, -half_height))) - - edgeloop_top = [] - edgeloop_bottom = [] - - for index in range(segments): - quat = Quaternion(z_axis, (index / segments) * PI_2) - - if index % 2: - # Uneven - radius = outer_radius - else: - # Even - radius = inner_radius - - edgeloop_top.append(len(verts)) - vec = Vector((radius, 0, half_height)) * quat - verts.append(vec) - - edgeloop_bottom.append(len(verts)) - vec = Vector((radius, 0, -half_height)) * quat - verts.append(vec) - - - - faces_top = createFaces([vert_idx_top], edgeloop_top, closed=True) - faces_outside = createFaces(edgeloop_top, edgeloop_bottom, closed=True) - faces_bottom = createFaces([vert_idx_bottom], edgeloop_bottom, - flipped=True, closed=True) - - faces.extend(faces_top) - faces.extend(faces_outside) - faces.extend(faces_bottom) - - return verts, faces - -def trapezohedron(s,r,h): - """ - s = segments - r = base radius - h = tip height - """ - - # calculate constants - a = 2*pi/(2*s) # angle between points along the equator - l = r*cos(a) # helper for e - e = h*(r-l)/(l+r) # the z offset for each vector along the equator so faces are planar - - # rotation for the points - quat = Quaternion((0,0,1),a) - - # first 3 vectors, every next one is calculated from the last, and the z-value is negated - verts = [Vector(i) for i in [(0,0,h),(0,0,-h),(r,0,e)]] - for i in range(2*s-1): - verts.append(verts[-1]*quat) # rotate further "a" radians around the z-axis - verts[-1].z *= -1 # negate last z-value to account for the zigzag - - faces = [] - for i in range(2,2+2*s,2): - n = [i+1,i+2,i+3] # vertices in current section - for j in range(3): # check whether the numbers dont go over len(verts) - if n[j]>=2*s+2: n[j]-=2*s # if so, subtract len(verts)-2 - - # add faces of current section - faces.append([0,i]+n[:2]) - faces.append([1,n[2],n[1],n[0]]) - - return verts,faces - -class AddSqorus(bpy.types.Operator): - '''Add a sqorus mesh.''' - bl_idname = "mesh.primitive_sqorus_add" - bl_label = "Add Sqorus" - bl_options = {'REGISTER', 'UNDO'} - - # edit - Whether to add or update. - edit = BoolProperty(name="", - description="", - default=False, - options={'HIDDEN'}) - hole_size = FloatProperty(name="Hole Size", - description="Size of the Hole", - min=0.01, - max=1.99, - default=2.0 / 3.0) - subdivide = BoolProperty(name="Subdivide Outside", - description="Enable to subdivide the faces on the outside." \ - " This results in equally spaced vertices.", - default=True) - align_matrix = Matrix() - - def execute(self, context): - props = self.properties - - # Create mesh geometry - verts, faces = add_sqorus( - props.hole_size, - props.subdivide) - - # Create mesh object (and meshdata) - obj = create_mesh_object(context, verts, [], faces, "Sqorus", - props.edit, self.align_matrix) - - return {'FINISHED'} - - def invoke(self, context, event): - self.align_matrix = align_matrix(context) - self.execute(context) - return {'FINISHED'} - -class AddWedge(bpy.types.Operator): - '''Add a wedge mesh.''' - bl_idname = "mesh.primitive_wedge_add" - bl_label = "Add Wedge" - bl_options = {'REGISTER', 'UNDO'} - - # edit - Whether to add or update. - edit = BoolProperty(name="", - description="", - default=False, - options={'HIDDEN'}) - size_x = FloatProperty(name="Size X", - description="Size along the X axis", - min=0.01, - max=9999.0, - default=2.0) - size_y = FloatProperty(name="Size Y", - description="Size along the Y axis", - min=0.01, - max=9999.0, - default=2.0) - size_z = FloatProperty(name="Size Z", - description="Size along the Z axis", - min=0.01, - max=9999.0, - default=2.00) - align_matrix = Matrix() - - def execute(self, context): - props = self.properties - - verts, faces = add_wedge( - props.size_x, - props.size_y, - props.size_z) - - obj = create_mesh_object(context, verts, [], faces, "Wedge", - props.edit, self.align_matrix) - - return {'FINISHED'} - - def invoke(self, context, event): - self.align_matrix = align_matrix(context) - self.execute(context) - return {'FINISHED'} - -class AddSpindle(bpy.types.Operator): - '''Add a spindle mesh.''' - bl_idname = "mesh.primitive_spindle_add" - bl_label = "Add Spindle" - bl_description = "Create a spindle mesh." - bl_options = {'REGISTER', 'UNDO'} - - # edit - Whether to add or update. - edit = BoolProperty(name="", - description="", - default=False, - options={'HIDDEN'}) - segments = IntProperty(name="Segments", - description="Number of segments of the spindle", - min=3, - max=512, - default=32) - radius = FloatProperty(name="Radius", - description="Radius of the spindle", - min=0.01, - max=9999.0, - default=1.0) - height = FloatProperty(name="Height", - description="Height of the spindle", - min=0.0, - max=100.0, - default=1.0) - cap_height = FloatProperty(name="Cap Height", - description="Cap height of the spindle", - min=-9999.0, - max=9999.0, - default=0.5) - align_matrix = Matrix() - - def execute(self, context): - props = self.properties - - verts, faces = add_spindle( - props.segments, - props.radius, - props.height, - props.cap_height) - - obj = create_mesh_object(context, verts, [], faces, "Spindle", - props.edit, self.align_matrix) - - return {'FINISHED'} - - def invoke(self, context, event): - self.align_matrix = align_matrix(context) - self.execute(context) - return {'FINISHED'} - -class AddStar(bpy.types.Operator): - '''Add a star mesh.''' - bl_idname = "mesh.primitive_star_add" - bl_label = "Add Star" - bl_options = {'REGISTER', 'UNDO'} - - # edit - Whether to add or update. - edit = BoolProperty(name="", - description="", - default=False, - options={'HIDDEN'}) - points = IntProperty(name="Points", - description="Number of points for the star", - min=2, - max=256, - default=5) - outer_radius = FloatProperty(name="Outer Radius", - description="Outer radius of the star", - min=0.01, - max=9999.0, - default=1.0) - innter_radius = FloatProperty(name="Inner Radius", - description="Inner radius of the star", - min=0.01, - max=9999.0, - default=0.5) - height = FloatProperty(name="Height", - description="Height of the star", - min=0.01, - max=9999.0, - default=0.5) - align_matrix = Matrix() - - def execute(self, context): - props = self.properties - - verts, faces = add_star( - props.points, - props.outer_radius, - props.innter_radius, - props.height) - - obj = create_mesh_object(context, verts, [], faces, "Star", - props.edit, self.align_matrix) - - return {'FINISHED'} - - def invoke(self, context, event): - self.align_matrix = align_matrix(context) - self.execute(context) - return {'FINISHED'} - -class AddTrapezohedron(bpy.types.Operator): - """Add a trapezohedron""" - bl_idname = "mesh.primitive_trapezohedron_add" - bl_label = "Add trapezohedron" - bl_description = "Create one of the regular solids" - bl_options = {'REGISTER', 'UNDO'} - - segments = IntProperty(name = "Segments", - description = "Number of repeated segments", - default = 4, min = 2, max = 256) - radius = FloatProperty(name = "Base radius", - description = "Radius of the middle", - default = 1.0, min = 0.01, max = 100.0) - height = FloatProperty(name = "Tip height", - description = "Height of the tip", - default = 1, min = 0.01, max = 100.0) - edit = BoolProperty(name="", - description="", - default=False, - options={'HIDDEN'}) - align_matrix = Matrix() - def execute(self,context): - props = self.properties - # generate mesh - verts,faces = trapezohedron(props.segments, - props.radius, - props.height) - - obj = create_mesh_object(context, verts, [], faces, "Trapazohedron", - props.edit, self.align_matrix) - - return {'FINISHED'} - -class INFO_MT_mesh_extras_add(bpy.types.Menu): - # Define the "Extras" menu - bl_idname = "INFO_MT_mesh_extras_add" - bl_label = "Extras" - - def draw(self, context): - layout = self.layout - layout.operator_context = 'INVOKE_REGION_WIN' - layout.operator("mesh.primitive_sqorus_add", - text="Sqorus") - layout.operator("mesh.primitive_wedge_add", - text="Wedge") - layout.operator("mesh.primitive_spindle_add", - text="Spindle") - layout.operator("mesh.primitive_star_add", - text="Star") - layout.operator("mesh.primitive_trapezohedron_add", - text="Trapezohedron") - - -# Register all operators and panels -import space_info - -# Define "Gemstones" menu -def menu_func(self, context): - self.layout.menu("INFO_MT_mesh_extras_add", icon="PLUGIN") - - -def register(): - # Add "Gemstones" menu to the "Add Mesh" menu - space_info.INFO_MT_mesh_add.append(menu_func) - - -def unregister(): - # Remove "Gemstones" menu from the "Add Mesh" menu. - space_info.INFO_MT_mesh_add.remove(menu_func) - -if __name__ == "__main__": - register() diff --git a/add_mesh_gears.py b/add_mesh_gears.py deleted file mode 100644 index 6063b035..00000000 --- a/add_mesh_gears.py +++ /dev/null @@ -1,937 +0,0 @@ -# add_mesh_gear.py (c) 2009, 2010 Michel J. Anders (varkenvarken) -# -# ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -# ***** END GPL LICENCE BLOCK ***** - -bl_addon_info = { - "name": "Gears", - "author": "Michel J. Anders (varkenvarken)", - "version": (2,4,1), - "blender": (2, 5, 3), - "api": 31854, - "location": "View3D > Add > Mesh > Gears ", - "description": "Adds a mesh Gear to the Add Mesh menu", - "warning": "", - "wiki_url": "http://wiki.blender.org/index.php/Extensions:2.5/Py/"\ - "Scripts/Add_Mesh/Add_Gear", - "tracker_url": "https://projects.blender.org/tracker/index.php?"\ - "func=detail&aid=21732&group_id=153&atid=469", - "category": "Add Mesh"} - -""" -What was needed to port it from 2.49 -> 2.50 alpha 0? - -The basic functions that calculate the geometry (verts and faces) are mostly -unchanged (add_tooth, add_spoke, add_gear) - -Also, the vertex group API is changed a little bit but the concepts -are the same: -========= -vertexgroup = ob.vertex_groups.new('NAME_OF_VERTEXGROUP') -ob.vertex_groups.assign(vertexgroup_vertex_indices, vertexgroup, weight, 'ADD') -========= - -Now for some reason the name does not 'stick' and we have to set it this way: -vertexgroup.name = 'NAME_OF_VERTEXGROUP' - -Conversion to 2.50 also meant we could simply do away with our crude user -interface. -Just definining the appropriate properties in the AddGear() operator will -display the properties in the Blender GUI with the added benefit of making -it interactive: changing a property will redo the AddGear() operator providing -the user with instant feedback. - -Finally we had to convert/throw away some print statements to print functions -as Blender nows uses Python 3.x - -The code to actually implement the AddGear() function is mostly copied from -add_mesh_torus() (distributed with Blender). -""" - -import bpy -import mathutils -from math import * -from bpy.props import * - -# calculates the matrix for the new object -# depending on user pref -def align_matrix(context): - loc = mathutils.Matrix.Translation(context.scene.cursor_location) - obj_align = context.user_preferences.edit.object_align - if (context.space_data.type == 'VIEW_3D' - and obj_align == 'VIEW'): - rot = context.space_data.region_3d.view_matrix.rotation_part().invert().resize4x4() - else: - rot = mathutils.Matrix() - align_matrix = loc * rot - return align_matrix - -# Create a new mesh (object) from verts/edges/faces. -# verts/edges/faces ... List of vertices/edges/faces for the -# new mesh (as used in from_pydata). -# name ... Name of the new mesh (& object). -# edit ... Replace existing mesh data. -# Note: Using "edit" will destroy/delete existing mesh data. -def create_mesh_object(context, verts, edges, faces, name, edit, align_matrix): - scene = context.scene - obj_act = scene.objects.active - - # Can't edit anything, unless we have an active obj. - if edit and not obj_act: - return None - - # Create new mesh - mesh = bpy.data.meshes.new(name) - - # Make a mesh from a list of verts/edges/faces. - mesh.from_pydata(verts, edges, faces) - - # Update mesh geometry after adding stuff. - mesh.update() - - # Deselect all objects. - bpy.ops.object.select_all(action='DESELECT') - - if edit: - # Replace geometry of existing object - - # Use the active obj and select it. - ob_new = obj_act - ob_new.select = True - - if obj_act.mode == 'OBJECT': - # Get existing mesh datablock. - old_mesh = ob_new.data - - # Set object data to nothing - ob_new.data = None - - # Clear users of existing mesh datablock. - old_mesh.user_clear() - - # Remove old mesh datablock if no users are left. - if (old_mesh.users == 0): - bpy.data.meshes.remove(old_mesh) - - # Assign new mesh datablock. - ob_new.data = mesh - - else: - # Create new object - ob_new = bpy.data.objects.new(name, mesh) - - # Link new object to the given scene and select it. - scene.objects.link(ob_new) - ob_new.select = True - - # Place the object at the 3D cursor location. - # apply viewRotaion - ob_new.matrix_world = align_matrix - - - if obj_act and obj_act.mode == 'EDIT': - if not edit: - # We are in EditMode, switch to ObjectMode. - bpy.ops.object.mode_set(mode='OBJECT') - - # Select the active object as well. - obj_act.select = True - - # Apply location of new object. - scene.update() - - # Join new object into the active. - bpy.ops.object.join() - - # Switching back to EditMode. - bpy.ops.object.mode_set(mode='EDIT') - - ob_new = obj_act - - else: - # We are in ObjectMode. - # Make the new object the active one. - scene.objects.active = ob_new - - return ob_new - - -# A very simple "bridge" tool. -# Connects two equally long vertex rows with faces. -# Returns a list of the new faces (list of lists) -# -# vertIdx1 ... First vertex list (list of vertex indices). -# vertIdx2 ... Second vertex list (list of vertex indices). -# closed ... Creates a loop (first & last are closed). -# flipped ... Invert the normal of the face(s). -# -# Note: You can set vertIdx1 to a single vertex index to create -# a fan/star of faces. -# Note: If both vertex idx list are the same length they have -# to have at least 2 vertices. -def createFaces(vertIdx1, vertIdx2, closed=False, flipped=False): - faces = [] - - if not vertIdx1 or not vertIdx2: - return None - - if len(vertIdx1) < 2 and len(vertIdx2) < 2: - return None - - fan = False - if (len(vertIdx1) != len(vertIdx2)): - if (len(vertIdx1) == 1 and len(vertIdx2) > 1): - fan = True - else: - return None - - total = len(vertIdx2) - - if closed: - # Bridge the start with the end. - if flipped: - face = [ - vertIdx1[0], - vertIdx2[0], - vertIdx2[total - 1]] - if not fan: - face.append(vertIdx1[total - 1]) - faces.append(face) - - else: - face = [vertIdx2[0], vertIdx1[0]] - if not fan: - face.append(vertIdx1[total - 1]) - face.append(vertIdx2[total - 1]) - faces.append(face) - - # Bridge the rest of the faces. - for num in range(total - 1): - if flipped: - if fan: - face = [vertIdx2[num], vertIdx1[0], vertIdx2[num + 1]] - else: - face = [vertIdx2[num], vertIdx1[num], - vertIdx1[num + 1], vertIdx2[num + 1]] - faces.append(face) - else: - if fan: - face = [vertIdx1[0], vertIdx2[num], vertIdx2[num + 1]] - else: - face = [vertIdx1[num], vertIdx2[num], - vertIdx2[num + 1], vertIdx1[num + 1]] - faces.append(face) - - return faces - - -# Calculate the vertex coordinates for a single -# section of a gear tooth. -# Returns 4 lists of vertex coords (list of tuples): -# *-*---*---* (1.) verts_inner_base -# | | | | -# *-*---*---* (2.) verts_outer_base -# | | | -# *---*---* (3.) verts_middle_tooth -# \ | / -# *-*-* (4.) verts_tip_tooth -# -# a -# t -# d -# radius -# Ad -# De -# base -# p_angle -# rack -# crown -def add_tooth(a, t, d, radius, Ad, De, base, p_angle, rack=0, crown=0.0): - A = [a, a + t / 4, a + t / 2, a + 3 * t / 4] - C = [cos(i) for i in A] - S = [sin(i) for i in A] - - Ra = radius + Ad - Rd = radius - De - Rb = Rd - base - - # Pressure angle calc - O = Ad * tan(p_angle) - p_angle = atan(O / Ra) - - if radius < 0: - p_angle = -p_angle - - if rack: - S = [sin(t / 4) * I for I in range(-2, 3)] - Sp = [0, sin(-t / 4 + p_angle), 0, sin(t / 4 - p_angle)] - - verts_inner_base = [(Rb, radius * S[I], d) for I in range(4)] - verts_outer_base = [(Rd, radius * S[I], d) for I in range(4)] - verts_middle_tooth = [(radius, radius * S[I], d) for I in range(1, 4)] - verts_tip_tooth = [(Ra, radius * Sp[I], d) for I in range(1, 4)] - - else: - Cp = [ - 0, - cos(a + t / 4 + p_angle), - cos(a + t / 2), - cos(a + 3 * t / 4 - p_angle)] - Sp = [0, - sin(a + t / 4 + p_angle), - sin(a + t / 2), - sin(a + 3 * t / 4 - p_angle)] - - verts_inner_base = [(Rb * C[I], Rb * S[I], d) - for I in range(4)] - verts_outer_base = [(Rd * C[I], Rd * S[I], d) - for I in range(4)] - verts_middle_tooth = [(radius * C[I], radius * S[I], d + crown / 3) - for I in range(1, 4)] - verts_tip_tooth = [(Ra * Cp[I], Ra * Sp[I], d + crown) - for I in range(1, 4)] - - return (verts_inner_base, verts_outer_base, - verts_middle_tooth, verts_tip_tooth) - - -# EXPERIMENTAL Calculate the vertex coordinates for a single -# section of a gearspoke. -# Returns them as a list of tuples. -# -# a -# t -# d -# radius -# De -# base -# s -# w -# l -# gap -# width -# -# @todo Finish this. -def add_spoke(a, t, d, radius, De, base, s, w, l, gap=0, width=19): - Rd = radius - De - Rb = Rd - base - Rl = Rb - - verts = [] - edgefaces = [] - edgefaces2 = [] - sf = [] - - if not gap: - for N in range(width, 1, -2): - edgefaces.append(len(verts)) - ts = t / 4 - tm = a + 2 * ts - te = asin(w / Rb) - td = te - ts - t4 = ts + td * (width - N) / (width - 3.0) - A = [tm + (i - int(N / 2)) * t4 for i in range(N)] - C = [cos(i) for i in A] - S = [sin(i) for i in A] - - verts.extend([(Rb * I, Rb * J, d) for (I, J) in zip(C, S)]) - edgefaces2.append(len(verts) - 1) - - Rb = Rb - s - - n = 0 - for N in range(width, 3, -2): - sf.extend([(i + n, i + 1 + n, i + 2 + n, i + N + n) - for i in range(0, N - 1, 2)]) - sf.extend([(i + 2 + n, i + N + n, i + N + 1 + n, i + N + 2 + n) - for i in range(0, N - 3, 2)]) - - n = n + N - - return verts, edgefaces, edgefaces2, sf - - -# Create gear geometry. -# Returns: -# * A list of vertices (list of tuples) -# * A list of faces (list of lists) -# * A list (group) of vertices of the tip (list of vertex indices). -# * A list (group) of vertices of the valley (list of vertex indices). -# -# teethNum ... Number of teeth on the gear. -# radius ... Radius of the gear, negative for crown gear -# Ad ... Addendum, extent of tooth above radius. -# De ... Dedendum, extent of tooth below radius. -# base ... Base, extent of gear below radius. -# p_angle ... Pressure angle. Skewness of tooth tip. (radiant) -# width ... Width, thickness of gear. -# skew ... Skew of teeth. (radiant) -# conangle ... Conical angle of gear. (radiant) -# rack -# crown ... Inward pointing extend of crown teeth. -# -# inner radius = radius - (De + base) -def add_gear(teethNum, radius, Ad, De, base, p_angle, - width=1, skew=0, conangle=0, rack=0, crown=0.0): - - if teethNum < 2: - return None, None, None, None - - t = 2 * pi / teethNum - - if rack: - teethNum = 1 - - scale = (radius - 2 * width * tan(conangle)) / radius - - verts = [] - faces = [] - vgroup_top = [] # Vertex group of top/tip? vertices. - vgroup_valley = [] # Vertex group of valley vertices - - verts_bridge_prev = [] - for toothCnt in range(teethNum): - a = toothCnt * t - - verts_bridge_start = [] - verts_bridge_end = [] - - verts_outside_top = [] - verts_outside_bottom = [] - for (s, d, c, top) \ - in [(0, -width, 1, True), \ - (skew, width, scale, False)]: - - verts1, verts2, verts3, verts4 = add_tooth(a + s, t, d, - radius * c, Ad * c, De * c, base * c, p_angle, - rack, crown) - - vertsIdx1 = list(range(len(verts), len(verts) + len(verts1))) - verts.extend(verts1) - vertsIdx2 = list(range(len(verts), len(verts) + len(verts2))) - verts.extend(verts2) - vertsIdx3 = list(range(len(verts), len(verts) + len(verts3))) - verts.extend(verts3) - vertsIdx4 = list(range(len(verts), len(verts) + len(verts4))) - verts.extend(verts4) - - verts_outside = [] - verts_outside.extend(vertsIdx2[:2]) - verts_outside.append(vertsIdx3[0]) - verts_outside.extend(vertsIdx4) - verts_outside.append(vertsIdx3[-1]) - verts_outside.append(vertsIdx2[-1]) - - if top: - #verts_inside_top = vertsIdx1 - verts_outside_top = verts_outside - - verts_bridge_start.append(vertsIdx1[0]) - verts_bridge_start.append(vertsIdx2[0]) - verts_bridge_end.append(vertsIdx1[-1]) - verts_bridge_end.append(vertsIdx2[-1]) - - else: - #verts_inside_bottom = vertsIdx1 - verts_outside_bottom = verts_outside - - verts_bridge_start.append(vertsIdx2[0]) - verts_bridge_start.append(vertsIdx1[0]) - verts_bridge_end.append(vertsIdx2[-1]) - verts_bridge_end.append(vertsIdx1[-1]) - - # Valley = first 2 vertices of outer base: - vgroup_valley.extend(vertsIdx2[:1]) - # Top/tip vertices: - vgroup_top.extend(vertsIdx4) - - faces_tooth_middle_top = createFaces(vertsIdx2[1:], vertsIdx3, - flipped=top) - faces_tooth_outer_top = createFaces(vertsIdx3, vertsIdx4, - flipped=top) - - faces_base_top = createFaces(vertsIdx1, vertsIdx2, flipped=top) - faces.extend(faces_base_top) - - faces.extend(faces_tooth_middle_top) - faces.extend(faces_tooth_outer_top) - - #faces_inside = createFaces(verts_inside_top, verts_inside_bottom) - #faces.extend(faces_inside) - - faces_outside = createFaces(verts_outside_top, verts_outside_bottom, - flipped=True) - faces.extend(faces_outside) - - if toothCnt == 0: - verts_bridge_first = verts_bridge_start - - # Bridge one tooth to the next - if verts_bridge_prev: - faces_bridge = createFaces(verts_bridge_prev, verts_bridge_start) - #, closed=True (for "inside" faces) - faces.extend(faces_bridge) - - # Remember "end" vertices for next tooth. - verts_bridge_prev = verts_bridge_end - - # Bridge the first to the last tooth. - faces_bridge_f_l = createFaces(verts_bridge_prev, verts_bridge_first) - #, closed=True (for "inside" faces) - faces.extend(faces_bridge_f_l) - - return verts, faces, vgroup_top, vgroup_valley - - -# Create spokes geometry. -# Returns: -# * A list of vertices (list of tuples) -# * A list of faces (list of lists) -# -# teethNum ... Number of teeth on the gear. -# radius ... Radius of the gear, negative for crown gear -# De ... Dedendum, extent of tooth below radius. -# base ... Base, extent of gear below radius. -# width ... Width, thickness of gear. -# conangle ... Conical angle of gear. (radiant) -# rack -# spoke -# spbevel -# spwidth -# splength -# spresol -# -# @todo Finish this -# @todo Create a function that takes a "Gear" and creates a -# matching "Gear Spokes" object. -def add_spokes(teethNum, radius, De, base, width=1, conangle=0, rack=0, - spoke=3, spbevel=0.1, spwidth=0.2, splength=1.0, spresol=9): - - if teethNum < 2: - return None, None, None, None - - if spoke < 2: - return None, None, None, None - - t = 2 * pi / teethNum - - if rack: - teethNum = 1 - - scale = (radius - 2 * width * tan(conangle)) / radius - - verts = [] - faces = [] - - c = scale # debug - - fl = len(verts) - for toothCnt in range(teethNum): - a = toothCnt * t - s = 0 # For test - - if toothCnt % spoke == 0: - for d in (-width, width): - sv, edgefaces, edgefaces2, sf = add_spoke(a + s, t, d, - radius * c, De * c, base * c, - spbevel, spwidth, splength, 0, spresol) - verts.extend(sv) - faces.extend([[j + fl for j in i] for i in sf]) - fl += len(sv) - - d1 = fl - len(sv) - d2 = fl - 2 * len(sv) - - faces.extend([(i + d2, j + d2, j + d1, i + d1) - for (i, j) in zip(edgefaces[:-1], edgefaces[1:])]) - faces.extend([(i + d2, j + d2, j + d1, i + d1) - for (i, j) in zip(edgefaces2[:-1], edgefaces2[1:])]) - - else: - for d in (-width, width): - sv, edgefaces, edgefaces2, sf = add_spoke(a + s, t, d, - radius * c, De * c, base * c, - spbevel, spwidth, splength, 1, spresol) - - verts.extend(sv) - fl += len(sv) - - d1 = fl - len(sv) - d2 = fl - 2 * len(sv) - - faces.extend([[i + d2, i + 1 + d2, i + 1 + d1, i + d1] - for (i) in range(0, 3)]) - faces.extend([[i + d2, i + 1 + d2, i + 1 + d1, i + d1] - for (i) in range(5, 8)]) - - return verts, faces - - -# Create worm geometry. -# Returns: -# * A list of vertices -# * A list of faces -# * A list (group) of vertices of the tip -# * A list (group) of vertices of the valley -# -# teethNum ... Number of teeth on the worm -# radius ... Radius of the gear, negative for crown gear -# Ad ... Addendum, extent of tooth above radius. -# De ... Dedendum, extent of tooth below radius. -# p_angle ... Pressure angle. Skewness of tooth tip. (radiant) -# width ... Width, thickness of gear. -# crown ... Inward pointing extend of crown teeth. -# -# @todo: Fix teethNum. Some numbers are not possible yet. -# @todo: Create start & end geoemtry (closing faces) -def add_worm(teethNum, rowNum, radius, Ad, De, p_angle, - width=1, skew=radians(11.25), crown=0.0): - - worm = teethNum - teethNum = 24 - - t = 2 * pi / teethNum - - verts = [] - faces = [] - vgroup_top = [] # Vertex group of top/tip? vertices. - vgroup_valley = [] # Vertex group of valley vertices - - #width = width / 2.0 - - edgeloop_prev = [] - for Row in range(rowNum): - edgeloop = [] - - for toothCnt in range(teethNum): - a = toothCnt * t - - s = Row * skew - d = Row * width - c = 1 - - isTooth = False - if toothCnt % (teethNum / worm) != 0: - # Flat - verts1, verts2, verts3, verts4 = add_tooth(a + s, t, d, - radius - De, 0.0, 0.0, 0, p_angle) - - # Ignore other verts than the "other base". - verts1 = verts3 = verts4 = [] - - else: - # Tooth - isTooth = True - verts1, verts2, verts3, verts4 = add_tooth(a + s, t, d, - radius * c, Ad * c, De * c, 0 * c, p_angle, 0, crown) - - # Remove various unneeded verts (if we are "inside" the tooth) - del(verts2[2]) # Central vertex in the base of the tooth. - del(verts3[1]) # Central vertex in the middle of the tooth. - - vertsIdx2 = list(range(len(verts), len(verts) + len(verts2))) - verts.extend(verts2) - vertsIdx3 = list(range(len(verts), len(verts) + len(verts3))) - verts.extend(verts3) - vertsIdx4 = list(range(len(verts), len(verts) + len(verts4))) - verts.extend(verts4) - - if isTooth: - verts_current = [] - verts_current.extend(vertsIdx2[:2]) - verts_current.append(vertsIdx3[0]) - verts_current.extend(vertsIdx4) - verts_current.append(vertsIdx3[-1]) - verts_current.append(vertsIdx2[-1]) - - # Valley = first 2 vertices of outer base: - vgroup_valley.extend(vertsIdx2[:1]) - # Top/tip vertices: - vgroup_top.extend(vertsIdx4) - - else: - # Flat - verts_current = vertsIdx2 - - # Valley - all of them. - vgroup_valley.extend(vertsIdx2) - - edgeloop.extend(verts_current) - - # Create faces between rings/rows. - if edgeloop_prev: - faces_row = createFaces(edgeloop, edgeloop_prev, closed=True) - faces.extend(faces_row) - - # Remember last ring/row of vertices for next ring/row iteration. - edgeloop_prev = edgeloop - - return verts, faces, vgroup_top, vgroup_valley - - -class AddGear(bpy.types.Operator): - '''Add a gear mesh.''' - bl_idname = "mesh.primitive_gear" - bl_label = "Add Gear" - bl_options = {'REGISTER', 'UNDO'} - - # edit - Whether to add or update. - edit = BoolProperty(name="", - description="", - default=False, - options={'HIDDEN'}) - number_of_teeth = IntProperty(name="Number of Teeth", - description="Number of teeth on the gear", - min=2, - max=265, - default=12) - radius = FloatProperty(name="Radius", - description="Radius of the gear, negative for crown gear", - min=-100.0, - max=100.0, - default=1.0) - addendum = FloatProperty(name="Addendum", - description="Addendum, extent of tooth above radius", - min=0.01, - max=100.0, - default=0.1) - dedendum = FloatProperty(name="Dedendum", - description="Dedendum, extent of tooth below radius", - min=0.0, - max=100.0, - default=0.1) - angle = FloatProperty(name="Pressure Angle", - description="Pressure angle, skewness of tooth tip (degrees)", - min=0.0, - max=45.0, - default=20.0) - base = FloatProperty(name="Base", - description="Base, extent of gear below radius", - min=0.0, - max=100.0, - default=0.2) - width = FloatProperty(name="Width", - description="Width, thickness of gear", - min=0.05, - max=100.0, - default=0.2) - skew = FloatProperty(name="Skewness", - description="Skew of teeth (degrees)", - min=-90.0, - max=90.0, - default=0.0) - conangle = FloatProperty(name="Conical angle", - description="Conical angle of gear (degrees)", - min=0.0, - max=90.0, - default=0.0) - crown = FloatProperty(name="Crown", - description="Inward pointing extend of crown teeth", - min=0.0, - max=100.0, - default=0.0) - align_matrix = mathutils.Matrix() - - def draw(self, context): - props = self.properties - layout = self.layout - box = layout.box() - box.prop(props, 'number_of_teeth') - box = layout.box() - box.prop(props, 'radius') - box.prop(props, 'width') - box.prop(props, 'base') - box = layout.box() - box.prop(props, 'dedendum') - box.prop(props, 'addendum') - box = layout.box() - box.prop(props, 'angle') - box.prop(props, 'skew') - box.prop(props, 'conangle') - box.prop(props, 'crown') - - - def execute(self, context): - props = self.properties - - verts, faces, verts_tip, verts_valley = add_gear( - props.number_of_teeth, - props.radius, - props.addendum, - props.dedendum, - props.base, - radians(props.angle), - width=props.width, - skew=radians(props.skew), - conangle=radians(props.conangle), - crown=props.crown) - - # Actually create the mesh object from this geometry data. - obj = create_mesh_object(context, verts, [], faces, "Gear", props.edit, self.align_matrix) - - # Create vertex groups from stored vertices. - tipGroup = obj.vertex_groups.new('Tips') - obj.vertex_groups.assign(verts_tip, tipGroup, 1.0, 'ADD') - - valleyGroup = obj.vertex_groups.new('Valleys') - obj.vertex_groups.assign(verts_valley, valleyGroup, 1.0, 'ADD') - - return {'FINISHED'} - - def invoke(self, context, event): - self.align_matrix = align_matrix(context) - self.execute(context) - return {'FINISHED'} - -class AddWormGear(bpy.types.Operator): - '''Add a worm gear mesh.''' - bl_idname = "mesh.primitive_worm_gear" - bl_label = "Add Worm Gear" - bl_options = {'REGISTER', 'UNDO'} - - # edit - Whether to add or update. - edit = BoolProperty(name="", - description="", - default=False, - options={'HIDDEN'}) - number_of_teeth = IntProperty(name="Number of Teeth", - description="Number of teeth on the gear", - min=2, - max=265, - default=12) - number_of_rows = IntProperty(name="Number of Rows", - description="Number of rows on the worm gear", - min=2, - max=265, - default=32) - radius = FloatProperty(name="Radius", - description="Radius of the gear, negative for crown gear", - min=-100.0, - max=100.0, - default=1.0) - addendum = FloatProperty(name="Addendum", - description="Addendum, extent of tooth above radius", - min=0.01, - max=100.0, - default=0.1) - dedendum = FloatProperty(name="Dedendum", - description="Dedendum, extent of tooth below radius", - min=0.0, - max=100.0, - default=0.1) - angle = FloatProperty(name="Pressure Angle", - description="Pressure angle, skewness of tooth tip (degrees)", - min=0.0, - max=45.0, - default=20.0) - row_height = FloatProperty(name="Row Height", - description="Height of each Row", - min=0.05, - max=100.0, - default=0.2) - skew = FloatProperty(name="Skewness per Row", - description="Skew of each row (degrees)", - min=-90.0, - max=90.0, - default=11.25) - crown = FloatProperty(name="Crown", - description="Inward pointing extend of crown teeth", - min=0.0, - max=100.0, - default=0.0) - align_matrix = mathutils.Matrix() - - def draw(self, context): - props = self.properties - layout = self.layout - box = layout.box() - box.prop(props, 'number_of_teeth') - box.prop(props, 'number_of_rows') - box.prop(props, 'radius') - box.prop(props, 'row_height') - box = layout.box() - box.prop(props, 'addendum') - box.prop(props, 'dedendum') - box = layout.box() - box.prop(props, 'angle') - box.prop(props, 'skew') - box.prop(props, 'crown') - - def execute(self, context): - props = self.properties - - verts, faces, verts_tip, verts_valley = add_worm( - props.number_of_teeth, - props.number_of_rows, - props.radius, - props.addendum, - props.dedendum, - radians(props.angle), - width=props.row_height, - skew=radians(props.skew), - crown=props.crown) - - # Actually create the mesh object from this geometry data. - obj = create_mesh_object(context, verts, [], faces, "Worm Gear", - props.edit, self.align_matrix) - - # Create vertex groups from stored vertices. - tipGroup = obj.vertex_groups.new('Tips') - obj.vertex_groups.assign(verts_tip, tipGroup, 1.0, 'ADD') - - valleyGroup = obj.vertex_groups.new('Valleys') - obj.vertex_groups.assign(verts_valley, valleyGroup, 1.0, 'ADD') - - return {'FINISHED'} - - def invoke(self, context, event): - self.align_matrix = align_matrix(context) - self.execute(context) - return {'FINISHED'} - -class INFO_MT_mesh_gears_add(bpy.types.Menu): - # Define the "Gears" menu - bl_idname = "INFO_MT_mesh_gears_add" - bl_label = "Gears" - - def draw(self, context): - layout = self.layout - layout.operator_context = 'INVOKE_REGION_WIN' - layout.operator("mesh.primitive_gear", - text="Gear") - layout.operator("mesh.primitive_worm_gear", - text="Worm") - - -# Define "Gears" menu -def menu_func(self, context): - self.layout.menu("INFO_MT_mesh_gears_add", icon="PLUGIN") - - -def register(): - # Add "Gears" entry to the "Add Mesh" menu. - bpy.types.INFO_MT_mesh_add.append(menu_func) - - -def unregister(): - # Remove "Gears" entry from the "Add Mesh" menu. - bpy.types.INFO_MT_mesh_add.remove(menu_func) - -if __name__ == "__main__": - register() diff --git a/add_mesh_gemstones.py b/add_mesh_gemstones.py deleted file mode 100644 index 984734e6..00000000 --- a/add_mesh_gemstones.py +++ /dev/null @@ -1,472 +0,0 @@ -# ##### 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -# ##### END GPL LICENSE BLOCK ##### - -bl_addon_info = { - "name": "Gemstones", - "author": "Pontiac, Fourmadmen, Dreampainter", - "version": (0,3), - "blender": (2, 5, 3), - "api": 31854, - "location": "View3D > Add > Mesh > Gemstones", - "description": "Adds various gemstone (Diamond & Gem) meshes.", - "warning": "", - "wiki_url": "http://wiki.blender.org/index.php/Extensions:2.5/Py/"\ - "Scripts/Add_Mesh/Add_Gemstones", - "tracker_url": "https://projects.blender.org/tracker/index.php?"\ - "func=detail&aid=21432&group_id=153&atid=469", - "category": "Add Mesh"} - -import bpy -from mathutils import * -from math import * -from bpy.props import * - -# calculates the matrix for the new object -# depending on user pref -def align_matrix(context): - loc = Matrix.Translation(context.scene.cursor_location) - obj_align = context.user_preferences.edit.object_align - if (context.space_data.type == 'VIEW_3D' - and obj_align == 'VIEW'): - rot = context.space_data.region_3d.view_matrix.rotation_part().invert().resize4x4() - else: - rot = Matrix() - align_matrix = loc * rot - return align_matrix - -# Create a new mesh (object) from verts/edges/faces. -# verts/edges/faces ... List of vertices/edges/faces for the -# new mesh (as used in from_pydata). -# name ... Name of the new mesh (& object). -# edit ... Replace existing mesh data. -# Note: Using "edit" will destroy/delete existing mesh data. -def create_mesh_object(context, verts, edges, faces, name, edit, align_matrix): - scene = context.scene - obj_act = scene.objects.active - - # Can't edit anything, unless we have an active obj. - if edit and not obj_act: - return None - - # Create new mesh - mesh = bpy.data.meshes.new(name) - - # Make a mesh from a list of verts/edges/faces. - mesh.from_pydata(verts, edges, faces) - - # Update mesh geometry after adding stuff. - mesh.update() - - # Deselect all objects. - bpy.ops.object.select_all(action='DESELECT') - - if edit: - # Replace geometry of existing object - - # Use the active obj and select it. - ob_new = obj_act - ob_new.select = True - - if obj_act.mode == 'OBJECT': - # Get existing mesh datablock. - old_mesh = ob_new.data - - # Set object data to nothing - ob_new.data = None - - # Clear users of existing mesh datablock. - old_mesh.user_clear() - - # Remove old mesh datablock if no users are left. - if (old_mesh.users == 0): - bpy.data.meshes.remove(old_mesh) - - # Assign new mesh datablock. - ob_new.data = mesh - - else: - # Create new object - ob_new = bpy.data.objects.new(name, mesh) - - # Link new object to the given scene and select it. - scene.objects.link(ob_new) - ob_new.select = True - - # Place the object at the 3D cursor location. - # apply viewRotaion - ob_new.matrix_world = align_matrix - - if obj_act and obj_act.mode == 'EDIT': - if not edit: - # We are in EditMode, switch to ObjectMode. - bpy.ops.object.mode_set(mode='OBJECT') - - # Select the active object as well. - obj_act.select = True - - # Apply location of new object. - scene.update() - - # Join new object into the active. - bpy.ops.object.join() - - # Switching back to EditMode. - bpy.ops.object.mode_set(mode='EDIT') - - ob_new = obj_act - - else: - # We are in ObjectMode. - # Make the new object the active one. - scene.objects.active = ob_new - - return ob_new - - -# A very simple "bridge" tool. -# Connects two equally long vertex rows with faces. -# Returns a list of the new faces (list of lists) -# -# vertIdx1 ... First vertex list (list of vertex indices). -# vertIdx2 ... Second vertex list (list of vertex indices). -# closed ... Creates a loop (first & last are closed). -# flipped ... Invert the normal of the face(s). -# -# Note: You can set vertIdx1 to a single vertex index to create -# a fan/star of faces. -# Note: If both vertex idx list are the same length they have -# to have at least 2 vertices. -def createFaces(vertIdx1, vertIdx2, closed=False, flipped=False): - faces = [] - - if not vertIdx1 or not vertIdx2: - return None - - if len(vertIdx1) < 2 and len(vertIdx2) < 2: - return None - - fan = False - if (len(vertIdx1) != len(vertIdx2)): - if (len(vertIdx1) == 1 and len(vertIdx2) > 1): - fan = True - else: - return None - - total = len(vertIdx2) - - if closed: - # Bridge the start with the end. - if flipped: - face = [ - vertIdx1[0], - vertIdx2[0], - vertIdx2[total - 1]] - if not fan: - face.append(vertIdx1[total - 1]) - faces.append(face) - - else: - face = [vertIdx2[0], vertIdx1[0]] - if not fan: - face.append(vertIdx1[total - 1]) - face.append(vertIdx2[total - 1]) - faces.append(face) - - # Bridge the rest of the faces. - for num in range(total - 1): - if flipped: - if fan: - face = [vertIdx2[num], vertIdx1[0], vertIdx2[num + 1]] - else: - face = [vertIdx2[num], vertIdx1[num], - vertIdx1[num + 1], vertIdx2[num + 1]] - faces.append(face) - else: - if fan: - face = [vertIdx1[0], vertIdx2[num], vertIdx2[num + 1]] - else: - face = [vertIdx1[num], vertIdx2[num], - vertIdx2[num + 1], vertIdx1[num + 1]] - faces.append(face) - - return faces - - -# @todo Clean up vertex&face creation process a bit. -def add_gem(r1, r2, seg, h1, h2): - """ - r1 = pavilion radius - r2 = crown radius - seg = number of segments - h1 = pavilion height - h2 = crown height - Generates the vertices and faces of the gem - """ - - verts = [] - - a = 2.0 * pi / seg # Angle between segments - offset = a / 2.0 # Middle between segments - - r3 = ((r1 + r2) / 2.0) / cos(offset) # Middle of crown - r4 = (r1 / 2.0) / cos(offset) # Middle of pavilion - h3 = h2 / 2.0 # Middle of crown height - h4 = -h1 / 2.0 # Middle of pavilion height - - # Tip - vert_tip = len(verts) - verts.append(Vector((0.0, 0.0, -h1))) - - # Middle vertex of the flat side (crown) - vert_flat = len(verts) - verts.append(Vector((0.0, 0.0, h2))) - - edgeloop_flat = [] - for i in range(seg): - s1 = sin(i * a) - s2 = sin(offset + i * a) - c1 = cos(i * a) - c2 = cos(offset + i * a) - - verts.append((r4 * s1, r4 * c1, h4)) # Middle of pavilion - verts.append((r1 * s2, r1 * c2, 0.0)) # Pavilion - verts.append((r3 * s1, r3 * c1, h3)) # Middle crown - edgeloop_flat.append(len(verts)) - verts.append((r2 * s2, r2 * c2, h2)) # Crown - - faces = [] - - for index in range(seg): - i = index * 4 - j = ((index + 1) % seg) * 4 - - faces.append([j + 2, vert_tip, i + 2, i + 3]) # Tip -> Middle of pav - faces.append([j + 2, i + 3, j + 3]) # Middle of pav -> pav - faces.append([j + 3, i + 3, j + 4]) # Pav -> Middle crown - faces.append([j + 4, i + 3, i + 4, i + 5]) # Crown quads - faces.append([j + 4, i + 5, j + 5]) # Middle crown -> crown - - faces_flat = createFaces([vert_flat], edgeloop_flat, closed=True) - faces.extend(faces_flat) - - return verts, faces - - -def add_diamond(segments, girdle_radius, table_radius, - crown_height, pavilion_height): - - PI_2 = pi * 2.0 - z_axis = (0.0, 0.0, -1.0) - - verts = [] - faces = [] - - height_flat = crown_height - height_middle = 0.0 - height_tip = -pavilion_height - - # Middle vertex of the flat side (crown) - vert_flat = len(verts) - verts.append(Vector((0.0, 0.0, height_flat))) - - # Tip - vert_tip = len(verts) - verts.append(Vector((0.0, 0.0, height_tip))) - - verts_flat = [] - verts_girdle = [] - - for index in range(segments): - quat = Quaternion(z_axis, (index / segments) * PI_2) - - angle = PI_2 * index / segments - - # Row for flat side - verts_flat.append(len(verts)) - vec = Vector((table_radius, 0.0, height_flat)) * quat - verts.append(vec) - - # Row for the middle/girdle - verts_girdle.append(len(verts)) - vec = Vector((girdle_radius, 0.0, height_middle)) * quat - verts.append(vec) - - # Flat face - faces_flat = createFaces([vert_flat], verts_flat, closed=True, - flipped=True) - # Side face - faces_side = createFaces(verts_girdle, verts_flat, closed=True) - # Tip faces - faces_tip = createFaces([vert_tip], verts_girdle, closed=True) - - faces.extend(faces_tip) - faces.extend(faces_side) - faces.extend(faces_flat) - - return verts, faces - - -class AddDiamond(bpy.types.Operator): - '''Add a diamond mesh.''' - bl_idname = "mesh.primitive_diamond_add" - bl_label = "Add Diamond" - bl_options = {'REGISTER', 'UNDO'} - - # edit - Whether to add or update. - edit = BoolProperty(name="", - description="", - default=False, - options={'HIDDEN'}) - segments = IntProperty(name="Segments", - description="Number of segments for the diamond", - min=3, - max=256, - default=32) - girdle_radius = FloatProperty(name="Girdle Radius", - description="Girdle radius of the diamond", - min=0.01, - max=9999.0, - default=1.0) - table_radius = FloatProperty(name="Table Radius", - description="Girdle radius of the diamond", - min=0.01, - max=9999.0, - default=0.6) - crown_height = FloatProperty(name="Crown Height", - description="Crown height of the diamond", - min=0.01, - max=9999.0, - default=0.35) - pavilion_height = FloatProperty(name="Pavilion Height", - description="Pavilion height of the diamond", - min=0.01, - max=9999.0, - default=0.8) - align_matrix = Matrix() - - def execute(self, context): - props = self.properties - verts, faces = add_diamond(props.segments, - props.girdle_radius, - props.table_radius, - props.crown_height, - props.pavilion_height) - - obj = create_mesh_object(context, verts, [], faces, - "Diamond", props.edit, self.align_matrix) - - return {'FINISHED'} - - def invoke(self, context, event): - self.align_matrix = align_matrix(context) - self.execute(context) - return {'FINISHED'} - -class AddGem(bpy.types.Operator): - """Add a diamond gem""" - bl_idname = "mesh.primitive_gem_add" - bl_label = "Add Gem" - bl_description = "Create an offset faceted gem." - bl_options = {'REGISTER', 'UNDO'} - - # edit - Whether to add or update. - edit = BoolProperty(name="", - description="", - default=False, - options={'HIDDEN'}) - segments = IntProperty(name="Segments", - description="Longitudial segmentation", - min=3, - max=265, - default=8,) - pavilion_radius = FloatProperty(name="Radius", - description="Radius of the gem", - min=0.01, - max=9999.0, - default=1.0) - crown_radius = FloatProperty(name="Table Radius", - description="Radius of the table(top).", - min=0.01, - max=9999.0, - default=0.6) - crown_height = FloatProperty(name="Table height", - description="Height of the top half.", - min=0.01, - max=9999.0, - default=0.35) - pavilion_height = FloatProperty(name="Pavilion height", - description="Height of bottom half.", - min=0.01, - max=9999.0, - default=0.8) - align_matrix = Matrix() - - def execute(self, context): - props = self.properties - - # create mesh - verts, faces = add_gem( - props.pavilion_radius, - props.crown_radius, - props.segments, - props.pavilion_height, - props.crown_height) - - obj = create_mesh_object(context, verts, [], faces, "Gem", props.edit, self.align_matrix) - - return {'FINISHED'} - - def invoke(self, context, event): - self.align_matrix = align_matrix(context) - self.execute(context) - return {'FINISHED'} - -class INFO_MT_mesh_gemstones_add(bpy.types.Menu): - # Define the "Gemstones" menu - bl_idname = "INFO_MT_mesh_gemstones_add" - bl_label = "Gemstones" - - def draw(self, context): - layout = self.layout - layout.operator_context = 'INVOKE_REGION_WIN' - layout.operator("mesh.primitive_diamond_add", - text="Diamond") - layout.operator("mesh.primitive_gem_add", - text="Gem") - - -# Register all operators and panels -import space_info - - -# Define "Gemstones" menu -def menu_func(self, context): - self.layout.menu("INFO_MT_mesh_gemstones_add", icon="PLUGIN") - - -def register(): - # Add "Gemstones" menu to the "Add Mesh" menu - space_info.INFO_MT_mesh_add.append(menu_func) - - -def unregister(): - # Remove "Gemstones" menu from the "Add Mesh" menu. - space_info.INFO_MT_mesh_add.remove(menu_func) - -if __name__ == "__main__": - register() diff --git a/add_mesh_pipe_joint.py b/add_mesh_pipe_joint.py deleted file mode 100644 index 76650814..00000000 --- a/add_mesh_pipe_joint.py +++ /dev/null @@ -1,1306 +0,0 @@ -# ##### 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -# ##### END GPL LICENSE BLOCK ##### - -bl_addon_info = { - "name": "Pipe Joints", - "author": "Buerbaum Martin (Pontiac)", - "version": (0, 10, 6), - "blender": (2, 5, 3), - "api": 31854, - "location": "View3D > Add > Mesh > Pipe Joint", - "description": "Adds 5 pipe Joint types to the Add Mesh menu", - "warning": "", - "wiki_url": "http://wiki.blender.org/index.php/Extensions:2.5/Py/"\ - "Scripts/Add_Mesh/Add_Pipe_Joints", - "tracker_url": "https://projects.blender.org/tracker/index.php?"\ - "func=detail&aid=21443&group_id=153&atid=469", - "category": "Add Mesh"} - -""" -Pipe Joints -This script lets the user create various types of pipe joints. - -Usage: -You have to activated the script in the "Add-Ons" tab (user preferences). -The functionality can then be accessed via the -"Add Mesh" -> "Pipe Joints" menu. -Note: Currently only the "Elbow" type supports odd number of vertices. - -Version history: -v0.10.6 - Removed "recall properties" from all functions. - Updated various code for new API. - API: mathutils.RotationMatrix -> mathutils.Matrix.Rotation - API: xxx.selected -> xxx.select - API: "invoke" function for each operator. - Updated for new bl_addon_info structure. - New code for the "align_matrix". - made script PEP8 compatible. -v0.10.5 - createFaces can now create fan/star like faces. -v0.10.4 - Updated the function "createFaces" a bit. No functional changes. -v0.10.3 - Updated store_recall_properties, apply_object_align - and create_mesh_object. - Changed how recall data is stored. - Added 'description'. -v0.10.2 - API change Mathutils -> mathutils (r557) - Fixed wiki url. -v0.10.1 - Use hidden "edit" property for "recall" operator. -v0.10 - Store "recall" properties in the created objects. - Align the geometry to the view if the user preference says so. -v0.9.10 - Use bl_addon_info for Add-On information. -v0.9.9 - Changed the script so it can be managed from the "Add-Ons" tab in - the user preferences. - Added dummy "PLUGIN" icon. -v0.9.8 - Fixed some new API stuff. - Mainly we now have the register/unregister functions. - Also the new() function for objects now accepts a mesh object. - Corrected FSF address. - Clean up of tooltips. -v0.9.7 - Use "unit" settings for angles as well. - This also lets me use radiant for all internal values.. -v0.9.6 - Use "unit" settings (i.e. none/metric/imperial). -v0.9.5 - Use mesh.from_pydata() for geometry creation. - So we can remove unpack_list and unpack_face_list again. -v0.9.4 - Creating of the pipe now works in mesh edit mode too. - Thanks to ideasman42 (Campbell Barton) for his nice work - on the torus script code :-). -v0.9.3 - Changed to a saner vertex/polygon creation process (previously - my usage of mesh.faces.add could only do quads) - For this I've copied the functions unpack_list and unpack_face_list - from import_scene_obj.py. - Elbow joint actually supports 3 vertices per circle. - Various comments. - Script _should_ now be PEP8 compatible. -v0.9.2 - Converted from tabs to spaces (4 spaces per tab). -v0.9.1 - Converted add_mesh and add_object to their new counterparts - "bpy.data.meshes.new() and "bpy.data.objects.new()" -v0.9 - Converted to 2.5. Made mostly pep8 compatible (exept for tabs and - stuff the check-script didn't catch). -v0.8.5 - Fixed bug in Elbow joint. Same problem as in 0.8.1 -v0.8.4 - Fixed bug in Y joint. Same problem as in 0.8.1 -v0.8.3 - Fixed bug in N joint. Same problem as in 0.8.1 -v0.8.2 - Fixed bug in X (cross) joint. Same problem as in 0.8.1 -v0.8.1 - Fixed bug in T joint. Angles greater than 90 deg combined with a - radius != 1 resulted in bad geometry (the radius was not taken into - account when calculating the joint vertices). -v0.8 - Added N-Joint. - Removed all uses of baseJointLocZ. It just clutters the code. -v0.7 - Added cross joint -v0.6 - No visible changes. Lots of internal ones though - (complete redesign of face creation process). - As a bonus the code is a bit easier to read now. - Added a nice&simple little "bridge" function - (createFaces) for these changes. -v0.5.1 - Made it possible to create asymmetric Y joints. - Renamed the 2 Wye Joints to something more fitting and unique. - One is now the Tee joint, the second one remains the Wye joint. -v0.5 - Added real Y joint. -v0.4.3 - Added check for odd vertex numbers. They are not (yet) supported. -v0.4.2 - Added pipe length to the GUI. -v0.4.1 - Removed the unfinished menu entries for now. -v0.4 - Tried to clean up the face creation in addTeeJoint -v0.3 - Code for wye (Y) shape (straight pipe with "branch" for now) -v0.2 - Restructured to allow different types of pipe (joints). -v0.1 - Initial revision. - -More links: -http://gitorious.org/blender-scripts/blender-pipe-joint-script -http://blenderartists.org/forum/showthread.php?t=154394 - -TODO: - -Use a rotation matrix for rotating the circle vertices: -rotation_matrix = mathutils.Matrix.Rotation(-math.pi/2, 4, 'x') -mesh.transform(rotation_matrix) -""" - -import bpy -import mathutils -from math import * -from bpy.props import * - - -# Apply view rotation to objects if "Align To" for -# new objects was set to "VIEW" in the User Preference. -# Is now handled in the invoke functions -# calculates the matrix for the new object -# depending on user pref -def align_matrix(context): - loc = mathutils.Matrix.Translation(context.scene.cursor_location) - obj_align = context.user_preferences.edit.object_align - if (context.space_data.type == 'VIEW_3D' - and obj_align == 'VIEW'): - view_mat = context.space_data.region_3d.view_matrix - rot = view_mat.rotation_part().invert().resize4x4() - else: - rot = mathutils.Matrix() - align_matrix = loc * rot - return align_matrix - - -# Create a new mesh (object) from verts/edges/faces. -# verts/edges/faces ... List of vertices/edges/faces for the -# new mesh (as used in from_pydata). -# name ... Name of the new mesh (& object). -# edit ... Replace existing mesh data. -# Note: Using "edit" will destroy/delete existing mesh data. -def create_mesh_object(context, verts, edges, faces, name, edit, align_matrix): - scene = context.scene - obj_act = scene.objects.active - - # Can't edit anything, unless we have an active obj. - if edit and not obj_act: - return None - - # Create new mesh - mesh = bpy.data.meshes.new(name) - - # Make a mesh from a list of verts/edges/faces. - mesh.from_pydata(verts, edges, faces) - - # Update mesh geometry after adding stuff. - mesh.update() - - # Deselect all objects. - bpy.ops.object.select_all(action='DESELECT') - - if edit: - # Replace geometry of existing object - - # Use the active obj and select it. - ob_new = obj_act - ob_new.select = True - - if obj_act.mode == 'OBJECT': - # Get existing mesh datablock. - old_mesh = ob_new.data - - # Set object data to nothing - ob_new.data = None - - # Clear users of existing mesh datablock. - old_mesh.user_clear() - - # Remove old mesh datablock if no users are left. - if (old_mesh.users == 0): - bpy.data.meshes.remove(old_mesh) - - # Assign new mesh datablock. - ob_new.data = mesh - - else: - # Create new object - ob_new = bpy.data.objects.new(name, mesh) - - # Link new object to the given scene and select it. - scene.objects.link(ob_new) - ob_new.select = True - - # Place the object at the 3D cursor location. - ob_new.matrix_world = align_matrix - - if obj_act and obj_act.mode == 'EDIT': - if not edit: - # We are in EditMode, switch to ObjectMode. - bpy.ops.object.mode_set(mode='OBJECT') - - # Select the active object as well. - obj_act.select = True - - # Apply location of new object. - scene.update() - - # Join new object into the active. - bpy.ops.object.join() - - # Switching back to EditMode. - bpy.ops.object.mode_set(mode='EDIT') - - ob_new = obj_act - - else: - # We are in ObjectMode. - # Make the new object the active one. - scene.objects.active = ob_new - - return ob_new - - -# A very simple "bridge" tool. -# Connects two equally long vertex rows with faces. -# Returns a list of the new faces (list of lists) -# -# vertIdx1 ... First vertex list (list of vertex indices). -# vertIdx2 ... Second vertex list (list of vertex indices). -# closed ... Creates a loop (first & last are closed). -# flipped ... Invert the normal of the face(s). -# -# Note: You can set vertIdx1 to a single vertex index to create -# a fan/star of faces. -# Note: If both vertex idx list are the same length they have -# to have at least 2 vertices. -def createFaces(vertIdx1, vertIdx2, closed=False, flipped=False): - faces = [] - - if not vertIdx1 or not vertIdx2: - return None - - if len(vertIdx1) < 2 and len(vertIdx2) < 2: - return None - - fan = False - if (len(vertIdx1) != len(vertIdx2)): - if (len(vertIdx1) == 1 and len(vertIdx2) > 1): - fan = True - else: - return None - - total = len(vertIdx2) - - if closed: - # Bridge the start with the end. - if flipped: - face = [ - vertIdx1[0], - vertIdx2[0], - vertIdx2[total - 1]] - if not fan: - face.append(vertIdx1[total - 1]) - faces.append(face) - - else: - face = [vertIdx2[0], vertIdx1[0]] - if not fan: - face.append(vertIdx1[total - 1]) - face.append(vertIdx2[total - 1]) - faces.append(face) - - # Bridge the rest of the faces. - for num in range(total - 1): - if flipped: - if fan: - face = [vertIdx2[num], vertIdx1[0], vertIdx2[num + 1]] - else: - face = [vertIdx2[num], vertIdx1[num], - vertIdx1[num + 1], vertIdx2[num + 1]] - faces.append(face) - else: - if fan: - face = [vertIdx1[0], vertIdx2[num], vertIdx2[num + 1]] - else: - face = [vertIdx1[num], vertIdx2[num], - vertIdx2[num + 1], vertIdx1[num + 1]] - faces.append(face) - - return faces - - -class AddElbowJoint(bpy.types.Operator): - # Create the vertices and polygons for a simple elbow (bent pipe). - '''Add an Elbow pipe mesh''' - bl_idname = "mesh.primitive_elbow_joint_add" - bl_label = "Add Pipe Elbow" - bl_options = {'REGISTER', 'UNDO'} - - # edit - Whether to add or update. - edit = BoolProperty(name="", - description="", - default=False, - options={'HIDDEN'}) - - radius = FloatProperty(name="Radius", - description="The radius of the pipe.", - default=1.0, - min=0.01, - max=100.0, - unit="LENGTH") - div = IntProperty(name="Divisions", - description="Number of vertices (divisions).", - default=32, min=3, max=256) - - angle = FloatProperty(name="Angle", - description="The angle of the branching pipe (i.e. the 'arm')." \ - " Measured from the center line of the main pipe.", - default=radians(45.0), - min=radians(-179.9), - max=radians(179.9), - unit="ROTATION") - - startLength = FloatProperty(name="Length Start", - description="Length of the beginning of the pipe.", - default=3.0, - min=0.01, - max=100.0, - unit="LENGTH") - endLength = FloatProperty(name="End Length", - description="Length of the end of the pipe.", - default=3.0, - min=0.01, - max=100.0, - unit="LENGTH") - align_matrix = mathutils.Matrix() - - def execute(self, context): - edit = self.properties.edit - - radius = self.properties.radius - div = self.properties.div - - angle = self.properties.angle - - startLength = self.properties.startLength - endLength = self.properties.endLength - - verts = [] - faces = [] - - loop1 = [] # The starting circle - loop2 = [] # The elbow circle - loop3 = [] # The end circle - - # Create start circle - for vertIdx in range(div): - curVertAngle = vertIdx * (2.0 * pi / div) - locX = sin(curVertAngle) - locY = cos(curVertAngle) - locZ = -startLength - loop1.append(len(verts)) - verts.append([locX * radius, locY * radius, locZ]) - - # Create deformed joint circle - for vertIdx in range(div): - curVertAngle = vertIdx * (2.0 * pi / div) - locX = sin(curVertAngle) - locY = cos(curVertAngle) - locZ = locX * tan(angle / 2.0) - loop2.append(len(verts)) - verts.append([locX * radius, locY * radius, locZ * radius]) - - # Create end circle - baseEndLocX = -endLength * sin(angle) - baseEndLocZ = endLength * cos(angle) - for vertIdx in range(div): - curVertAngle = vertIdx * (2.0 * pi / div) - # Create circle - locX = sin(curVertAngle) * radius - locY = cos(curVertAngle) * radius - locZ = 0.0 - - # Rotate circle - locZ = locX * cos(pi / 2.0 - angle) - locX = locX * sin(pi / 2.0 - angle) - - loop3.append(len(verts)) - # Translate and add circle vertices to the list. - verts.append([baseEndLocX + locX, locY, baseEndLocZ + locZ]) - - # Create faces - faces.extend(createFaces(loop1, loop2, closed=True)) - faces.extend(createFaces(loop2, loop3, closed=True)) - - obj = create_mesh_object(context, verts, [], faces, - "Elbow Joint", edit, self.align_matrix) - - return {'FINISHED'} - - def invoke(self, context, event): - self.align_matrix = align_matrix(context) - self.execute(context) - return {'FINISHED'} - - -class AddTeeJoint(bpy.types.Operator): - # Create the vertices and polygons for a simple tee (T) joint. - # The base arm of the T can be positioned in an angle if needed though. - '''Add a Tee-Joint mesh''' - bl_idname = "mesh.primitive_tee_joint_add" - bl_label = "Add Pipe Tee-Joint" - bl_options = {'REGISTER', 'UNDO'} - - # edit - Whether to add or update. - edit = BoolProperty(name="", - description="", - default=False, - options={'HIDDEN'}) - - radius = FloatProperty(name="Radius", - description="The radius of the pipe.", - default=1.0, - min=0.01, - max=100.0, - unit="LENGTH") - div = IntProperty(name="Divisions", - description="Number of vertices (divisions).", - default=32, - min=4, - max=256) - - angle = FloatProperty(name="Angle", - description="The angle of the branching pipe (i.e. the 'arm')." \ - " Measured from the center line of the main pipe.", - default=radians(90.0), - min=radians(0.1), - max=radians(179.9), - unit="ROTATION") - - startLength = FloatProperty(name="Length Start", - description="Length of the beginning of the" \ - " main pipe (the straight one).", - default=3.0, - min=0.01, - max=100.0, - unit="LENGTH") - endLength = FloatProperty(name="End Length", - description="Length of the end of the" \ - " main pipe (the straight one).", - default=3.0, - min=0.01, - max=100.0, - unit="LENGTH") - branchLength = FloatProperty(name="Arm Length", - description="Length of the arm pipe (the bent one).", - default=3.0, - min=0.01, - max=100.0, - unit="LENGTH") - align_matrix = mathutils.Matrix() - - def execute(self, context): - edit = self.properties.edit - - radius = self.properties.radius - div = self.properties.div - - angle = self.properties.angle - - startLength = self.properties.startLength - endLength = self.properties.endLength - branchLength = self.properties.branchLength - - if (div % 2): - # Odd vertice number not supported (yet). - return {'CANCELLED'} - - verts = [] - faces = [] - - # List of vert indices of each cross section - loopMainStart = [] # Vert indices for the - # beginning of the main pipe. - loopJoint1 = [] # Vert indices for joint that is used - # to connect the joint & loopMainStart. - loopJoint2 = [] # Vert indices for joint that is used - # to connect the joint & loopArm. - loopJoint3 = [] # Vert index for joint that is used - # to connect the joint & loopMainEnd. - loopArm = [] # Vert indices for the end of the arm. - loopMainEnd = [] # Vert indices for the - # end of the main pipe. - - # Create start circle (main pipe) - for vertIdx in range(div): - curVertAngle = vertIdx * (2.0 * pi / div) - locX = sin(curVertAngle) - locY = cos(curVertAngle) - locZ = -startLength - loopMainStart.append(len(verts)) - verts.append([locX * radius, locY * radius, locZ]) - - # Create deformed joint circle - vertTemp1 = None - vertTemp2 = None - for vertIdx in range(div): - curVertAngle = vertIdx * (2.0 * pi / div) - locX = sin(curVertAngle) - locY = cos(curVertAngle) - - if vertIdx == 0: - vertTemp1 = len(verts) - if vertIdx == div / 2: - # @todo: This will possibly break if we - # ever support odd divisions. - vertTemp2 = len(verts) - - loopJoint1.append(len(verts)) - if (vertIdx < div / 2): - # Straight side of main pipe. - locZ = 0 - loopJoint3.append(len(verts)) - else: - # Branching side - locZ = locX * tan(angle / 2.0) - loopJoint2.append(len(verts)) - - verts.append([locX * radius, locY * radius, locZ * radius]) - - # Create 2. deformed joint (half-)circle - loopTemp = [] - for vertIdx in range(div): - if (vertIdx > div / 2): - curVertAngle = vertIdx * (2.0 * pi / div) - locX = sin(curVertAngle) - locY = -cos(curVertAngle) - locZ = -(radius * locX * tan((pi - angle) / 2.0)) - loopTemp.append(len(verts)) - verts.append([locX * radius, locY * radius, locZ]) - - loopTemp2 = loopTemp[:] - - # Finalise 2. loop - loopTemp.reverse() - loopTemp.append(vertTemp1) - loopJoint2.reverse() - loopJoint2.extend(loopTemp) - loopJoint2.reverse() - - # Finalise 3. loop - loopTemp2.append(vertTemp2) - loopTemp2.reverse() - loopJoint3.extend(loopTemp2) - - # Create end circle (branching pipe) - baseEndLocX = -branchLength * sin(angle) - baseEndLocZ = branchLength * cos(angle) - for vertIdx in range(div): - curVertAngle = vertIdx * (2.0 * pi / div) - # Create circle - locX = sin(curVertAngle) * radius - locY = cos(curVertAngle) * radius - locZ = 0.0 - - # Rotate circle - locZ = locX * cos(pi / 2.0 - angle) - locX = locX * sin(pi / 2.0 - angle) - - loopArm.append(len(verts)) - - # Add translated circle. - verts.append([baseEndLocX + locX, locY, baseEndLocZ + locZ]) - - # Create end circle (main pipe) - for vertIdx in range(div): - curVertAngle = vertIdx * (2.0 * pi / div) - locX = sin(curVertAngle) - locY = cos(curVertAngle) - locZ = endLength - loopMainEnd.append(len(verts)) - verts.append([locX * radius, locY * radius, locZ]) - - # Create faces - faces.extend(createFaces(loopMainStart, loopJoint1, closed=True)) - faces.extend(createFaces(loopJoint2, loopArm, closed=True)) - faces.extend(createFaces(loopJoint3, loopMainEnd, closed=True)) - - obj = create_mesh_object(context, verts, [], faces, - "Tee Joint", edit, self.align_matrix) - - return {'FINISHED'} - - def invoke(self, context, event): - self.align_matrix = align_matrix(context) - self.execute(context) - return {'FINISHED'} - - -class AddWyeJoint(bpy.types.Operator): - '''Add a Wye-Joint mesh''' - bl_idname = "mesh.primitive_wye_joint_add" - bl_label = "Add Pipe Wye-Joint" - bl_options = {'REGISTER', 'UNDO'} - - # edit - Whether to add or update. - edit = BoolProperty(name="", - description="", - default=False, - options={'HIDDEN'}) - - radius = FloatProperty(name="Radius", - description="The radius of the pipe.", - default=1.0, - min=0.01, - max=100.0, - unit="LENGTH") - div = IntProperty(name="Divisions", - description="Number of vertices (divisions).", - default=32, - min=4, - max=256) - - angle1 = FloatProperty(name="Angle 1", - description="The angle of the 1. branching pipe." \ - " Measured from the center line of the main pipe.", - default=radians(45.0), - min=radians(-179.9), - max=radians(179.9), - unit="ROTATION") - angle2 = FloatProperty(name="Angle 2", - description="The angle of the 2. branching pipe." \ - " Measured from the center line of the main pipe.", - default=radians(45.0), - min=radians(-179.9), - max=radians(179.9), - unit="ROTATION") - - startLength = FloatProperty(name="Length Start", - description="Length of the beginning of the" \ - " main pipe (the straight one).", - default=3.0, - min=0.01, - max=100.0, - unit="LENGTH") - branch1Length = FloatProperty(name="Length Arm 1", - description="Length of the 1. arm.", - default=3.0, - min=0.01, - max=100.0, - unit="LENGTH") - branch2Length = FloatProperty(name="Length Arm 2", - description="Length of the 2. arm.", - default=3.0, - min=0.01, - max=100.0, - unit="LENGTH") - align_matrix = mathutils.Matrix() - - def execute(self, context): - edit = self.properties.edit - - radius = self.properties.radius - div = self.properties.div - - angle1 = self.properties.angle1 - angle2 = self.properties.angle2 - - startLength = self.properties.startLength - branch1Length = self.properties.branch1Length - branch2Length = self.properties.branch2Length - - if (div % 2): - # Odd vertice number not supported (yet). - return {'CANCELLED'} - - verts = [] - faces = [] - - # List of vert indices of each cross section - loopMainStart = [] # Vert indices for - # the beginning of the main pipe. - loopJoint1 = [] # Vert index for joint that is used - # to connect the joint & loopMainStart. - loopJoint2 = [] # Vert index for joint that - # is used to connect the joint & loopArm1. - loopJoint3 = [] # Vert index for joint that is - # used to connect the joint & loopArm2. - loopArm1 = [] # Vert idxs for end of the 1. arm. - loopArm2 = [] # Vert idxs for end of the 2. arm. - - # Create start circle - for vertIdx in range(div): - curVertAngle = vertIdx * (2.0 * pi / div) - locX = sin(curVertAngle) - locY = cos(curVertAngle) - locZ = -startLength - loopMainStart.append(len(verts)) - verts.append([locX * radius, locY * radius, locZ]) - - # Create deformed joint circle - vertTemp1 = None - vertTemp2 = None - for vertIdx in range(div): - curVertAngle = vertIdx * (2.0 * pi / div) - locX = sin(curVertAngle) - locY = cos(curVertAngle) - - if vertIdx == 0: - vertTemp2 = len(verts) - if vertIdx == div / 2: - # @todo: This will possibly break if we - # ever support odd divisions. - vertTemp1 = len(verts) - - loopJoint1.append(len(verts)) - if (vertIdx > div / 2): - locZ = locX * tan(angle1 / 2.0) - loopJoint2.append(len(verts)) - else: - locZ = locX * tan(-angle2 / 2.0) - loopJoint3.append(len(verts)) - - verts.append([locX * radius, locY * radius, locZ * radius]) - - # Create 2. deformed joint (half-)circle - loopTemp = [] - angleJoint = (angle2 - angle1) / 2.0 - for vertIdx in range(div): - if (vertIdx > div / 2): - curVertAngle = vertIdx * (2.0 * pi / div) - - locX = (-sin(curVertAngle) * sin(angleJoint) - / sin(angle2 - angleJoint)) - locY = -cos(curVertAngle) - locZ = (-(sin(curVertAngle) * cos(angleJoint) - / sin(angle2 - angleJoint))) - - loopTemp.append(len(verts)) - verts.append([locX * radius, locY * radius, locZ * radius]) - - loopTemp2 = loopTemp[:] - - # Finalise 2. loop - loopTemp.append(vertTemp1) - loopTemp.reverse() - loopTemp.append(vertTemp2) - loopJoint2.reverse() - loopJoint2.extend(loopTemp) - loopJoint2.reverse() - - # Finalise 3. loop - loopTemp2.reverse() - loopJoint3.extend(loopTemp2) - - # Create end circle (1. branching pipe) - baseEndLocX = -branch1Length * sin(angle1) - baseEndLocZ = branch1Length * cos(angle1) - for vertIdx in range(div): - curVertAngle = vertIdx * (2.0 * pi / div) - # Create circle - locX = sin(curVertAngle) * radius - locY = cos(curVertAngle) * radius - locZ = 0.0 - - # Rotate circle - locZ = locX * cos(pi / 2.0 - angle1) - locX = locX * sin(pi / 2.0 - angle1) - - loopArm1.append(len(verts)) - # Add translated circle. - verts.append([baseEndLocX + locX, locY, baseEndLocZ + locZ]) - - # Create end circle (2. branching pipe) - baseEndLocX = branch2Length * sin(angle2) - baseEndLocZ = branch2Length * cos(angle2) - for vertIdx in range(div): - curVertAngle = vertIdx * (2.0 * pi / div) - # Create circle - locX = sin(curVertAngle) * radius - locY = cos(curVertAngle) * radius - locZ = 0.0 - - # Rotate circle - locZ = locX * cos(pi / 2.0 + angle2) - locX = locX * sin(pi / 2.0 + angle2) - - loopArm2.append(len(verts)) - # Add translated circle - verts.append([baseEndLocX + locX, locY, baseEndLocZ + locZ]) - - # Create faces - faces.extend(createFaces(loopMainStart, loopJoint1, closed=True)) - faces.extend(createFaces(loopJoint2, loopArm1, closed=True)) - faces.extend(createFaces(loopJoint3, loopArm2, closed=True)) - - obj = create_mesh_object(context, verts, [], faces, - "Wye Joint", edit, self.align_matrix) - - return {'FINISHED'} - - def invoke(self, context, event): - self.align_matrix = align_matrix(context) - self.execute(context) - return {'FINISHED'} - - -class AddCrossJoint(bpy.types.Operator): - '''Add a Cross-Joint mesh''' - # Create the vertices and polygons for a coss (+ or X) pipe joint. - bl_idname = "mesh.primitive_cross_joint_add" - bl_label = "Add Pipe Cross-Joint" - bl_options = {'REGISTER', 'UNDO'} - - # edit - Whether to add or update. - edit = BoolProperty(name="", - description="", - default=False, - options={'HIDDEN'}) - - radius = FloatProperty(name="Radius", - description="The radius of the pipe.", - default=1.0, - min=0.01, - max=100.0, - unit="LENGTH") - div = IntProperty(name="Divisions", - description="Number of vertices (divisions).", - default=32, - min=4, - max=256) - - angle1 = FloatProperty(name="Angle 1", - description="The angle of the 1. arm (from the main axis).", - default=radians(90.0), - min=radians(-179.9), - max=radians(179.9), - unit="ROTATION") - angle2 = FloatProperty(name="Angle 2", - description="The angle of the 2. arm (from the main axis).", - default=radians(90.0), - min=radians(-179.9), - max=radians(179.9), - unit="ROTATION") - angle3 = FloatProperty(name="Angle 3 (center)", - description="The angle of the center arm (from the main axis).", - default=radians(0.0), - min=radians(-179.9), - max=radians(179.9), - unit="ROTATION") - - startLength = FloatProperty(name="Length Start", - description="Length of the beginning of the " \ - "main pipe (the straight one).", - default=3.0, - min=0.01, - max=100.0, - unit="LENGTH") - branch1Length = FloatProperty(name="Length Arm 1", - description="Length of the 1. arm.", - default=3.0, - min=0.01, - max=100.0, - unit="LENGTH") - branch2Length = FloatProperty(name="Length Arm 2", - description="Length of the 2. arm.", - default=3.0, - min=0.01, - max=100.0, - unit="LENGTH") - branch3Length = FloatProperty(name="Length Arm 3 (center)", - description="Length of the center arm.", - default=3.0, - min=0.01, - max=100.0, - unit="LENGTH") - align_matrix = mathutils.Matrix() - - def execute(self, context): - edit = self.properties.edit - - radius = self.properties.radius - div = self.properties.div - - angle1 = self.properties.angle1 - angle2 = self.properties.angle2 - angle3 = self.properties.angle3 - - startLength = self.properties.startLength - branch1Length = self.properties.branch1Length - branch2Length = self.properties.branch2Length - branch3Length = self.properties.branch3Length - if (div % 2): - # Odd vertice number not supported (yet). - return {'CANCELLED'} - - verts = [] - faces = [] - - # List of vert indices of each cross section - loopMainStart = [] # Vert indices for the - # beginning of the main pipe. - loopJoint1 = [] # Vert index for joint that is used - # to connect the joint & loopMainStart. - loopJoint2 = [] # Vert index for joint that is used - # to connect the joint & loopArm1. - loopJoint3 = [] # Vert index for joint that is used - # to connect the joint & loopArm2. - loopJoint4 = [] # Vert index for joint that is used - # to connect the joint & loopArm3. - loopArm1 = [] # Vert idxs for the end of the 1. arm. - loopArm2 = [] # Vert idxs for the end of the 2. arm. - loopArm3 = [] # Vert idxs for the center arm end. - - # Create start circle - for vertIdx in range(div): - curVertAngle = vertIdx * (2.0 * pi / div) - locX = sin(curVertAngle) - locY = cos(curVertAngle) - locZ = -startLength - loopMainStart.append(len(verts)) - verts.append([locX * radius, locY * radius, locZ]) - - # Create 1. deformed joint circle - vertTemp1 = None - vertTemp2 = None - for vertIdx in range(div): - curVertAngle = vertIdx * (2.0 * pi / div) - locX = sin(curVertAngle) - locY = cos(curVertAngle) - - if vertIdx == 0: - vertTemp2 = len(verts) - if vertIdx == div / 2: - # @todo: This will possibly break if we - # ever support odd divisions. - vertTemp1 = len(verts) - - loopJoint1.append(len(verts)) - if (vertIdx > div / 2): - locZ = locX * tan(angle1 / 2.0) - loopJoint2.append(len(verts)) - else: - locZ = locX * tan(-angle2 / 2.0) - loopJoint3.append(len(verts)) - - verts.append([locX * radius, locY * radius, locZ * radius]) - - loopTemp2 = loopJoint2[:] - - # Create 2. deformed joint circle - loopTempA = [] - loopTempB = [] - angleJoint1 = (angle1 - angle3) / 2.0 - angleJoint2 = (angle2 + angle3) / 2.0 - for vertIdx in range(div): - curVertAngle = vertIdx * (2.0 * pi / div) - - # Skip pole vertices - # @todo: This will possibly break if - # we ever support odd divisions. - if not (vertIdx == 0) and not (vertIdx == div / 2): - - if (vertIdx > div / 2): - angleJoint = angleJoint1 - angle = angle1 - Z = -1.0 - loopTempA.append(len(verts)) - - else: - angleJoint = angleJoint2 - angle = angle2 - Z = 1.0 - loopTempB.append(len(verts)) - - locX = (sin(curVertAngle) * sin(angleJoint) - / sin(angle - angleJoint)) - locY = -cos(curVertAngle) - locZ = (Z * (sin(curVertAngle) * cos(angleJoint) - / sin(angle - angleJoint))) - - verts.append([locX * radius, locY * radius, locZ * radius]) - - loopTempA2 = loopTempA[:] - loopTempB2 = loopTempB[:] - loopTempB3 = loopTempB[:] - - # Finalise 2. loop - loopTempA.append(vertTemp1) - loopTempA.reverse() - loopTempA.append(vertTemp2) - loopJoint2.reverse() - loopJoint2.extend(loopTempA) - loopJoint2.reverse() - - # Finalise 3. loop - loopJoint3.extend(loopTempB3) - - # Finalise 4. loop - loopTempA2.append(vertTemp1) - loopTempA2.reverse() - loopTempB2.append(vertTemp2) - loopJoint4.extend(reversed(loopTempB2)) - loopJoint4.extend(loopTempA2) - - # Create end circle (1. branching pipe) - baseEndLocX = -branch1Length * sin(angle1) - baseEndLocZ = branch1Length * cos(angle1) - for vertIdx in range(div): - curVertAngle = vertIdx * (2.0 * pi / div) - # Create circle - locX = sin(curVertAngle) * radius - locY = cos(curVertAngle) * radius - locZ = 0.0 - - # Rotate circle - locZ = locX * cos(pi / 2.0 - angle1) - locX = locX * sin(pi / 2.0 - angle1) - - loopArm1.append(len(verts)) - # Add translated circle. - verts.append([baseEndLocX + locX, locY, baseEndLocZ + locZ]) - - # Create end circle (2. branching pipe) - baseEndLocX = branch2Length * sin(angle2) - baseEndLocZ = branch2Length * cos(angle2) - for vertIdx in range(div): - curVertAngle = vertIdx * (2.0 * pi / div) - # Create circle - locX = sin(curVertAngle) * radius - locY = cos(curVertAngle) * radius - locZ = 0.0 - - # Rotate circle - locZ = locX * cos(pi / 2.0 + angle2) - locX = locX * sin(pi / 2.0 + angle2) - - loopArm2.append(len(verts)) - # Add translated circle - verts.append([baseEndLocX + locX, locY, baseEndLocZ + locZ]) - - # Create end circle (center pipe) - baseEndLocX = branch3Length * sin(angle3) - baseEndLocZ = branch3Length * cos(angle3) - for vertIdx in range(div): - curVertAngle = vertIdx * (2.0 * pi / div) - # Create circle - locX = sin(curVertAngle) * radius - locY = cos(curVertAngle) * radius - locZ = 0.0 - - # Rotate circle - locZ = locX * cos(pi / 2.0 + angle3) - locX = locX * sin(pi / 2.0 + angle3) - - loopArm3.append(len(verts)) - # Add translated circle - verts.append([baseEndLocX + locX, locY, baseEndLocZ + locZ]) - - # Create faces - faces.extend(createFaces(loopMainStart, loopJoint1, closed=True)) - faces.extend(createFaces(loopJoint2, loopArm1, closed=True)) - faces.extend(createFaces(loopJoint3, loopArm2, closed=True)) - faces.extend(createFaces(loopJoint4, loopArm3, closed=True)) - - obj = create_mesh_object(context, verts, [], faces, - "Cross Joint", edit, self.align_matrix) - - return {'FINISHED'} - - def invoke(self, context, event): - self.align_matrix = align_matrix(context) - self.execute(context) - return {'FINISHED'} - - -class AddNJoint(bpy.types.Operator): - '''Add a N-Joint mesh''' - # Create the vertices and polygons for a regular n-joint. - bl_idname = "mesh.primitive_n_joint_add" - bl_label = "Add Pipe N-Joint" - bl_options = {'REGISTER', 'UNDO'} - - # edit - Whether to add or update. - edit = BoolProperty(name="", - description="", - default=False, - options={'HIDDEN'}) - - radius = FloatProperty(name="Radius", - description="The radius of the pipe.", - default=1.0, - min=0.01, - max=100.0, - unit="LENGTH") - div = IntProperty(name="Divisions", - description="Number of vertices (divisions).", - default=32, - min=4, - max=256) - number = IntProperty(name="Arms/Joints", - description="Number of joints/arms", - default=5, - min=2, - max=99999) - length = FloatProperty(name="Length", - description="Length of each joint/arm", - default=3.0, - min=0.01, - max=100.0, - unit="LENGTH") - align_matrix = mathutils.Matrix() - - def execute(self, context): - edit = self.properties.edit - radius = self.properties.radius - div = self.properties.div - number = self.properties.number - length = self.properties.length - - if (div % 2): - # Odd vertice number not supported (yet). - return {'CANCELLED'} - - if (number < 2): - return {'CANCELLED'} - - verts = [] - faces = [] - - loopsEndCircles = [] - loopsJointsTemp = [] - loopsJoints = [] - - vertTemp1 = None - vertTemp2 = None - - angleDiv = (2.0 * pi / number) - - # Create vertices for the end circles. - for num in range(number): - circle = [] - # Create start circle - angle = num * angleDiv - - baseEndLocX = length * sin(angle) - baseEndLocZ = length * cos(angle) - for vertIdx in range(div): - curVertAngle = vertIdx * (2.0 * pi / div) - # Create circle - locX = sin(curVertAngle) * radius - locY = cos(curVertAngle) * radius - locZ = 0.0 - - # Rotate circle - locZ = locX * cos(pi / 2.0 + angle) - locX = locX * sin(pi / 2.0 + angle) - - circle.append(len(verts)) - # Add translated circle - verts.append([baseEndLocX + locX, locY, baseEndLocZ + locZ]) - - loopsEndCircles.append(circle) - - # Create vertices for the joint circles. - loopJoint = [] - for vertIdx in range(div): - curVertAngle = vertIdx * (2.0 * pi / div) - locX = sin(curVertAngle) - locY = cos(curVertAngle) - - skipVert = False - # Store pole vertices - if vertIdx == 0: - if (num == 0): - vertTemp2 = len(verts) - else: - skipVert = True - elif vertIdx == div / 2: - # @todo: This will possibly break if we - # ever support odd divisions. - if (num == 0): - vertTemp1 = len(verts) - else: - skipVert = True - - if not skipVert: - if (vertIdx > div / 2): - locZ = -locX * tan((pi - angleDiv) / 2.0) - loopJoint.append(len(verts)) - - # Rotate the vert - cosAng = cos(-angle) - sinAng = sin(-angle) - LocXnew = locX * cosAng - locZ * sinAng - LocZnew = locZ * cosAng + locX * sinAng - locZ = LocZnew - locX = LocXnew - - verts.append([ - locX * radius, - locY * radius, - locZ * radius]) - else: - # These two vertices will only be - # added the very first time. - if vertIdx == 0 or vertIdx == div / 2: - verts.append([locX * radius, locY * radius, locZ]) - - loopsJointsTemp.append(loopJoint) - - # Create complete loops (loopsJoints) out of the - # double number of half loops in loopsJointsTemp. - for halfLoopIdx in range(len(loopsJointsTemp)): - if (halfLoopIdx == len(loopsJointsTemp) - 1): - idx1 = halfLoopIdx - idx2 = 0 - else: - idx1 = halfLoopIdx - idx2 = halfLoopIdx + 1 - - loopJoint = [] - loopJoint.append(vertTemp2) - loopJoint.extend(reversed(loopsJointsTemp[idx2])) - loopJoint.append(vertTemp1) - loopJoint.extend(loopsJointsTemp[idx1]) - - loopsJoints.append(loopJoint) - - # Create faces from the two - # loop arrays (loopsJoints -> loopsEndCircles). - for loopIdx in range(len(loopsEndCircles)): - faces.extend( - createFaces(loopsJoints[loopIdx], - loopsEndCircles[loopIdx], closed=True)) - - obj = create_mesh_object(context, verts, [], faces, - "N Joint", edit, self.align_matrix) - - return {'FINISHED'} - - def invoke(self, context, event): - self.align_matrix = align_matrix(context) - self.execute(context) - return {'FINISHED'} - - -class INFO_MT_mesh_pipe_joints_add(bpy.types.Menu): - # Define the "Pipe Joints" menu - bl_idname = "INFO_MT_mesh_pipe_joints_add" - bl_label = "Pipe Joints" - - def draw(self, context): - layout = self.layout - layout.operator_context = 'INVOKE_REGION_WIN' - layout.operator("mesh.primitive_elbow_joint_add", - text="Pipe Elbow") - layout.operator("mesh.primitive_tee_joint_add", - text="Pipe T-Joint") - layout.operator("mesh.primitive_wye_joint_add", - text="Pipe Y-Joint") - layout.operator("mesh.primitive_cross_joint_add", - text="Pipe Cross-Joint") - layout.operator("mesh.primitive_n_joint_add", - text="Pipe N-Joint") - -################################ - -import space_info - - -# Define "Pipe Joints" menu -def menu_func(self, context): - self.layout.menu("INFO_MT_mesh_pipe_joints_add", icon="PLUGIN") - - -def register(): - # Add "Pipe Joints" menu to the "Add Mesh" menu - space_info.INFO_MT_mesh_add.append(menu_func) - - -def unregister(): - # Remove "Pipe Joints" menu from the "Add Mesh" menu. - space_info.INFO_MT_mesh_add.remove(menu_func) - -if __name__ == "__main__": - register() diff --git a/add_mesh_solid.py b/add_mesh_solid.py deleted file mode 100644 index 0822250a..00000000 --- a/add_mesh_solid.py +++ /dev/null @@ -1,902 +0,0 @@ -# ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -# ***** END GPL LICENCE BLOCK ***** - -bl_addon_info = { - "name": "Regular Solids", - "author": "DreamPainter", - "version": (1,), - "blender": (2, 5, 3), - "api": 31854, - "location": "View3D > Add > Mesh > Regular Solids", - "description": "Add a Regular Solid mesh.", - "warning": "", - "wiki_url": "http://wiki.blender.org/index.php/Extensions:2.5/Py/"\ - "Scripts/Add_Mesh/Add_Solid", - "tracker_url": "https://projects.blender.org/tracker/index.php?"\ - "func=detail&aid=22405&group_id=153&atid=469", - "category": "Add Mesh"} - - -import bpy -from bpy.props import FloatProperty,EnumProperty,BoolProperty -from math import sqrt -from mathutils import Vector,Matrix -#from rawMeshUtils import * -from functools import reduce - -# Apply view rotation to objects if "Align To" for -# new objects was set to "VIEW" in the User Preference. -def apply_object_align(context, ob): - obj_align = bpy.context.user_preferences.edit.object_align - - if (context.space_data.type == 'VIEW_3D' - and obj_align == 'VIEW'): - view3d = context.space_data - region = view3d.region_3d - viewMatrix = region.view_matrix - rot = viewMatrix.rotation_part() - ob.rotation_euler = rot.invert().to_euler() - - -# Create a new mesh (object) from verts/edges/faces. -# verts/edges/faces ... List of vertices/edges/faces for the -# new mesh (as used in from_pydata). -# name ... Name of the new mesh (& object). -# edit ... Replace existing mesh data. -# Note: Using "edit" will destroy/delete existing mesh data. -def create_mesh_object(context, verts, edges, faces, name, edit): - scene = context.scene - obj_act = scene.objects.active - - # Can't edit anything, unless we have an active obj. - if edit and not obj_act: - return None - - # Create new mesh - mesh = bpy.data.meshes.new(name) - - # Make a mesh from a list of verts/edges/faces. - mesh.from_pydata(verts, edges, faces) - - # Update mesh geometry after adding stuff. - mesh.update() - - # Deselect all objects. - bpy.ops.object.select_all(action='DESELECT') - - if edit: - # Replace geometry of existing object - - # Use the active obj and select it. - ob_new = obj_act - ob_new.select = True - - if obj_act.mode == 'OBJECT': - # Get existing mesh datablock. - old_mesh = ob_new.data - - # Set object data to nothing - ob_new.data = None - - # Clear users of existing mesh datablock. - old_mesh.user_clear() - - # Remove old mesh datablock if no users are left. - if (old_mesh.users == 0): - bpy.data.meshes.remove(old_mesh) - - # Assign new mesh datablock. - ob_new.data = mesh - - else: - # Create new object - ob_new = bpy.data.objects.new(name, mesh) - - # Link new object to the given scene and select it. - scene.objects.link(ob_new) - ob_new.select = True - - # Place the object at the 3D cursor location. - ob_new.location = scene.cursor_location - - apply_object_align(context, ob_new) - - if obj_act and obj_act.mode == 'EDIT': - if not edit: - # We are in EditMode, switch to ObjectMode. - bpy.ops.object.mode_set(mode='OBJECT') - - # Select the active object as well. - obj_act.select = True - - # Apply location of new object. - scene.update() - - # Join new object into the active. - bpy.ops.object.join() - - # Switching back to EditMode. - bpy.ops.object.mode_set(mode='EDIT') - - ob_new = obj_act - - else: - # We are in ObjectMode. - # Make the new object the active one. - scene.objects.active = ob_new - - return ob_new - - -# A very simple "bridge" tool. -# Connects two equally long vertex rows with faces. -# Returns a list of the new faces (list of lists) -# -# vertIdx1 ... First vertex list (list of vertex indices). -# vertIdx2 ... Second vertex list (list of vertex indices). -# closed ... Creates a loop (first & last are closed). -# flipped ... Invert the normal of the face(s). -# -# Note: You can set vertIdx1 to a single vertex index to create -# a fan/star of faces. -# Note: If both vertex idx list are the same length they have -# to have at least 2 vertices. -def createFaces(vertIdx1, vertIdx2, closed=False, flipped=False): - faces = [] - - if not vertIdx1 or not vertIdx2: - return None - - if len(vertIdx1) < 2 and len(vertIdx2) < 2: - return None - - fan = False - if (len(vertIdx1) != len(vertIdx2)): - if (len(vertIdx1) == 1 and len(vertIdx2) > 1): - fan = True - else: - return None - - total = len(vertIdx2) - - if closed: - # Bridge the start with the end. - if flipped: - face = [ - vertIdx1[0], - vertIdx2[0], - vertIdx2[total - 1]] - if not fan: - face.append(vertIdx1[total - 1]) - faces.append(face) - - else: - face = [vertIdx2[0], vertIdx1[0]] - if not fan: - face.append(vertIdx1[total - 1]) - face.append(vertIdx2[total - 1]) - faces.append(face) - - # Bridge the rest of the faces. - for num in range(total - 1): - if flipped: - if fan: - face = [vertIdx2[num], vertIdx1[0], vertIdx2[num + 1]] - else: - face = [vertIdx2[num], vertIdx1[num], - vertIdx1[num + 1], vertIdx2[num + 1]] - faces.append(face) - else: - if fan: - face = [vertIdx1[0], vertIdx2[num], vertIdx2[num + 1]] - else: - face = [vertIdx1[num], vertIdx2[num], - vertIdx2[num + 1], vertIdx1[num + 1]] - faces.append(face) - - return faces -# this function creates a chain of quads and, when necessary, a remaining tri -# for each polygon created in this script. be aware though, that this function -# assumes each polygon is convex. -# poly: list of faces, or a single face, like those -# needed for mesh.from_pydata. -# returns the tesselated faces. -def createPolys(poly): - # check for faces - if len(poly) == 0: - return [] - # one or more faces - if type(poly[0]) == type(1): - poly = [poly] # if only one, make it a list of one face - faces = [] - for i in poly: - l = len(i) - # let all faces of 3 or 4 verts be - if l < 5: - faces.append(i) - # split all polygons in half and bridge the two halves - else: - half = int(l/2) - f = createFaces(i[:half],[i[-1-j] for j in range(half)]) - faces.extend(f) - # if the polygon has an odd number of verts, add the last tri - if l%2 == 1: - faces.append([i[half-1],i[half],i[half+1]]) - return faces - -# function to make the reduce function work as a workaround to sum a list of vectors -def Asum(list): - return reduce(lambda a,b: a+b, list) - -# creates the 5 platonic solids as a base for the rest -# plato: should be one of {"4","6","8","12","20"}. decides what solid the -# outcome will be. -# returns a list of vertices and faces and the appropriate name -def source(plato): - verts = [] - faces = [] - - # Tetrahedron - if plato == "4": - # Calculate the necessary constants - s = sqrt(2)/3.0 - t = -1/3 - u = sqrt(6)/3 - - # create the vertices and faces - v = [(0,0,1),(2*s,0,t),(-s,u,t),(-s,-u,t)] - faces = [[0,1,2],[0,2,3],[0,3,1],[1,3,2]] - - # Hexahedron (cube) - elif plato == "6": - # Calculate the necessary constants - s = 1/sqrt(3) - - # create the vertices and faces - v = [(-s,-s,-s),(s,-s,-s),(s,s,-s),(-s,s,-s),(-s,-s,s),(s,-s,s),(s,s,s),(-s,s,s)] - faces = [[0,3,2,1],[0,1,5,4],[0,4,7,3],[6,5,1,2],[6,2,3,7],[6,7,4,5]] - - # Octahedron - elif plato == "8": - # create the vertices and faces - v = [(1,0,0),(-1,0,0),(0,1,0),(0,-1,0),(0,0,1),(0,0,-1)] - faces = [[4,0,2],[4,2,1],[4,1,3],[4,3,0],[5,2,0],[5,1,2],[5,3,1],[5,0,3]] - - # Dodecahedron - elif plato == "12": - # Calculate the necessary constants - s = 1/sqrt(3) - t = sqrt((3-sqrt(5))/6) - u = sqrt((3+sqrt(5))/6) - - # create the vertices and faces - v = [(s,s,s),(s,s,-s),(s,-s,s),(s,-s,-s),(-s,s,s),(-s,s,-s),(-s,-s,s),(-s,-s,-s), - (t,u,0),(-t,u,0),(t,-u,0),(-t,-u,0),(u,0,t),(u,0,-t),(-u,0,t),(-u,0,-t),(0,t,u), - (0,-t,u),(0,t,-u),(0,-t,-u)] - faces = [[0,8,9,4,16],[0,12,13,1,8],[0,16,17,2,12],[8,1,18,5,9],[12,2,10,3,13], - [16,4,14,6,17],[9,5,15,14,4],[6,11,10,2,17],[3,19,18,1,13],[7,15,5,18,19], - [7,11,6,14,15],[7,19,3,10,11]] - - # Icosahedron - elif plato == "20": - # Calculate the necessary constants - s = (1+sqrt(5))/2 - t = sqrt(1+s*s) - s = s/t - t = 1/t - - # create the vertices and faces - v = [(s,t,0),(-s,t,0),(s,-t,0),(-s,-t,0),(t,0,s),(t,0,-s),(-t,0,s),(-t,0,-s), - (0,s,t),(0,-s,t),(0,s,-t),(0,-s,-t)] - faces = [[0,8,4],[0,5,10],[2,4,9],[2,11,5],[1,6,8],[1,10,7],[3,9,6],[3,7,11], - [0,10,8],[1,8,10],[2,9,11],[3,11,9],[4,2,0],[5,0,2],[6,1,3],[7,3,1], - [8,6,4],[9,4,6],[10,5,7],[11,7,5]] - - # handles faulty values of plato - else: - print("Choose keyword 'plato' from {'4','6','8','12','20'}") - return None - - # convert the tuples to Vectors - verts = [Vector(i) for i in v] - - return verts,faces - -# processes the raw data from source -def createSolid(plato,vtrunc,etrunc,dual,snub): - verts = [] - faces = [] - edges = [] - # the duals from each platonic solid - dualSource = {"4":"4", - "6":"8", - "8":"6", - "12":"20", - "20":"12"} - - # constants saving space and readability - vtrunc *= 0.5 - etrunc *= 0.5 - supposed_size = 0 - noSnub = (snub == "0") or (etrunc == 0.5) or (etrunc == 0) - lSnub = (snub == "L") and (0 < etrunc < 0.5) - rSnub = (snub == "R") and (0 < etrunc < 0.5) - - # no truncation - if vtrunc == 0: - if dual: # dual is as simple as another, but mirrored platonic solid - vInput,fInput = source(dualSource[plato]) - supposed_size = Asum([vInput[i] for i in fInput[0]]).length/len(fInput[0]) - vInput = [-i*supposed_size for i in vInput] # mirror it - return vInput,fInput - return source(plato) - # simple truncation of the source - elif 0.5 >= vtrunc > 0: - vInput,fInput = source(plato) - # truncation is now equal to simple truncation of the dual of the source - elif vtrunc > 0.5: - vInput,fInput = source(dualSource[plato]) - supposed_size = Asum([vInput[i] for i in fInput[0]]).length/len(fInput[0]) - # account for the source being a dual - vtrunc = 1-vtrunc - if vtrunc == 0: # no truncation - if dual: - vInput,fInput = source(plato) - vInput = [i*supposed_size for i in vInput] - return vInput,fInput,sourceName - vInput = [-i*supposed_size for i in vInput] - return vInput,fInput - - # generate a database for creating the faces. this exists out of a list for - # every vertex in the source - # 0 : vertex id - # 1 : vertices connected to this vertex, listed ccw(Counter Clock Wise) - # 2 : vertices generated to form the faces of this vertex - # 3 : faces connected to this vertex, listed ccw - # 4 : dictionairy containing the verts used by the connected faces - # 5 : list of edges that use this vertex, listed ccw - # 6 : dictionairy containing the verts used by the connected edges - v = [[i,[],[],[],{},[],{}] for i in range(len(vInput))] - - # this piece of code, generates the database and the lists in ccw order - for x in range(len(fInput)): - i = fInput[x] - # in every faces, check which vertices connect the each vert and sort - # in ccw order - for j in range(-1,len(i)-1): - # only generate an edge dict, if edge truncation is needed - if etrunc: - # list edges as [min,max], to evade confusion - first = min([i[j-1],i[j]]) - last = max([i[j-1],i[j]]) - # if an edge is not allready in, add it and give the index - try: - y = edges.index([first,last]) - except: - edges.append([first,last]) - y = len(edges)-1 - # add a dict item - v[i[j]][6][str(y)] = [0,0] - # the vertex before and after the current vertex, check whether they - # are allready in the database - after = i[j+1] not in v[i[j]][1] - before = i[j-1] not in v[i[j]][1] - # sort them and add faces and, when necessary, edges in the database - if after: - if before: - v[i[j]][1].append(i[j+1]) - v[i[j]][1].append(i[j-1]) - v[i[j]][3].append(x) - if etrunc: v[i[j]][5].append(y) - else: - z = v[i[j]][1].index(i[j-1]) - v[i[j]][1].insert(z,i[j+1]) - v[i[j]][3].insert(z,x) - if etrunc: v[i[j]][5].insert(z,y) - else: - z = v[i[j]][1].index(i[j+1]) - v[i[j]][3].insert(z,x) - if etrunc: v[i[j]][5].insert(z,y) - if before: - v[i[j]][1].insert(z+1,i[j-1]) - # add the current face to the current vertex in the dict - v[i[j]][4][str(x)] = [0,0] - - # generate vert-only truncated vertices by linear interpolation - for i in v: - for j in range(len(i[1])): - verts.append(vInput[i[0]]*(1-vtrunc)+vInput[i[1][j]]*vtrunc) - l = len(verts)-1 - # face resulting from truncating this vertex - i[2].append(l) - # this vertex is used by both faces using this edge - i[4][str(i[3][j])][1] = l - i[4][str(i[3][j-1])][0] = l - - # only truncate edges when needed - vert_faces = [] - if etrunc: - # generate a new list of vertices, by linear interpolating each vert-face - nVerts = [] - for i in v: - f = [] - # weird range so we dont run out of array bounds - for j in range(-1,len(i[2])-1): - # making use of the fact that the snub operation takes only - # one of the two vertices per edge. so rSnub only takes the - # first, lSnub only takes the second, and noSnub takes both - if rSnub or noSnub: - # interpolate - nVerts.append((1-etrunc)*verts[i[2][j]] + etrunc*verts[i[2][j-1]]) - # add last vertex to the vert-face, face-face and edge-face - l = len(nVerts)-1 - f.append(l) - i[4][str(i[3][j-1])][0] = l - i[6][str(i[5][j-1])][1] = l - if lSnub or noSnub: - # interpolate - nVerts.append((1-etrunc)*verts[i[2][j]] + etrunc*verts[i[2][j+1]]) - # add last vertex to the vert-face, face-face and edge-face - l = len(nVerts)-1 - f.append(l) - i[4][str(i[3][j])][1] = l - i[6][str(i[5][j-1])][0] = l - # add vert-face - vert_faces.append(f) - - # snub operator creates 2 tri's instead of a planar quad, needing the - # next piece of code. making use of the dictionairy to create them. - if lSnub or rSnub: - edge_faces = [] - for x in range(len(edges)): - one = v[edges[x][0]] # the first vertex of this edge - two = v[edges[x][1]] # the second - # using max() since the dict consists of one filled spot and one - # empty('cause only one vert is created) - f = [max(two[6][str(x)]),max(one[6][str(x)])] - index = one[5].index(x) - # create this tri from the middle line and the the previous edge - # on this vertex - if lSnub: - f.append(max(one[6][str(one[5][index-1])])) - else: # or in this case, the next - if index+1 >= len(one[5]): index = -1 - f.append(max(one[6][str(one[5][index+1])])) - edge_faces.append(f) - - # do the same for the other end of the edge - f = [max(one[6][str(x)]),max(two[6][str(x)])] - index = two[5].index(x) - if lSnub: - f.append(max(two[6][str(two[5][index-1])])) - else: - if index+1 >= len(one[5]): index = -1 - f.append(max(two[6][str(two[5][index+1])])) - edge_faces.append(f) - else: - # generate edge-faces from the dictionairy, simple quads for noSnub - edge_faces = [] - for i in range(len(edges)): - f = [] - for j in edges[i]: - f.extend(v[j][6][str(i)]) - edge_faces.append(f) - verts = nVerts - else: - # generate vert-faces for non-edge-truncation - vert_faces = [i[2] for i in v] - - # calculate supposed vertex length to ensure continuity - if supposed_size: - supposed_size *= len(vert_faces[0])/Asum([verts[i] for i in vert_faces[0]]).length - verts = [-i*supposed_size for i in verts] - - # generate face-faces by looking up the old verts and replacing them with - # the vertices in the dictionairy - face_faces = [] - for x in range(len(fInput)): - f = [] - for j in fInput[x]: - # again using the fact, that only one of the two verts is used - # for snub operation - if rSnub and etrunc: - f.append(v[j][4][str(x)][0]) - elif lSnub and etrunc: - f.append(v[j][4][str(x)][1]) - else: - # for cool graphics, comment the first line and uncomment the second line - # then work the vTrunc property, leave the other properties at 0 - # (can also change 0 to 1 in second line to change from ccw to cw) - f.extend(v[j][4][str(x)]) # first - #f.append(v[j][4][str(x)][0]) # second - face_faces.append(f) - - if dual: - # create verts by taking the average of all vertices that make up each - # face. do it in this order to ease the following face creation - nVerts = [] - for i in vert_faces: - nVerts.append(Asum([verts[j] for j in i])/len(i)) - if etrunc: - eStart = len(nVerts) - for i in edge_faces: - nVerts.append(Asum([verts[j] for j in i])/len(i)) - fStart = len(nVerts) - for i in face_faces: - nVerts.append(Asum([verts[j] for j in i])/len(i)) - # the special face generation for snub duals, it sucks, even i dont get it - if lSnub or rSnub: - for x in range(len(fInput)): - i = fInput[x] - for j in range(-1,len(i)-1): - - if i[j] > i[j+1]: - eNext = edges.index([i[j+1],i[j]]) - [a,b] = [1,0] - else: - eNext = edges.index([i[j],i[j+1]]) - [a,b] = [0,1] - if i[j] > i[j-1]: - ePrev = edges.index([i[j-1],i[j]]) - [c,d] = [0,1] - else: - ePrev = edges.index([i[j],i[j-1]]) - [c,d] = [1,0] - if lSnub: - f = [eStart+2*eNext+b,eStart+2*eNext+a,i[j]] - f.append(eStart+2*ePrev+d) - f.append(fStart + x) - else: - f = [eStart+2*ePrev+c,eStart+2*ePrev+d,i[j]] - f.append(eStart+2*eNext+a) - f.append(fStart + x) - if supposed_size: faces.append(f) - else: faces.append(f[2:]+f[:2]) - else: - # for noSnub situations, the face generation is somewhat easier. - # first calculate what order faces must be added to ensure convex solids - # this by calculating the angle between the middle of the four vertices - # and the first face. if the face is above the middle, use that diagonal - # otherwise use the other diagonal - if etrunc: - f = [v[0][0],eStart+v[0][5][-1],fStart+v[0][3][0],eStart+v[0][5][0]] - else: - f = [v[0][0],fStart+v[0][3][0],v[0][1][0],fStart+v[0][3][-1]] - p = [nVerts[i] for i in f] - mid = 0.25*Asum(p) - norm = (p[1]-p[0]).cross(p[2]-p[0]) - dot = norm.dot(mid-p[0])/(norm.length*(mid-p[0]).length) - tollerance = 0.001 # ~ cos(0.06 degrees) - if ((dot > tollerance) and (not supposed_size)) or ((dot < -tollerance) and (supposed_size)): - direction = 1 # first diagonal - elif ((dot < -tollerance) and (not supposed_size)) or ((dot > tollerance) and (supposed_size)): - direction = -1 # second diagonal - else: - direction = 0 # no diagonal, face is planar (somewhat) - - if etrunc: # for every vertex - for i in v: # add the face, consisting of the vert,edge,next - # edge and face between those edges - for j in range(len(i[1])): - f = [i[0],eStart+i[5][j-1],fStart+i[3][j],eStart+i[5][j]] - if direction == 1: # first diagonal - faces.extend([[f[0],f[1],f[3]],[f[1],f[2],f[3]]]) - elif direction == -1: # first diagonal - faces.extend([[f[0],f[1],f[2]],[f[0],f[2],f[3]]]) - else: - faces.append(f) # no diagonal - else: - for i in v: # for every vertex - for j in range(len(i[1])): - if i[0] < i[1][j]: # face consists of vert, vert on other - # end of edge and both faces using that - # edge, so exclude verts allready used - f = [i[0],fStart+i[3][j], i[1][j],fStart+i[3][j-1]] - if direction == -1: # secong diagonal - faces.extend([[f[0],f[1],f[3]],[f[1],f[2],f[3]]]) - elif direction == 1: # first diagonal - faces.extend([[f[0],f[1],f[2]],[f[0],f[2],f[3]]]) - else: - faces.append(f) # no diagonal - verts = nVerts # use new vertices - else: - # concatenate all faces, since they dont have to be used sepperately anymore - faces = face_faces - if etrunc: faces += edge_faces - faces += vert_faces - - return verts,faces - - -class Solids(bpy.types.Operator): - """Add one of the (regular) solids (mesh)""" - bl_idname = "mesh.primitive_solid_add" - bl_label = "(Regular) solids" - bl_description = "Add one of the platoic or archimedean solids" - bl_options = {'REGISTER', 'UNDO'} - - source = EnumProperty(items = (("4","Tetrahedron",""), - ("6","Hexahedron",""), - ("8","Octahedron",""), - ("12","Dodecahedron",""), - ("20","Icosahedron","")), - name = "Source", - description = "Starting point of your solid") - size = FloatProperty(name = "Size", - description = "Radius of the sphere through the vertices", - min = 0.01, - soft_min = 0.01, - max = 100, - soft_max = 100, - default = 1.0) - vTrunc = FloatProperty(name = "Vertex Truncation", - description = "Ammount of vertex truncation", - min = 0.0, - soft_min = 0.0, - max = 2.0, - soft_max = 2.0, - default = 0.0, - precision = 3, - step = 0.5) - eTrunc = FloatProperty(name = "Edge Truncation", - description = "Ammount of edge truncation", - min = 0.0, - soft_min = 0.0, - max = 1.0, - soft_max = 1.0, - default = 0.0, - precision = 3, - step = 0.2) - snub = EnumProperty(items = (("0","No Snub",""), - ("L","Left Snub",""), - ("R","Right Snub","")), - name = "Snub", - description = "Create the snub version") - dual = BoolProperty(name="Dual", - description="Create the dual of the current solid", - default=False) - keepSize = BoolProperty(name="Keep Size", - description="Keep the whole solid at a constant size", - default=False) - preset = EnumProperty(items = (("0","Custom",""), - ("t4","Truncated Tetrahedron",""), - ("r4","Cuboctahedron",""), - ("t6","Truncated Cube",""), - ("t8","Truncated Octahedron",""), - ("b6","Rhombicuboctahedron",""), - ("c6","Truncated Cuboctahedron",""), - ("s6","Snub Cube",""), - ("r12","Icosidodecahedron",""), - ("t12","Truncated Dodecahedron",""), - ("t20","Truncated Icosahedron",""), - ("b12","Rhombicosidodecahedron",""), - ("c12","Truncated Icosidodecahedron",""), - ("s12","Snub Dodecahedron",""), - ("dt4","Triakis Tetrahedron",""), - ("dr4","Rhombic Dodecahedron",""), - ("dt6","Triakis Octahedron",""), - ("dt8","Triakis Hexahedron",""), - ("db6","Deltoidal Icositetrahedron",""), - ("dc6","Disdyakis Dodecahedron",""), - ("ds6","Pentagonal Icositetrahedron",""), - ("dr12","Rhombic Triacontahedron",""), - ("dt12","Triakis Icosahedron",""), - ("dt20","Pentakis Dodecahedron",""), - ("db12","Deltoidal Hexecontahedron",""), - ("dc12","Disdyakis Triacontahedron",""), - ("ds12","Pentagonal Hexecontahedron",""), - ("c","Cube",""), - ("sb","Soccer ball","")), - name = "Presets", - description = "Parameters for some hard names") - - # actual preset values - p = {"t4":["4",2/3,0,0,"0"], - "r4":["4",1,1,0,"0"], - "t6":["6",2/3,0,0,"0"], - "t8":["8",2/3,0,0,"0"], - "b6":["6",1.0938,1,0,"0"], - "c6":["6",1.0572,0.585786,0,"0"], - "s6":["6",1.0875,0.704,0,"L"], - "r12":["12",1,0,0,"0"], - "t12":["12",2/3,0,0,"0"], - "t20":["20",2/3,0,0,"0"], - "b12":["12",1.1338,1,0,"0"], - "c12":["20",0.921,0.553,0,"0"], - "s12":["12",1.1235,0.68,0,"L"], - "dt4":["4",2/3,0,1,"0"], - "dr4":["4",1,2/3,1,"0"], - "dt6":["6",4/3,0,1,"0"], - "dt8":["8",1,0,1,"0"], - "db6":["6",1.0938,0.756,1,"0"], - "dc6":["6",1,1,1,"0"], - "ds6":["6",1.0875,0.704,1,"L"], - "dr12":["12",1.54,0,1,"0"], - "dt12":["12",5/3,0,1,"0"], - "dt20":["20",2/3,0,1,"0"], - "db12":["12",1,0.912,1,"0"], - "dc12":["20",0.921,1,1,"0"], - "ds12":["12",1.1235,0.68,1,"L"], - "c":["6",0,0,0,"0"], - "sb":["20",2/3,0,0,"0"]} - - edit = BoolProperty(name="", - description="", - default=False, - options={'HIDDEN'}) - - def execute(self,context): - # turn off undo for better performance (3 - 5x faster), also makes sure - # that mesh ops are undoable and entire script acts as one operator - bpy.context.user_preferences.edit.use_global_undo = False - - props = self.properties - - #if preset, set preset - if props.preset != "0": - using = self.p[props.preset] - props.source = using[0] - props.vTrunc = using[1] - props.eTrunc = using[2] - props.dual = using[3] - props.snub = using[4] - props.preset = "0" - - # generate mesh - verts,faces = createSolid(props.source, - props.vTrunc, - props.eTrunc, - props.dual, - props.snub) - - # turn n-gons in quads and tri's - faces = createPolys(faces) - - # resize to normal size, or if keepSize, make sure all verts are of length 'size' - if props.keepSize: - rad = props.size/verts[0].length - else: rad = props.size - verts = [i*rad for i in verts] - - # generate object - obj = create_mesh_object(context,verts,[],faces,"Solid",props.edit) - - # vertices will be on top of each other in some cases, - # so remove doubles then - if ((props.vTrunc == 1) and (props.eTrunc == 0)) or (props.eTrunc == 1): - current_mode = obj.mode - if current_mode == 'OBJECT': - bpy.ops.object.mode_set(mode='EDIT') - bpy.ops.mesh.select_all(action='SELECT') - bpy.ops.mesh.remove_doubles() - bpy.ops.object.mode_set(mode=current_mode) - - # snub duals suck, so make all normals point outwards - if props.dual and (props.snub != "0"): - current_mode = obj.mode - if current_mode == 'OBJECT': - bpy.ops.object.mode_set(mode='EDIT') - bpy.ops.mesh.select_all(action='SELECT') - bpy.ops.mesh.normals_make_consistent() - bpy.ops.object.mode_set(mode=current_mode) - - # turn undo back on - bpy.context.user_preferences.edit.use_global_undo = True - - return {'FINISHED'} - -class Solids_add_menu(bpy.types.Menu): - """Define the menu with presets""" - bl_idname = "Solids_add_menu" - bl_label = "Solids" - - def draw(self,context): - layout = self.layout - layout.operator_context = 'INVOKE_REGION_WIN' - layout.operator(Solids.bl_idname, text = "Solid") - layout.menu(PlatonicMenu.bl_idname, text = "Platonic") - layout.menu(ArchiMenu.bl_idname, text = "Archimeadean") - layout.menu(CatalanMenu.bl_idname, text = "Catalan") - layout.menu(OtherMenu.bl_idname, text = "Others") - -class PlatonicMenu(bpy.types.Menu): - """Define Platonic menu""" - bl_idname = "Platonic_calls" - bl_label = "Platonic" - - def draw(self,context): - layout = self.layout - layout.operator_context = 'INVOKE_REGION_WIN' - layout.operator(Solids.bl_idname, text = "Tetrahedron").source = "4" - layout.operator(Solids.bl_idname, text = "Hexahedron").source = "6" - layout.operator(Solids.bl_idname, text = "Octahedron").source = "8" - layout.operator(Solids.bl_idname, text = "Dodecahedron").source = "12" - layout.operator(Solids.bl_idname, text = "Icosahedron").source = "20" - -class ArchiMenu(bpy.types.Menu): - """Defines Achimedean preset menu""" - bl_idname = "Achimedean_calls" - bl_label = "Archimedean" - - def draw(self,context): - layout = self.layout - layout.operator_context = 'INVOKE_REGION_WIN' - layout.operator(Solids.bl_idname, text = "Truncated Tetrahedron").preset = "t4" - layout.operator(Solids.bl_idname, text = "Cuboctahedron").preset = "r4" - layout.operator(Solids.bl_idname, text = "Truncated Cube").preset = "t6" - layout.operator(Solids.bl_idname, text = "Truncated Octahedron").preset = "t8" - layout.operator(Solids.bl_idname, text = "Rhombicuboctahedron").preset = "b6" - layout.operator(Solids.bl_idname, text = "Truncated Cuboctahedron").preset = "c6" - layout.operator(Solids.bl_idname, text = "Snub Cube").preset = "s6" - layout.operator(Solids.bl_idname, text = "Icosidodecahedron").preset = "r12" - layout.operator(Solids.bl_idname, text = "Truncated Dodecahedron").preset = "t12" - layout.operator(Solids.bl_idname, text = "Truncated Icosahedron").preset = "t20" - layout.operator(Solids.bl_idname, text = "Rhombicosidodecahedron").preset = "b12" - layout.operator(Solids.bl_idname, text = "Truncated Icosidodecahedron").preset = "c12" - layout.operator(Solids.bl_idname, text = "Snub Dodecahedron").preset = "s12" - -class CatalanMenu(bpy.types.Menu): - """Defines Catalan preset menu""" - bl_idname = "Catalan_calls" - bl_label = "Catalan" - - def draw(self, context): - layout = self.layout - layout.operator_context = 'INVOKE_REGION_WIN' - layout.operator(Solids.bl_idname, text = "Triakis Tetrahedron").preset = "dt4" - layout.operator(Solids.bl_idname, text = "Rhombic Dodecahedron").preset = "dr4" - layout.operator(Solids.bl_idname, text = "Triakis Octahedron").preset = "dt6" - layout.operator(Solids.bl_idname, text = "Triakis Hexahedron").preset = "dt8" - layout.operator(Solids.bl_idname, text = "Deltoidal Icositetrahedron").preset = "db6" - layout.operator(Solids.bl_idname, text = "Disdyakis Dodecahedron").preset = "dc6" - layout.operator(Solids.bl_idname, text = "Pentagonal Icositetrahedron").preset = "ds6" - layout.operator(Solids.bl_idname, text = "Rhombic Triacontahedron").preset = "dr12" - layout.operator(Solids.bl_idname, text = "Triakis Icosahedron").preset = "dt12" - layout.operator(Solids.bl_idname, text = "Pentakis Dodecahedron").preset = "dt20" - layout.operator(Solids.bl_idname, text = "Deltoidal Hexecontahedron").preset = "dt20" - layout.operator(Solids.bl_idname, text = "Disdyakis Triacontahedron").preset = "db12" - layout.operator(Solids.bl_idname, text = "Pentagonal Hexecontahedron").preset = "ds12" - -class OtherMenu(bpy.types.Menu): - """Defines Others preset menu""" - bl_idname = "Others_calls" - bl_label = "Others" - - def draw(self, context): - layout = self.layout - layout.operator_context = 'INVOKE_REGION_WIN' - layout.operator(Solids.bl_idname, text = "Cube").preset = "c" - layout.operator(Solids.bl_idname, text = "Soccer ball").preset = "sb" - - -import space_info - - -def menu_func(self, context): - self.layout.menu(Solids_add_menu.bl_idname, icon="PLUGIN") - - -def register(): - space_info.INFO_MT_mesh_add.append(menu_func) - -def unregister(): - space_info.INFO_MT_mesh_add.remove(menu_func) - -if __name__ == "__main__": - register() diff --git a/add_mesh_twisted_torus.py b/add_mesh_twisted_torus.py deleted file mode 100644 index c2a598ec..00000000 --- a/add_mesh_twisted_torus.py +++ /dev/null @@ -1,363 +0,0 @@ -# add_mesh_twisted_torus.py Copyright (C) 2009-2010, Paulo Gomes -# tuga3d {at} gmail {dot} com -# add twisted torus to the blender 2.50 add->mesh menu -# ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -# ***** END GPL LICENCE BLOCK ***** - -bl_addon_info = { - "name": "Twisted Torus", - "author": "Paulo_Gomes", - "version": (0,11), - "blender": (2, 5, 3), - "api": 31854, - "location": "View3D > Add > Mesh ", - "description": "Adds a mesh Twisted Torus to the Add Mesh menu", - "warning": "", - "wiki_url": "http://wiki.blender.org/index.php/Extensions:2.5/Py/"\ - "Scripts/Add_Mesh/Add_Twisted_Torus", - "tracker_url": "https://projects.blender.org/tracker/index.php?"\ - "func=detail&aid=21622&group_id=153&atid=469", - "category": "Add Mesh"} - -""" -Usage: - -* Launch from Add Mesh menu - -* Modify parameters as desired or keep defaults -""" - - -import bpy -from bpy.props import * - -import mathutils -from mathutils import * -from math import cos, sin, pi - -# calculates the matrix for the new object -# depending on user pref -def align_matrix(context): - loc = Matrix.Translation(context.scene.cursor_location) - obj_align = context.user_preferences.edit.object_align - if (context.space_data.type == 'VIEW_3D' - and obj_align == 'VIEW'): - rot = context.space_data.region_3d.view_matrix.rotation_part().invert().resize4x4() - else: - rot = Matrix() - align_matrix = loc * rot - return align_matrix - - -# Create a new mesh (object) from verts/edges/faces. -# verts/edges/faces ... List of vertices/edges/faces for the -# new mesh (as used in from_pydata). -# name ... Name of the new mesh (& object). -# edit ... Replace existing mesh data. -# Note: Using "edit" will destroy/delete existing mesh data. -def create_mesh_object(context, verts, edges, faces, name, edit, align_matrix): - scene = context.scene - obj_act = scene.objects.active - - # Can't edit anything, unless we have an active obj. - if edit and not obj_act: - return None - - # Create new mesh - mesh = bpy.data.meshes.new(name) - - # Make a mesh from a list of verts/edges/faces. - mesh.from_pydata(verts, edges, faces) - - # Update mesh geometry after adding stuff. - mesh.update() - - # Deselect all objects. - bpy.ops.object.select_all(action='DESELECT') - - if edit: - # Replace geometry of existing object - - # Use the active obj and select it. - ob_new = obj_act - ob_new.select = True - - if obj_act.mode == 'OBJECT': - # Get existing mesh datablock. - old_mesh = ob_new.data - - # Set object data to nothing - ob_new.data = None - - # Clear users of existing mesh datablock. - old_mesh.user_clear() - - # Remove old mesh datablock if no users are left. - if (old_mesh.users == 0): - bpy.data.meshes.remove(old_mesh) - - # Assign new mesh datablock. - ob_new.data = mesh - - else: - # Create new object - ob_new = bpy.data.objects.new(name, mesh) - - # Link new object to the given scene and select it. - scene.objects.link(ob_new) - ob_new.select = True - - # Place the object at the 3D cursor location. - # apply viewRotaion - ob_new.matrix_world = align_matrix - - if obj_act and obj_act.mode == 'EDIT': - if not edit: - # We are in EditMode, switch to ObjectMode. - bpy.ops.object.mode_set(mode='OBJECT') - - # Select the active object as well. - obj_act.select = True - - # Apply location of new object. - scene.update() - - # Join new object into the active. - bpy.ops.object.join() - - # Switching back to EditMode. - bpy.ops.object.mode_set(mode='EDIT') - - ob_new = obj_act - - else: - # We are in ObjectMode. - # Make the new object the active one. - scene.objects.active = ob_new - - return ob_new - - -# A very simple "bridge" tool. -# Connects two equally long vertex rows with faces. -# Returns a list of the new faces (list of lists) -# -# vertIdx1 ... First vertex list (list of vertex indices). -# vertIdx2 ... Second vertex list (list of vertex indices). -# closed ... Creates a loop (first & last are closed). -# flipped ... Invert the normal of the face(s). -# -# Note: You can set vertIdx1 to a single vertex index to create -# a fan/star of faces. -# Note: If both vertex idx list are the same length they have -# to have at least 2 vertices. -def createFaces(vertIdx1, vertIdx2, closed=False, flipped=False): - faces = [] - - if not vertIdx1 or not vertIdx2: - return None - - if len(vertIdx1) < 2 and len(vertIdx2) < 2: - return None - - fan = False - if (len(vertIdx1) != len(vertIdx2)): - if (len(vertIdx1) == 1 and len(vertIdx2) > 1): - fan = True - else: - return None - - total = len(vertIdx2) - - if closed: - # Bridge the start with the end. - if flipped: - face = [ - vertIdx1[0], - vertIdx2[0], - vertIdx2[total - 1]] - if not fan: - face.append(vertIdx1[total - 1]) - faces.append(face) - - else: - face = [vertIdx2[0], vertIdx1[0]] - if not fan: - face.append(vertIdx1[total - 1]) - face.append(vertIdx2[total - 1]) - faces.append(face) - - # Bridge the rest of the faces. - for num in range(total - 1): - if flipped: - if fan: - face = [vertIdx2[num], vertIdx1[0], vertIdx2[num + 1]] - else: - face = [vertIdx2[num], vertIdx1[num], - vertIdx1[num + 1], vertIdx2[num + 1]] - faces.append(face) - else: - if fan: - face = [vertIdx1[0], vertIdx2[num], vertIdx2[num + 1]] - else: - face = [vertIdx1[num], vertIdx2[num], - vertIdx2[num + 1], vertIdx1[num + 1]] - faces.append(face) - - return faces - - -def add_twisted_torus(major_rad, minor_rad, major_seg, minor_seg, twists): - PI_2 = pi * 2.0 - z_axis = (0.0, 0.0, 1.0) - - verts = [] - faces = [] - - edgeloop_prev = [] - for major_index in range(major_seg): - quat = Quaternion(z_axis, (major_index / major_seg) * PI_2) - rot_twists = PI_2 * major_index / major_seg * twists - - edgeloop = [] - - # Create section ring - for minor_index in range(minor_seg): - angle = (PI_2 * minor_index / minor_seg) + rot_twists - - vec = Vector(( - major_rad + (cos(angle) * minor_rad), - 0.0, - sin(angle) * minor_rad)) - vec = vec * quat - - edgeloop.append(len(verts)) - verts.append(vec) - - # Remember very first edgeloop. - if major_index == 0: - edgeloop_first = edgeloop - - # Bridge last with current ring - if edgeloop_prev: - f = createFaces(edgeloop_prev, edgeloop, closed=True) - faces.extend(f) - - edgeloop_prev = edgeloop - - # Bridge first and last ring - f = createFaces(edgeloop_prev, edgeloop_first, closed=True) - faces.extend(f) - - return verts, faces - - -class AddTwistedTorus(bpy.types.Operator): - '''Add a torus mesh''' - bl_idname = "mesh.primitive_twisted_torus_add" - bl_label = "Add Torus" - bl_options = {'REGISTER', 'UNDO'} - - # edit - Whether to add or update. - edit = BoolProperty(name="", - description="", - default=False, - options={'HIDDEN'}) - major_radius = FloatProperty(name="Major Radius", - description="Radius from the origin to the" \ - " center of the cross section", - min=0.01, - max=100.0, - default=1.0) - minor_radius = FloatProperty(name="Minor Radius", - description="Radius of the torus' cross section", - min=0.01, - max=100.0, - default=0.25) - major_segments = IntProperty(name="Major Segments", - description="Number of segments for the main ring of the torus", - min=3, - max=256, - default=48) - minor_segments = IntProperty(name="Minor Segments", - description="Number of segments for the minor ring of the torus", - min=3, - max=256, - default=12) - twists = IntProperty(name="Twists", - description="Number of twists of the torus", - min=0, - max=256, - default=1) - - use_abso = BoolProperty(name="Use Int+Ext Controls", - description="Use the Int / Ext controls for torus dimensions", - default=False) - abso_major_rad = FloatProperty(name="Exterior Radius", - description="Total Exterior Radius of the torus", - min=0.01, - max=100.0, - default=1.0) - abso_minor_rad = FloatProperty(name="Inside Radius", - description="Total Interior Radius of the torus", - min=0.01, - max=100.0, - default=0.5) - align_matrix = Matrix() - - def execute(self, context): - props = self.properties - - if props.use_abso == True: - extra_helper = (props.abso_major_rad - props.abso_minor_rad) * 0.5 - props.major_radius = props.abso_minor_rad + extra_helper - props.minor_radius = extra_helper - - verts, faces = add_twisted_torus( - props.major_radius, - props.minor_radius, - props.major_segments, - props.minor_segments, - props.twists) - - # Actually create the mesh object from this geometry data. - obj = create_mesh_object(context, verts, [], faces, "TwistedTorus", - props.edit, self.align_matrix) - - return {'FINISHED'} - - def invoke(self, context, event): - self.align_matrix = align_matrix(context) - self.execute(context) - return {'FINISHED'} - -# Add to the menu -def menu_func(self, context): - self.layout.operator(AddTwistedTorus.bl_idname, text="Twisted Torus", icon='MESH_TORUS') - - -def register(): - bpy.types.INFO_MT_mesh_add.append(menu_func) - - -def unregister(): - bpy.types.INFO_MT_mesh_add.remove(menu_func) - -if __name__ == "__main__": - register() diff --git a/curve_simplify.py b/curve_simplify.py deleted file mode 100644 index f723b99d..00000000 --- a/curve_simplify.py +++ /dev/null @@ -1,597 +0,0 @@ -# ##### 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -# ##### END GPL LICENSE BLOCK ##### - -bl_addon_info = { - "name": "Simplify curves", - "author": "testscreenings", - "version": (1,), - "blender": (2, 5, 3), - "api": 31667, - "location": "Toolshelf > search > simplify curves", - "description": "This script simplifies 3D curves and fcurves", - "warning": "", - "wiki_url": "http://wiki.blender.org/index.php/Extensions:2.5/Py/"\ - "Scripts/Curve/Curve_Simplify", - "tracker_url": "https://projects.blender.org/tracker/index.php?"\ - "func=detail&aid=22327&group_id=153&atid=468", - "category": "Add Curve"} - -""" -This script simplifies Curves. -""" - -#################################################### -import bpy -from bpy.props import * -import mathutils -import math - -############################## -#### simplipoly algorithm #### -############################## -# get SplineVertIndicies to keep -def simplypoly(splineVerts, options): - # main vars - newVerts = [] # list of vertindices to keep - points = splineVerts # list of 3dVectors - pointCurva = [] # table with curvatures - curvatures = [] # averaged curvatures per vert - for p in points: - pointCurva.append([]) - order = options[3] # order of sliding beziercurves - k_thresh = options[2] # curvature threshold - dis_error = options[6] # additional distance error - - # get curvatures per vert - for i, point in enumerate(points[:-(order-1)]): - BVerts = points[i:i+order] - for b, BVert in enumerate(BVerts[1:-1]): - deriv1 = getDerivative(BVerts, 1/(order-1), order-1) - deriv2 = getDerivative(BVerts, 1/(order-1), order-2) - curva = getCurvature(deriv1, deriv2) - pointCurva[i+b+1].append(curva) - - # average the curvatures - for i in range(len(points)): - avgCurva = sum(pointCurva[i]) / (order-1) - curvatures.append(avgCurva) - - # get distancevalues per vert - same as Ramer-Douglas-Peucker - # but for every vert - distances = [0.0] #first vert is always kept - for i, point in enumerate(points[1:-1]): - dist = altitude(points[i], points[i+2], points[i+1]) - distances.append(dist) - distances.append(0.0) # last vert is always kept - - # generate list of vertindicies to keep - # tested against averaged curvatures and distances of neighbour verts - newVerts.append(0) # first vert is always kept - for i, curv in enumerate(curvatures): - if (curv >= k_thresh*0.01 - or distances[i] >= dis_error*0.1): - newVerts.append(i) - newVerts.append(len(curvatures)-1) # last vert is always kept - - return newVerts - -# get binomial coefficient -def binom(n, m): - b = [0] * (n+1) - b[0] = 1 - for i in range(1, n+1): - b[i] = 1 - j = i-1 - while j > 0: - b[j] += b[j-1] - j-= 1 - return b[m] - -# get nth derivative of order(len(verts)) bezier curve -def getDerivative(verts, t, nth): - order = len(verts) - 1 - nth - QVerts = [] - - if nth: - for i in range(nth): - if QVerts: - verts = QVerts - derivVerts = [] - for i in range(len(verts)-1): - derivVerts.append(verts[i+1] - verts[i]) - QVerts = derivVerts - else: - QVerts = verts - - if len(verts[0]) == 3: - point = mathutils.Vector((0, 0, 0)) - if len(verts[0]) == 2: - point = mathutils.Vector((0, 0)) - - for i, vert in enumerate(QVerts): - point += binom(order, i) * math.pow(t, i) * math.pow(1-t, order-i) * vert - deriv = point - - return deriv - -# get curvature from first, second derivative -def getCurvature(deriv1, deriv2): - if deriv1.length == 0: # in case of points in straight line - curvature = 0 - return curvature - curvature = (deriv1.cross(deriv2)).length / math.pow(deriv1.length, 3) - return curvature - -######################################### -#### Ramer-Douglas-Peucker algorithm #### -######################################### -# get altitude of vert -def altitude(point1, point2, pointn): - edge1 = point2 - point1 - edge2 = pointn - point1 - if edge2.length == 0: - altitude = 0 - return altitude - if edge1.length == 0: - altitude = edge2.length - return altitude - alpha = edge1.angle(edge2) - altitude = math.sin(alpha) * edge2.length - return altitude - -# iterate through verts -def iterate(points, newVerts, error): - new = [] - for newIndex in range(len(newVerts)-1): - bigVert = 0 - alti_store = 0 - for i, point in enumerate(points[newVerts[newIndex]+1:newVerts[newIndex+1]]): - alti = altitude(points[newVerts[newIndex]], points[newVerts[newIndex+1]], point) - if alti > alti_store: - alti_store = alti - if alti_store >= error: - bigVert = i+1+newVerts[newIndex] - if bigVert: - new.append(bigVert) - if new == []: - return False - return new - -#### get SplineVertIndicies to keep -def simplify_RDP(splineVerts, options): - #main vars - error = options[4] - - # set first and last vert - newVerts = [0, len(splineVerts)-1] - - # iterate through the points - new = 1 - while new != False: - new = iterate(splineVerts, newVerts, error) - if new: - newVerts += new - newVerts.sort() - return newVerts - -########################## -#### CURVE GENERATION #### -########################## -# set bezierhandles to auto -def setBezierHandles(newCurve): - scene = bpy.context.scene - bpy.ops.object.mode_set(mode='EDIT', toggle=True) - bpy.ops.curve.select_all(action='SELECT') - bpy.ops.curve.handle_type_set(type='AUTOMATIC') - bpy.ops.object.mode_set(mode='OBJECT', toggle=True) - -# get array of new coords for new spline from vertindices -def vertsToPoints(newVerts, splineVerts, splineType): - # main vars - newPoints = [] - - # array for BEZIER spline output - if splineType == 'BEZIER': - for v in newVerts: - newPoints += splineVerts[v].to_tuple() - - # array for nonBEZIER output - else: - for v in newVerts: - newPoints += (splineVerts[v].to_tuple()) - if splineType == 'NURBS': - newPoints.append(1) #for nurbs w=1 - else: #for poly w=0 - newPoints.append(0) - return newPoints - -######################### -#### MAIN OPERATIONS #### -######################### - -def main(context, obj, options): - #print("\n_______START_______") - # main vars - mode = options[0] - output = options[1] - degreeOut = options[5] - keepShort = options[7] - bpy.ops.object.select_all(action='DESELECT') - scene = context.scene - splines = obj.data.splines.values() - - # create curvedatablock - curve = bpy.data.curves.new("simple_"+obj.name, type = 'CURVE') - - # go through splines - for spline_i, spline in enumerate(splines): - # test if spline is a long enough - if len(spline.points) >= 7 or keepShort: - #check what type of spline to create - if output == 'INPUT': - splineType = spline.type - else: - splineType = output - - # get vec3 list to simplify - if spline.type == 'BEZIER': # get bezierverts - splineVerts = [splineVert.co.copy() - for splineVert in spline.bezier_points.values()] - - else: # verts from all other types of curves - splineVerts = [splineVert.co.copy().resize3D() - for splineVert in spline.points.values()] - - # simplify spline according to mode - if mode == 'distance': - newVerts = simplify_RDP(splineVerts, options) - - if mode == 'curvature': - newVerts = simplypoly(splineVerts, options) - - # convert indicies into vectors3D - newPoints = vertsToPoints(newVerts, splineVerts, splineType) - - # create new spline - newSpline = curve.splines.new(type = splineType) - - # put newPoints into spline according to type - if splineType == 'BEZIER': - newSpline.bezier_points.add(int(len(newPoints)*0.33)) - newSpline.bezier_points.foreach_set('co', newPoints) - else: - newSpline.points.add(int(len(newPoints)*0.25 - 1)) - newSpline.points.foreach_set('co', newPoints) - - # set degree of outputNurbsCurve - if output == 'NURBS': - newSpline.order_u = degreeOut - - # splineoptions - newSpline.use_endpoint_u = spline.use_endpoint_u - - # create ne object and put into scene - newCurve = bpy.data.objects.new("simple_"+obj.name, curve) - scene.objects.link(newCurve) - newCurve.select = True - scene.objects.active = newCurve - newCurve.matrix_world = obj.matrix_world - - # set bezierhandles to auto - setBezierHandles(newCurve) - - #print("________END________\n") - return - -################## -## get preoperator fcurves -def getFcurveData(obj): - fcurves = [] - for fc in obj.animation_data.action.fcurves: - if fc.select: - fcVerts = [vcVert.co.copy().resize3D() - for vcVert in fc.keyframe_points.values()] - fcurves.append(fcVerts) - return fcurves - -def selectedfcurves(obj): - fcurves_sel = [] - for i, fc in enumerate(obj.animation_data.action.fcurves): - if fc.select: - fcurves_sel.append(fc) - return fcurves_sel - -########################################################### -## fCurves Main -def fcurves_simplify(context, obj, options, fcurves): - # main vars - mode = options[0] - scene = context.scene - fcurves_obj = obj.animation_data.action.fcurves - - #get indicies of selected fcurves - fcurve_sel = selectedfcurves(obj) - - # go through fcurves - for fcurve_i, fcurve in enumerate(fcurves): - # test if fcurve is long enough - if len(fcurve) >= 7: - - # simplify spline according to mode - if mode == 'distance': - newVerts = simplify_RDP(fcurve, options) - - if mode == 'curvature': - newVerts = simplypoly(fcurve, options) - - # convert indicies into vectors3D - newPoints = [] - - #this is different from the main() function for normal curves, different api... - for v in newVerts: - newPoints.append(fcurve[v]) - - #remove all points from curve first - for i in range(len(fcurve)-1,0,-1): - fcurve_sel[fcurve_i].keyframe_points.remove(fcurve_sel[fcurve_i].keyframe_points[i]) - # put newPoints into fcurve - for v in newPoints: - fcurve_sel[fcurve_i].keyframe_points.add(frame=v[0],value=v[1]) - #fcurve.points.foreach_set('co', newPoints) - return - -################################################# -#### ANIMATION CURVES OPERATOR ################## -################################################# -class GRAPH_OT_simplify(bpy.types.Operator): - '''''' - bl_idname = "graph.simplify" - bl_label = "simplifiy f-curves" - bl_description = "simplify selected f-curves" - bl_options = {'REGISTER', 'UNDO'} - - ## Properties - opModes = [ - ('distance', 'distance', 'distance'), - ('curvature', 'curvature', 'curvature')] - mode = EnumProperty(name="Mode", - description="choose algorithm to use", - items=opModes) - k_thresh = FloatProperty(name="k", - min=0, soft_min=0, - default=0, precision=3, - description="threshold") - pointsNr = IntProperty(name="n", - min=5, soft_min=5, - max=16, soft_max=9, - default=5, - description="degree of curve to get averaged curvatures") - error = FloatProperty(name="error", - description="maximum error to allow - distance", - min=0.0, soft_min=0.0, - default=0, precision=3) - degreeOut = IntProperty(name="degree", - min=3, soft_min=3, - max=7, soft_max=7, - default=5, - description="degree of new curve") - dis_error = FloatProperty(name="distance error", - description="maximum error in Blenderunits to allow - distance", - min=0, soft_min=0, - default=0.0, precision=3) - fcurves = [] - - ''' Remove curvature mode as long as it isnn't significantly improved - - def draw(self, context): - props = self.properties - layout = self.layout - col = layout.column() - col.label('Mode:') - col.prop(props, 'mode', expand=True) - if self.properties.mode == 'distance': - box = layout.box() - box.label(props.mode, icon='ARROW_LEFTRIGHT') - box.prop(props, 'error', expand=True) - if self.properties.mode == 'curvature': - box = layout.box() - box.label('degree', icon='SMOOTHCURVE') - box.prop(props, 'pointsNr', expand=True) - box.label('threshold', icon='PARTICLE_PATH') - box.prop(props, 'k_thresh', expand=True) - box.label('distance', icon='ARROW_LEFTRIGHT') - box.prop(props, 'dis_error', expand=True) - col = layout.column() - ''' - - def draw(self, context): - props = self.properties - layout = self.layout - col = layout.column() - col.prop(props, 'error', expand=True) - - ## Check for animdata - @classmethod - def poll(cls, context): - obj = context.active_object - fcurves = False - if obj: - animdata = obj.animation_data - if animdata: - act = animdata.action - if act: - fcurves = act.fcurves - return (obj and fcurves) - - ## execute - def execute(self, context): - #print("------START------") - - options = [ - self.properties.mode, #0 - self.properties.mode, #1 - self.properties.k_thresh, #2 - self.properties.pointsNr, #3 - self.properties.error, #4 - self.properties.degreeOut, #6 - self.properties.dis_error] #7 - - obj = context.active_object - - if not self.fcurves: - self.fcurves = getFcurveData(obj) - - fcurves_simplify(context, obj, options, self.fcurves) - - #print("-------END-------") - return {'FINISHED'} - -########################### -##### Curves OPERATOR ##### -########################### -class CURVE_OT_simplify(bpy.types.Operator): - '''''' - bl_idname = "curve.simplify" - bl_label = "simplifiy curves" - bl_description = "simplify curves" - bl_options = {'REGISTER', 'UNDO'} - - ## Properties - opModes = [ - ('distance', 'distance', 'distance'), - ('curvature', 'curvature', 'curvature')] - mode = EnumProperty(name="Mode", - description="choose algorithm to use", - items=opModes) - SplineTypes = [ - ('INPUT', 'Input', 'same type as input spline'), - ('NURBS', 'Nurbs', 'NURBS'), - ('BEZIER', 'Bezier', 'BEZIER'), - ('POLY', 'Poly', 'POLY')] - output = EnumProperty(name="Output splines", - description="Type of splines to output", - items=SplineTypes) - k_thresh = FloatProperty(name="k", - min=0, soft_min=0, - default=0, precision=3, - description="threshold") - pointsNr = IntProperty(name="n", - min=5, soft_min=5, - max=9, soft_max=9, - default=5, - description="degree of curve to get averaged curvatures") - error = FloatProperty(name="error in Bu", - description="maximum error in Blenderunits to allow - distance", - min=0, soft_min=0, - default=0.0, precision=3) - degreeOut = IntProperty(name="degree", - min=3, soft_min=3, - max=7, soft_max=7, - default=5, - description="degree of new curve") - dis_error = FloatProperty(name="distance error", - description="maximum error in Blenderunits to allow - distance", - min=0, soft_min=0, - default=0.0) - keepShort = BoolProperty(name="keep short Splines", - description="keep short splines (less then 7 points)", - default=True) - - ''' Remove curvature mode as long as it isnn't significantly improved - - def draw(self, context): - props = self.properties - layout = self.layout - col = layout.column() - col.label('Mode:') - col.prop(props, 'mode', expand=True) - if self.properties.mode == 'distance': - box = layout.box() - box.label(props.mode, icon='ARROW_LEFTRIGHT') - box.prop(props, 'error', expand=True) - if self.properties.mode == 'curvature': - box = layout.box() - box.label('degree', icon='SMOOTHCURVE') - box.prop(props, 'pointsNr', expand=True) - box.label('threshold', icon='PARTICLE_PATH') - box.prop(props, 'k_thresh', expand=True) - box.label('distance', icon='ARROW_LEFTRIGHT') - box.prop(props, 'dis_error', expand=True) - col = layout.column() - col.separator() - col.prop(props, 'output', text='Output', icon='OUTLINER_OB_CURVE') - if props.output == 'NURBS': - col.prop(props, 'degreeOut', expand=True) - col.prop(props, 'keepShort', expand=True) - ''' - - def draw(self, context): - props = self.properties - layout = self.layout - col = layout.column() - col.prop(props, 'error', expand=True) - col.prop(props, 'output', text='Output', icon='OUTLINER_OB_CURVE') - if props.output == 'NURBS': - col.prop(props, 'degreeOut', expand=True) - col.prop(props, 'keepShort', expand=True) - - - ## Check for curve - @classmethod - def poll(cls, context): - obj = context.active_object - return (obj and obj.type == 'CURVE') - - ## execute - def execute(self, context): - #print("------START------") - - options = [ - self.properties.mode, #0 - self.properties.output, #1 - self.properties.k_thresh, #2 - self.properties.pointsNr, #3 - self.properties.error, #4 - self.properties.degreeOut, #5 - self.properties.dis_error, #6 - self.properties.keepShort] #7 - - - bpy.context.user_preferences.edit.use_global_undo = False - - bpy.ops.object.mode_set(mode='OBJECT', toggle=True) - obj = context.active_object - - main(context, obj, options) - - bpy.context.user_preferences.edit.use_global_undo = True - - #print("-------END-------") - return {'FINISHED'} - -################################################# -#### REGISTER ################################### -################################################# -def register(): - pass - -def unregister(): - pass - -if __name__ == "__main__": - register() diff --git a/io_anim_camera.py b/io_anim_camera.py deleted file mode 100644 index 50951226..00000000 --- a/io_anim_camera.py +++ /dev/null @@ -1,164 +0,0 @@ -# ##### 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -# ##### END GPL LICENSE BLOCK ##### - -# - -bl_addon_info = { - "name": "Export Camera Animation", - "author": "Campbell Barton", - "version": (0,1), - "blender": (2, 5, 3), - "api": 31667, - "location": "File > Export > Camera Animation", - "description": "Export Cameras & Markers", - "warning": "", - "wiki_url": "http://wiki.blender.org/index.php/Extensions:2.5/Py/"\ - "Scripts/File_I-O/Camera_Animation", - "tracker_url": "https://projects.blender.org/tracker/index.php?"\ - "func=detail&aid=22835&group_id=153&atid=469", - "category": "Import/Export"} - - -import bpy - - -def writeCameras(context, filepath, frame_start, frame_end, only_selected=False): - - data_attrs = ['lens', 'shift_x', 'shift_y', 'dof_distance', 'clip_start', 'clip_end', 'draw_size'] - obj_attrs = ['hide_render'] - - fw = open(filepath, 'w').write - - scene = bpy.context.scene - - cameras = [] - - for obj in scene.objects: - if only_selected and not obj.select: - continue - if obj.type != 'CAMERA': - continue - - cameras.append((obj, obj.data)) - - frame_range = range(frame_start, frame_end + 1) - - fw("cameras = {}\n") - fw("scene = bpy.context.scene\n") - fw("frame = scene.frame_current - 1\n") - fw("\n") - - for obj, obj_data in cameras: - fw("data = bpy.data.cameras.new('%s')\n" % obj.name) - for attr in data_attrs: - fw("data.%s = %s\n" % (attr, repr(getattr(obj_data, attr)))) - - fw("obj = bpy.data.objects.new('%s', data)\n" % obj.name) - - for attr in obj_attrs: - fw("obj.%s = %s\n" % (attr, repr(getattr(obj, attr)))) - - fw("scene.objects.link(obj)\n") - fw("cameras['%s'] = obj\n" % obj.name) - fw("\n") - - - for f in frame_range: - scene.frame_set(f) - fw("# new frame\n") - fw("scene.frame_set(%d + frame)\n" % f) - - for obj, obj_data in cameras: - fw("obj = cameras['%s']\n" % obj.name) - - matrix = obj.matrix_world.copy() - fw("obj.location = %s\n" % repr(tuple(matrix.translation_part()))) - fw("obj.scale = %s\n" % repr(tuple(matrix.scale_part()))) - fw("obj.rotation_euler = %s\n" % repr(tuple(matrix.to_euler()))) - - fw("obj.keyframe_insert('location')\n") - fw("obj.keyframe_insert('scale')\n") - fw("obj.keyframe_insert('rotation_euler')\n") - - # only key the angle - fw("data = obj.data\n") - fw("data.lens = %s\n" % obj_data.lens) - fw("data.keyframe_insert('lens')\n") - - fw("\n") - - # now markers - fw("# markers\n") - for marker in scene.timeline_markers: - fw("marker = scene.timeline_markers.new('%s')\n" % marker.name) - fw("marker.frame = %d + frame\n" % marker.frame) - - # will fail if the cameras not selected - if marker.camera: - fw("marker.camera = cameras.get('%s')\n" % marker.camera.name) - fw("\n") - - -from bpy.props import * - - -class CameraExporter(bpy.types.Operator): - '''Save a python script which re-creartes cameras and markers elsewhere''' - bl_idname = "export_animation.cameras" - bl_label = "Export Camera & Markers" - - filepath = StringProperty(name="File Path", description="File path used for importing the RAW file", maxlen=1024, default="") - - frame_start = IntProperty(name="Start Frame", - description="Start frame for export", - default=1, min=1, max=300000) - frame_end = IntProperty(name="End Frame", - description="End frame for export", - default=250, min=1, max=300000) - only_selected = BoolProperty(name="Only Selected", - default=True) - - def execute(self, context): - writeCameras(context, self.properties.filepath, self.properties.frame_start, self.properties.frame_end, self.properties.show_only_selected) - return {'FINISHED'} - - def invoke(self, context, event): - self.properties.frame_start = context.scene.frame_start - self.properties.frame_end = context.scene.frame_end - - wm = context.window_manager - wm.add_fileselect(self) - return {'RUNNING_MODAL'} - - -def menu_export(self, context): - import os - default_path = os.path.splitext(bpy.data.filepath)[0] + ".py" - self.layout.operator(CameraExporter.bl_idname, text="Cameras & Markers (.py)").filepath = default_path - - -def register(): - bpy.types.INFO_MT_file_export.append(menu_export) - - -def unregister(): - bpy.types.INFO_MT_file_export.remove(menu_export) - - -if __name__ == "__main__": - register() diff --git a/io_export_directx_x.py b/io_export_directx_x.py deleted file mode 100644 index e32f542a..00000000 --- a/io_export_directx_x.py +++ /dev/null @@ -1,1154 +0,0 @@ -# ***** 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 3 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, see . -# All rights reserved. -# ***** GPL LICENSE BLOCK ***** - -bl_addon_info = { - "name": "Export DirectX Model Format (.x)", - "author": "Chris Foster (Kira Vakaan)", - "version": (1,6), - "blender": (2, 5, 3), - "api": 31667, - "location": "File > Export", - "description": "Export to the DirectX Model Format (.x)", - "warning": "", - "wiki_url": "http://wiki.blender.org/index.php/Extensions:2.5/Py/"\ - "Scripts/File_I-O/DirectX_Exporter", - "tracker_url": "https://projects.blender.org/tracker/index.php?"\ - "func=detail&aid=22795&group_id=153&atid=469", - "category": "Import/Export"} - -import os -from math import radians - -import bpy -from mathutils import * - -#Container for the exporter settings -class DirectXExporterSettings: - def __init__(self, - context, - FilePath, - CoordinateSystem=1, - RotateX=True, - FlipNormals=False, - ApplyModifiers=False, - IncludeFrameRate=False, - ExportTextures=True, - ExportArmatures=False, - ExportAnimation=0, - ExportMode=1, - Verbose=False): - self.context = context - self.FilePath = FilePath - self.CoordinateSystem = int(CoordinateSystem) - self.RotateX = RotateX - self.FlipNormals = FlipNormals - self.ApplyModifiers = ApplyModifiers - self.IncludeFrameRate = IncludeFrameRate - self.ExportTextures = ExportTextures - self.ExportArmatures = ExportArmatures - self.ExportAnimation = int(ExportAnimation) - self.ExportMode = int(ExportMode) - self.Verbose = Verbose - - -def LegalName(Name): - NewName = Name.replace(".", "_") - NewName = NewName.replace(" ", "_") - if NewName[0].isdigit() or NewName in ["ARRAY", - "DWORD", - "UCHAR", - "BINARY", - "FLOAT", - "ULONGLONG", - "BINARY_RESOURCE", - "SDWORD", - "UNICODE", - "CHAR", - "STRING", - "WORD", - "CSTRING", - "SWORD", - "DOUBLE", - "TEMPLATE"]: - NewName = "_" + NewName - return NewName - - -def ExportDirectX(Config): - print("----------\nExporting to {}".format(Config.FilePath)) - if Config.Verbose: - print("Opening File...", end=" ") - Config.File = open(Config.FilePath, "w") - if Config.Verbose: - print("Done") - - if Config.Verbose: - print("Generating Object list for export...", end=" ") - if Config.ExportMode == 1: - Config.ExportList = [Object for Object in Config.context.scene.objects - if Object.type in ("ARMATURE", "EMPTY", "MESH") - and Object.parent == None] - else: - ExportList = [Object for Object in Config.context.selected_objects - if Object.type in ("ARMATURE", "EMPTY", "MESH")] - Config.ExportList = [Object for Object in ExportList - if Object.parent not in ExportList] - if Config.Verbose: - print("Done") - - if Config.Verbose: - print("Setting up...", end=" ") - Config.SystemMatrix = Matrix() - if Config.RotateX: - Config.SystemMatrix *= Matrix.Rotation(radians(-90), 4, "X") - if Config.CoordinateSystem == 1: - Config.SystemMatrix *= Matrix.Scale(-1, 4, Vector((0, 1, 0))) - Config.InverseSystemMatrix = Config.SystemMatrix.copy().invert() - - #Used for animating rotations - Config.SystemQuaternion = Quaternion((1,0,0,0)) - if Config.RotateX: - Config.SystemQuaternion = Matrix.Rotation(radians(-90), 3, "X").to_quat() - Config.InverseSystemQuaternion = Config.SystemQuaternion.copy().inverse() - Config.FlipZ = -1 if Config.CoordinateSystem == 1 else 1 - - if Config.ExportAnimation: - CurrentFrame = bpy.context.scene.frame_current - bpy.context.scene.frame_current = bpy.context.scene.frame_current - if Config.Verbose: - print("Done") - - if Config.Verbose: - print("Writing Header...", end=" ") - WriteHeader(Config) - if Config.Verbose: - print("Done") - - Config.Whitespace = 0 - Config.ObjectList = [] - if Config.Verbose: - print("Writing Objects...") - WriteObjects(Config, Config.ExportList) - if Config.Verbose: - print("Done") - - if Config.ExportAnimation: - if Config.IncludeFrameRate: - if Config.Verbose: - print("Writing Frame Rate...", end=" ") - Config.File.write("{}AnimTicksPerSecond {{\n".format(" " * Config.Whitespace)) - Config.Whitespace += 1 - Config.File.write("{}{};\n".format(" " * Config.Whitespace, int(bpy.context.scene.render.fps / bpy.context.scene.render.fps_base))) - Config.Whitespace -= 1 - Config.File.write("{}}}\n".format(" " * Config.Whitespace)) - if Config.Verbose: - print("Done") - if Config.Verbose: - print("Writing Animation...") - if Config.ExportAnimation==1: - WriteKeyedAnimationSet(Config) - else: - WriteFullAnimationSet(Config) - bpy.context.scene.frame_current = CurrentFrame - if Config.Verbose: - print("Done") - - CloseFile(Config) - print("Finished") - - -def GetObjectChildren(Parent): - return [Object for Object in Parent.children - if Object.type in ("ARMATURE", "EMPTY", "MESH")] - -#Returns the vertex count of Mesh, counting each vertex for every face. -def GetMeshVertexCount(Mesh): - VertexCount = 0 - for Face in Mesh.faces: - VertexCount += len(Face.vertices) - return VertexCount - -#Returns the file path of first image texture from Material. -def GetMaterialTexture(Material): - if Material: - #Create a list of Textures that have type "IMAGE" - ImageTextures = [Material.texture_slots[TextureSlot].texture for TextureSlot in Material.texture_slots.keys() if Material.texture_slots[TextureSlot].texture.type == "IMAGE"] - #Refine a new list with only image textures that have a file source - ImageFiles = [os.path.basename(Texture.image.filepath) for Texture in ImageTextures if Texture.image.source == "FILE"] - if ImageFiles: - return ImageFiles[0] - return None - - -def WriteHeader(Config): - Config.File.write("xof 0303txt 0032\n\n") - if Config.ExportArmatures: - Config.File.write("template XSkinMeshHeader {\n\ - <3cf169ce-ff7c-44ab-93c0-f78f62d172e2>\n\ - WORD nMaxSkinWeightsPerVertex;\n\ - WORD nMaxSkinWeightsPerFace;\n\ - WORD nBones;\n\ -}\n\n\ -template SkinWeights {\n\ - <6f0d123b-bad2-4167-a0d0-80224f25fabb>\n\ - STRING transformNodeName;\n\ - DWORD nWeights;\n\ - array DWORD vertexIndices[nWeights];\n\ - array float weights[nWeights];\n\ - Matrix4x4 matrixOffset;\n\ -}\n\n") - - -def WriteObjects(Config, ObjectList): - Config.ObjectList += ObjectList - - for Object in ObjectList: - if Config.Verbose: - print(" Writing Object: {}...".format(Object.name)) - Config.File.write("{}Frame {} {{\n".format(" " * Config.Whitespace, LegalName(Object.name))) - - Config.Whitespace += 1 - if Config.Verbose: - print(" Writing Local Matrix...", end=" ") - WriteLocalMatrix(Config, Object) - if Config.Verbose: - print("Done") - - if Config.ExportArmatures and Object.type == "ARMATURE": - Armature = Object.data - ParentList = [Bone for Bone in Armature.bones if Bone.parent == None] - if Config.Verbose: - print(" Writing Armature Bones...") - WriteArmatureBones(Config, Object, ParentList) - if Config.Verbose: - print(" Done") - - ChildList = GetObjectChildren(Object) - if Config.Verbose: - print(" Writing Children...") - WriteObjects(Config, ChildList) - if Config.Verbose: - print(" Done Writing Children") - - if Object.type == "MESH": - if Config.Verbose: - print(" Generating Mesh...", end=" ") - if Config.ApplyModifiers: - if Config.ExportArmatures: - #Create a copy of the object and remove all armature modifiers so an unshaped - #mesh can be created from it. - Object2 = Object.copy() - for Modifier in [Modifier for Modifier in Object2.modifiers if Modifier.type == "ARMATURE"]: - Object2.modifiers.remove(Modifier) - Mesh = Object2.create_mesh(bpy.context.scene, True, "PREVIEW") - else: - Mesh = Object.create_mesh(bpy.context.scene, True, "PREVIEW") - else: - Mesh = Object.create_mesh(bpy.context.scene, False, "PREVIEW") - if Config.Verbose: - print("Done") - print(" Writing Mesh...") - WriteMesh(Config, Object, Mesh) - if Config.Verbose: - print(" Done") - if Config.ApplyModifiers and Config.ExportArmatures: - bpy.data.objects.remove(Object2) - bpy.data.meshes.remove(Mesh) - - Config.Whitespace -= 1 - Config.File.write("{}}} //End of {}\n".format(" " * Config.Whitespace, LegalName(Object.name))) - if Config.Verbose: - print(" Done Writing Object: {}".format(Object.name)) - - -def WriteLocalMatrix(Config, Object): - LocalMatrix = Config.SystemMatrix * Object.matrix_local * Config.InverseSystemMatrix - - Config.File.write("{}FrameTransformMatrix {{\n".format(" " * Config.Whitespace)) - Config.Whitespace += 1 - Config.File.write("{}{:9f},{:9f},{:9f},{:9f},\n".format(" " * Config.Whitespace, LocalMatrix[0][0], LocalMatrix[0][1], LocalMatrix[0][2], LocalMatrix[0][3])) - Config.File.write("{}{:9f},{:9f},{:9f},{:9f},\n".format(" " * Config.Whitespace, LocalMatrix[1][0], LocalMatrix[1][1], LocalMatrix[1][2], LocalMatrix[1][3])) - Config.File.write("{}{:9f},{:9f},{:9f},{:9f},\n".format(" " * Config.Whitespace, LocalMatrix[2][0], LocalMatrix[2][1], LocalMatrix[2][2], LocalMatrix[2][3])) - Config.File.write("{}{:9f},{:9f},{:9f},{:9f};;\n".format(" " * Config.Whitespace, LocalMatrix[3][0], LocalMatrix[3][1], LocalMatrix[3][2], LocalMatrix[3][3])) - Config.Whitespace -= 1 - Config.File.write("{}}}\n".format(" " * Config.Whitespace)) - - -def WriteArmatureBones(Config, Object, ChildList): - PoseBones = Object.pose.bones - for Bone in ChildList: - if Config.Verbose: - print(" Writing Bone: {}...".format(Bone.name), end=" ") - Config.File.write("{}Frame {} {{\n".format(" " * Config.Whitespace, LegalName(Object.name) + "_" + LegalName(Bone.name))) - Config.Whitespace += 1 - - PoseBone = PoseBones[Bone.name] - - if Bone.parent: - BoneMatrix = (PoseBone.parent.matrix * - Matrix.Rotation(radians(-90), 4, "X")).invert() - else: - BoneMatrix = Matrix() - - BoneMatrix *= PoseBone.matrix * Matrix.Rotation(radians(-90), 4, "X") - BoneMatrix = Config.SystemMatrix * BoneMatrix * Config.InverseSystemMatrix - - Config.File.write("{}FrameTransformMatrix {{\n".format(" " * Config.Whitespace)) - Config.Whitespace += 1 - Config.File.write("{}{:9f},{:9f},{:9f},{:9f},\n".format(" " * Config.Whitespace, BoneMatrix[0][0], BoneMatrix[0][1], BoneMatrix[0][2], BoneMatrix[0][3])) - Config.File.write("{}{:9f},{:9f},{:9f},{:9f},\n".format(" " * Config.Whitespace, BoneMatrix[1][0], BoneMatrix[1][1], BoneMatrix[1][2], BoneMatrix[1][3])) - Config.File.write("{}{:9f},{:9f},{:9f},{:9f},\n".format(" " * Config.Whitespace, BoneMatrix[2][0], BoneMatrix[2][1], BoneMatrix[2][2], BoneMatrix[2][3])) - Config.File.write("{}{:9f},{:9f},{:9f},{:9f};;\n".format(" " * Config.Whitespace, BoneMatrix[3][0], BoneMatrix[3][1], BoneMatrix[3][2], BoneMatrix[3][3])) - Config.Whitespace -= 1 - Config.File.write("{}}}\n".format(" " * Config.Whitespace)) - - if Config.Verbose: - print("Done") - WriteArmatureBones(Config, Object, Bone.children) - Config.Whitespace -= 1 - - Config.File.write("{}}} //End of {}\n".format(" " * Config.Whitespace, LegalName(Object.name) + "_" + LegalName(Bone.name))) - - -def WriteMesh(Config, Object, Mesh): - Config.File.write("{}Mesh {{ //{} Mesh\n".format(" " * Config.Whitespace, LegalName(Mesh.name))) - Config.Whitespace += 1 - - if Config.Verbose: - print(" Writing Mesh Vertices...", end=" ") - WriteMeshVertices(Config, Mesh) - if Config.Verbose: - print("Done\n Writing Mesh Normals...", end=" ") - WriteMeshNormals(Config, Mesh) - if Config.Verbose: - print("Done\n Writing Mesh Materials...", end=" ") - WriteMeshMaterials(Config, Mesh) - if Config.Verbose: - print("Done") - if Mesh.uv_textures: - if Config.Verbose: - print(" Writing Mesh UV Coordinates...", end=" ") - WriteMeshUVCoordinates(Config, Mesh) - if Config.Verbose: - print("Done") - if Config.ExportArmatures: - if Config.Verbose: - print(" Writing Mesh Skin Weights...", end=" ") - WriteMeshSkinWeights(Config, Object, Mesh) - if Config.Verbose: - print("Done") - - Config.Whitespace -= 1 - Config.File.write("{}}} //End of {} Mesh\n".format(" " * Config.Whitespace, LegalName(Mesh.name))) - - -def WriteMeshVertices(Config, Mesh): - Index = 0 - VertexCount = GetMeshVertexCount(Mesh) - Config.File.write("{}{};\n".format(" " * Config.Whitespace, VertexCount)) - - for Face in Mesh.faces: - Vertices = list(Face.vertices) - - if Config.CoordinateSystem == 1: - Vertices = Vertices[::-1] - for Vertex in [Mesh.vertices[Vertex] for Vertex in Vertices]: - Position = Config.SystemMatrix * Vertex.co - Config.File.write("{}{:9f};{:9f};{:9f};".format(" " * Config.Whitespace, Position[0], Position[1], Position[2])) - Index += 1 - if Index == VertexCount: - Config.File.write(";\n") - else: - Config.File.write(",\n") - - Index = 0 - Config.File.write("{}{};\n".format(" " * Config.Whitespace, len(Mesh.faces))) - - for Face in Mesh.faces: - Config.File.write("{}{};".format(" " * Config.Whitespace, len(Face.vertices))) - for Vertex in Face.vertices: - Config.File.write("{};".format(Index)) - Index += 1 - if Index == VertexCount: - Config.File.write(";\n") - else: - Config.File.write(",\n") - - -def WriteMeshNormals(Config, Mesh): - Config.File.write("{}MeshNormals {{ //{} Normals\n".format(" " * Config.Whitespace, LegalName(Mesh.name))) - Config.Whitespace += 1 - - Index = 0 - VertexCount = GetMeshVertexCount(Mesh) - Config.File.write("{}{};\n".format(" " * Config.Whitespace, VertexCount)) - - for Face in Mesh.faces: - Vertices = list(Face.vertices) - - if Config.CoordinateSystem == 1: - Vertices = Vertices[::-1] - for Vertex in [Mesh.vertices[Vertex] for Vertex in Vertices]: - if Face.use_smooth: - Normal = Config.SystemMatrix * Vertex.normal - else: - Normal = Config.SystemMatrix * Face.normal - if Config.FlipNormals: - Normal = -Normal - Config.File.write("{}{:9f};{:9f};{:9f};".format(" " * Config.Whitespace, Normal[0], Normal[1], Normal[2])) - Index += 1 - if Index == VertexCount: - Config.File.write(";\n") - else: - Config.File.write(",\n") - - Index = 0 - Config.File.write("{}{};\n".format(" " * Config.Whitespace, len(Mesh.faces))) - - for Face in Mesh.faces: - Config.File.write("{}{};".format(" " * Config.Whitespace, len(Face.vertices))) - for Vertex in Face.vertices: - Config.File.write("{};".format(Index)) - Index += 1 - if Index == VertexCount: - Config.File.write(";\n") - else: - Config.File.write(",\n") - Config.Whitespace -= 1 - Config.File.write("{}}} //End of {} Normals\n".format(" " * Config.Whitespace, LegalName(Mesh.name))) - - -def WriteMeshMaterials(Config, Mesh): - Config.File.write("{}MeshMaterialList {{ //{} Material List\n".format(" " * Config.Whitespace, LegalName(Mesh.name))) - Config.Whitespace += 1 - - Materials = Mesh.materials - if Materials.keys(): - MaterialIndexes = {} - for Face in Mesh.faces: - if Materials[Face.material_index] not in MaterialIndexes: - MaterialIndexes[Materials[Face.material_index]] = len(MaterialIndexes) - - FaceCount = len(Mesh.faces) - Index = 0 - Config.File.write("{}{};\n{}{};\n".format(" " * Config.Whitespace, len(MaterialIndexes), " " * Config.Whitespace, FaceCount)) - for Face in Mesh.faces: - Config.File.write("{}{}".format(" " * Config.Whitespace, MaterialIndexes[Materials[Face.material_index]])) - Index += 1 - if Index == FaceCount: - Config.File.write(";;\n") - else: - Config.File.write(",\n") - - Materials = [Item[::-1] for Item in MaterialIndexes.items()] - Materials.sort() - for Material in Materials: - WriteMaterial(Config, Material[1]) - else: - Config.File.write("{}1;\n{}1;\n{}0;;\n".format(" " * Config.Whitespace, " " * Config.Whitespace, " " * Config.Whitespace)) - WriteMaterial(Config) - - Config.Whitespace -= 1 - Config.File.write("{}}} //End of {} Material List\n".format(" " * Config.Whitespace, LegalName(Mesh.name))) - - -def WriteMaterial(Config, Material=None): - if Material: - Config.File.write("{}Material {} {{\n".format(" " * Config.Whitespace, LegalName(Material.name))) - Config.Whitespace += 1 - - Diffuse = list(Material.diffuse_color) - Diffuse.append(Material.alpha) - Specularity = Material.specular_intensity - Specular = list(Material.specular_color) - - Config.File.write("{}{:9f};{:9f};{:9f};{:9f};;\n".format(" " * Config.Whitespace, Diffuse[0], Diffuse[1], Diffuse[2], Diffuse[3])) - Config.File.write("{}{:9f};\n".format(" " * Config.Whitespace, 2 * (1.0 - Specularity))) - Config.File.write("{}{:9f};{:9f};{:9f};;\n".format(" " * Config.Whitespace, Specular[0], Specular[1], Specular[2])) - else: - Config.File.write("{}Material Default_Material {{\n".format(" " * Config.Whitespace)) - Config.Whitespace += 1 - Config.File.write("{} 1.000000; 1.000000; 1.000000; 1.000000;;\n".format(" " * Config.Whitespace)) - Config.File.write("{} 1.500000;\n".format(" " * Config.Whitespace)) - Config.File.write("{} 1.000000; 1.000000; 1.000000;;\n".format(" " * Config.Whitespace)) - Config.File.write("{} 0.000000; 0.000000; 0.000000;;\n".format(" " * Config.Whitespace)) - if Config.ExportTextures: - Texture = GetMaterialTexture(Material) - if Texture: - Config.File.write("{}TextureFilename {{\"{}\";}}\n".format(" " * Config.Whitespace, Texture)) - Config.Whitespace -= 1 - Config.File.write("{}}}\n".format(" " * Config.Whitespace)) - - -def WriteMeshUVCoordinates(Config, Mesh): - Config.File.write("{}MeshTextureCoords {{ //{} UV Coordinates\n".format(" " * Config.Whitespace, LegalName(Mesh.name))) - Config.Whitespace += 1 - - UVCoordinates = None - for UV in Mesh.uv_textures: - if UV.active_render: - UVCoordinates = UV.data - break - - Index = 0 - VertexCount = GetMeshVertexCount(Mesh) - Config.File.write("{}{};\n".format(" " * Config.Whitespace, VertexCount)) - - for Face in UVCoordinates: - Vertices = [] - for Vertex in Face.uv: - Vertices.append(tuple(Vertex)) - if Config.CoordinateSystem == 1: - Vertices = Vertices[::-1] - for Vertex in Vertices: - Config.File.write("{}{:9f};{:9f};".format(" " * Config.Whitespace, Vertex[0], 1 - Vertex[1])) - Index += 1 - if Index == VertexCount: - Config.File.write(";\n") - else: - Config.File.write(",\n") - Config.Whitespace -= 1 - Config.File.write("{}}} //End of {} UV Coordinates\n".format(" " * Config.Whitespace, LegalName(Mesh.name))) - - -def WriteMeshSkinWeights(Config, Object, Mesh): - ArmatureList = [Modifier for Modifier in Object.modifiers if Modifier.type == "ARMATURE"] - if ArmatureList: - ArmatureObject = ArmatureList[0].object - ArmatureBones = ArmatureObject.data.bones - - PoseBones = ArmatureObject.pose.bones - - MaxInfluences = 0 - UsedBones = set() - #Maps bones to a list of vertices they affect - VertexGroups = {} - - for Vertex in Mesh.vertices: - #BoneInfluences contains the bones of the armature that affect the current vertex - BoneInfluences = [PoseBones[Object.vertex_groups[Group.group].name] for Group in Vertex.groups if Object.vertex_groups[Group.group].name in PoseBones] - if len(BoneInfluences) > MaxInfluences: - MaxInfluences = len(BoneInfluences) - for Bone in BoneInfluences: - UsedBones.add(Bone) - if Bone not in VertexGroups: - VertexGroups[Bone] = [Vertex] - else: - VertexGroups[Bone].append(Vertex) - BoneCount = len(UsedBones) - - Config.File.write("{}XSkinMeshHeader {{\n".format(" " * Config.Whitespace)) - Config.Whitespace += 1 - Config.File.write("{}{};\n{}{};\n{}{};\n".format(" " * Config.Whitespace, MaxInfluences, " " * Config.Whitespace, MaxInfluences * 3, " " * Config.Whitespace, BoneCount)) - Config.Whitespace -= 1 - Config.File.write("{}}}\n".format(" " * Config.Whitespace)) - - for Bone in UsedBones: - VertexCount = 0 - VertexIndexes = [Vertex.index for Vertex in VertexGroups[Bone]] - for Face in Mesh.faces: - for Vertex in Face.vertices: - if Vertex in VertexIndexes: - VertexCount += 1 - - Config.File.write("{}SkinWeights {{\n".format(" " * Config.Whitespace)) - Config.Whitespace += 1 - Config.File.write("{}\"{}\";\n{}{};\n".format(" " * Config.Whitespace, LegalName(ArmatureObject.name) + "_" + LegalName(Bone.name), " " * Config.Whitespace, VertexCount)) - - VertexWeights = [] - Index = 0 - WrittenIndexes = 0 - for Face in Mesh.faces: - FaceVertices = list(Face.vertices) - if Config.CoordinateSystem == 1: - FaceVertices = FaceVertices[::-1] - for Vertex in FaceVertices: - if Vertex in VertexIndexes: - Config.File.write("{}{}".format(" " * Config.Whitespace, Index)) - - GroupIndexes = {Object.vertex_groups[Group.group].name: Index for Index, Group in enumerate(Mesh.vertices[Vertex].groups) if Object.vertex_groups[Group.group].name in PoseBones} - - WeightTotal = 0.0 - for Weight in [Group.weight for Group in Mesh.vertices[Vertex].groups if Object.vertex_groups[Group.group].name in PoseBones]: - WeightTotal += Weight - - if WeightTotal: - VertexWeights.append(Mesh.vertices[Vertex].groups[GroupIndexes[Bone.name]].weight / WeightTotal) - else: - VertexWeights.append(0.0) - - WrittenIndexes += 1 - if WrittenIndexes == VertexCount: - Config.File.write(";\n") - else: - Config.File.write(",\n") - Index += 1 - - for Index, Weight in enumerate(VertexWeights): - Config.File.write("{}{:8f}".format(" " * Config.Whitespace, Weight)) - if Index == (VertexCount - 1): - Config.File.write(";\n") - else: - Config.File.write(",\n") - - RestBone = ArmatureBones[Bone.name] - - #BoneMatrix transforms mesh vertices into the space of the bone. - #Here are the final transformations in order: - # - Object Space to World Space - # - World Space to Armature Space - # - Armature Space to Bone Space (The bone matrix needs to be rotated 90 degrees to align with Blender's world axes) - #This way, when BoneMatrix is transformed by the bone's Frame matrix, the vertices will be in their final world position. - - BoneMatrix = (RestBone.matrix_local * Matrix.Rotation(radians(-90), 4, "X")).invert() - BoneMatrix *= ArmatureObject.matrix_world.copy().invert() - BoneMatrix *= Object.matrix_world - - BoneMatrix = Config.SystemMatrix * BoneMatrix * Config.InverseSystemMatrix - - Config.File.write("{}{:9f},{:9f},{:9f},{:9f},\n".format(" " * Config.Whitespace, BoneMatrix[0][0], BoneMatrix[0][1], BoneMatrix[0][2], BoneMatrix[0][3])) - Config.File.write("{}{:9f},{:9f},{:9f},{:9f},\n".format(" " * Config.Whitespace, BoneMatrix[1][0], BoneMatrix[1][1], BoneMatrix[1][2], BoneMatrix[1][3])) - Config.File.write("{}{:9f},{:9f},{:9f},{:9f},\n".format(" " * Config.Whitespace, BoneMatrix[2][0], BoneMatrix[2][1], BoneMatrix[2][2], BoneMatrix[2][3])) - Config.File.write("{}{:9f},{:9f},{:9f},{:9f};;\n".format(" " * Config.Whitespace, BoneMatrix[3][0], BoneMatrix[3][1], BoneMatrix[3][2], BoneMatrix[3][3])) - Config.Whitespace -= 1 - Config.File.write("{}}} //End of {} Skin Weights\n".format(" " * Config.Whitespace, LegalName(ArmatureObject.name) + "_" + LegalName(Bone.name))) - - -def WriteKeyedAnimationSet(Config): - Config.File.write("{}AnimationSet {{\n".format(" " * Config.Whitespace)) - Config.Whitespace += 1 - for Object in [Object for Object in Config.ObjectList if Object.animation_data]: - if Config.Verbose: - print(" Writing Animation Data for Object: {}".format(Object.name)) - Action = Object.animation_data.action - if Action: - PositionFCurves = [None, None, None] - RotationFCurves = [None, None, None] - ScaleFCurves = [None, None, None] - for FCurve in Action.fcurves: - if FCurve.data_path == "location": - PositionFCurves[FCurve.array_index] = FCurve - elif FCurve.data_path == "rotation_euler": - RotationFCurves[FCurve.array_index] = FCurve - elif FCurve.data_path == "scale": - ScaleFCurves[FCurve.array_index] = FCurve - if [FCurve for FCurve in PositionFCurves + RotationFCurves + ScaleFCurves if FCurve]: - Config.File.write("{}Animation {{\n".format(" " * Config.Whitespace)) - Config.Whitespace += 1 - Config.File.write("{}{{{}}}\n".format(" " * Config.Whitespace, LegalName(Object.name))) - - #Position - if Config.Verbose: - print(" Writing Position...", end=" ") - AllKeyframes = set() - for Index, FCurve in enumerate(PositionFCurves): - if FCurve: - Keyframes = [] - for Keyframe in FCurve.keyframe_points: - Keyframes.append(Keyframe.co) - AllKeyframes.add(int(Keyframe.co[0])) - PositionFCurves[Index] = {int(Keyframe): Value for Keyframe, Value in Keyframes} - Config.File.write("{}AnimationKey {{ //Position\n".format(" " * Config.Whitespace)) - Config.Whitespace += 1 - AllKeyframes = list(AllKeyframes) - AllKeyframes.sort() - if len(AllKeyframes): - Config.File.write("{}2;\n{}{};\n".format(" " * Config.Whitespace, " " * Config.Whitespace, len(AllKeyframes))) - for Keyframe in AllKeyframes: - bpy.context.scene.frame_set(Keyframe) - Position = Vector() - Position[0] = ((PositionFCurves[0][Keyframe] if Keyframe in PositionFCurves[0] else Object.location[0]) if PositionFCurves[0] else Object.location[0]) - Position[1] = ((PositionFCurves[1][Keyframe] if Keyframe in PositionFCurves[1] else Object.location[1]) if PositionFCurves[1] else Object.location[1]) - Position[2] = ((PositionFCurves[2][Keyframe] if Keyframe in PositionFCurves[2] else Object.location[2]) if PositionFCurves[2] else Object.location[2]) - Position = Config.SystemMatrix * Position - Config.File.write("{}{}{:9f},{:9f},{:9f};;\n".format(" " * Config.Whitespace, (str(Keyframe - bpy.context.scene.frame_start) + ";3;").ljust(8), Position[0], Position[1], Position[2])) - else: - Config.File.write("{}2;\n{}1;\n".format(" " * Config.Whitespace, " " * Config.Whitespace)) - bpy.context.scene.frame_set(bpy.context.scene.frame_start) - Position = Config.SystemMatrix * Object.location - Config.File.write("{}{}{:9f},{:9f},{:9f};;\n".format(" " * Config.Whitespace, ("0;3;").ljust(8), Position[0], Position[1], Position[2])) - Config.Whitespace -= 1 - Config.File.write("{}}}\n".format(" " * Config.Whitespace)) - if Config.Verbose: - print("Done") - - #Rotation - if Config.Verbose: - print(" Writing Rotation...", end=" ") - AllKeyframes = set() - for Index, FCurve in enumerate(RotationFCurves): - if FCurve: - Keyframes = [] - for Keyframe in FCurve.keyframe_points: - Keyframes.append(Keyframe.co) - AllKeyframes.add(int(Keyframe.co[0])) - RotationFCurves[Index] = {int(Keyframe): Value for Keyframe, Value in Keyframes} - Config.File.write("{}AnimationKey {{ //Rotation\n".format(" " * Config.Whitespace)) - Config.Whitespace += 1 - AllKeyframes = list(AllKeyframes) - AllKeyframes.sort() - if len(AllKeyframes): - Config.File.write("{}0;\n{}{};\n".format(" " * Config.Whitespace, " " * Config.Whitespace, len(AllKeyframes))) - for Keyframe in AllKeyframes: - bpy.context.scene.frame_set(Keyframe) - Rotation = Euler() - Rotation[0] = ((RotationFCurves[0][Keyframe] if Keyframe in RotationFCurves[0] else Object.rotation_euler[0]) if RotationFCurves[0] else Object.rotation_euler[0]) - Rotation[1] = ((RotationFCurves[1][Keyframe] if Keyframe in RotationFCurves[1] else Object.rotation_euler[1]) if RotationFCurves[1] else Object.rotation_euler[1]) - Rotation[2] = ((RotationFCurves[2][Keyframe] if Keyframe in RotationFCurves[2] else Object.rotation_euler[2]) if RotationFCurves[2] else Object.rotation_euler[2]) - Rotation = (Config.SystemMatrix * (Rotation.to_matrix().to_4x4()) * Config.InverseSystemMatrix).to_quat() - Config.File.write("{}{}{:9f},{:9f},{:9f},{:9f};;\n".format(" " * Config.Whitespace, (str(Keyframe - bpy.context.scene.frame_start) + ";4;").ljust(8), - Rotation[0], Rotation[1], Rotation[2], Rotation[3])) - else: - Config.File.write("{}0;\n{}1;\n".format(" " * Config.Whitespace, " " * Config.Whitespace)) - bpy.context.scene.frame_set(bpy.context.scene.frame_start) - Rotation = (Config.SystemMatrix * (Object.rotation_euler.to_matrix().to_4x4()) * Config.InverseSystemMatrix).to_quat() - Config.File.write("{}{}{:9f},{:9f},{:9f},{:9f};;\n".format(" " * Config.Whitespace, ("0;4;").ljust(8), -Rotation[0], Rotation[1], Rotation[2], Rotation[3])) - Config.Whitespace -= 1 - Config.File.write("{}}}\n".format(" " * Config.Whitespace)) - if Config.Verbose: - print("Done") - - #Scale - if Config.Verbose: - print(" Writing Scale...", end=" ") - AllKeyframes = set() - for Index, FCurve in enumerate(ScaleFCurves): - if FCurve: - Keyframes = [] - for Keyframe in FCurve.keyframe_points: - Keyframes.append(Keyframe.co) - AllKeyframes.add(int(Keyframe.co[0])) - ScaleFCurves[Index] = {int(Keyframe): Value for Keyframe, Value in Keyframes} - Config.File.write("{}AnimationKey {{ //Scale\n".format(" " * Config.Whitespace)) - Config.Whitespace += 1 - AllKeyframes = list(AllKeyframes) - AllKeyframes.sort() - if len(AllKeyframes): - Config.File.write("{}1;\n{}{};\n".format(" " * Config.Whitespace, " " * Config.Whitespace, len(AllKeyframes))) - for Keyframe in AllKeyframes: - bpy.context.scene.frame_set(Keyframe) - Scale = Vector() - Scale[0] = ((ScaleFCurves[0][Keyframe] if Keyframe in ScaleFCurves[0] else Object.scale[0]) if ScaleFCurves[0] else Object.scale[0]) - Scale[1] = ((ScaleFCurves[1][Keyframe] if Keyframe in ScaleFCurves[1] else Object.scale[1]) if ScaleFCurves[1] else Object.scale[1]) - Scale[2] = ((ScaleFCurves[2][Keyframe] if Keyframe in ScaleFCurves[2] else Object.scale[2]) if ScaleFCurves[2] else Object.scale[2]) - Scale = Config.SystemMatrix * Scale - Config.File.write("{}{}{:9f},{:9f},{:9f};;\n".format(" " * Config.Whitespace, (str(Keyframe - bpy.context.scene.frame_start) + ";3;").ljust(8), Scale[0], Scale[1], Scale[2])) - else: - Config.File.write("{}1;\n{}1;\n".format(" " * Config.Whitespace, " " * Config.Whitespace)) - bpy.context.scene.frame_set(bpy.context.scene.frame_start) - Scale = Config.SystemMatrix * Object.scale - Config.File.write("{}{}{:9f},{:9f},{:9f};;\n".format(" " * Config.Whitespace, ("0;3;").ljust(8), Scale[0], Scale[1], Scale[2])) - Config.Whitespace -= 1 - Config.File.write("{}}}\n".format(" " * Config.Whitespace)) - if Config.Verbose: - print("Done") - - Config.Whitespace -= 1 - Config.File.write("{}}}\n".format(" " * Config.Whitespace)) - else: - if Config.Verbose: - print(" Object has no useable animation data.") - - if Config.ExportArmatures and Object.type == "ARMATURE": - if Config.Verbose: - print(" Writing Armature Bone Animation Data...") - PoseBones = Object.pose.bones - for Bone in PoseBones: - if Config.Verbose: - print(" Writing Bone: {}...".format(Bone.name)) - PositionFCurves = [None, None, None] - RotationFCurves = [None, None, None, None] - ScaleFCurves = [None, None, None] - for FCurve in Action.fcurves: - if FCurve.data_path == "pose.bones[\"{}\"].location".format(Bone.name): - PositionFCurves[FCurve.array_index] = FCurve - elif FCurve.data_path == "pose.bones[\"{}\"].rotation_quaternion".format(Bone.name): - RotationFCurves[FCurve.array_index] = FCurve - elif FCurve.data_path == "pose.bones[\"{}\"].scale".format(Bone.name): - ScaleFCurves[FCurve.array_index] = FCurve - if not [FCurve for FCurve in PositionFCurves + RotationFCurves + ScaleFCurves if FCurve]: - if Config.Verbose: - print(" Bone has no useable animation data.\n Done") - continue - - Config.File.write("{}Animation {{\n".format(" " * Config.Whitespace)) - Config.Whitespace += 1 - Config.File.write("{}{{{}}}\n".format(" " * Config.Whitespace, LegalName(Object.name) + "_" + LegalName(Bone.name))) - - #Position - if Config.Verbose: - print(" Writing Position...", end=" ") - AllKeyframes = set() - for Index, FCurve in enumerate(PositionFCurves): - if FCurve: - Keyframes = [] - for Keyframe in FCurve.keyframe_points: - Keyframes.append(Keyframe.co) - AllKeyframes.add(int(Keyframe.co[0])) - PositionFCurves[Index] = {int(Keyframe): Value for Keyframe, Value in Keyframes} - Config.File.write("{}AnimationKey {{ //Position\n".format(" " * Config.Whitespace)) - Config.Whitespace += 1 - AllKeyframes = list(AllKeyframes) - AllKeyframes.sort() - if not len(AllKeyframes): - AllKeyframes = [bpy.context.scene.frame_start] - Config.File.write("{}2;\n{}{};\n".format(" " * Config.Whitespace, " " * Config.Whitespace, len(AllKeyframes))) - for Keyframe in AllKeyframes: - bpy.context.scene.frame_set(Keyframe) - - if Bone.parent: - PoseMatrix = (Bone.parent.matrix * Matrix.Rotation(radians(-90), 4, "X")).invert() - else: - PoseMatrix = Matrix() - PoseMatrix *= Bone.matrix * Matrix.Rotation(radians(-90), 4, "X") - - PoseMatrix = Config.SystemMatrix * PoseMatrix * Config.InverseSystemMatrix - - Position = PoseMatrix.translation_part() - Config.File.write("{}{}{:9f},{:9f},{:9f};;\n".format(" " * Config.Whitespace, (str(Keyframe - bpy.context.scene.frame_start) + ";3;").ljust(8), Position[0], Position[1], Position[2])) - Config.Whitespace -= 1 - Config.File.write("{}}}\n".format(" " * Config.Whitespace)) - if Config.Verbose: - print("Done") - - #Rotation - if Config.Verbose: - print(" Writing Rotation...", end=" ") - AllKeyframes = set() - for Index, FCurve in enumerate(RotationFCurves): - if FCurve: - Keyframes = [] - for Keyframe in FCurve.keyframe_points: - Keyframes.append(Keyframe.co) - AllKeyframes.add(int(Keyframe.co[0])) - RotationFCurves[Index] = {int(Keyframe): Value for Keyframe, Value in Keyframes} - Config.File.write("{}AnimationKey {{ //Rotation\n".format(" " * Config.Whitespace)) - Config.Whitespace += 1 - AllKeyframes = list(AllKeyframes) - AllKeyframes.sort() - if not len(AllKeyframes): - AllKeyframes = [bpy.context.scene.frame_start] - Config.File.write("{}0;\n{}{};\n".format(" " * Config.Whitespace, " " * Config.Whitespace, len(AllKeyframes))) - for Keyframe in AllKeyframes: - bpy.context.scene.frame_set(Keyframe) - - if Bone.parent: - PoseMatrix = (Bone.parent.matrix * Matrix.Rotation(radians(-90), 4, "X")).invert() - else: - PoseMatrix = Matrix() - PoseMatrix *= Bone.matrix * Matrix.Rotation(radians(-90), 4, "X") - - PoseMatrix = Config.SystemMatrix * PoseMatrix * Config.InverseSystemMatrix - - Rotation = PoseMatrix.rotation_part().to_quat() - Config.File.write("{}{}{:9f},{:9f},{:9f},{:9f};;\n".format(" " * Config.Whitespace, (str(Keyframe - bpy.context.scene.frame_start) + ";4;").ljust(8), -Rotation[0], Rotation[1], Rotation[2], Rotation[3])) - Config.Whitespace -= 1 - Config.File.write("{}}}\n".format(" " * Config.Whitespace)) - if Config.Verbose: - print("Done") - - #Scale - if Config.Verbose: - print(" Writing Scale...", end=" ") - AllKeyframes = set() - for Index, FCurve in enumerate(ScaleFCurves): - if FCurve: - Keyframes = [] - for Keyframe in FCurve.keyframe_points: - Keyframes.append(Keyframe.co) - AllKeyframes.add(int(Keyframe.co[0])) - ScaleFCurves[Index] = {int(Keyframe): Value for Keyframe, Value in Keyframes} - Config.File.write("{}AnimationKey {{ //Scale\n".format(" " * Config.Whitespace)) - Config.Whitespace += 1 - AllKeyframes = list(AllKeyframes) - AllKeyframes.sort() - if not len(AllKeyframes): - AllKeyframes = [bpy.context.scene.frame_start] - Config.File.write("{}1;\n{}{};\n".format(" " * Config.Whitespace, " " * Config.Whitespace, len(AllKeyframes))) - for Keyframe in AllKeyframes: - bpy.context.scene.frame_set(Keyframe) - - if Bone.parent: - PoseMatrix = (Bone.parent.matrix * Matrix.Rotation(radians(-90), 4, "X")).invert() - else: - PoseMatrix = Matrix() - PoseMatrix *= Bone.matrix * Matrix.Rotation(radians(-90), 4, "X") - - PoseMatrix = Config.SystemMatrix * PoseMatrix * Config.InverseSystemMatrix - - Scale = PoseMatrix.scale_part() - Config.File.write("{}{}{:9f},{:9f},{:9f};;\n".format(" " * Config.Whitespace, (str(Keyframe - bpy.context.scene.frame_start) + ";3;").ljust(8), Scale[0], Scale[1], Scale[2])) - Config.Whitespace -= 1 - Config.File.write("{}}}\n".format(" " * Config.Whitespace)) - if Config.Verbose: - print("Done") - - Config.Whitespace -= 1 - Config.File.write("{}}}\n".format(" " * Config.Whitespace)) - if Config.Verbose: - print(" Done") #Done with Armature Bone - if Config.Verbose: - print(" Done") #Done with Armature Bone data - if Config.Verbose: - print(" Done") #Done with Object - - Config.Whitespace -= 1 - Config.File.write("{}}} //End of AnimationSet\n".format(" " * Config.Whitespace)) - - -def WriteFullAnimationSet(Config): - Config.File.write("{}AnimationSet {{\n".format(" " * Config.Whitespace)) - Config.Whitespace += 1 - - KeyframeCount = bpy.context.scene.frame_end - bpy.context.scene.frame_start + 1 - - for Object in Config.ObjectList: - if Config.Verbose: - print(" Writing Animation Data for Object: {}".format(Object.name)) - - Config.File.write("{}Animation {{\n".format(" " * Config.Whitespace)) - Config.Whitespace += 1 - Config.File.write("{}{{{}}}\n".format(" " * Config.Whitespace, LegalName(Object.name))) - - #Position - if Config.Verbose: - print(" Writing Position...", end=" ") - Config.File.write("{}AnimationKey {{ //Position\n".format(" " * Config.Whitespace)) - Config.Whitespace += 1 - Config.File.write("{}2;\n{}{};\n".format(" " * Config.Whitespace, " " * Config.Whitespace, KeyframeCount)) - for Frame in range(0, KeyframeCount): - bpy.context.scene.frame_set(Frame + bpy.context.scene.frame_start) - Position = Config.SystemMatrix * Object.location - Config.File.write("{}{}{:9f},{:9f},{:9f};;\n".format(" " * Config.Whitespace, (str(Frame) + ";3;").ljust(8), Position[0], Position[1], Position[2])) - Config.Whitespace -= 1 - Config.File.write("{}}}\n".format(" " * Config.Whitespace)) - if Config.Verbose: - print("Done") - - #Rotation - if Config.Verbose: - print(" Writing Rotation...", end=" ") - Config.File.write("{}AnimationKey {{ //Rotation\n".format(" " * Config.Whitespace)) - Config.Whitespace += 1 - Config.File.write("{}0;\n{}{};\n".format(" " * Config.Whitespace, " " * Config.Whitespace, KeyframeCount)) - for Frame in range(0, KeyframeCount): - bpy.context.scene.frame_set(Frame + bpy.context.scene.frame_start) - Rotation = Config.SystemQuaternion.cross(Object.rotation_euler.to_quat().cross(Config.InverseSystemQuaternion)) - Config.File.write("{}{}{:9f},{:9f},{:9f},{:9f};;\n".format(" " * Config.Whitespace, (str(Frame) + ";4;").ljust(8), Rotation[0], Rotation[1], Rotation[2], Config.FlipZ * Rotation[3])) - Config.Whitespace -= 1 - Config.File.write("{}}}\n".format(" " * Config.Whitespace)) - if Config.Verbose: - print("Done") - - #Scale - if Config.Verbose: - print(" Writing Scale...", end=" ") - Config.File.write("{}AnimationKey {{ //Scale\n".format(" " * Config.Whitespace)) - Config.Whitespace += 1 - Config.File.write("{}1;\n{}{};\n".format(" " * Config.Whitespace, " " * Config.Whitespace, KeyframeCount)) - for Frame in range(0, KeyframeCount): - bpy.context.scene.frame_set(Frame + bpy.context.scene.frame_start) - Scale = Config.SystemMatrix * Object.scale - Config.File.write("{}{}{:9f},{:9f},{:9f};;\n".format(" " * Config.Whitespace, (str(Frame) + ";3;").ljust(8), Scale[0], Scale[1], Scale[2])) - Config.Whitespace -= 1 - Config.File.write("{}}}\n".format(" " * Config.Whitespace)) - if Config.Verbose: - print("Done") - - Config.Whitespace -= 1 - Config.File.write("{}}}\n".format(" " * Config.Whitespace)) - - if Config.ExportArmatures and Object.type == "ARMATURE": - if Config.Verbose: - print(" Writing Armature Bone Animation Data...") - PoseBones = Object.pose.bones - for Bone in PoseBones: - if Config.Verbose: - print(" Writing Bone: {}...".format(Bone.name)) - - Config.File.write("{}Animation {{\n".format(" " * Config.Whitespace)) - Config.Whitespace += 1 - Config.File.write("{}{{{}}}\n".format(" " * Config.Whitespace, LegalName(Object.name) + "_" + LegalName(Bone.name))) - - #Position - if Config.Verbose: - print(" Writing Position...", end=" ") - Config.File.write("{}AnimationKey {{ //Position\n".format(" " * Config.Whitespace)) - Config.Whitespace += 1 - Config.File.write("{}2;\n{}{};\n".format(" " * Config.Whitespace, " " * Config.Whitespace, KeyframeCount)) - for Frame in range(0, KeyframeCount): - bpy.context.scene.frame_set(Frame + bpy.context.scene.frame_start) - - if Bone.parent: - PoseMatrix = (Bone.parent.matrix * Matrix.Rotation(radians(-90), 4, "X")).invert() - else: - PoseMatrix = Matrix() - PoseMatrix *= Bone.matrix * Matrix.Rotation(radians(-90), 4, "X") - - PoseMatrix = Config.SystemMatrix * PoseMatrix * Config.InverseSystemMatrix - - Position = PoseMatrix.translation_part() - Config.File.write("{}{}{:9f},{:9f},{:9f};;\n".format(" " * Config.Whitespace, (str(Frame) + ";3;").ljust(8), Position[0], Position[1], Position[2])) - Config.Whitespace -= 1 - Config.File.write("{}}}\n".format(" " * Config.Whitespace)) - if Config.Verbose: - print("Done") - - #Rotation - if Config.Verbose: - print(" Writing Rotation...", end=" ") - Config.File.write("{}AnimationKey {{ //Rotation\n".format(" " * Config.Whitespace)) - Config.Whitespace += 1 - Config.File.write("{}0;\n{}{};\n".format(" " * Config.Whitespace, " " * Config.Whitespace, KeyframeCount)) - for Frame in range(0, KeyframeCount): - bpy.context.scene.frame_set(Frame + bpy.context.scene.frame_start) - #Whew! I'm sure this could be simplified. - Rotation = Config.SystemQuaternion.cross(Matrix.Rotation(radians(90), 4, "X").to_quat().cross(Bone.rotation_quaternion.cross(Matrix.Rotation(radians(-90), 4, "X").to_quat().cross(Config.InverseSystemQuaternion)))) - Config.File.write("{}{}{:9f},{:9f},{:9f},{:9f};;\n".format(" " * Config.Whitespace, (str(Frame) + ";4;").ljust(8), Rotation[0], Rotation[1], Rotation[2], Config.FlipZ * Rotation[3])) - Config.Whitespace -= 1 - Config.File.write("{}}}\n".format(" " * Config.Whitespace)) - if Config.Verbose: - print("Done") - - #Scale - if Config.Verbose: - print(" Writing Scale...", end=" ") - Config.File.write("{}AnimationKey {{ //Scale\n".format(" " * Config.Whitespace, KeyframeCount)) - Config.Whitespace += 1 - Config.File.write("{}1;\n{}{};\n".format(" " * Config.Whitespace, " " * Config.Whitespace, KeyframeCount)) - for Frame in range(0, KeyframeCount): - bpy.context.scene.frame_set(Frame + bpy.context.scene.frame_start) - - if Bone.parent: - PoseMatrix = (Bone.parent.matrix * Matrix.Rotation(radians(-90), 4, "X")).invert() - else: - PoseMatrix = Matrix() - PoseMatrix *= Bone.matrix * Matrix.Rotation(radians(-90), 4, "X") - - PoseMatrix = Config.SystemMatrix * PoseMatrix * Config.InverseSystemMatrix - - Scale = PoseMatrix.scale_part() - Config.File.write("{}{}{:9f},{:9f},{:9f};;\n".format(" " * Config.Whitespace, (str(Frame) + ";3;").ljust(8), Scale[0], Scale[1], Scale[2])) - Config.Whitespace -= 1 - Config.File.write("{}}}\n".format(" " * Config.Whitespace)) - if Config.Verbose: - print("Done") - - Config.Whitespace -= 1 - Config.File.write("{}}}\n".format(" " * Config.Whitespace)) - if Config.Verbose: - print(" Done") #Done with Armature Bone - if Config.Verbose: - print(" Done") #Done with Armature Bone data - if Config.Verbose: - print(" Done") #Done with Object - - Config.Whitespace -= 1 - Config.File.write("{}}} //End of AnimationSet\n".format(" " * Config.Whitespace)) - - -def CloseFile(Config): - if Config.Verbose: - print("Closing File...", end=" ") - Config.File.close() - if Config.Verbose: - print("Done") - -CoordinateSystems = [] -CoordinateSystems.append(("1", "Left-Handed", "")) -CoordinateSystems.append(("2", "Right-Handed", "")) - -AnimationModes = [] -AnimationModes.append(("0", "None", "")) -AnimationModes.append(("1", "Keyframes Only", "")) -AnimationModes.append(("2", "Full Animation", "")) - -ExportModes = [] -ExportModes.append(("1", "All Objects", "")) -ExportModes.append(("2", "Selected Objects", "")) - -from bpy.props import * - - -class DirectXExporter(bpy.types.Operator): - """Export to the DirectX model format (.x)""" - - bl_idname = "export.directx" - bl_label = "Export DirectX" - - filepath = StringProperty() - filename = StringProperty() - directory = StringProperty() - - #Coordinate System - CoordinateSystem = EnumProperty(name="System", description="Select a coordinate system to export to", items=CoordinateSystems, default="1") - - #General Options - RotateX = BoolProperty(name="Rotate X 90 Degrees", description="Rotate the entire scene 90 degrees around the X axis so Y is up.", default=True) - FlipNormals = BoolProperty(name="Flip Normals", description="", default=False) - ApplyModifiers = BoolProperty(name="Apply Modifiers", description="Apply object modifiers before export.", default=False) - IncludeFrameRate = BoolProperty(name="Include Frame Rate", description="Include the AnimTicksPerSecond template which is used by some engines to control animation speed.", default=False) - ExportTextures = BoolProperty(name="Export Textures", description="Reference external image files to be used by the model.", default=True) - ExportArmatures = BoolProperty(name="Export Armatures", description="Export the bones of any armatures to deform meshes.", default=False) - ExportAnimation = EnumProperty(name="Animations", description="Select the type of animations to export. Only object and armature bone animations can be exported. Full Animation exports every frame.", items=AnimationModes, default="0") - - #Export Mode - ExportMode = EnumProperty(name="Export", description="Select which objects to export. Only Mesh, Empty, and Armature objects will be exported.", items=ExportModes, default="1") - - Verbose = BoolProperty(name="Verbose", description="Run the exporter in debug mode. Check the console for output.", default=False) - - def execute(self, context): - #Append .x if needed - FilePath = self.properties.filepath - if not FilePath.lower().endswith(".x"): - FilePath += ".x" - - Config = DirectXExporterSettings(context, - FilePath, - CoordinateSystem=self.properties.CoordinateSystem, - RotateX=self.properties.RotateX, - FlipNormals=self.properties.FlipNormals, - ApplyModifiers=self.properties.ApplyModifiers, - IncludeFrameRate=self.properties.IncludeFrameRate, - ExportTextures=self.properties.ExportTextures, - ExportArmatures=self.properties.ExportArmatures, - ExportAnimation=self.properties.ExportAnimation, - ExportMode=self.properties.ExportMode, - Verbose=self.properties.Verbose) - ExportDirectX(Config) - return {"FINISHED"} - - def invoke(self, context, event): - WindowManager = context.window_manager - WindowManager.add_fileselect(self) - return {"RUNNING_MODAL"} - - -def menu_func(self, context): - default_path = os.path.splitext(bpy.data.filepath)[0] + ".x" - self.layout.operator(DirectXExporter.bl_idname, text="DirectX (.x)").filepath = default_path - - -def register(): - bpy.types.INFO_MT_file_export.append(menu_func) - - -def unregister(): - bpy.types.INFO_MT_file_export.remove(menu_func) - - -if __name__ == "__main__": - register() diff --git a/io_export_unreal_psk_psa.py b/io_export_unreal_psk_psa.py deleted file mode 100644 index 46cb0ae5..00000000 --- a/io_export_unreal_psk_psa.py +++ /dev/null @@ -1,1593 +0,0 @@ - # ***** 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 3 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, see . - # All rights reserved. - # ***** GPL LICENSE BLOCK ***** - -bl_addon_info = { - "name": "Export Skeleletal Mesh/Animation Data", - "author": "Darknet/Optimus_P-Fat/Active_Trash/Sinsoft", - "version": (2,0), - "blender": (2, 5, 3), - "api": 31667, - "location": "File > Export > Skeletal Mesh/Animation Data (.psk/.psa)", - "description": "Export Unreal Engine (.psk)", - "warning": "", - "wiki_url": "http://wiki.blender.org/index.php/Extensions:2.5/Py/"\ - "Scripts/File_I-O/Unreal_psk_psa", - "tracker_url": "https://projects.blender.org/tracker/index.php?"\ - "func=detail&aid=21366&group_id=153&atid=469", - "category": "Import/Export"} - -""" --- Unreal Skeletal Mesh and Animation Export (.psk and .psa) export script v0.0.1 --
- -- NOTES: -- This script Exports To Unreal's PSK and PSA file formats for Skeletal Meshes and Animations.
-- This script DOES NOT support vertex animation! These require completely different file formats.
- -- v0.0.1 -- Initial version - -- v0.0.2 -- This version adds support for more than one material index! - -[ - Edit by: Darknet -- v0.0.3 - v0.0.12 -- This will work on UT3 and it is a stable version that work with vehicle for testing. -- Main Bone fix no dummy needed to be there. -- Just bone issues position, rotation, and offset for psk. -- The armature bone position, rotation, and the offset of the bone is fix. It was to deal with skeleton mesh export for psk. -- Animation is fix for position, offset, rotation bone support one rotation direction when armature build. -- It will convert your mesh into triangular when exporting to psk file. -- Did not work with psa export yet. - -- v0.0.13 -- The animatoin will support different bone rotations when export the animation. - -- v0.0.14 -- Fixed Action set keys frames when there is no pose keys and it will ignore it. - -- v0.0.15 -- Fixed multiple objects when exporting to psk. Select one mesh to export to psk. -- ] - -- v0.1.1 -- Blender 2.50 svn (Support) - -Credit to: -- export_cal3d.py (Position of the Bones Format) -- blender2md5.py (Animation Translation Format) -- export_obj.py (Blender 2.5/Pyhton 3.x Format) - -- freenode #blendercoder -> user -> ideasman42 - -- Give Credit to those who work on this script. - -- http://sinsoft.com -""" - -import os -import time -import datetime -import bpy -import mathutils -import operator - -from struct import pack, calcsize - - -# REFERENCE MATERIAL JUST IN CASE: -# -# U = x / sqrt(x^2 + y^2 + z^2) -# V = y / sqrt(x^2 + y^2 + z^2) -# -# Triangles specifed counter clockwise for front face -# -#defines for sizeofs -SIZE_FQUAT = 16 -SIZE_FVECTOR = 12 -SIZE_VJOINTPOS = 44 -SIZE_ANIMINFOBINARY = 168 -SIZE_VCHUNKHEADER = 32 -SIZE_VMATERIAL = 88 -SIZE_VBONE = 120 -SIZE_FNAMEDBONEBINARY = 120 -SIZE_VRAWBONEINFLUENCE = 12 -SIZE_VQUATANIMKEY = 32 -SIZE_VVERTEX = 16 -SIZE_VPOINT = 12 -SIZE_VTRIANGLE = 12 - -######################################################################## -# Generic Object->Integer mapping -# the object must be usable as a dictionary key -class ObjMap: - def __init__(self): - self.dict = {} - self.next = 0 - def get(self, obj): - if obj in self.dict: - return self.dict[obj] - else: - id = self.next - self.next = self.next + 1 - self.dict[obj] = id - return id - - def items(self): - getval = operator.itemgetter(0) - getkey = operator.itemgetter(1) - return map(getval, sorted(self.dict.items(), key=getkey)) - -######################################################################## -# RG - UNREAL DATA STRUCTS - CONVERTED FROM C STRUCTS GIVEN ON UDN SITE -# provided here: http://udn.epicgames.com/Two/BinaryFormatSpecifications.html -# updated UDK (Unreal Engine 3): http://udn.epicgames.com/Three/BinaryFormatSpecifications.html -class FQuat: - def __init__(self): - self.X = 0.0 - self.Y = 0.0 - self.Z = 0.0 - self.W = 1.0 - - def dump(self): - data = pack('ffff', self.X, self.Y, self.Z, self.W) - return data - - def __cmp__(self, other): - return cmp(self.X, other.X) \ - or cmp(self.Y, other.Y) \ - or cmp(self.Z, other.Z) \ - or cmp(self.W, other.W) - - def __hash__(self): - return hash(self.X) ^ hash(self.Y) ^ hash(self.Z) ^ hash(self.W) - - def __str__(self): - return "[%f,%f,%f,%f](FQuat)" % (self.X, self.Y, self.Z, self.W) - -class FVector(object): - def __init__(self, X=0.0, Y=0.0, Z=0.0): - self.X = X - self.Y = Y - self.Z = Z - - def dump(self): - data = pack('fff', self.X, self.Y, self.Z) - return data - - def __cmp__(self, other): - return cmp(self.X, other.X) \ - or cmp(self.Y, other.Y) \ - or cmp(self.Z, other.Z) - - def _key(self): - return (type(self).__name__, self.X, self.Y, self.Z) - - def __hash__(self): - return hash(self._key()) - - def __eq__(self, other): - if not hasattr(other, '_key'): - return False - return self._key() == other._key() - - def dot(self, other): - return self.X * other.X + self.Y * other.Y + self.Z * other.Z - - def cross(self, other): - return FVector(self.Y * other.Z - self.Z * other.Y, - self.Z * other.X - self.X * other.Z, - self.X * other.Y - self.Y * other.X) - - def sub(self, other): - return FVector(self.X - other.X, - self.Y - other.Y, - self.Z - other.Z) - -class VJointPos: - def __init__(self): - self.Orientation = FQuat() - self.Position = FVector() - self.Length = 0.0 - self.XSize = 0.0 - self.YSize = 0.0 - self.ZSize = 0.0 - - def dump(self): - data = self.Orientation.dump() + self.Position.dump() + pack('4f', self.Length, self.XSize, self.YSize, self.ZSize) - return data - -class AnimInfoBinary: - def __init__(self): - self.Name = "" # length=64 - self.Group = "" # length=64 - self.TotalBones = 0 - self.RootInclude = 0 - self.KeyCompressionStyle = 0 - self.KeyQuotum = 0 - self.KeyPrediction = 0.0 - self.TrackTime = 0.0 - self.AnimRate = 0.0 - self.StartBone = 0 - self.FirstRawFrame = 0 - self.NumRawFrames = 0 - - def dump(self): - data = pack('64s64siiiifffiii', self.Name, self.Group, self.TotalBones, self.RootInclude, self.KeyCompressionStyle, self.KeyQuotum, self.KeyPrediction, self.TrackTime, self.AnimRate, self.StartBone, self.FirstRawFrame, self.NumRawFrames) - return data - -class VChunkHeader: - def __init__(self, name, type_size): - self.ChunkID = name # length=20 - self.TypeFlag = 1999801 # special value - self.DataSize = type_size - self.DataCount = 0 - - def dump(self): - data = pack('20siii', self.ChunkID, self.TypeFlag, self.DataSize, self.DataCount) - return data - -class VMaterial: - def __init__(self): - self.MaterialName = "" # length=64 - self.TextureIndex = 0 - self.PolyFlags = 0 # DWORD - self.AuxMaterial = 0 - self.AuxFlags = 0 # DWORD - self.LodBias = 0 - self.LodStyle = 0 - - def dump(self): - data = pack('64siLiLii', self.MaterialName, self.TextureIndex, self.PolyFlags, self.AuxMaterial, self.AuxFlags, self.LodBias, self.LodStyle) - return data - -class VBone: - def __init__(self): - self.Name = "" # length = 64 - self.Flags = 0 # DWORD - self.NumChildren = 0 - self.ParentIndex = 0 - self.BonePos = VJointPos() - - def dump(self): - data = pack('64sLii', self.Name, self.Flags, self.NumChildren, self.ParentIndex) + self.BonePos.dump() - return data - -#same as above - whatever - this is how Epic does it... -class FNamedBoneBinary: - def __init__(self): - self.Name = "" # length = 64 - self.Flags = 0 # DWORD - self.NumChildren = 0 - self.ParentIndex = 0 - self.BonePos = VJointPos() - - self.IsRealBone = 0 # this is set to 1 when the bone is actually a bone in the mesh and not a dummy - - def dump(self): - data = pack('64sLii', self.Name, self.Flags, self.NumChildren, self.ParentIndex) + self.BonePos.dump() - return data - -class VRawBoneInfluence: - def __init__(self): - self.Weight = 0.0 - self.PointIndex = 0 - self.BoneIndex = 0 - - def dump(self): - data = pack('fii', self.Weight, self.PointIndex, self.BoneIndex) - return data - -class VQuatAnimKey: - def __init__(self): - self.Position = FVector() - self.Orientation = FQuat() - self.Time = 0.0 - - def dump(self): - data = self.Position.dump() + self.Orientation.dump() + pack('f', self.Time) - return data - -class VVertex(object): - def __init__(self): - self.PointIndex = 0 # WORD - self.U = 0.0 - self.V = 0.0 - self.MatIndex = 0 #BYTE - self.Reserved = 0 #BYTE - - def dump(self): - data = pack('HHffBBH', self.PointIndex, 0, self.U, self.V, self.MatIndex, self.Reserved, 0) - return data - - def __cmp__(self, other): - return cmp(self.PointIndex, other.PointIndex) \ - or cmp(self.U, other.U) \ - or cmp(self.V, other.V) \ - or cmp(self.MatIndex, other.MatIndex) \ - or cmp(self.Reserved, other.Reserved) - - def _key(self): - return (type(self).__name__,self.PointIndex, self.U, self.V,self.MatIndex,self.Reserved) - - def __hash__(self): - return hash(self._key()) - - def __eq__(self, other): - if not hasattr(other, '_key'): - return False - return self._key() == other._key() - -class VPoint(object): - def __init__(self): - self.Point = FVector() - - def dump(self): - return self.Point.dump() - - def __cmp__(self, other): - return cmp(self.Point, other.Point) - - def _key(self): - return (type(self).__name__, self.Point) - - def __hash__(self): - return hash(self._key()) - - def __eq__(self, other): - if not hasattr(other, '_key'): - return False - return self._key() == other._key() - -class VTriangle: - def __init__(self): - self.WedgeIndex0 = 0 # WORD - self.WedgeIndex1 = 0 # WORD - self.WedgeIndex2 = 0 # WORD - self.MatIndex = 0 # BYTE - self.AuxMatIndex = 0 # BYTE - self.SmoothingGroups = 0 # DWORD - - def dump(self): - data = pack('HHHBBL', self.WedgeIndex0, self.WedgeIndex1, self.WedgeIndex2, self.MatIndex, self.AuxMatIndex, self.SmoothingGroups) - return data - -# END UNREAL DATA STRUCTS -######################################################################## - -######################################################################## -#RG - helper class to handle the normal way the UT files are stored -#as sections consisting of a header and then a list of data structures -class FileSection: - def __init__(self, name, type_size): - self.Header = VChunkHeader(name, type_size) - self.Data = [] # list of datatypes - - def dump(self): - data = self.Header.dump() - for i in range(len(self.Data)): - data = data + self.Data[i].dump() - return data - - def UpdateHeader(self): - self.Header.DataCount = len(self.Data) - -class PSKFile: - def __init__(self): - self.GeneralHeader = VChunkHeader("ACTRHEAD", 0) - self.Points = FileSection("PNTS0000", SIZE_VPOINT) #VPoint - self.Wedges = FileSection("VTXW0000", SIZE_VVERTEX) #VVertex - self.Faces = FileSection("FACE0000", SIZE_VTRIANGLE) #VTriangle - self.Materials = FileSection("MATT0000", SIZE_VMATERIAL) #VMaterial - self.Bones = FileSection("REFSKELT", SIZE_VBONE) #VBone - self.Influences = FileSection("RAWWEIGHTS", SIZE_VRAWBONEINFLUENCE) #VRawBoneInfluence - - #RG - this mapping is not dumped, but is used internally to store the new point indices - # for vertex groups calculated during the mesh dump, so they can be used again - # to dump bone influences during the armature dump - # - # the key in this dictionary is the VertexGroup/Bone Name, and the value - # is a list of tuples containing the new point index and the weight, in that order - # - # Layout: - # { groupname : [ (index, weight), ... ], ... } - # - # example: - # { 'MyVertexGroup' : [ (0, 1.0), (5, 1.0), (3, 0.5) ] , 'OtherGroup' : [(2, 1.0)] } - - self.VertexGroups = {} - - def AddPoint(self, p): - #print ('AddPoint') - self.Points.Data.append(p) - - def AddWedge(self, w): - #print ('AddWedge') - self.Wedges.Data.append(w) - - def AddFace(self, f): - #print ('AddFace') - self.Faces.Data.append(f) - - def AddMaterial(self, m): - #print ('AddMaterial') - self.Materials.Data.append(m) - - def AddBone(self, b): - #print ('AddBone [%s]: Position: (x=%f, y=%f, z=%f) Rotation=(%f,%f,%f,%f)' % (b.Name, b.BonePos.Position.X, b.BonePos.Position.Y, b.BonePos.Position.Z, b.BonePos.Orientation.X,b.BonePos.Orientation.Y,b.BonePos.Orientation.Z,b.BonePos.Orientation.W)) - self.Bones.Data.append(b) - - def AddInfluence(self, i): - #print ('AddInfluence') - self.Influences.Data.append(i) - - def UpdateHeaders(self): - self.Points.UpdateHeader() - self.Wedges.UpdateHeader() - self.Faces.UpdateHeader() - self.Materials.UpdateHeader() - self.Bones.UpdateHeader() - self.Influences.UpdateHeader() - - def dump(self): - self.UpdateHeaders() - data = self.GeneralHeader.dump() + self.Points.dump() + self.Wedges.dump() + self.Faces.dump() + self.Materials.dump() + self.Bones.dump() + self.Influences.dump() - return data - - def GetMatByIndex(self, mat_index): - if mat_index >= 0 and len(self.Materials.Data) > mat_index: - return self.Materials.Data[mat_index] - else: - m = VMaterial() - m.MaterialName = "Mat%i" % mat_index - self.AddMaterial(m) - return m - - def PrintOut(self): - print ("--- PSK FILE EXPORTED ---") - print ('point count: %i' % len(self.Points.Data)) - print ('wedge count: %i' % len(self.Wedges.Data)) - print ('face count: %i' % len(self.Faces.Data)) - print ('material count: %i' % len(self.Materials.Data)) - print ('bone count: %i' % len(self.Bones.Data)) - print ('inlfuence count: %i' % len(self.Influences.Data)) - print ('-------------------------') - -# PSA FILE NOTES FROM UDN: -# -# The raw key array holds all the keys for all the bones in all the specified sequences, -# organized as follows: -# For each AnimInfoBinary's sequence there are [Number of bones] times [Number of frames keys] -# in the VQuatAnimKeys, laid out as tracks of [numframes] keys for each bone in the order of -# the bones as defined in the array of FnamedBoneBinary in the PSA. -# -# Once the data from the PSK (now digested into native skeletal mesh) and PSA (digested into -# a native animation object containing one or more sequences) are associated together at runtime, -# bones are linked up by name. Any bone in a skeleton (from the PSK) that finds no partner in -# the animation sequence (from the PSA) will assume its reference pose stance ( as defined in -# the offsets & rotations that are in the VBones making up the reference skeleton from the PSK) - -class PSAFile: - def __init__(self): - self.GeneralHeader = VChunkHeader("ANIMHEAD", 0) - self.Bones = FileSection("BONENAMES", SIZE_FNAMEDBONEBINARY) #FNamedBoneBinary - self.Animations = FileSection("ANIMINFO", SIZE_ANIMINFOBINARY) #AnimInfoBinary - self.RawKeys = FileSection("ANIMKEYS", SIZE_VQUATANIMKEY) #VQuatAnimKey - - # this will take the format of key=Bone Name, value = (BoneIndex, Bone Object) - # THIS IS NOT DUMPED - self.BoneLookup = {} - - def dump(self): - data = self.Generalheader.dump() + self.Bones.dump() + self.Animations.dump() + self.RawKeys.dump() - return data - - def AddBone(self, b): - #LOUD - #print "AddBone: " + b.Name - self.Bones.Data.append(b) - - def AddAnimation(self, a): - #LOUD - #print "AddAnimation: %s, TotalBones: %i, AnimRate: %f, NumRawFrames: %i, TrackTime: %f" % (a.Name, a.TotalBones, a.AnimRate, a.NumRawFrames, a.TrackTime) - self.Animations.Data.append(a) - - def AddRawKey(self, k): - #LOUD - #print "AddRawKey [%i]: Time: %f, Quat: x=%f, y=%f, z=%f, w=%f, Position: x=%f, y=%f, z=%f" % (len(self.RawKeys.Data), k.Time, k.Orientation.X, k.Orientation.Y, k.Orientation.Z, k.Orientation.W, k.Position.X, k.Position.Y, k.Position.Z) - self.RawKeys.Data.append(k) - - def UpdateHeaders(self): - self.Bones.UpdateHeader() - self.Animations.UpdateHeader() - self.RawKeys.UpdateHeader() - - def GetBoneByIndex(self, bone_index): - if bone_index >= 0 and len(self.Bones.Data) > bone_index: - return self.Bones.Data[bone_index] - - def IsEmpty(self): - return (len(self.Bones.Data) == 0 or len(self.Animations.Data) == 0) - - def StoreBone(self, b): - self.BoneLookup[b.Name] = [-1, b] - - def UseBone(self, bone_name): - if bone_name in self.BoneLookup: - bone_data = self.BoneLookup[bone_name] - - if bone_data[0] == -1: - bone_data[0] = len(self.Bones.Data) - self.AddBone(bone_data[1]) - #self.Bones.Data.append(bone_data[1]) - - return bone_data[0] - - def GetBoneByName(self, bone_name): - if bone_name in self.BoneLookup: - bone_data = self.BoneLookup[bone_name] - return bone_data[1] - - def GetBoneIndex(self, bone_name): - if bone_name in self.BoneLookup: - bone_data = self.BoneLookup[bone_name] - return bone_data[0] - - def dump(self): - self.UpdateHeaders() - data = self.GeneralHeader.dump() + self.Bones.dump() + self.Animations.dump() + self.RawKeys.dump() - return data - - def PrintOut(self): - print ('--- PSA FILE EXPORTED ---') - print ('bone count: %i' % len(self.Bones.Data)) - print ('animation count: %i' % len(self.Animations.Data)) - print ('rawkey count: %i' % len(self.RawKeys.Data)) - print ('-------------------------') - -#################################### -# helpers to create bone structs -def make_vbone(name, parent_index, child_count, orientation_quat, position_vect): - bone = VBone() - bone.Name = name - bone.ParentIndex = parent_index - bone.NumChildren = child_count - bone.BonePos.Orientation = orientation_quat - bone.BonePos.Position.X = position_vect.x - bone.BonePos.Position.Y = position_vect.y - bone.BonePos.Position.Z = position_vect.z - - #these values seem to be ignored? - #bone.BonePos.Length = tail.length - #bone.BonePos.XSize = tail.x - #bone.BonePos.YSize = tail.y - #bone.BonePos.ZSize = tail.z - - return bone - -def make_namedbonebinary(name, parent_index, child_count, orientation_quat, position_vect, is_real): - bone = FNamedBoneBinary() - bone.Name = name - bone.ParentIndex = parent_index - bone.NumChildren = child_count - bone.BonePos.Orientation = orientation_quat - bone.BonePos.Position.X = position_vect.x - bone.BonePos.Position.Y = position_vect.y - bone.BonePos.Position.Z = position_vect.z - bone.IsRealBone = is_real - return bone - -################################################## -#RG - check to make sure face isnt a line -#The face has to be triangle not a line -def is_1d_face(blender_face,mesh): - #ID Vertex of id point - v0 = blender_face.vertices[0] - v1 = blender_face.vertices[1] - v2 = blender_face.vertices[2] - - return (mesh.vertices[v0].co == mesh.vertices[v1].co or \ - mesh.vertices[v1].co == mesh.vertices[v2].co or \ - mesh.vertices[v2].co == mesh.vertices[v0].co) - return False - -################################################## -# http://en.wikibooks.org/wiki/Blender_3D:_Blending_Into_Python/Cookbook#Triangulate_NMesh - -#blender 2.50 format using the Operators/command convert the mesh to tri mesh -def triangulateNMesh(object): - bneedtri = False - scene = bpy.context.scene - bpy.ops.object.mode_set(mode='OBJECT') - for i in scene.objects: i.select = False #deselect all objects - object.select = True - scene.objects.active = object #set the mesh object to current - bpy.ops.object.mode_set(mode='OBJECT') - print("Checking mesh if needs to convert quad to Tri...") - for face in object.data.faces: - if (len(face.vertices) > 3): - bneedtri = True - break - - bpy.ops.object.mode_set(mode='OBJECT') - if bneedtri == True: - print("Converting quad to tri mesh...") - me_da = object.data.copy() #copy data - me_ob = object.copy() #copy object - #note two copy two types else it will use the current data or mesh - me_ob.data = me_da - bpy.context.scene.objects.link(me_ob)#link the object to the scene #current object location - for i in scene.objects: i.select = False #deselect all objects - me_ob.select = True - scene.objects.active = me_ob #set the mesh object to current - bpy.ops.object.mode_set(mode='EDIT') #Operators - bpy.ops.mesh.select_all(action='SELECT')#select all the face/vertex/edge - bpy.ops.mesh.quads_convert_to_tris() #Operators - bpy.context.scene.update() - bpy.ops.object.mode_set(mode='OBJECT') # set it in object - bpy.context.scene.unrealtriangulatebool = True - print("Triangulate Mesh Done!") - else: - print("No need to convert tri mesh.") - me_ob = object - return me_ob - -#Blender Bone Index -class BBone: - def __init__(self): - self.bone = "" - self.index = 0 -bonedata = [] -BBCount = 0 -#deal with mesh bones groups vertex point -def BoneIndex(bone): - global BBCount, bonedata - #print("//==============") - #print(bone.name , "ID:",BBCount) - BB = BBone() - BB.bone = bone.name - BB.index = BBCount - bonedata.append(BB) - BBCount += 1 - for current_child_bone in bone.children: - BoneIndex(current_child_bone) - -def BoneIndexArmature(blender_armature): - global BBCount - #print("\n Buildng bone before mesh \n") - #objectbone = blender_armature.pose #Armature bone - #print(blender_armature) - objectbone = blender_armature[0].pose - #print(dir(ArmatureData)) - - for bone in objectbone.bones: - if(bone.parent == None): - BoneIndex(bone) - #BBCount += 1 - break - -# Actual object parsing functions -def parse_meshes(blender_meshes, psk_file): - #this is use to call the bone name and the index array for group index matches - global bonedata - #print("BONE DATA",len(bonedata)) - print ("----- parsing meshes -----") - print("Number of Object Meshes:",len(blender_meshes)) - for current_obj in blender_meshes: #number of mesh that should be one mesh here - - current_obj = triangulateNMesh(current_obj) - #print(dir(current_obj)) - print("Mesh Name:",current_obj.name) - current_mesh = current_obj.data - - #if len(current_obj.materials) > 0: - # object_mat = current_obj.materials[0] - object_material_index = current_obj.active_material_index - - points = ObjMap() - wedges = ObjMap() - - discarded_face_count = 0 - print (" -- Dumping Mesh Faces -- LEN:", len(current_mesh.faces)) - for current_face in current_mesh.faces: - #print ' -- Dumping UVs -- ' - #print current_face.uv_textures - - if len(current_face.vertices) != 3: - raise RuntimeError("Non-triangular face (%i)" % len(current_face.vertices)) - - #No Triangulate Yet - # if len(current_face.vertices) != 3: - # raise RuntimeError("Non-triangular face (%i)" % len(current_face.vertices)) - # #TODO: add two fake faces made of triangles? - - #RG - apparently blender sometimes has problems when you do quad to triangle - # conversion, and ends up creating faces that have only TWO points - - # one of the points is simply in the vertex list for the face twice. - # This is bad, since we can't get a real face normal for a LINE, we need - # a plane for this. So, before we add the face to the list of real faces, - # ensure that the face is actually a plane, and not a line. If it is not - # planar, just discard it and notify the user in the console after we're - # done dumping the rest of the faces - - if not is_1d_face(current_face,current_mesh): - #print("faces") - wedge_list = [] - vect_list = [] - - #get or create the current material - m = psk_file.GetMatByIndex(object_material_index) - - face_index = current_face.index - has_UV = False - faceUV = None - - if len(current_mesh.uv_textures) > 0: - has_UV = True - #print("face index: ",face_index) - #faceUV = current_mesh.uv_textures.active.data[face_index]#UVs for current face - #faceUV = current_mesh.uv_textures.active.data[0]#UVs for current face - #print(face_index,"<[FACE NUMBER") - uv_layer = current_mesh.uv_textures.active - faceUV = uv_layer.data[face_index] - #print("============================") - #size(data) is number of texture faces. Each face has UVs - #print("DATA face uv: ",len(faceUV.uv), " >> ",(faceUV.uv[0][0])) - - for i in range(3): - vert_index = current_face.vertices[i] - vert = current_mesh.vertices[vert_index] - uv = [] - #assumes 3 UVs Per face (for now). - if (has_UV): - if len(faceUV.uv) != 3: - print ("WARNING: Current face is missing UV coordinates - writing 0,0...") - print ("WARNING: Face has more than 3 UVs - writing 0,0...") - uv = [0.0, 0.0] - else: - #uv.append(faceUV.uv[i][0]) - #uv.append(faceUV.uv[i][1]) - uv = [faceUV.uv[i][0],faceUV.uv[i][1]] #OR bottom works better # 24 for cube - #uv = list(faceUV.uv[i]) #30 just cube - else: - print ("No UVs?") - uv = [0.0, 0.0] - #print("UV >",uv) - #uv = [0.0, 0.0] #over ride uv that is not fixed - #print(uv) - #flip V coordinate because UEd requires it and DOESN'T flip it on its own like it - #does with the mesh Y coordinates. - #this is otherwise known as MAGIC-2 - uv[1] = 1.0 - uv[1] - - #deal with the min and max value - #if value is over the set limit it will null the uv texture - if (uv[0] > 1): - uv[0] = 1 - if (uv[0] < 0): - uv[0] = 0 - if (uv[1] > 1): - uv[1] = 1 - if (uv[1] < 0): - uv[1] = 0 - - - # RE - Append untransformed vector (for normal calc below) - # TODO: convert to Blender.Mathutils - vect_list.append(FVector(vert.co.x, vert.co.y, vert.co.z)) - - # Transform position for export - #vpos = vert.co * object_material_index - vpos = vert.co * current_obj.matrix_local - # Create the point - p = VPoint() - p.Point.X = vpos.x - p.Point.Y = vpos.y - p.Point.Z = vpos.z - - # Create the wedge - w = VVertex() - w.MatIndex = object_material_index - w.PointIndex = points.get(p) # get index from map - #Set UV TEXTURE - w.U = uv[0] - w.V = uv[1] - index_wedge = wedges.get(w) - wedge_list.append(index_wedge) - - #print results - #print 'result PointIndex=%i, U=%f, V=%f, wedge_index=%i' % ( - # w.PointIndex, - # w.U, - # w.V, - # wedge_index) - - # Determine face vertex order - # get normal from blender - no = current_face.normal - - # TODO: convert to Blender.Mathutils - # convert to FVector - norm = FVector(no[0], no[1], no[2]) - - # Calculate the normal of the face in blender order - tnorm = vect_list[1].sub(vect_list[0]).cross(vect_list[2].sub(vect_list[1])) - - # RE - dot the normal from blender order against the blender normal - # this gives the product of the two vectors' lengths along the blender normal axis - # all that matters is the sign - dot = norm.dot(tnorm) - - # print results - #print 'face norm: (%f,%f,%f), tnorm=(%f,%f,%f), dot=%f' % ( - # norm.X, norm.Y, norm.Z, - # tnorm.X, tnorm.Y, tnorm.Z, - # dot) - - tri = VTriangle() - # RE - magic: if the dot product above > 0, order the vertices 2, 1, 0 - # if the dot product above < 0, order the vertices 0, 1, 2 - # if the dot product is 0, then blender's normal is coplanar with the face - # and we cannot deduce which side of the face is the outside of the mesh - if (dot > 0): - (tri.WedgeIndex2, tri.WedgeIndex1, tri.WedgeIndex0) = wedge_list - elif (dot < 0): - (tri.WedgeIndex0, tri.WedgeIndex1, tri.WedgeIndex2) = wedge_list - else: - dindex0 = current_face.vertices[0]; - dindex1 = current_face.vertices[1]; - dindex2 = current_face.vertices[2]; - raise RuntimeError("normal vector coplanar with face! points:", current_mesh.vertices[dindex0].co, current_mesh.vertices[dindex1].co, current_mesh.vertices[dindex2].co) - - tri.MatIndex = object_material_index - #print(tri) - psk_file.AddFace(tri) - - else: - discarded_face_count = discarded_face_count + 1 - - print (" -- Dumping Mesh Points -- LEN:",len(points.dict)) - for point in points.items(): - psk_file.AddPoint(point) - print (" -- Dumping Mesh Wedge -- LEN:",len(wedges.dict)) - for wedge in wedges.items(): - psk_file.AddWedge(wedge) - - #RG - if we happend upon any non-planar faces above that we've discarded, - # just let the user know we discarded them here in case they want - # to investigate - - if discarded_face_count > 0: - print ("INFO: Discarded %i non-planar faces." % (discarded_face_count)) - - #RG - walk through the vertex groups and find the indexes into the PSK points array - #for them, then store that index and the weight as a tuple in a new list of - #verts for the group that we can look up later by bone name, since Blender matches - #verts to bones for influences by having the VertexGroup named the same thing as - #the bone - - #vertex group. - for bonegroup in bonedata: - #print("bone gourp build:",bonegroup.bone) - vert_list = [] - for current_vert in current_mesh.vertices: - #print("INDEX V:",current_vert.index) - vert_index = current_vert.index - for vgroup in current_vert.groups:#vertex groupd id - vert_weight = vgroup.weight - if(bonegroup.index == vgroup.group): - p = VPoint() - vpos = current_vert.co * current_obj.matrix_local - p.Point.X = vpos.x - p.Point.Y = vpos.y - p.Point.Z = vpos.z - #print(current_vert.co) - point_index = points.get(p) #point index - v_item = (point_index, vert_weight) - vert_list.append(v_item) - #bone name, [point id and wieght] - #print("Add Vertex Group:",bonegroup.bone, " No. Points:",len(vert_list)) - psk_file.VertexGroups[bonegroup.bone] = vert_list - - #unrealtriangulatebool #this will remove the mesh from the scene - if (bpy.context.scene.unrealtriangulatebool == True): - print("Remove tmp Mesh [ " ,current_obj.name, " ] from scene >" ,(bpy.context.scene.unrealtriangulatebool )) - bpy.ops.object.mode_set(mode='OBJECT') # set it in object - bpy.context.scene.objects.unlink(current_obj) - -def make_fquat(bquat): - quat = FQuat() - - #flip handedness for UT = set x,y,z to negative (rotate in other direction) - quat.X = -bquat.x - quat.Y = -bquat.y - quat.Z = -bquat.z - - quat.W = bquat.w - return quat - -def make_fquat_default(bquat): - quat = FQuat() - - quat.X = bquat.x - quat.Y = bquat.y - quat.Z = bquat.z - - quat.W = bquat.w - return quat - -# ================================================================================================= -# TODO: remove this 1am hack -nbone = 0 -def parse_bone(blender_bone, psk_file, psa_file, parent_id, is_root_bone, parent_matrix, parent_root): - global nbone # look it's evil! - #print '-------------------- Dumping Bone ---------------------- ' - - #If bone does not have parent that mean it the root bone - if blender_bone.parent == None: - parent_root = blender_bone - - - child_count = len(blender_bone.children) - #child of parent - child_parent = blender_bone.parent - - if child_parent != None: - print ("--Bone Name:",blender_bone.name ," parent:" , blender_bone.parent.name, "ID:", nbone) - else: - print ("--Bone Name:",blender_bone.name ," parent: None" , "ID:", nbone) - - if child_parent != None: - quat_root = blender_bone.matrix - quat = make_fquat(quat_root.to_quat()) - - quat_parent = child_parent.matrix.to_quat().inverse() - parent_head = child_parent.head * quat_parent - parent_tail = child_parent.tail * quat_parent - - set_position = (parent_tail - parent_head) + blender_bone.head - else: - # ROOT BONE - #This for root - set_position = blender_bone.head * parent_matrix #ARMATURE OBJECT Locction - rot_mat = blender_bone.matrix * parent_matrix.rotation_part() #ARMATURE OBJECT Rotation - #print(dir(rot_mat)) - - quat = make_fquat_default(rot_mat.to_quat()) - - print ("[[======= FINAL POSITION:", set_position) - final_parent_id = parent_id - - #RG/RE - - #if we are not seperated by a small distance, create a dummy bone for the displacement - #this is only needed for root bones, since UT assumes a connected skeleton, and from here - #down the chain we just use "tail" as an endpoint - #if(head.length > 0.001 and is_root_bone == 1): - if(0): - pb = make_vbone("dummy_" + blender_bone.name, parent_id, 1, FQuat(), tail) - psk_file.AddBone(pb) - pbb = make_namedbonebinary("dummy_" + blender_bone.name, parent_id, 1, FQuat(), tail, 0) - psa_file.StoreBone(pbb) - final_parent_id = nbone - nbone = nbone + 1 - #tail = tail-head - - my_id = nbone - - pb = make_vbone(blender_bone.name, final_parent_id, child_count, quat, set_position) - psk_file.AddBone(pb) - pbb = make_namedbonebinary(blender_bone.name, final_parent_id, child_count, quat, set_position, 1) - psa_file.StoreBone(pbb) - - nbone = nbone + 1 - - #RG - dump influences for this bone - use the data we collected in the mesh dump phase - # to map our bones to vertex groups - #print("///////////////////////") - #print("set influence") - if blender_bone.name in psk_file.VertexGroups: - vertex_list = psk_file.VertexGroups[blender_bone.name] - #print("vertex list:", len(vertex_list), " of >" ,blender_bone.name ) - for vertex_data in vertex_list: - #print("set influence vettex") - point_index = vertex_data[0] - vertex_weight = vertex_data[1] - influence = VRawBoneInfluence() - influence.Weight = vertex_weight - #influence.BoneIndex = my_id - influence.BoneIndex = my_id - influence.PointIndex = point_index - #print(influence) - #print ('Adding Bone Influence for [%s] = Point Index=%i, Weight=%f' % (blender_bone.name, point_index, vertex_weight)) - #print("adding influence") - psk_file.AddInfluence(influence) - - #blender_bone.matrix_local - #recursively dump child bones - mainparent = parent_matrix - #if len(blender_bone.children) > 0: - for current_child_bone in blender_bone.children: - parse_bone(current_child_bone, psk_file, psa_file, my_id, 0, mainparent, parent_root) - -def parse_armature(blender_armature, psk_file, psa_file): - print ("----- parsing armature -----") - print ('blender_armature length: %i' % (len(blender_armature))) - - #magic 0 sized root bone for UT - this is where all armature dummy bones will attach - #dont increment nbone here because we initialize it to 1 (hackity hackity hack) - - #count top level bones first. NOT EFFICIENT. - child_count = 0 - for current_obj in blender_armature: - current_armature = current_obj.data - bones = [x for x in current_armature.bones if not x.parent == None] - child_count += len(bones) - - for current_obj in blender_armature: - print ("Current Armature Name: " + current_obj.name) - current_armature = current_obj.data - #armature_id = make_armature_bone(current_obj, psk_file, psa_file) - - #we dont want children here - only the top level bones of the armature itself - #we will recursively dump the child bones as we dump these bones - """ - bones = [x for x in current_armature.bones if not x.parent == None] - #will ingore this part of the ocde - """ - for current_bone in current_armature.bones: #list the bone. #note this will list all the bones. - if(current_bone.parent == None): - parse_bone(current_bone, psk_file, psa_file, 0, 0, current_obj.matrix_local, None) - break - -# get blender objects by type -def get_blender_objects(objects, intype): - return [x for x in objects if x.type == intype] - -#strips current extension (if any) from filename and replaces it with extension passed in -def make_filename_ext(filename, extension): - new_filename = '' - extension_index = filename.find('.') - - if extension_index == -1: - new_filename = filename + extension - else: - new_filename = filename[0:extension_index] + extension - - return new_filename - -# returns the quaternion Grassman product a*b -# this is the same as the rotation a(b(x)) -# (ie. the same as B*A if A and B are matrices representing -# the rotations described by quaternions a and b) -def grassman(a, b): - return mathutils.Quaternion( - a.w*b.w - a.x*b.x - a.y*b.y - a.z*b.z, - a.w*b.x + a.x*b.w + a.y*b.z - a.z*b.y, - a.w*b.y - a.x*b.z + a.y*b.w + a.z*b.x, - a.w*b.z + a.x*b.y - a.y*b.x + a.z*b.w) - -def parse_animation(blender_scene, blender_armatures, psa_file): - #to do list: - #need to list the action sets - #need to check if there animation - #need to check if animation is has one frame then exit it - print ('\n----- parsing animation -----') - ##print(dir(blender_scene)) - - #print(dir(blender_armatures)) - - render_data = blender_scene.render - bHaveAction = True - - anim_rate = render_data.fps - - #print("dir:",dir(blender_scene)) - #print(dir(bpy.data.actions)) - #print("dir:",dir(bpy.data.actions[0])) - - - print("==== Blender Settings ====") - print ('Scene: %s Start Frame: %i, End Frame: %i' % (blender_scene.name, blender_scene.frame_start, blender_scene.frame_end)) - print ('Frames Per Sec: %i' % anim_rate) - print ("Default FPS: 24" ) - - cur_frame_index = 0 - - #print(dir(bpy.data.actions)) - #print(dir(bpy.context.scene.background_set)) - - #list of armature objects - for arm in blender_armatures: - #check if there animation data from armature or something - #print(dir(arm.animation_data)) - #print("[["+dir(arm.animation_data.action)) - if not arm.animation_data: - print("======================================") - print("Check Animation Data: None") - print("Armature has no animation, skipping...") - print("======================================") - break - - if not arm.animation_data.action: - print("======================================") - print("Check Action: None") - print("Armature has no animation, skipping...") - print("======================================") - break - act = arm.animation_data.action - #print(dir(act)) - action_name = act.name - - if not len(act.fcurves): - print("//===========================================================") - print("// None bone pose set keys for this action set... skipping...") - print("//===========================================================") - bHaveAction = False - - #this deal with action export control - if bHaveAction == True: - print("") - print("==== Action Set ====") - print("Action Name:",action_name) - #look for min and max frame that current set keys - framemin, framemax = act.frame_range - #print("max frame:",framemax) - start_frame = int(framemin) - end_frame = int(framemax) - scene_frames = range(start_frame, end_frame+1) - frame_count = len(scene_frames) - #=================================================== - anim = AnimInfoBinary() - anim.Name = action_name - anim.Group = "" #what is group? - anim.NumRawFrames = frame_count - anim.AnimRate = anim_rate - anim.FirstRawFrame = cur_frame_index - #=================================================== - count_previous_keys = len(psa_file.RawKeys.Data) - print("Frame Key Set Count:",frame_count, "Total Frame:",frame_count) - #print("init action bones...") - unique_bone_indexes = {} - # bone lookup table - bones_lookup = {} - - #build bone node for animation keys needed to be set - for bone in arm.data.bones: - bones_lookup[bone.name] = bone - #print("bone name:",bone.name) - frame_count = len(scene_frames) - #print ('Frame Count: %i' % frame_count) - pose_data = arm.pose - - #these must be ordered in the order the bones will show up in the PSA file! - ordered_bones = {} - ordered_bones = sorted([(psa_file.UseBone(x.name), x) for x in pose_data.bones], key=operator.itemgetter(0)) - - ############################# - # ORDERED FRAME, BONE - #for frame in scene_frames: - - for i in range(frame_count): - frame = scene_frames[i] - #LOUD - #print ("==== outputting frame %i ===" % frame) - - if frame_count > i+1: - next_frame = scene_frames[i+1] - #print "This Frame: %i, Next Frame: %i" % (frame, next_frame) - else: - next_frame = -1 - #print "This Frame: %i, Next Frame: NONE" % frame - - #frame start from 1 as number one from blender - blender_scene.frame_set(frame) - - cur_frame_index = cur_frame_index + 1 - for bone_data in ordered_bones: - bone_index = bone_data[0] - pose_bone = bone_data[1] - #print("[=====POSE NAME:",pose_bone.name) - - #print("LENG >>.",len(bones_lookup)) - blender_bone = bones_lookup[pose_bone.name] - - #just need the total unique bones used, later for this AnimInfoBinary - unique_bone_indexes[bone_index] = bone_index - #LOUD - #print ("-------------------", pose_bone.name) - head = pose_bone.head - - posebonemat = mathutils.Matrix(pose_bone.matrix) - parent_pose = pose_bone.parent - if parent_pose != None: - parentposemat = mathutils.Matrix(parent_pose.matrix) - #blender 2.4X it been flip around with new 2.50 (mat1 * mat2) should now be (mat2 * mat1) - posebonemat = parentposemat.invert() * posebonemat - head = posebonemat.translation_part() - quat = posebonemat.to_quat().normalize() - vkey = VQuatAnimKey() - vkey.Position.X = head.x - vkey.Position.Y = head.y - vkey.Position.Z = head.z - - if parent_pose != None: - quat = make_fquat(quat) - else: - quat = make_fquat_default(quat) - - vkey.Orientation = quat - #print("Head:",head) - #print("Orientation",quat) - - #time from now till next frame = diff / framesPerSec - if next_frame >= 0: - diff = next_frame - frame - else: - diff = 1.0 - - #print ("Diff = ", diff) - vkey.Time = float(diff)/float(anim_rate) - - psa_file.AddRawKey(vkey) - - #done looping frames - #done looping armatures - #continue adding animInfoBinary counts here - - anim.TotalBones = len(unique_bone_indexes) - print("Bones Count:",anim.TotalBones) - anim.TrackTime = float(frame_count) / anim.AnimRate - print("Time Track Frame:",anim.TrackTime) - psa_file.AddAnimation(anim) - print("==== Finish Action Build(s) ====") - -exportmessage = "Export Finish" - -def fs_callback(filename, context, user_setting): - #this deal with repeat export and the reset settings - global bonedata, BBCount, nbone, exportmessage - bonedata = []#clear array - BBCount = 0 - nbone = 0 - - start_time = time.clock() - - print ("========EXPORTING TO UNREAL SKELETAL MESH FORMATS========\r\n") - print("Blender Version:", bpy.app.version_string) - - psk = PSKFile() - psa = PSAFile() - - #sanity check - this should already have the extension, but just in case, we'll give it one if it doesn't - psk_filename = make_filename_ext(filename, '.psk') - - #make the psa filename - psa_filename = make_filename_ext(filename, '.psa') - - print ('PSK File: ' + psk_filename) - print ('PSA File: ' + psa_filename) - - barmature = True - bmesh = True - blender_meshes = [] - blender_armature = [] - selectmesh = [] - selectarmature = [] - - current_scene = context.scene - cur_frame = current_scene.frame_current #store current frame before we start walking them during animation parse - objects = current_scene.objects - - print("Checking object count...") - for next_obj in objects: - if next_obj.type == 'MESH': - blender_meshes.append(next_obj) - if (next_obj.select): - #print("mesh object select") - selectmesh.append(next_obj) - if next_obj.type == 'ARMATURE': - blender_armature.append(next_obj) - if (next_obj.select): - #print("armature object select") - selectarmature.append(next_obj) - - print("Mesh Count:",len(blender_meshes)," Armature Count:",len(blender_armature)) - print("====================================") - print("Checking Mesh Condtion(s):") - if len(blender_meshes) == 1: - print(" - One Mesh Scene") - elif (len(blender_meshes) > 1) and (len(selectmesh) == 1): - print(" - One Mesh [Select]") - else: - print(" - Too Many Meshes!") - print(" - Select One Mesh Object!") - bmesh = False - print("====================================") - print("Checking Armature Condtion(s):") - if len(blender_armature) == 1: - print(" - One Armature Scene") - elif (len(blender_armature) > 1) and (len(selectarmature) == 1): - print(" - One Armature [Select]") - else: - print(" - Too Armature Meshes!") - print(" - Select One Armature Object Only!") - barmature = False - - if (bmesh == False) or (barmature == False): - exportmessage = "Export Fail! Check Log." - print("=================================") - print("= Export Fail! =") - print("=================================") - else: - exportmessage = "Export Finish!" - #need to build a temp bone index for mesh group vertex - BoneIndexArmature(blender_armature) - - try: - ####################### - # STEP 1: MESH DUMP - # we build the vertexes, wedges, and faces in here, as well as a vertexgroup lookup table - # for the armature parse - print("//===============================") - print("// STEP 1") - print("//===============================") - parse_meshes(blender_meshes, psk) - except: - context.scene.frame_set(cur_frame) #set frame back to original frame - print ("Exception during Mesh Parse") - raise - - try: - ####################### - # STEP 2: ARMATURE DUMP - # IMPORTANT: do this AFTER parsing meshes - we need to use the vertex group data from - # the mesh parse in here to generate bone influences - print("//===============================") - print("// STEP 2") - print("//===============================") - parse_armature(blender_armature, psk, psa) - - except: - context.scene.frame_set(cur_frame) #set frame back to original frame - print ("Exception during Armature Parse") - raise - - try: - ####################### - # STEP 3: ANIMATION DUMP - # IMPORTANT: do AFTER parsing bones - we need to do bone lookups in here during animation frames - print("//===============================") - print("// STEP 3") - print("//===============================") - parse_animation(current_scene, blender_armature, psa) - - except: - context.scene.frame_set(cur_frame) #set frame back to original frame - print ("Exception during Animation Parse") - raise - - # reset current frame - - context.scene.frame_set(cur_frame) #set frame back to original frame - - ########################## - # FILE WRITE - print("//===========================================") - print("// bExportPsk:",bpy.context.scene.unrealexportpsk," bExportPsa:",bpy.context.scene.unrealexportpsa) - print("//===========================================") - if bpy.context.scene.unrealexportpsk == True: - print("Writing Skeleton Mesh Data...") - #RG - dump psk file - psk.PrintOut() - file = open(psk_filename, "wb") - file.write(psk.dump()) - file.close() - print ("Successfully Exported File: " + psk_filename) - if bpy.context.scene.unrealexportpsa == True: - print("Writing Animaiton Data...") - #RG - dump psa file - if not psa.IsEmpty(): - psa.PrintOut() - file = open(psa_filename, "wb") - file.write(psa.dump()) - file.close() - print ("Successfully Exported File: " + psa_filename) - else: - print ("No Animations (.psa file) to Export") - - print ('PSK/PSA Export Script finished in %.2f seconds' % (time.clock() - start_time)) - - #MSG BOX EXPORT COMPLETE - #... - - #DONE - print ("PSK/PSA Export Complete") - -def write_data(path, context, user_setting): - print("//============================") - print("// running psk/psa export...") - print("//============================") - fs_callback(path, context, user_setting) - pass - -from bpy.props import * - -exporttypedata = [] - -# [index,text field,0] #or something like that -exporttypedata.append(("0","PSK","Export PSK")) -exporttypedata.append(("1","PSA","Export PSA")) -exporttypedata.append(("2","ALL","Export ALL")) - -bpy.types.Scene.unrealfpsrate = IntProperty( - name="fps rate", - description="Set the frame per second (fps) for unreal.", - default=24,min=1,max=100) - -bpy.types.Scene.unrealexport_settings = EnumProperty( - name="Export:", - description="Select a export settings (psk/psa/all)...", - items = exporttypedata, default = '0') - -bpy.types.Scene.unrealtriangulatebool = BoolProperty( - name="Triangulate Mesh", - description="Convert Quad to Tri Mesh Boolean...", - default=False) - -bpy.types.Scene.unrealactionexportall = BoolProperty( - name="All Actions", - description="This let you export all actions from current armature.[Not Build Yet]", - default=False) - -bpy.types.Scene.unrealexportpsk = BoolProperty( - name="bool export psa", - description="bool for exporting this psk format", - default=False) - -bpy.types.Scene.unrealexportpsa = BoolProperty( - name="bool export psa", - description="bool for exporting this psa format", - default=False) - -class ExportUDKAnimData(bpy.types.Operator): - global exportmessage - '''Export Skeleton Mesh / Animation Data file(s)''' - bl_idname = "export.udk_anim_data" # this is important since its how bpy.ops.export.udk_anim_data is constructed - bl_label = "Export PSK/PSA" - __doc__ = "One mesh and one armature else select one mesh or armature to be exported." - - # List of operator properties, the attributes will be assigned - # to the class instance from the operator settings before calling. - - filepath = StringProperty(name="File Path", description="Filepath used for exporting the PSA file", maxlen= 1024, default= "") - use_setting = BoolProperty(name="No Options Yet", description="No Options Yet", default= True) - pskexportbool = BoolProperty(name="Export PSK", description="Export Skeletal Mesh", default= True) - psaexportbool = BoolProperty(name="Export PSA", description="Export Action Set (Animation Data)", default= True) - actionexportall = BoolProperty(name="All Actions", description="This will export all the actions that matches the current armature.", default=False) - - @classmethod - def poll(cls, context): - return context.active_object != None - - def execute(self, context): - #check if skeleton mesh is needed to be exported - if (self.properties.pskexportbool): - bpy.context.scene.unrealexportpsk = True - else: - bpy.context.scene.unrealexportpsk = False - #check if animation data is needed to be exported - if (self.properties.psaexportbool): - bpy.context.scene.unrealexportpsa = True - else: - bpy.context.scene.unrealexportpsa = False - - write_data(self.properties.filepath, context, self.properties.use_setting) - - self.report({'WARNING', 'INFO'}, exportmessage) - return {'FINISHED'} - - def invoke(self, context, event): - wm = context.window_manager - wm.add_fileselect(self) - return {'RUNNING_MODAL'} - - -class VIEW3D_PT_unrealtools_objectmode(bpy.types.Panel): - bl_space_type = "VIEW_3D" - bl_region_type = "TOOLS" - bl_label = "Unreal Tools" - - @classmethod - def poll(cls, context): - return context.active_object - - def draw(self, context): - layout = self.layout - #layout.label(text="Unreal Tools") - rd = context.scene - #drop box - layout.prop(rd, "unrealexport_settings",expand=True) - #layout.prop(rd, "unrealexport_settings") - #button - layout.operator("object.UnrealExport") - #FPS #it use the real data from your scene - layout.prop(rd.render, "fps") - - layout.prop(rd, "unrealactionexportall") - #row = layout.row() - #row.label(text="Action Set(s)(not build)") - #for action in bpy.data.actions: - #print(dir( action)) - #print(action.frame_range) - #row = layout.row() - #row.prop(action, "name") - - #print(dir(action.groups[0])) - #for g in action.groups:#those are bones - #print("group...") - #print(dir(g)) - #print("////////////") - #print((g.name)) - #print("////////////") - - #row.label(text="Active:" + action.select) - btrimesh = False - -class OBJECT_OT_UnrealExport(bpy.types.Operator): - global exportmessage - bl_idname = "OBJECT_OT_UnrealExport" - bl_label = "Unreal Export" - __doc__ = "Select export setting for .psk/.psa or both." - - def invoke(self, context, event): - #path = StringProperty(name="File Path", description="File path used for exporting the PSA file", maxlen= 1024, default= "") - print("Init Export Script:") - if(int(bpy.context.scene.unrealexport_settings) == 0): - bpy.context.scene.unrealexportpsk = True - bpy.context.scene.unrealexportpsa = False - print("Exporting PSK...") - if(int(bpy.context.scene.unrealexport_settings) == 1): - bpy.context.scene.unrealexportpsk = False - bpy.context.scene.unrealexportpsa = True - print("Exporting PSA...") - if(int(bpy.context.scene.unrealexport_settings) == 2): - bpy.context.scene.unrealexportpsk = True - bpy.context.scene.unrealexportpsa = True - print("Exporting ALL...") - - default_path = os.path.splitext(bpy.data.filepath)[0] + ".psk" - fs_callback(default_path, bpy.context, False) - - #self.report({'WARNING', 'INFO'}, exportmessage) - self.report({'INFO'}, exportmessage) - return{'FINISHED'} - - -def menu_func(self, context): - bpy.context.scene.unrealexportpsk = True - bpy.context.scene.unrealexportpsa = True - default_path = os.path.splitext(bpy.data.filepath)[0] + ".psk" - self.layout.operator("export.udk_anim_data", text="Skeleton Mesh / Animation Data (.psk/.psa)").filepath = default_path - - -def register(): - bpy.types.INFO_MT_file_export.append(menu_func) - -def unregister(): - bpy.types.INFO_MT_file_export.remove(menu_func) - -if __name__ == "__main__": - register() diff --git a/io_import_images_as_planes.py b/io_import_images_as_planes.py deleted file mode 100644 index 50dd2cff..00000000 --- a/io_import_images_as_planes.py +++ /dev/null @@ -1,525 +0,0 @@ -# ##### 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -# ##### END GPL LICENSE BLOCK ##### - -bl_addon_info = { - "name": "Import Images as Planes", - "author": "Florian Meyer (testscreenings)", - "version": (0,7), - "blender": (2, 5, 3), - "api": 31667, - "location": "File > Import > Images as Planes", - "description": "Imports images and creates planes with the appropriate aspect ratio. The images are mapped to the planes.", - "warning": "", - "wiki_url": "http://wiki.blender.org/index.php/Extensions:2.5/Py/"\ - "Scripts/Add_Mesh/Planes_from_Images", - "tracker_url": "https://projects.blender.org/tracker/index.php?"\ - "func=detail&aid=21751&group_id=153&atid=469", - "category": "Import/Export"} - -""" -This script imports images and creates Planes with them as textures. -At the moment the naming for objects, materials, textures and meshes -is derived from the imagename. - -One can either import a single image, or all images in one directory. -When imporing a directory one can either check the checkbox or leave -the filename empty. - -As a bonus one can choose to import images of only one type. -Atm this is the list of possible extensions: -extList = - ('jpeg', 'jpg', 'png', 'tga', 'tiff', 'tif', 'exr', - 'hdr', 'avi', 'mov', 'mp4', 'ogg', 'bmp', 'cin', 'dpx', 'psd') - -If someone knows a better way of telling if a file is an image which -Blender can read, please tell so ;) - -when importing images that are allready referenced they are not -reimported but the old ones reused as not to clutter the materials, -textures and image lists. -Instead the plane gets linked against an existing material. - -If one reimports images but chooses different material/texture mapping -new materials are created. -So one doesn't has to go through everything if one decides differently -after importing 236 images. - -It also has an option to translate pixeldimensions into Blenderunits. -""" - -import bpy -from bpy.props import * -from os import listdir -from mathutils import Vector - - -EXT_LIST = { - 'jpeg': ['jpeg', 'jpg', 'jpe'], - 'png': ['png'], - 'tga': ['tga', 'tpic'], - 'tiff': ['tiff', 'tif'], - 'exr': ['exr'], - 'hdr': ['hdr'], - 'avi': ['avi'], - 'mov': ['mov', 'qt'], - 'mp4': ['mp4'], - 'ogg': ['ogg', 'ogv'], - 'bmp': ['bmp', 'dib'], - 'cin': ['cin'], - 'dpx': ['dpx'], - 'psd': ['psd']} - - -# Apply view rotation to objects if "Align To" for new objects -# was set to "VIEW" in the User Preference. -def apply_view_rotation(ob): - context = bpy.context - align = bpy.context.user_preferences.edit.object_align - - if (context.space_data.type == 'VIEW_3D' - and align == 'VIEW'): - view3d = context.space_data - region = view3d.region_3d - viewMatrix = region.view_matrix - rot = viewMatrix.rotation_part() - ob.rotation_euler = rot.invert().to_euler() - - -# Create plane mesh -def createPlaneMesh(dimension, img): - # x is the x-aspectRatio. - x = img.size[0] / img.size[1] - y = 1 - - if dimension[0]: - x = (img.size[0] * (1.0 / dimension[1])) * 0.5 - y = (img.size[1] * (1.0 / dimension[1])) * 0.5 - - verts = [] - faces = [] - - v1 = (-x, -y, 0) - v2 = (x, -y, 0) - v3 = (x, y, 0) - v4 = (-x, y, 0) - - verts.append(v1) - verts.append(v2) - verts.append(v3) - verts.append(v4) - - faces.append([0, 1, 2, 3]) - - return verts, faces - - -# Create plane object -def createPlaneObj(img, dimension): - scene = bpy.context.scene - - verts, faces = createPlaneMesh(dimension, img) - - me = bpy.data.meshes.new(img.name) - me.from_pydata(verts, [], faces) - me.update() - - plane = bpy.data.objects.new(img.name, me) - plane.data.uv_textures.new() - - scene.objects.link(plane) - plane.location = scene.cursor_location - apply_view_rotation(plane) - - return plane - - -# Check if a file extension matches any -# valid (i.e. recognized) image/movie format. -def isImageFile(extension): - for ext, ext_list in EXT_LIST.items(): - if extension in ext_list: - return True - - return False - - -# Get imagepaths from directory -def getImageFilesInDirectory(directory, extension): - import os - - # Get all files in the directory. - allFiles = listdir(directory) - allImages = [] - - extensions = [] - - # Import all images files? - if extension == '*': - all = True - - else: - all = False - # Get the possible extensions - extensions = EXT_LIST[extension] - - # Put all image files in the list. - for file in allFiles: - # Get the file extension (includes the ".") - e = os.path.splitext(file)[1] - - # Separate by "." and get the last list-entry. - e = e.rpartition(".")[-1] - - # Convert to lower case - e = e.lower() - - if (e in extensions - or (all and isImageFile(e))): - allImages.append(file) - - return allImages - - -# Get image datablock from the (image's) filepath. -def getImage(path): - img = [] - - # Check every Image if it is already there. - for image in bpy.data.images: - # If image with same path exists take that one. - if image.filepath == path: - img = image - - # Else create new Image and load from path. - if not img: - name = path.rpartition('\\')[2].rpartition('.')[0] - img = bpy.data.images.new(name) - img.source = 'FILE' - img.filepath = path - - return img - - -# Create/get Material -def getMaterial(tex, mapping): - mat = [] - - # Check all existing materials. - for material in bpy.data.materials: - # If a material with name and mapping - # texture with image exists, take that one... - if (material.name == tex.image.name - and tex.name in material.texture_slots - and material.mapping == mapping): - mat = material - - # ... otherwise create new one and apply mapping. - if not mat: - mat = bpy.data.materials.new(name=tex.name) - mtex = mat.texture_slots.add() - mtex.texture = tex - mtex.texture_coords = 'UV' - mtex.use_map_color_diffuse = True - - mat.mapping = mapping - mat.name = tex.name - - return mat - - -# Create/get Texture -def getTexture(path, img): - tex = [] - - # Check all existing textures. - for texture in bpy.data.textures: - # If an (image)texture with image exists, take that one... - if (texture.type == 'IMAGE' - and texture.image - and texture.image.filepath == path): - tex = texture - - # ... otherwise create a new one and apply mapping. - if not tex: - name = path.rpartition('\\')[2].rpartition('.')[0] - tex = bpy.data.textures.new(name=name, type='IMAGE') - tex.image = img - - return tex - - -# Custom material property - get -def mapget(self): - """Custom property of the images_as_planes addon.""" - mapping = [] - mapping.append(self.use_shadeless) - mapping.append(self.use_transparency) - mapping.append(self.alpha) - mapping.append(self.specular_alpha) - mapping.append(self.transparency_method) - - if (self.texture_slots[0] - and self.texture_slots[0].texture.type == 'IMAGE' - and self.texture_slots[0].texture.image): - mapping.append(self.texture_slots[0].texture.image.use_premultiply) - - else: - mapping.append("no image") - - return mapping - - -# Custom material property - set -def mapset(self, value): - self.use_shadeless = value[0] - self.use_transparency = value[1] - self.alpha = float(value[2]) - self.specular_alpha = float(value[3]) - self.transparency_method = value[4] - - if (self.texture_slots[0] - and self.texture_slots[0].texture.type == 'IMAGE' - and self.texture_slots[0].texture.image): - self.texture_slots[0].texture.image.use_premultiply = value[5] - if self.alpha: - self.texture_slots[0].use_map_alpha=True - - -bpy.types.Material.mapping = property(mapget, mapset) - - -def main(filePath, options, mapping, dimension): - images = [] - scene = bpy.context.scene - - # If "Create from Directory" (no filepath or checkbox) #### - if options['dir'] or not filePath[1]: - imageFiles = getImageFilesInDirectory(filePath[2], options['ext']) - - # Check if images are loaded and put them in the list. - for imageFile in imageFiles: - img = getImage(str(filePath[2]) + "\\" + str(imageFile)) - images.append(img) - - # Deselect all objects. - bpy.ops.object.select_all(action='DESELECT') - - # Assign/get all things. - for img in images: - # Create/get Texture - tex = getTexture(img.filepath, img) - - # Create/get Material - mat = getMaterial(tex, mapping) - - # Create Plane - plane = createPlaneObj(img, dimension) - - # Assign Material - plane.data.materials.append(mat) - - # Put Image into UVTextureLayer - plane.data.uv_textures[0].data[0].image = img - plane.data.uv_textures[0].data[0].use_image = True - plane.data.uv_textures[0].data[0].blend_type = 'ALPHA' - plane.data.uv_textures[0].data[0].use_twoside = True - - plane.select = True - scene.objects.active = plane - - # If "Create Single Plane" (filepath and is image) - else: - # Deselect all objects. - bpy.ops.object.select_all(action='DESELECT') - - # Check if image is loaded. - img = getImage(filePath[0]) - - # Create/get Texture - tex = getTexture(filePath[0], img) - - # Create/get Material - mat = getMaterial(tex, mapping) - - # Create Plane - plane = createPlaneObj(img, dimension) - - # Assign Material - plane.data.materials.append(mat) - - # Put image into UVTextureLayer - plane.data.uv_textures[0].data[0].image = img - plane.data.uv_textures[0].data[0].use_image = True - plane.data.uv_textures[0].data[0].blend_type = 'ALPHA' - plane.data.uv_textures[0].data[0].use_twoside = True - - plane.select = True - scene.objects.active = plane - - -# Operator -class ImportImagesAsPlanes(bpy.types.Operator): - '''''' - bl_idname = "import.images_as_planes" - bl_label = "Import Images as Planes" - bl_description = "Create mesh plane(s) from image files" \ - " with the appropiate aspect ratio." - bl_options = {'REGISTER', 'UNDO'} - - filepath = StringProperty(name="File Path", - description="Filepath used for importing the file", - maxlen=1024, - default="") - filename = StringProperty(name="File Name", - description="Name of the file.") - directory = StringProperty(name="Directory", - description="Directory of the file.") - fromDirectory = BoolProperty(name="All in directory", - description="Import all image files (of the selected type)" \ - " in this directory.", - default=False) - - extEnum = [ - ('*', 'All image formats', - 'Import all know image (or movie) formats.'), - ('jpeg', 'JPEG (.jpg, .jpeg, .jpe)', - 'Joint Photographic Experts Group'), - ('png', 'PNG (.png)', 'Portable Network Graphics'), - ('tga', 'Truevision TGA (.tga, tpic)', ''), - ('tiff', 'TIFF (.tif, .tiff)', 'Tagged Image File Format'), - ('exr', 'OpenEXR (.exr)', 'OpenEXR HDR imaging image file format'), - ('hdr', 'Radiance HDR (.hdr, .pic)', ''), - ('avi', 'AVI (.avi)', 'Audio Video Interleave'), - ('mov', 'QuickTime (.mov, .qt)', ''), - ('mp4', 'MPEG-4 (.mp4)', ' MPEG-4 Part 14'), - ('ogg', 'OGG Theora (.ogg, .ogv)', ''), - ('bmp', 'BMP (.bmp, .dib)', 'Windows Bitmap'), - ('cin', 'CIN (.cin)', ''), - ('dpx', 'DPX (.dpx)', 'DPX (Digital Picture Exchange)'), - ('psd', 'PSD (.psd)', 'Photoshop Document')] - extension = EnumProperty(name="Extension", - description="Only import files of this type.", - items=extEnum) - - shadeless = BoolProperty(name="Shadeless", - description="Set material to shadeless", - default=False) - transp = BoolProperty(name="Use alpha", - description="Use alphachannel for transparency.", - default=False) - premultiply = BoolProperty(name="Premultiply", - description="Premultiply image", - default=False) - - tEnum = [ - ('Z_TRANSPARENCY', - 'Z Transparency', - 'Use alpha buffer for transparent faces'), - ('RAYTRACE', - 'Raytrace', - 'Use raytracing for transparent refraction rendering.')] - transp_method = EnumProperty(name="Transp. Method", - description="Transparency Method", - items=tEnum) - useDim = BoolProperty(name="Use image dimensions", - description="Use the images pixels to derive the size of the plane.", - default=False) - factor = IntProperty(name="Pixels/BU", - description="Number of pixels per Blenderunit.", - min=1, - default=500) - - def draw(self, context): - props = self.properties - layout = self.layout - box = layout.box() - box.label('Filter:', icon='FILTER') - box.prop(props, 'fromDirectory') - box.prop(props, 'extension', icon='FILE_IMAGE') - box = layout.box() - box.label('Material mappings:', icon='MATERIAL') - box.prop(props, 'use_shadeless') - box.prop(props, 'transp') - box.prop(props, 'use_premultiply') - box.prop(props, 'transp_method', expand=True) - box = layout.box() - box.label('Plane dimensions:', icon='ARROW_LEFTRIGHT') - box.prop(props, 'useDim') - box.prop(props, 'factor', expand=True) - - def execute(self, context): - # File Path - filepath = self.properties.filepath - filename = self.properties.filename - directory = self.properties.directory - filePath = (filepath, filename, directory) - - # General Options - fromDirectory = self.properties.fromDirectory - extension = self.properties.extension - options = {'dir': fromDirectory, 'ext': extension} - - # Mapping - alphavalue = 1 - transp = self.properties.transp - if transp: - alphavalue = 0 - - shadeless = self.properties.use_shadeless - transp_method = self.properties.transp_method - premultiply = self.properties.use_premultiply - - mapping = ([shadeless, - transp, - alphavalue, - alphavalue, - transp_method, - premultiply]) - - # Use Pixelsdimensions - useDim = self.properties.useDim - factor = self.properties.factor - dimension = (useDim, factor) - - # Call Main Function - main(filePath, options, mapping, dimension) - - return {'FINISHED'} - - def invoke(self, context, event): - wm = bpy.context.window_manager - wm.add_fileselect(self) - - return {'RUNNING_MODAL'} - - -# Registering / Unregister -def menu_func(self, context): - self.layout.operator(ImportImagesAsPlanes.bl_idname, text="Images as Planes", icon='PLUGIN') - - -def register(): - bpy.types.INFO_MT_file_import.append(menu_func) - - -def unregister(): - bpy.types.INFO_MT_file_import.remove(menu_func) - - -if __name__ == "__main__": - register() diff --git a/io_import_scene_lwo.py b/io_import_scene_lwo.py deleted file mode 100644 index c2d75f97..00000000 --- a/io_import_scene_lwo.py +++ /dev/null @@ -1,1247 +0,0 @@ -# ##### 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -# ##### END GPL LICENSE BLOCK ##### - -# - -bl_addon_info= { - "name": "Import LightWave Objects", - "author": "Ken Nign (Ken9)", - "version": (1, 2), - "blender": (2, 5, 3), - "api": 31744, - "location": "File > Import > LightWave Object (.lwo)", - "description": "Imports a LWO file including any UV, Morph and Color maps. Can convert Skelegons to an Armature.", - "warning": "", - "wiki_url": "http://wiki.blender.org/index.php/Extensions:2.5/Py/"\ - "Scripts/File_I-O/LightWave_Object", - "tracker_url": "", - "category": "Import/Export"} - -# Copyright (c) Ken Nign 2010 -# ken@virginpi.com -# -# Version 1.2 - Sep 7, 2010 -# -# Loads a LightWave .lwo object file, including the vertex maps such as -# UV, Morph, Color and Weight maps. -# -# Will optionally create an Armature from an embedded Skelegon rig. -# -# Point orders are maintained so that .mdds can exchanged with other -# 3D programs. -# -# -# Notes: -# NGons, polygons with more than 4 points are supported, but are -# added (as triangles) after the vertex maps have been applied. Thus they -# won't contain all the vertex data that the original ngon had. -# -# Blender is limited to only 8 UV Texture and 8 Vertex Color maps, -# thus only the first 8 of each can be imported. -# -# History: -# -# 1.2 Added Absolute Morph and CC Edge Weight support. -# Made edge creation safer. -# 1.0 First Release - - -import os -import io -import time -import struct -import chunk - -import bpy -import mathutils -from geometry import PolyFill - - -class _obj_layer(object): - __slots__ = ( - "name", - "index", - "parent_index", - "pivot", - "pols", - "bones", - "bone_names", - "bone_rolls", - "pnts", - "wmaps", - "colmaps", - "uvmaps", - "morphs", - "edge_weights", - "surf_tags", - "has_subds", - ) - def __init__(self): - self.name= "" - self.index= -1 - self.parent_index= -1 - self.pivot= [0, 0, 0] - self.pols= [] - self.bones= [] - self.bone_names= {} - self.bone_rolls= {} - self.pnts= [] - self.wmaps= {} - self.colmaps= {} - self.uvmaps= {} - self.morphs= {} - self.edge_weights= {} - self.surf_tags= {} - self.has_subds= False - - -class _obj_surf(object): - __slots__ = ( - "bl_mat", - "name", - "source_name", - "colr", - "diff", - "lumi", - "spec", - "refl", - "rblr", - "tran", - "rind", - "tblr", - "trnl", - "glos", - "shrp", - "smooth", - ) - - def __init__(self): - self.bl_mat= None - self.name= "Default" - self.source_name= "" - self.colr= [1.0, 1.0, 1.0] - self.diff= 1.0 # Diffuse - self.lumi= 0.0 # Luminosity - self.spec= 0.0 # Specular - self.refl= 0.0 # Reflectivity - self.rblr= 0.0 # Reflection Bluring - self.tran= 0.0 # Transparency (the opposite of Blender's Alpha value) - self.rind= 1.0 # RT Transparency IOR - self.tblr= 0.0 # Refraction Bluring - self.trnl= 0.0 # Translucency - self.glos= 0.4 # Glossiness - self.shrp= 0.0 # Diffuse Sharpness - self.smooth= False # Surface Smoothing - - -def load_lwo(filename, - context, - ADD_SUBD_MOD=True, - LOAD_HIDDEN=False, - SKEL_TO_ARM=True): - '''Read the LWO file, hand off to version specific function.''' - name, ext= os.path.splitext(os.path.basename(filename)) - file= open(filename, 'rb') - - try: - header, chunk_size, chunk_name = struct.unpack(">4s1L4s", file.read(12)) - except: - print("Error parsing file header!") - file.close() - return - - layers= [] - surfs= {} - tags= [] - # Gather the object data using the version specific handler. - if chunk_name == b'LWO2': - read_lwo2(file, filename, layers, surfs, tags, ADD_SUBD_MOD, LOAD_HIDDEN, SKEL_TO_ARM) - elif chunk_name == b'LWOB' or chunk_name == b'LWLO': - # LWOB and LWLO are the old format, LWLO is a layered object. - read_lwob(file, filename, layers, surfs, tags, ADD_SUBD_MOD) - else: - print("Not a supported file type!") - file.close() - return - - file.close() - - # With the data gathered, build the object(s). - build_objects(layers, surfs, tags, name, ADD_SUBD_MOD, SKEL_TO_ARM) - - layers= None - surfs.clear() - tags= None - - -def read_lwo2(file, filename, layers, surfs, tags, add_subd_mod, load_hidden, skel_to_arm): - '''Read version 2 file, LW 6+.''' - handle_layer= True - last_pols_count= 0 - just_read_bones= False - print("Importing LWO: " + filename + "\nLWO v2 Format") - - while True: - try: - rootchunk = chunk.Chunk(file) - except EOFError: - break - - if rootchunk.chunkname == b'TAGS': - read_tags(rootchunk.read(), tags) - elif rootchunk.chunkname == b'LAYR': - handle_layer= read_layr(rootchunk.read(), layers, load_hidden) - elif rootchunk.chunkname == b'PNTS' and handle_layer: - read_pnts(rootchunk.read(), layers) - elif rootchunk.chunkname == b'VMAP' and handle_layer: - vmap_type = rootchunk.read(4) - - if vmap_type == b'WGHT': - read_weightmap(rootchunk.read(), layers) - elif vmap_type == b'MORF': - read_morph(rootchunk.read(), layers, False) - elif vmap_type == b'SPOT': - read_morph(rootchunk.read(), layers, True) - elif vmap_type == b'TXUV': - read_uvmap(rootchunk.read(), layers) - elif vmap_type == b'RGB ' or vmap_type == b'RGBA': - read_colmap(rootchunk.read(), layers) - else: - rootchunk.skip() - - elif rootchunk.chunkname == b'VMAD' and handle_layer: - vmad_type= rootchunk.read(4) - - if vmad_type == b'TXUV': - read_uv_vmad(rootchunk.read(), layers, last_pols_count) - elif vmad_type == b'RGB ' or vmad_type == b'RGBA': - read_color_vmad(rootchunk.read(), layers, last_pols_count) - elif vmad_type == b'WGHT': - # We only read the Edge Weight map if it's there. - read_weight_vmad(rootchunk.read(), layers) - else: - rootchunk.skip() - - elif rootchunk.chunkname == b'POLS' and handle_layer: - face_type = rootchunk.read(4) - just_read_bones= False - # PTCH is LW's Subpatches, SUBD is CatmullClark. - if (face_type == b'FACE' or face_type == b'PTCH' or - face_type == b'SUBD') and handle_layer: - last_pols_count= read_pols(rootchunk.read(), layers) - if face_type != b'FACE': - layers[-1].has_subds= True - elif face_type == b'BONE' and handle_layer: - read_bones(rootchunk.read(), layers) - just_read_bones= True - else: - rootchunk.skip() - - elif rootchunk.chunkname == b'PTAG' and handle_layer: - tag_type,= struct.unpack("4s", rootchunk.read(4)) - if tag_type == b'SURF' and not just_read_bones: - # Ignore the surface data if we just read a bones chunk. - read_surf_tags(rootchunk.read(), layers, last_pols_count) - - elif skel_to_arm: - if tag_type == b'BNUP': - read_bone_tags(rootchunk.read(), layers, tags, 'BNUP') - elif tag_type == b'BONE': - read_bone_tags(rootchunk.read(), layers, tags, 'BONE') - else: - rootchunk.skip() - else: - rootchunk.skip() - elif rootchunk.chunkname == b'SURF': - read_surf(rootchunk.read(), surfs) - else: - #if handle_layer: - #print("Skipping Chunk:", rootchunk.chunkname) - rootchunk.skip() - - -def read_lwob(file, filename, layers, surfs, tags, add_subd_mod): - '''Read version 1 file, LW < 6.''' - last_pols_count= 0 - print("Importing LWO: " + filename + "\nLWO v1 Format") - - while True: - try: - rootchunk = chunk.Chunk(file) - except EOFError: - break - - if rootchunk.chunkname == b'SRFS': - read_tags(rootchunk.read(), tags) - elif rootchunk.chunkname == b'LAYR': - read_layr_5(rootchunk.read(), layers) - elif rootchunk.chunkname == b'PNTS': - if len(layers) == 0: - # LWOB files have no LAYR chunk to set this up. - nlayer= _obj_layer() - nlayer.name= "Layer 1" - layers.append(nlayer) - read_pnts(rootchunk.read(), layers) - elif rootchunk.chunkname == b'POLS': - last_pols_count= read_pols_5(rootchunk.read(), layers) - elif rootchunk.chunkname == b'PCHS': - last_pols_count= read_pols_5(rootchunk.read(), layers) - layers[-1].has_subds= True - elif rootchunk.chunkname == b'PTAG': - tag_type,= struct.unpack("4s", rootchunk.read(4)) - if tag_type == b'SURF': - read_surf_tags_5(rootchunk.read(), layers, last_pols_count) - else: - rootchunk.skip() - elif rootchunk.chunkname == b'SURF': - read_surf_5(rootchunk.read(), surfs) - else: - # For Debugging \/. - #if handle_layer: - #print("Skipping Chunk: ", rootchunk.chunkname) - rootchunk.skip() - - -def read_lwostring(raw_name): - '''Parse a zero-padded string.''' - - i = raw_name.find(b'\0') - name_len = i + 1 - if name_len % 2 == 1: # Test for oddness. - name_len += 1 - - if i > 0: - # Some plugins put non-text strings in the tags chunk. - name = raw_name[0:i].decode("utf-8", "ignore") - else: - name = "" - - return name, name_len - - -def read_vx(pointdata): - '''Read a variable-length index.''' - if pointdata[0] != 255: - index= pointdata[0]*256 + pointdata[1] - size= 2 - else: - index= pointdata[1]*65536 + pointdata[2]*256 + pointdata[3] - size= 4 - - return index, size - - -def read_tags(tag_bytes, object_tags): - '''Read the object's Tags chunk.''' - offset= 0 - chunk_len= len(tag_bytes) - - while offset < chunk_len: - tag, tag_len= read_lwostring(tag_bytes[offset:]) - offset+= tag_len - object_tags.append(tag) - - -def read_layr(layr_bytes, object_layers, load_hidden): - '''Read the object's layer data.''' - new_layr= _obj_layer() - new_layr.index, flags= struct.unpack(">HH", layr_bytes[0:4]) - - if flags > 0 and not load_hidden: - return False - - print("Reading Object Layer") - offset= 4 - pivot= struct.unpack(">fff", layr_bytes[offset:offset+12]) - # Swap Y and Z to match Blender's pitch. - new_layr.pivot= [pivot[0], pivot[2], pivot[1]] - offset+= 12 - layr_name, name_len = read_lwostring(layr_bytes[offset:]) - offset+= name_len - - if layr_name: - new_layr.name= layr_name - else: - new_layr.name= "Layer %d" % (new_layr.index + 1) - - if len(layr_bytes) == offset+2: - new_layr.parent_index,= struct.unpack(">h", layr_bytes[offset:offset+2]) - - object_layers.append(new_layr) - return True - - -def read_layr_5(layr_bytes, object_layers): - '''Read the object's layer data.''' - # XXX: Need to check what these two exactly mean for a LWOB/LWLO file. - new_layr= _obj_layer() - new_layr.index, flags= struct.unpack(">HH", layr_bytes[0:4]) - - print("Reading Object Layer") - offset= 4 - layr_name, name_len = read_lwostring(layr_bytes[offset:]) - offset+= name_len - - if name_len > 2 and layr_name != 'noname': - new_layr.name= layr_name - else: - new_layr.name= "Layer %d" % new_layr.index - - object_layers.append(new_layr) - - -def read_pnts(pnt_bytes, object_layers): - '''Read the layer's points.''' - print("\tReading Layer ("+object_layers[-1].name+") Points") - offset= 0 - chunk_len= len(pnt_bytes) - - while offset < chunk_len: - pnts= struct.unpack(">fff", pnt_bytes[offset:offset+12]) - offset+= 12 - # Re-order the points so that the mesh has the right pitch, - # the pivot already has the correct order. - pnts= [pnts[0] - object_layers[-1].pivot[0],\ - pnts[2] - object_layers[-1].pivot[1],\ - pnts[1] - object_layers[-1].pivot[2]] - object_layers[-1].pnts.append(pnts) - - -def read_weightmap(weight_bytes, object_layers): - '''Read a weight map's values.''' - chunk_len= len(weight_bytes) - offset= 2 - name, name_len= read_lwostring(weight_bytes[offset:]) - offset+= name_len - weights= [] - - while offset < chunk_len: - pnt_id, pnt_id_len= read_vx(weight_bytes[offset:offset+4]) - offset+= pnt_id_len - value,= struct.unpack(">f", weight_bytes[offset:offset+4]) - offset+= 4 - weights.append([pnt_id, value]) - - object_layers[-1].wmaps[name]= weights - - -def read_morph(morph_bytes, object_layers, is_abs): - '''Read an endomorph's relative or absolute displacement values.''' - chunk_len= len(morph_bytes) - offset= 2 - name, name_len= read_lwostring(morph_bytes[offset:]) - offset+= name_len - deltas= [] - - while offset < chunk_len: - pnt_id, pnt_id_len= read_vx(morph_bytes[offset:offset+4]) - offset+= pnt_id_len - pos= struct.unpack(">fff", morph_bytes[offset:offset+12]) - offset+= 12 - pnt= object_layers[-1].pnts[pnt_id] - - if is_abs: - deltas.append([pnt_id, pos[0], pos[2], pos[1]]) - else: - # Swap the Y and Z to match Blender's pitch. - deltas.append([pnt_id, pnt[0]+pos[0], pnt[1]+pos[2], pnt[2]+pos[1]]) - - object_layers[-1].morphs[name]= deltas - - -def read_colmap(col_bytes, object_layers): - '''Read the RGB or RGBA color map.''' - chunk_len= len(col_bytes) - dia,= struct.unpack(">H", col_bytes[0:2]) - offset= 2 - name, name_len= read_lwostring(col_bytes[offset:]) - offset+= name_len - colors= {} - - if dia == 3: - while offset < chunk_len: - pnt_id, pnt_id_len= read_vx(col_bytes[offset:offset+4]) - offset+= pnt_id_len - col= struct.unpack(">fff", col_bytes[offset:offset+12]) - offset+= 12 - colors[pnt_id]= (col[0], col[1], col[2]) - elif dia == 4: - while offset < chunk_len: - pnt_id, pnt_id_len= read_vx(col_bytes[offset:offset+4]) - offset+= pnt_id_len - col= struct.unpack(">ffff", col_bytes[offset:offset+16]) - offset+= 16 - colors[pnt_id]= (col[0], col[1], col[2]) - - if name in object_layers[-1].colmaps: - if "PointMap" in object_layers[-1].colmaps[name]: - object_layers[-1].colmaps[name]["PointMap"].update(colors) - else: - object_layers[-1].colmaps[name]["PointMap"]= colors - else: - object_layers[-1].colmaps[name]= dict(PointMap=colors) - - -def read_color_vmad(col_bytes, object_layers, last_pols_count): - '''Read the Discontinous (per-polygon) RGB values.''' - chunk_len= len(col_bytes) - dia,= struct.unpack(">H", col_bytes[0:2]) - offset= 2 - name, name_len= read_lwostring(col_bytes[offset:]) - offset+= name_len - colors= {} - abs_pid= len(object_layers[-1].pols) - last_pols_count - - if dia == 3: - while offset < chunk_len: - pnt_id, pnt_id_len= read_vx(col_bytes[offset:offset+4]) - offset+= pnt_id_len - pol_id, pol_id_len= read_vx(col_bytes[offset:offset+4]) - offset+= pol_id_len - - # The PolyID in a VMAD can be relative, this offsets it. - pol_id+= abs_pid - col= struct.unpack(">fff", col_bytes[offset:offset+12]) - offset+= 12 - if pol_id in colors: - colors[pol_id][pnt_id]= (col[0], col[1], col[2]) - else: - colors[pol_id]= dict({pnt_id: (col[0], col[1], col[2])}) - elif dia == 4: - while offset < chunk_len: - pnt_id, pnt_id_len= read_vx(col_bytes[offset:offset+4]) - offset+= pnt_id_len - pol_id, pol_id_len= read_vx(col_bytes[offset:offset+4]) - offset+= pol_id_len - - pol_id+= abs_pid - col= struct.unpack(">ffff", col_bytes[offset:offset+16]) - offset+= 16 - if pol_id in colors: - colors[pol_id][pnt_id]= (col[0], col[1], col[2]) - else: - colors[pol_id]= dict({pnt_id: (col[0], col[1], col[2])}) - - if name in object_layers[-1].colmaps: - if "FaceMap" in object_layers[-1].colmaps[name]: - object_layers[-1].colmaps[name]["FaceMap"].update(colors) - else: - object_layers[-1].colmaps[name]["FaceMap"]= colors - else: - object_layers[-1].colmaps[name]= dict(FaceMap=colors) - - -def read_uvmap(uv_bytes, object_layers): - '''Read the simple UV coord values.''' - chunk_len= len(uv_bytes) - offset= 2 - name, name_len= read_lwostring(uv_bytes[offset:]) - offset+= name_len - uv_coords= {} - - while offset < chunk_len: - pnt_id, pnt_id_len= read_vx(uv_bytes[offset:offset+4]) - offset+= pnt_id_len - pos= struct.unpack(">ff", uv_bytes[offset:offset+8]) - offset+= 8 - uv_coords[pnt_id]= (pos[0], pos[1]) - - if name in object_layers[-1].uvmaps: - if "PointMap" in object_layers[-1].uvmaps[name]: - object_layers[-1].uvmaps[name]["PointMap"].update(uv_coords) - else: - object_layers[-1].uvmaps[name]["PointMap"]= uv_coords - else: - object_layers[-1].uvmaps[name]= dict(PointMap=uv_coords) - - -def read_uv_vmad(uv_bytes, object_layers, last_pols_count): - '''Read the Discontinous (per-polygon) uv values.''' - chunk_len= len(uv_bytes) - offset= 2 - name, name_len= read_lwostring(uv_bytes[offset:]) - offset+= name_len - uv_coords= {} - abs_pid= len(object_layers[-1].pols) - last_pols_count - - while offset < chunk_len: - pnt_id, pnt_id_len= read_vx(uv_bytes[offset:offset+4]) - offset+= pnt_id_len - pol_id, pol_id_len= read_vx(uv_bytes[offset:offset+4]) - offset+= pol_id_len - - pol_id+= abs_pid - pos= struct.unpack(">ff", uv_bytes[offset:offset+8]) - offset+= 8 - if pol_id in uv_coords: - uv_coords[pol_id][pnt_id]= (pos[0], pos[1]) - else: - uv_coords[pol_id]= dict({pnt_id: (pos[0], pos[1])}) - - if name in object_layers[-1].uvmaps: - if "FaceMap" in object_layers[-1].uvmaps[name]: - object_layers[-1].uvmaps[name]["FaceMap"].update(uv_coords) - else: - object_layers[-1].uvmaps[name]["FaceMap"]= uv_coords - else: - object_layers[-1].uvmaps[name]= dict(FaceMap=uv_coords) - - -def read_weight_vmad(ew_bytes, object_layers): - '''Read the VMAD Weight values.''' - chunk_len= len(ew_bytes) - offset= 2 - name, name_len= read_lwostring(ew_bytes[offset:]) - if name != "Edge Weight": - return # We just want the Catmull-Clark edge weights - - offset+= name_len - prev_pol= -1 - prev_pnt= -1 - prev_weight= 0.0 - first_pnt= -1 - poly_pnts= 0 - while offset < chunk_len: - pnt_id, pnt_id_len= read_vx(ew_bytes[offset:offset+4]) - offset+= pnt_id_len - pol_id, pol_id_len= read_vx(ew_bytes[offset:offset+4]) - offset+= pol_id_len - - weight,= struct.unpack(">f", ew_bytes[offset:offset+4]) - offset+= 4 - if prev_pol == pol_id: - # Points on the same poly should define an edge. - object_layers[-1].edge_weights["{0} {1}".format(prev_pnt, pnt_id)]= weight - poly_pnts += 1 - else: - if poly_pnts > 2: - # Make an edge from the first and last points. - object_layers[-1].edge_weights["{0} {1}".format(first_pnt, prev_pnt)]= prev_weight - first_pnt= pnt_id - prev_pol= pol_id - poly_pnts= 1 - - prev_pnt= pnt_id - prev_weight= weight - - if poly_pnts > 2: - object_layers[-1].edge_weights["{0} {1}".format(first_pnt, prev_pnt)]= prev_weight - - -def read_pols(pol_bytes, object_layers): - '''Read the layer's polygons, each one is just a list of point indexes.''' - print("\tReading Layer ("+object_layers[-1].name+") Polygons") - offset= 0 - pols_count = len(pol_bytes) - old_pols_count= len(object_layers[-1].pols) - - while offset < pols_count: - pnts_count,= struct.unpack(">H", pol_bytes[offset:offset+2]) - offset+= 2 - all_face_pnts= [] - for j in range(pnts_count): - face_pnt, data_size= read_vx(pol_bytes[offset:offset+4]) - offset+= data_size - all_face_pnts.append(face_pnt) - - object_layers[-1].pols.append(all_face_pnts) - - return len(object_layers[-1].pols) - old_pols_count - - -def read_pols_5(pol_bytes, object_layers): - ''' - Read the polygons, each one is just a list of point indexes. - But it also includes the surface index. - ''' - print("\tReading Layer ("+object_layers[-1].name+") Polygons") - offset= 0 - chunk_len= len(pol_bytes) - old_pols_count= len(object_layers[-1].pols) - poly= 0 - - while offset < chunk_len: - pnts_count,= struct.unpack(">H", pol_bytes[offset:offset+2]) - offset+= 2 - all_face_pnts= [] - for j in range(pnts_count): - face_pnt,= struct.unpack(">H", pol_bytes[offset:offset+2]) - offset+= 2 - all_face_pnts.append(face_pnt) - - object_layers[-1].pols.append(all_face_pnts) - sid,= struct.unpack(">h", pol_bytes[offset:offset+2]) - offset+= 2 - sid= abs(sid) - 1 - if sid not in object_layers[-1].surf_tags: - object_layers[-1].surf_tags[sid]= [] - object_layers[-1].surf_tags[sid].append(poly) - poly+= 1 - - return len(object_layers[-1].pols) - old_pols_count - - -def read_bones(bone_bytes, object_layers): - '''Read the layer's skelegons.''' - print("\tReading Layer ("+object_layers[-1].name+") Bones") - offset= 0 - bones_count = len(bone_bytes) - - while offset < bones_count: - pnts_count,= struct.unpack(">H", bone_bytes[offset:offset+2]) - offset+= 2 - all_bone_pnts= [] - for j in range(pnts_count): - bone_pnt, data_size= read_vx(bone_bytes[offset:offset+4]) - offset+= data_size - all_bone_pnts.append(bone_pnt) - - object_layers[-1].bones.append(all_bone_pnts) - - -def read_bone_tags(tag_bytes, object_layers, object_tags, type): - '''Read the bone name or roll tags.''' - offset= 0 - chunk_len= len(tag_bytes) - - if type == 'BONE': - bone_dict= object_layers[-1].bone_names - elif type == 'BNUP': - bone_dict= object_layers[-1].bone_rolls - else: - return - - while offset < chunk_len: - pid, pid_len= read_vx(tag_bytes[offset:offset+4]) - offset+= pid_len - tid,= struct.unpack(">H", tag_bytes[offset:offset+2]) - offset+= 2 - bone_dict[pid]= object_tags[tid] - - -def read_surf_tags(tag_bytes, object_layers, last_pols_count): - '''Read the list of PolyIDs and tag indexes.''' - print("\tReading Layer ("+object_layers[-1].name+") Surface Assignments") - offset= 0 - chunk_len= len(tag_bytes) - - # Read in the PolyID/Surface Index pairs. - abs_pid= len(object_layers[-1].pols) - last_pols_count - while offset < chunk_len: - pid, pid_len= read_vx(tag_bytes[offset:offset+4]) - offset+= pid_len - sid,= struct.unpack(">H", tag_bytes[offset:offset+2]) - offset+=2 - if sid not in object_layers[-1].surf_tags: - object_layers[-1].surf_tags[sid]= [] - object_layers[-1].surf_tags[sid].append(pid + abs_pid) - - -def read_surf(surf_bytes, object_surfs): - '''Read the object's surface data.''' - if len(object_surfs) == 0: - print("Reading Object Surfaces") - - surf= _obj_surf() - name, name_len= read_lwostring(surf_bytes) - if len(name) != 0: - surf.name = name - - # We have to read this, but we won't use it...yet. - s_name, s_name_len= read_lwostring(surf_bytes[name_len:]) - offset= name_len+s_name_len - block_size= len(surf_bytes) - while offset < block_size: - subchunk_name,= struct.unpack("4s", surf_bytes[offset:offset+4]) - offset+= 4 - subchunk_len,= struct.unpack(">H", surf_bytes[offset:offset+2]) - offset+= 2 - - # Now test which subchunk it is. - if subchunk_name == b'COLR': - surf.colr= struct.unpack(">fff", surf_bytes[offset:offset+12]) - # Don't bother with any envelopes for now. - - elif subchunk_name == b'DIFF': - surf.diff,= struct.unpack(">f", surf_bytes[offset:offset+4]) - - elif subchunk_name == b'LUMI': - surf.lumi,= struct.unpack(">f", surf_bytes[offset:offset+4]) - - elif subchunk_name == b'SPEC': - surf.spec,= struct.unpack(">f", surf_bytes[offset:offset+4]) - - elif subchunk_name == b'REFL': - surf.refl,= struct.unpack(">f", surf_bytes[offset:offset+4]) - - elif subchunk_name == b'RBLR': - surf.rblr,= struct.unpack(">f", surf_bytes[offset:offset+4]) - - elif subchunk_name == b'TRAN': - surf.tran,= struct.unpack(">f", surf_bytes[offset:offset+4]) - - elif subchunk_name == b'RIND': - surf.rind,= struct.unpack(">f", surf_bytes[offset:offset+4]) - - elif subchunk_name == b'TBLR': - surf.tblr,= struct.unpack(">f", surf_bytes[offset:offset+4]) - - elif subchunk_name == b'TRNL': - surf.trnl,= struct.unpack(">f", surf_bytes[offset:offset+4]) - - elif subchunk_name == b'GLOS': - surf.glos,= struct.unpack(">f", surf_bytes[offset:offset+4]) - - elif subchunk_name == b'SHRP': - surf.shrp,= struct.unpack(">f", surf_bytes[offset:offset+4]) - - elif subchunk_name == b'SMAN': - s_angle,= struct.unpack(">f", surf_bytes[offset:offset+4]) - if s_angle > 0.0: - surf.smooth = True - - offset+= subchunk_len - - object_surfs[surf.name]= surf - - -def read_surf_5(surf_bytes, object_surfs): - '''Read the object's surface data.''' - if len(object_surfs) == 0: - print("Reading Object Surfaces") - - surf= _obj_surf() - name, name_len= read_lwostring(surf_bytes) - if len(name) != 0: - surf.name = name - - offset= name_len - chunk_len= len(surf_bytes) - while offset < chunk_len: - subchunk_name,= struct.unpack("4s", surf_bytes[offset:offset+4]) - offset+= 4 - subchunk_len,= struct.unpack(">H", surf_bytes[offset:offset+2]) - offset+= 2 - - # Now test which subchunk it is. - if subchunk_name == b'COLR': - color= struct.unpack(">BBBB", surf_bytes[offset:offset+4]) - surf.colr= [color[0] / 255.0, color[1] / 255.0, color[2] / 255.0] - - elif subchunk_name == b'DIFF': - surf.diff,= struct.unpack(">h", surf_bytes[offset:offset+2]) - surf.diff/= 256.0 # Yes, 256 not 255. - - elif subchunk_name == b'LUMI': - surf.lumi,= struct.unpack(">h", surf_bytes[offset:offset+2]) - surf.lumi/= 256.0 - - elif subchunk_name == b'SPEC': - surf.spec,= struct.unpack(">h", surf_bytes[offset:offset+2]) - surf.spec/= 256.0 - - elif subchunk_name == b'REFL': - surf.refl,= struct.unpack(">h", surf_bytes[offset:offset+2]) - surf.refl/= 256.0 - - elif subchunk_name == b'TRAN': - surf.tran,= struct.unpack(">h", surf_bytes[offset:offset+2]) - surf.tran/= 256.0 - - elif subchunk_name == b'RIND': - surf.rind,= struct.unpack(">f", surf_bytes[offset:offset+4]) - - elif subchunk_name == b'GLOS': - surf.glos,= struct.unpack(">h", surf_bytes[offset:offset+2]) - - elif subchunk_name == b'SMAN': - s_angle,= struct.unpack(">f", surf_bytes[offset:offset+4]) - if s_angle > 0.0: - surf.smooth = True - - offset+= subchunk_len - - object_surfs[surf.name]= surf - - -def create_mappack(data, map_name, map_type): - '''Match the map data to faces.''' - pack= {} - - def color_pointmap(map): - for fi in range(len(data.pols)): - if fi not in pack: - pack[fi]= [] - for pnt in data.pols[fi]: - if pnt in map: - pack[fi].append(map[pnt]) - else: - pack[fi].append((1.0, 1.0, 1.0)) - - def color_facemap(map): - for fi in range(len(data.pols)): - if fi not in pack: - pack[fi]= [] - for p in data.pols[fi]: - pack[fi].append((1.0, 1.0, 1.0)) - if fi in map: - for po in range(len(data.pols[fi])): - if data.pols[fi][po] in map[fi]: - pack[fi].insert(po, map[fi][data.pols[fi][po]]) - del pack[fi][po+1] - - def uv_pointmap(map): - for fi in range(len(data.pols)): - if fi not in pack: - pack[fi]= [] - for p in data.pols[fi]: - pack[fi].append((-0.1,-0.1)) - for po in range(len(data.pols[fi])): - pnt_id= data.pols[fi][po] - if pnt_id in map: - pack[fi].insert(po, map[pnt_id]) - del pack[fi][po+1] - - def uv_facemap(map): - for fi in range(len(data.pols)): - if fi not in pack: - pack[fi]= [] - for p in data.pols[fi]: - pack[fi].append((-0.1,-0.1)) - if fi in map: - for po in range(len(data.pols[fi])): - pnt_id= data.pols[fi][po] - if pnt_id in map[fi]: - pack[fi].insert(po, map[fi][pnt_id]) - del pack[fi][po+1] - - if map_type == "COLOR": - # Look at the first map, is it a point or face map - if "PointMap" in data.colmaps[map_name]: - color_pointmap(data.colmaps[map_name]["PointMap"]) - - if "FaceMap" in data.colmaps[map_name]: - color_facemap(data.colmaps[map_name]["FaceMap"]) - elif map_type == "UV": - if "PointMap" in data.uvmaps[map_name]: - uv_pointmap(data.uvmaps[map_name]["PointMap"]) - - if "FaceMap" in data.uvmaps[map_name]: - uv_facemap(data.uvmaps[map_name]["FaceMap"]) - - return pack - - -def build_armature(layer_data, bones): - '''Build an armature from the skelegon data in the mesh.''' - print("Building Armature") - - # New Armatures include a default bone, remove it. - bones.remove(bones[0]) - - # Now start adding the bones at the point locations. - prev_bone= None - for skb_idx in range(len(layer_data.bones)): - if skb_idx in layer_data.bone_names: - nb= bones.new(layer_data.bone_names[skb_idx]) - else: - nb= bones.new("Bone") - - nb.head= layer_data.pnts[layer_data.bones[skb_idx][0]] - nb.tail= layer_data.pnts[layer_data.bones[skb_idx][1]] - - if skb_idx in layer_data.bone_rolls: - xyz= layer_data.bone_rolls[skb_idx].split(' ') - vec= mathutils.Vector() - vec.x= float(xyz[0]) - vec.y= float(xyz[1]) - vec.z= float(xyz[2]) - quat= vec.to_track_quat('Y', 'Z') - nb.roll= quat.to_euler('XYZ')[2] * -1 - # XXX: This code may need a second look and test. - else: - nb.roll= 0.0 - - if prev_bone != None: - if nb.head == prev_bone.tail: - nb.parent= prev_bone - - nb.use_connect= True - prev_bone= nb - - -def build_objects(object_layers, object_surfs, object_tags, object_name, add_subd_mod, skel_to_arm): - '''Using the gathered data, create the objects.''' - ob_dict= {} # Used for the parenting setup. - print("Adding %d Materials" % len(object_surfs)) - - for surf_key in object_surfs: - surf_data= object_surfs[surf_key] - surf_data.bl_mat= bpy.data.materials.new(surf_data.name) - surf_data.bl_mat.diffuse_color= (surf_data.colr[:]) - surf_data.bl_mat.diffuse_intensity= surf_data.diff - surf_data.bl_mat.emit= surf_data.lumi - surf_data.bl_mat.specular_intensity= surf_data.spec - if surf_data.refl != 0.0: - surf_data.bl_mat.raytrace_mirror.use= True - surf_data.bl_mat.raytrace_mirror.reflect_factor= surf_data.refl - surf_data.bl_mat.raytrace_mirror.gloss_factor= 1.0-surf_data.rblr - if surf_data.tran != 0.0: - surf_data.bl_mat.use_transparency= True - surf_data.bl_mat.transparency_method= 'RAYTRACE' - surf_data.bl_mat.alpha= 1.0 - surf_data.tran - surf_data.bl_mat.raytrace_transparency.ior= surf_data.rind - surf_data.bl_mat.raytrace_transparency.gloss_factor= 1.0 - surf_data.tblr - surf_data.bl_mat.translucency= surf_data.trnl - surf_data.bl_mat.specular_hardness= int(4*((10*surf_data.glos)*(10*surf_data.glos)))+4 - # The Gloss is as close as possible given the differences. - - # Single layer objects use the object file's name instead. - if len(object_layers) and object_layers[-1].name == 'Layer 1': - object_layers[-1].name= object_name - print("Building '%s' Object" % object_name) - else: - print("Building %d Objects" % len(object_layers)) - - for layer_data in object_layers: - me= bpy.data.meshes.new(layer_data.name) - me.vertices.add(len(layer_data.pnts)) - me.faces.add(len(layer_data.pols)) - # for vi in range(len(layer_data.pnts)): - # me.vertices[vi].co= layer_data.pnts[vi] - - # faster, would be faster again to use an array - me.vertices.foreach_set("co", [axis for co in layer_data.pnts for axis in co]) - - ngons= {} # To keep the FaceIdx consistant, handle NGons later. - edges= [] # Holds the FaceIdx of the 2-point polys. - for fi, fpol in enumerate(layer_data.pols): - fpol.reverse() # Reversing gives correct normal directions - # PointID 0 in the last element causes Blender to think it's un-used. - if fpol[-1] == 0: - fpol.insert(0, fpol[-1]) - del fpol[-1] - - vlen= len(fpol) - if vlen == 3 or vlen == 4: - for i in range(vlen): - me.faces[fi].vertices_raw[i]= fpol[i] - elif vlen == 2: - edges.append(fi) - elif vlen != 1: - ngons[fi]= fpol # Deal with them later - - ob= bpy.data.objects.new(layer_data.name, me) - bpy.context.scene.objects.link(ob) - ob_dict[layer_data.index]= [ob, layer_data.parent_index] - - # Move the object so the pivot is in the right place. - ob.location= layer_data.pivot - - # Create the Material Slots and assign the MatIndex to the correct faces. - mat_slot= 0 - for surf_key in layer_data.surf_tags: - if object_tags[surf_key] in object_surfs: - me.materials.append(object_surfs[object_tags[surf_key]].bl_mat) - - for fi in layer_data.surf_tags[surf_key]: - me.faces[fi].material_index= mat_slot - me.faces[fi].use_smooth= object_surfs[object_tags[surf_key]].smooth - - mat_slot+=1 - - # Create the Vertex Groups (LW's Weight Maps). - if len(layer_data.wmaps) > 0: - print("Adding %d Vertex Groups" % len(layer_data.wmaps)) - for wmap_key in layer_data.wmaps: - vgroup= ob.vertex_groups.new() - vgroup.name= wmap_key - wlist= layer_data.wmaps[wmap_key] - for pvp in wlist: - ob.vertex_groups.assign([pvp[0]], vgroup, pvp[1], 'REPLACE') - - # Create the Shape Keys (LW's Endomorphs). - if len(layer_data.morphs) > 0: - print("Adding %d Shapes Keys" % len(layer_data.morphs)) - ob.add_shape_key('Basis') # Got to have a Base Shape. - for morph_key in layer_data.morphs: - skey= ob.add_shape_key(morph_key) - dlist= layer_data.morphs[morph_key] - for pdp in dlist: - me.shape_keys.keys[skey.name].data[pdp[0]].co= [pdp[1], pdp[2], pdp[3]] - - # Create the Vertex Color maps. - if len(layer_data.colmaps) > 0: - print("Adding %d Vertex Color Maps" % len(layer_data.colmaps)) - for cmap_key in layer_data.colmaps: - map_pack= create_mappack(layer_data, cmap_key, "COLOR") - vcol= me.vertex_colors.new(cmap_key) - if not vcol: - break - for fi in map_pack: - if fi > len(vcol.data): - continue - face= map_pack[fi] - colf= vcol.data[fi] - - if len(face) > 2: - colf.color1= face[0] - colf.color2= face[1] - colf.color3= face[2] - if len(face) == 4: - colf.color4= face[3] - - # Create the UV Maps. - if len(layer_data.uvmaps) > 0: - print("Adding %d UV Textures" % len(layer_data.uvmaps)) - for uvmap_key in layer_data.uvmaps: - map_pack= create_mappack(layer_data, uvmap_key, "UV") - uvm= me.uv_textures.new(uvmap_key) - if not uvm: - break - for fi in map_pack: - if fi > len(uvm.data): - continue - face= map_pack[fi] - uvf= uvm.data[fi] - - if len(face) > 2: - uvf.uv1= face[0] - uvf.uv2= face[1] - uvf.uv3= face[2] - if len(face) == 4: - uvf.uv4= face[3] - - # Now add the NGons. - if len(ngons) > 0: - for ng_key in ngons: - face_offset= len(me.faces) - ng= ngons[ng_key] - v_locs= [] - for vi in range(len(ng)): - v_locs.append(mathutils.Vector(layer_data.pnts[ngons[ng_key][vi]])) - tris= PolyFill([v_locs]) - me.faces.add(len(tris)) - for tri in tris: - face= me.faces[face_offset] - face.vertices_raw[0]= ng[tri[0]] - face.vertices_raw[1]= ng[tri[1]] - face.vertices_raw[2]= ng[tri[2]] - face.material_index= me.faces[ng_key].material_index - face.use_smooth= me.faces[ng_key].use_smooth - face_offset+= 1 - - # FaceIDs are no longer a concern, so now update the mesh. - has_edges= len(edges) > 0 or len(layer_data.edge_weights) > 0 - me.update(calc_edges=has_edges) - - # Add the edges. - edge_offset= len(me.edges) - me.edges.add(len(edges)) - for edge_fi in edges: - me.edges[edge_offset].vertices[0]= layer_data.pols[edge_fi][0] - me.edges[edge_offset].vertices[1]= layer_data.pols[edge_fi][1] - edge_offset+= 1 - - # Apply the Edge Weighting. - if len(layer_data.edge_weights) > 0: - for edge in me.edges: - edge_sa= "{0} {1}".format(edge.vertices[0], edge.vertices[1]) - edge_sb= "{0} {1}".format(edge.vertices[1], edge.vertices[0]) - if edge_sa in layer_data.edge_weights: - edge.crease= layer_data.edge_weights[edge_sa] - elif edge_sb in layer_data.edge_weights: - edge.crease= layer_data.edge_weights[edge_sb] - - # Unfortunately we can't exlude certain faces from the subdivision. - if layer_data.has_subds and add_subd_mod: - ob.modifiers.new(name="Subsurf", type='SUBSURF') - - # Should we build an armature from the embedded rig? - if len(layer_data.bones) > 0 and skel_to_arm: - bpy.ops.object.armature_add() - arm_object= bpy.context.active_object - arm_object.name= "ARM_" + layer_data.name - arm_object.data.name= arm_object.name - arm_object.location= layer_data.pivot - bpy.ops.object.mode_set(mode='EDIT') - build_armature(layer_data, arm_object.data.edit_bones) - bpy.ops.object.mode_set(mode='OBJECT') - - # Clear out the dictionaries for this layer. - layer_data.bone_names.clear() - layer_data.bone_rolls.clear() - layer_data.wmaps.clear() - layer_data.colmaps.clear() - layer_data.uvmaps.clear() - layer_data.morphs.clear() - layer_data.surf_tags.clear() - - # With the objects made, setup the parents and re-adjust the locations. - for ob_key in ob_dict: - if ob_dict[ob_key][1] != -1 and ob_dict[ob_key][1] in ob_dict: - parent_ob = ob_dict[ob_dict[ob_key][1]] - ob_dict[ob_key][0].parent= parent_ob[0] - ob_dict[ob_key][0].location-= parent_ob[0].location - - bpy.context.scene.update() - - print("Done Importing LWO File") - - -from bpy.props import * - - -class IMPORT_OT_lwo(bpy.types.Operator): - '''Import LWO Operator.''' - bl_idname= "import_scene.lwo" - bl_label= "Import LWO" - bl_description= "Import a LightWave Object file." - bl_options= {'REGISTER', 'UNDO'} - - filepath= StringProperty(name="File Path", description="Filepath used for importing the LWO file", maxlen=1024, default="") - - ADD_SUBD_MOD= BoolProperty(name="Apply SubD Modifier", description="Apply the Subdivision Surface modifier to layers with Subpatches", default=True) - LOAD_HIDDEN= BoolProperty(name="Load Hidden Layers", description="Load object layers that have been marked as hidden", default=False) - SKEL_TO_ARM= BoolProperty(name="Create Armature", description="Create an armature from an embedded Skelegon rig", default=True) - - def execute(self, context): - load_lwo(self.properties.filepath, - context, - self.properties.ADD_SUBD_MOD, - self.properties.LOAD_HIDDEN, - self.properties.SKEL_TO_ARM) - return {'FINISHED'} - - def invoke(self, context, event): - wm= context.window_manager - wm.add_fileselect(self) - return {'RUNNING_MODAL'} - - -def menu_func(self, context): - self.layout.operator(IMPORT_OT_lwo.bl_idname, text="LightWave Object (.lwo)") - -def register(): - bpy.types.INFO_MT_file_import.append(menu_func) - -def unregister(): - bpy.types.INFO_MT_file_import.remove(menu_func) - -if __name__ == "__main__": - register() diff --git a/io_import_scene_mhx.py b/io_import_scene_mhx.py deleted file mode 100644 index bc637c9e..00000000 --- a/io_import_scene_mhx.py +++ /dev/null @@ -1,2245 +0,0 @@ -# ##### 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -# ##### END GPL LICENSE BLOCK ##### - -bl_addon_info = { - "name": "Import MakeHuman (.mhx)", - "author": "Thomas Larsson", - "version": (0,9,5), - "blender": (2, 5, 3), - "api": 31667, - "location": "File > Import", - "description": "Import files in the MakeHuman eXchange format (.mhx)", - "warning": "Alpha version", - "wiki_url": "http://wiki.blender.org/index.php/Extensions:2.5/Py/" - "Scripts/File_I-O/Make_Human", - "tracker_url": "https://projects.blender.org/tracker/index.php?" - "func=detail&aid=21872&group_id=153&atid=469", - "category": "Import/Export"} - -""" -**Project Name:** MakeHuman - -**Product Home Page:** http://www.makehuman.org/ - -**Code Home Page:** http://code.google.com/p/makehuman/ - -**Authors:** Thomas Larsson - -**Copyright(c):** MakeHuman Team 2001-2010 - -**Licensing:** GPL3 (see also http://sites.google.com/site/makehumandocs/licensing) - -**Coding Standards:** See http://sites.google.com/site/makehumandocs/developers-guide - -Abstract -MHX (MakeHuman eXchange format) importer for Blender 2.5x. -Version 0.9 - -""" - -""" -Place this file in the .blender/scripts/addons dir -You have to activated the script in the "Add-Ons" tab (user preferences). -Access from the File > Import menu. -""" - -# -# -# - -import bpy -import os -import time -import mathutils -from mathutils import * -import geometry -import string - -MAJOR_VERSION = 0 -MINOR_VERSION = 9 -MHX249 = False -Blender24 = False -Blender25 = True -TexDir = "~/makehuman/exports" - -# -# -# - -theScale = 1.0 -useMesh = 1 -doSmash = 1 -verbosity = 2 -warnedTextureDir = False -warnedVersion = False - -true = True -false = False -Epsilon = 1e-6 -nErrors = 0 -theTempDatum = None - -todo = [] - -# -# toggle flags -# - -T_ArmIK = 0x01 -T_LegIK = 0x02 -T_Replace = 0x20 -T_Face = 0x40 -T_Shape = 0x80 -T_Mesh = 0x100 -T_Armature = 0x200 -T_Proxy = 0x400 -T_Panel = 0x800 - -T_Rigify = 0x1000 -T_Preset = 0x2000 -T_Symm = 0x4000 -T_MHX = 0x8000 - -toggle = T_Replace + T_ArmIK + T_LegIK + T_Mesh + T_Armature + T_Face - -# -# setFlagsAndFloats(rigFlags): -# -# Global floats -fLegIK = 0.0 -fArmIK = 0.0 -fFingerPanel = 0.0 -fFingerIK = 0.0 -fFingerCurl = 0.0 - -# rigLeg and rigArm flags -T_Toes = 0x0001 -T_GoboFoot = 0x0002 -T_InvFoot = 0x0004 - -T_FingerPanel = 0x100 -T_FingerCurl = 0x0200 -T_FingerIK = 0x0400 - - -T_LocalFKIK = 0x8000 - -rigLeg = 0 -rigArm = 0 - -def setFlagsAndFloats(rigFlags): - global toggle, rigLeg, rigArm - - (footRig, fingerRig) = rigFlags - rigLeg = 0 - rigArm = 0 - if footRig == 'Reverse foot': rigLeg |= T_InvFoot - elif footRig == 'Gobo': rigLeg |= T_GoboFoot - - if fingerRig == 'Panel': rigArm |= T_FingerPanel - elif fingerRig == 'IK': rigArm |= T_FingerIK - elif fingerRig == 'Curl': rigArm |= T_FingerCurl - - toggle |= T_Panel - - # Global floats, used as influences - global fFingerCurl, fLegIK, fArmIK, fFingerIK - - fFingerCurl = 1.0 if rigArm&T_FingerCurl else 0.0 - fLegIK = 1.0 if toggle&T_LegIK else 0.0 - fArmIK = 1.0 if toggle&T_ArmIK else 0.0 - fFingerIK = 1.0 if rigArm&T_FingerIK else 0.0 - - return - - -# -# Dictionaries -# - -loadedData = { - 'NONE' : {}, - - 'Object' : {}, - 'Mesh' : {}, - 'Armature' : {}, - 'Lamp' : {}, - 'Camera' : {}, - 'Lattice' : {}, - 'Curve' : {}, - - 'Material' : {}, - 'Image' : {}, - 'MaterialTextureSlot' : {}, - 'Texture' : {}, - - 'Bone' : {}, - 'BoneGroup' : {}, - 'Rigify' : {}, - - 'Action' : {}, - 'Group' : {}, - - 'MeshTextureFaceLayer' : {}, - 'MeshColorLayer' : {}, - 'VertexGroup' : {}, - 'ShapeKey' : {}, - 'ParticleSystem' : {}, - - 'ObjectConstraints' : {}, - 'ObjectModifiers' : {}, - 'MaterialSlot' : {}, -} - -Plural = { - 'Object' : 'objects', - 'Mesh' : 'meshes', - 'Lattice' : 'lattices', - 'Curve' : 'curves', - 'Group' : 'groups', - 'Empty' : 'empties', - 'Armature' : 'armatures', - 'Bone' : 'bones', - 'BoneGroup' : 'bone_groups', - 'Pose' : 'poses', - 'PoseBone' : 'pose_bones', - 'Material' : 'materials', - 'Texture' : 'textures', - 'Image' : 'images', - 'Camera' : 'cameras', - 'Lamp' : 'lamps', - 'World' : 'worlds', -} - -# -# Creators -# - -def uvtexCreator(me, name): - print("uvtexCreator", me, name) - return me.uv_textures.new(name) - - -def vertcolCreator(me, name): - print("vertcolCreator", me, name) - return me.vertex_colors.new(name) - - -# -# loadMhx(filePath, context, flags): -# - -def loadMhx(filePath, context, flags): - global toggle - toggle = flags - readMhxFile(filePath) - return - -# -# readMhxFile(filePath, rigFlags): -# - -def readMhxFile(filePath, rigFlags): - global todo, nErrors - - fileName = os.path.expanduser(filePath) - (shortName, ext) = os.path.splitext(fileName) - if ext != ".mhx": - print("Error: Not a mhx file: " + fileName) - return - print( "Opening MHX file "+ fileName ) - time1 = time.clock() - - ignore = False - stack = [] - tokens = [] - key = "toplevel" - level = 0 - nErrors = 0 - - setFlagsAndFloats(rigFlags) - - file= open(fileName, "rU") - print( "Tokenizing" ) - lineNo = 0 - for line in file: - # print(line) - lineSplit= line.split() - lineNo += 1 - if len(lineSplit) == 0: - pass - elif lineSplit[0] == '#': - pass - elif lineSplit[0] == 'end': - try: - sub = tokens - tokens = stack.pop() - if tokens: - tokens[-1][2] = sub - level -= 1 - except: - print( "Tokenizer error at or before line %d" % lineNo ) - print( line ) - dummy = stack.pop() - elif lineSplit[-1] == ';': - if lineSplit[0] == '\\': - key = lineSplit[1] - tokens.append([key,lineSplit[2:-1],[]]) - else: - key = lineSplit[0] - tokens.append([key,lineSplit[1:-1],[]]) - else: - key = lineSplit[0] - tokens.append([key,lineSplit[1:],[]]) - stack.append(tokens) - level += 1 - tokens = [] - file.close() - - if level != 0: - raise NameError("Tokenizer out of kilter %d" % level) - clearScene() - print( "Parsing" ) - parse(tokens) - - for (expr, glbals, lcals) in todo: - try: - # print("Doing %s" % expr) - exec(expr, glbals, lcals) - except: - msg = "Failed: "+expr - print( msg ) - nErrors += 1 - #raise NameError(msg) - - print("Postprocess") - postProcess() - print("HideLayers") - hideLayers() - time2 = time.clock() - print("toggle = %x" % toggle) - msg = "File %s loaded in %g s" % (fileName, time2-time1) - if nErrors: - msg += " but there where %d errors. " % (nErrors) - print(msg) - return # loadMhx - -# -# getObject(name, var, glbals, lcals): -# - -def getObject(name, var, glbals, lcals): - try: - ob = loadedData['Object'][name] - except: - if name != "None": - expr = "%s = loadedData['Object'][name]" % var - print("Todo ", expr) - todo.append((expr, glbals, lcals)) - ob = None - return ob - -# -# parse(tokens): -# - -ifResult = False - -def parse(tokens): - global warnedVersion, MHX249, ifResult - - for (key, val, sub) in tokens: - # print("Parse %s" % key) - data = None - if key == 'MHX': - if int(val[0]) != MAJOR_VERSION and int(val[1]) != MINOR_VERSION and not warnedVersion: - print("Warning: \nThis file was created with another version of MHX\n") - warnedVersion = True - - elif key == 'MHX249': - MHX249 = eval(val[0]) - print("Blender 2.49 compatibility mode is %s\n" % MHX249) - - elif key == 'if': - try: - ifResult = eval(val[0]) - except: - ifResult = False - if ifResult: - parse(sub) - - elif key == 'elif': - if not ifResult: - try: - ifResult = eval(val[0]) - except: - ifResult = False - if ifResult: - parse(sub) - - elif key == 'else': - if not ifResult: - parse(sub) - - - elif MHX249: - pass - - elif key == 'print': - msg = concatList(val) - print(msg) - elif key == 'warn': - msg = concatList(val) - print(msg) - elif key == 'error': - msg = concatList(val) - raise NameError(msg) - elif key == "Object": - parseObject(val, sub) - elif key == "Mesh": - data = parseMesh(val, sub) - elif key == "Curve": - data = parseCurve(val, sub) - elif key == "Lattice": - data = parseLattice(val, sub) - elif key == "Group": - data = parseGroup(val, sub) - elif key == "Armature": - data = parseArmature(val, sub) - elif key == "Pose": - data = parsePose(val, sub) - elif key == "Action": - data = parseAction(val, sub) - elif key == "Material": - data = parseMaterial(val, sub) - elif key == "Texture": - data = parseTexture(val, sub) - elif key == "Image": - data = parseImage(val, sub) - elif key == "Process": - parseProcess(val, sub) - elif key == 'AnimationData': - try: - ob = loadedData['Object'][val[0]] - except: - ob = None - if ob: - bpy.context.scene.objects.active = ob - parseAnimationData(ob, sub) - elif key == 'ShapeKeys': - try: - ob = loadedData['Object'][val[0]] - except: - ob = None - if ob: - bpy.context.scene.objects.active = ob - parseShapeKeys(ob, ob.data, val, sub) - else: - data = parseDefaultType(key, val, sub) - - if data and key != 'Mesh': - print( data ) - return - -# -# parseDefaultType(typ, args, tokens): -# - -def parseDefaultType(typ, args, tokens): - global todo - - name = args[0] - data = None - expr = "bpy.data.%s.new('%s')" % (Plural[typ], name) - print(expr) - data = eval(expr) - print(" ok", data) - - bpyType = typ.capitalize() - print(bpyType, name, data) - loadedData[bpyType][name] = data - if data == None: - return None - - for (key, val, sub) in tokens: - #print("%s %s" % (key, val)) - defaultKey(key, val, sub, 'data', [], globals(), locals()) - print("Done ", data) - return data - -# -# concatList(elts) -# - -def concatList(elts): - string = "" - for elt in elts: - string += " %s" % elt - return string - -# -# parseAction(args, tokens): -# parseFCurve(fcu, args, tokens): -# parseKeyFramePoint(pt, args, tokens): -# - -def parseAction(args, tokens): - name = args[0] - if invalid(args[1]): - return - - ob = bpy.context.object - bpy.ops.object.mode_set(mode='POSE') - if ob.animation_data: - ob.animation_data.action = None - created = {} - for (key, val, sub) in tokens: - if key == 'FCurve': - prepareActionFCurve(ob, created, val, sub) - - act = ob.animation_data.action - loadedData['Action'][name] = act - if act == None: - print("Ignoring action %s" % name) - return act - act.name = name - print("Action", name, act, ob) - - for (key, val, sub) in tokens: - if key == 'FCurve': - fcu = parseActionFCurve(act, ob, val, sub) - else: - defaultKey(key, val, sub, 'act', [], globals(), locals()) - ob.animation_data.action = None - bpy.ops.object.mode_set(mode='OBJECT') - return act - -def prepareActionFCurve(ob, created, args, tokens): - dataPath = args[0] - index = args[1] - (expr, channel) = channelFromDataPath(dataPath, index) - try: - if channel in created[expr]: - return - else: - created[expr].append(channel) - except: - created[expr] = [channel] - - times = [] - for (key, val, sub) in tokens: - if key == 'kp': - times.append(int(val[0])) - - try: - data = eval(expr) - except: - print("Ignoring illegal expression: %s" % expr) - return - - n = 0 - for t in times: - #bpy.context.scene.current_frame = t - bpy.ops.anim.change_frame(frame = t) - try: - data.keyframe_insert(channel) - n += 1 - except: - pass - #print("failed", data, expr, channel) - if n != len(times): - print("Mismatch", n, len(times), expr, channel) - return - -def channelFromDataPath(dataPath, index): - words = dataPath.split(']') - if len(words) == 1: - # location - expr = "ob" - channel = dataPath - elif len(words) == 2: - # pose.bones["tongue"].location - expr = "ob.%s]" % (words[0]) - cwords = words[1].split('.') - channel = cwords[1] - elif len(words) == 3: - # pose.bones["brow.R"]["mad"] - expr = "ob.%s]" % (words[0]) - cwords = words[1].split('"') - channel = cwords[1] - # print(expr, channel, index) - return (expr, channel) - -def parseActionFCurve(act, ob, args, tokens): - dataPath = args[0] - index = args[1] - (expr, channel) = channelFromDataPath(dataPath, index) - index = int(args[1]) - - success = False - for fcu in act.fcurves: - (expr1, channel1) = channelFromDataPath(fcu.data_path, fcu.array_index) - if expr1 == expr and channel1 == channel and fcu.array_index == index: - success = True - break - if not success: - return None - - n = 0 - for (key, val, sub) in tokens: - if key == 'kp': - try: - pt = fcu.keyframe_points[n] - pt.use_interpolation = 'LINEAR' - pt = parseKeyFramePoint(pt, val, sub) - n += 1 - except: - pass - #print(tokens) - #raise NameError("kp", fcu, n, len(fcu.keyframe_points), val) - else: - defaultKey(key, val, sub, 'fcu', [], globals(), locals()) - return fcu - -def parseKeyFramePoint(pt, args, tokens): - pt.co = (float(args[0]), float(args[1])) - if len(args) > 2: - pt.handle_left = (float(args[2]), float(args[3])) - pt.handle_right = (float(args[3]), float(args[5])) - return pt - -# -# parseAnimationData(rna, tokens): -# parseDriver(drv, args, tokens): -# parseDriverVariable(var, args, tokens): -# - -def parseAnimationData(rna, tokens): - if 0 and toggle & T_MHX: - return - if rna.animation_data == None: - rna.animation_data_create() - adata = rna.animation_data - for (key, val, sub) in tokens: - if key == 'FCurve': - fcu = parseAnimDataFCurve(adata, rna, val, sub) - else: - defaultKey(key, val, sub, 'adata', [], globals(), locals()) - return adata - -def parseAnimDataFCurve(adata, rna, args, tokens): - if invalid(args[2]): - return - dataPath = args[0] - index = int(args[1]) - # print("parseAnimDataFCurve", adata, dataPath, index) - for (key, val, sub) in tokens: - if key == 'Driver': - fcu = parseDriver(adata, dataPath, index, rna, val, sub) - elif key == 'FModifier': - parseFModifier(fcu, val, sub) - else: - defaultKey(key, val, sub, 'fcu', [], globals(), locals()) - return fcu - -""" - fcurve = con.driver_add("influence", 0) - driver = fcurve.driver - driver.type = 'AVERAGE' -""" -def parseDriver(adata, dataPath, index, rna, args, tokens): - if dataPath[-1] == ']': - words = dataPath.split(']') - expr = "rna." + words[0] + ']' - pwords = words[1].split('"') - prop = pwords[1] - # print("prop", expr, prop) - bone = eval(expr) - return None - else: - words = dataPath.split('.') - channel = words[-1] - expr = "rna" - for n in range(len(words)-1): - expr += "." + words[n] - expr += ".driver_add('%s', index)" % channel - - # print("expr", rna, expr) - fcu = eval(expr) - drv = fcu.driver - drv.type = args[0] - for (key, val, sub) in tokens: - if key == 'DriverVariable': - var = parseDriverVariable(drv, rna, val, sub) - else: - defaultKey(key, val, sub, 'drv', [], globals(), locals()) - return fcu - -def parseDriverVariable(drv, rna, args, tokens): - var = drv.variables.new() - var.name = args[0] - var.type = args[1] - nTarget = 0 - # print("var", var, var.name, var.type) - for (key, val, sub) in tokens: - if key == 'Target': - parseDriverTarget(var, nTarget, rna, val, sub) - nTarget += 1 - else: - defaultKey(key, val, sub, 'var', [], globals(), locals()) - return var - -def parseFModifier(fcu, args, tokens): - #fmod = fcu.modifiers.new() - fmod = fcu.modifiers[0] - #fmod.type = args[0] - #print("fmod", fmod, fmod.type) - for (key, val, sub) in tokens: - defaultKey(key, val, sub, 'fmod', [], globals(), locals()) - return fmod - -""" - var = driver.variables.new() - var.name = target_bone - var.targets[0].id_type = 'OBJECT' - var.targets[0].id = obj - var.targets[0].rna_path = driver_path -""" -def parseDriverTarget(var, nTarget, rna, args, tokens): - targ = var.targets[nTarget] - # targ.rna_path = args[0] - # targ.id_type = args[1] - targ.id = loadedData['Object'][args[0]] - for (key, val, sub) in tokens: - defaultKey(key, val, sub, 'targ', [], globals(), locals()) - #print("Targ", targ, targ.id, targ.data_path, targ.id_type, targ.bone_target, targ.use_local_space_transform) - return targ - - -# -# parseMaterial(args, ext, tokens): -# parseMTex(mat, args, tokens): -# parseTexture(args, tokens): -# - -def parseMaterial(args, tokens): - global todo - name = args[0] - #print("Parse material "+name) - mat = bpy.data.materials.new(name) - if mat == None: - return None - loadedData['Material'][name] = mat - #print("Material %s %s %s" % (mat, name, loadedData['Material'][name])) - for (key, val, sub) in tokens: - if key == 'MTex': - parseMTex(mat, val, sub) - elif key == 'Ramp': - parseRamp(mat, val, sub) - elif key == 'SSS': - parseSSS(mat, val, sub) - elif key == 'Strand': - parseStrand(mat, val, sub) - else: - exclude = ['specular_intensity', 'use_tangent_shading'] - defaultKey(key, val, sub, 'mat', [], globals(), locals()) - #print("Done ", mat) - - return mat - -def parseMTex(mat, args, tokens): - global todo - index = int(args[0]) - texname = args[1] - texco = args[2] - mapto = args[3] - - mtex = mat.texture_slots.add() - mtex.texture = loadedData['Texture'][texname] - mtex.texture_coords = texco - mtex.use_map_color_diffuse = True # XXX, fixme, mapto not used - - for (key, val, sub) in tokens: - defaultKey(key, val, sub, "mtex", [], globals(), locals()) - - return mtex - -def parseTexture(args, tokens): - global todo - if verbosity > 2: - print( "Parsing texture %s" % args ) - tex = bpy.data.textures.new(name=args[0], type=args[1]) - loadedData['Texture'][name] = tex - - for (key, val, sub) in tokens: - if key == 'Image': - try: - imgName = val[0] - img = loadedData['Image'][imgName] - tex.image = img - except: - msg = "Unable to load image '%s'" % val[0] - elif key == 'Ramp': - parseRamp(tex, val, sub) - else: - defaultKey(key, val, sub, "tex", ['use_nodes', 'use_textures', 'contrast'], globals(), locals()) - - return tex - -def parseRamp(data, args, tokens): - nvar = "data.%s" % args[0] - use = "data.use_%s = True" % args[0] - exec(use) - ramp = eval(nvar) - elts = ramp.elements - n = 0 - for (key, val, sub) in tokens: - # print("Ramp", key, val) - if key == 'Element': - elts[n].color = eval(val[0]) - elts[n].position = eval(val[1]) - n += 1 - else: - defaultKey(key, val, sub, "tex", ['use_nodes', 'use_textures', 'contrast'], globals(), locals()) - -def parseSSS(mat, args, tokens): - sss = mat.subsurface_scattering - for (key, val, sub) in tokens: - defaultKey(key, val, sub, "sss", [], globals(), locals()) - -def parseStrand(mat, args, tokens): - strand = mat.strand - for (key, val, sub) in tokens: - defaultKey(key, val, sub, "strand", [], globals(), locals()) - -# -# doLoadImage(filepath): -# loadImage(filepath): -# parseImage(args, tokens): -# - -def doLoadImage(filepath): - path1 = os.path.expanduser(filepath) - file1 = os.path.realpath(path1) - if os.path.isfile(file1): - print( "Found file "+file1 ) - try: - img = bpy.data.images.load(file1) - return img - except: - print( "Cannot read image" ) - return None - else: - print( "No file "+file1 ) - return None - - -def loadImage(filepath): - global TexDir, warnedTextureDir, loadedData - - texDir = os.path.expanduser(TexDir) - path1 = os.path.expanduser(filepath) - file1 = os.path.realpath(path1) - (path, filename) = os.path.split(file1) - (name, ext) = os.path.splitext(filename) - print( "Loading ", filepath, " = ", filename ) - - # img = doLoadImage(texDir+"/"+name+".png") - # if img: - # return img - - img = doLoadImage(texDir+"/"+filename) - if img: - return img - - # img = doLoadImage(path+"/"+name+".png") - # if img: - # return img - - img = doLoadImage(path+"/"+filename) - if img: - return img - - if warnedTextureDir: - return None - warnedTextureDir = True - return None - TexDir = Draw.PupStrInput("TexDir? ", path, 100) - - texDir = os.path.expanduser(TexDir) - img = doLoadImage(texDir+"/"+name+".png") - if img: - return img - - img = doLoadImage(TexDir+"/"+filename) - return img - -def parseImage(args, tokens): - global todo - imgName = args[0] - img = None - for (key, val, sub) in tokens: - if key == 'Filename': - filename = val[0] - for n in range(1,len(val)): - filename += " " + val[n] - img = loadImage(filename) - if img == None: - return None - img.name = imgName - else: - defaultKey(key, val, sub, "img", ['depth', 'is_dirty', 'has_data', 'size', 'type'], globals(), locals()) - print ("Image %s" % img ) - loadedData['Image'][imgName] = img - return img - -# -# parseObject(args, tokens): -# createObject(type, name, data, datName): -# createObjectAndData(args, typ): -# - -def parseObject(args, tokens): - if verbosity > 2: - print( "Parsing object %s" % args ) - name = args[0] - typ = args[1] - datName = args[2] - try: - data = loadedData[typ.capitalize()][datName] - except: - data = None - - if data == None and typ != 'EMPTY': - print("Failed to find data: %s %s %s" % (name, typ, datName)) - return - - try: - ob = loadedData['Object'][name] - bpy.context.scene.objects.active = ob - #print("Found data") - except: - ob = createObject(typ, name, data, datName) - if bpy.context.object != ob: - print("Context", ob, bpy.context.object, bpy.context.scene.objects.active) - # ob = foo - - for (key, val, sub) in tokens: - if key == 'Modifier': - parseModifier(ob, val, sub) - elif key == 'Constraint': - parseConstraint(ob.constraints, val, sub) - elif key == 'AnimationData': - if eval(val[0]): - parseAnimationData(ob, sub) - elif key == 'ParticleSystem': - parseParticleSystem(ob, val, sub) - else: - defaultKey(key, val, sub, "ob", ['type', 'data'], globals(), locals()) - - # Needed for updating layers - bpy.ops.object.mode_set(mode='EDIT') - bpy.ops.object.mode_set(mode='OBJECT') - return - -def createObject(typ, name, data, datName): - #print( "Creating object %s %s %s" % (typ, name, data) ) - ob = bpy.data.objects.new(name, data) - loadedData[typ][datName] = data - loadedData['Object'][name] = ob - return ob - -def linkObject(ob, data): - #print("Data", data, ob.data) - if data and ob.data == None: - ob.data = data - scn = bpy.context.scene - scn.objects.link(ob) - scn.objects.active = ob - #print("Linked object", ob) - #print("Scene", scn) - #print("Active", scn.objects.active) - #print("Context", bpy.context.object) - return ob - -def createObjectAndData(args, typ): - datName = args[0] - obName = args[1] - bpy.ops.object.add(type=typ.upper()) - ob = bpy.context.object - ob.name = obName - ob.data.name = datName - loadedData[typ][datName] = ob.data - loadedData['Object'][obName] = ob - return ob.data - - -# -# parseModifier(ob, args, tokens): -# - -def parseModifier(ob, args, tokens): - name = args[0] - typ = args[1] - if typ == 'PARTICLE_SYSTEM': - return None - mod = ob.modifiers.new(name, typ) - for (key, val, sub) in tokens: - defaultKey(key, val, sub, 'mod', [], globals(), locals()) - return mod - -# -# parseParticleSystem(ob, args, tokens): -# parseParticles(particles, args, tokens): -# parseParticle(par, args, tokens): -# - -def parseParticleSystem(ob, args, tokens): - print(ob, bpy.context.object) - pss = ob.particle_systems - print(pss, pss.values()) - name = args[0] - typ = args[1] - #psys = pss.new(name, typ) - bpy.ops.object.particle_system_add() - print(pss, pss.values()) - psys = pss[-1] - psys.name = name - psys.settings.type = typ - loadedData['ParticleSystem'][name] = psys - print("Psys", psys) - - for (key, val, sub) in tokens: - if key == 'Particles': - parseParticles(psys, val, sub) - else: - defaultKey(key, val, sub, 'psys', [], globals(), locals()) - return psys - -def parseParticles(psys, args, tokens): - particles = psys.particles - bpy.ops.particle.particle_edit_toggle() - n = 0 - for (key, val, sub) in tokens: - if key == 'Particle': - parseParticle(particles[n], val, sub) - n += 1 - else: - for par in particles: - defaultKey(key, val, sub, 'par', [], globals(), locals()) - bpy.ops.particle.particle_edit_toggle() - return particles - -def parseParticle(par, args, tokens): - n = 0 - for (key, val, sub) in tokens: - if key == 'h': - h = par.is_hair[n] - h.location = eval(val[0]) - h.time = int(val[1]) - h.weight = float(val[2]) - n += 1 - elif key == 'location': - par.location = eval(val[0]) - return - -# -# unpackList(list_of_tuples): -# - -def unpackList(list_of_tuples): - l = [] - for t in list_of_tuples: - l.extend(t) - return l - -# -# parseMesh (args, tokens): -# - -def parseMesh (args, tokens): - global todo - if verbosity > 2: - print( "Parsing mesh %s" % args ) - - mename = args[0] - obname = args[1] - me = bpy.data.meshes.new(mename) - ob = createObject('Mesh', obname, me, mename) - - verts = [] - edges = [] - faces = [] - vertsTex = [] - texFaces = [] - - for (key, val, sub) in tokens: - if key == 'Verts': - verts = parseVerts(sub) - elif key == 'Edges': - edges = parseEdges(sub) - elif key == 'Faces': - faces = parseFaces(sub) - - if faces: - #x = me.from_pydata(verts, [], faces) - me.vertices.add(len(verts)) - me.faces.add(len(faces)) - me.vertices.foreach_set("co", unpackList(verts)) - me.faces.foreach_set("vertices_raw", unpackList(faces)) - else: - #x = me.from_pydata(verts, edges, []) - me.vertices.add(len(verts)) - me.edges.add(len(edges)) - me.vertices.foreach_set("co", unpackList(verts)) - me.edges.foreach_set("vertices", unpackList(edges)) - #print(x) - me.update() - #print(me) - linkObject(ob, me) - - mats = [] - for (key, val, sub) in tokens: - if key in ('Verts', 'Edges'): - pass - elif key == 'Faces': - parseFaces2(sub, me) - elif key == 'MeshTextureFaceLayer': - parseUvTexture(val, sub, me) - elif key == 'MeshColorLayer': - parseVertColorLayer(val, sub, me) - elif key == 'VertexGroup': - parseVertexGroup(ob, me, val, sub) - elif key == 'ShapeKeys': - parseShapeKeys(ob, me, val, sub) - elif key == 'Material': - try: - me.materials.append(loadedData['Material'][val[0]]) - except: - print("Could not add material", val[0]) - else: - defaultKey(key, val, sub, "me", [], globals(), locals()) - - return me - -# -# parseVerts(tokens): -# parseEdges(tokens): -# parseFaces(tokens): -# parseFaces2(tokens, me): -# - -def parseVerts(tokens): - verts = [] - for (key, val, sub) in tokens: - if key == 'v': - verts.append( (float(val[0]), float(val[1]), float(val[2])) ) - return verts - -def parseEdges(tokens): - edges = [] - for (key, val, sub) in tokens: - if key == 'e': - edges.append((int(val[0]), int(val[1]))) - return edges - -def parseFaces(tokens): - faces = [] - for (key, val, sub) in tokens: - if key == 'f': - if len(val) == 3: - face = [int(val[0]), int(val[1]), int(val[2]), 0] - elif len(val) == 4: - face = [int(val[0]), int(val[1]), int(val[2]), int(val[3])] - faces.append(face) - return faces - -def parseFaces2(tokens, me): - n = 0 - for (key, val, sub) in tokens: - if key == 'ft': - f = me.faces[n] - f.material_index = int(val[0]) - f.use_smooth = int(val[1]) - n += 1 - elif key == 'ftall': - mat = int(val[0]) - smooth = int(val[1]) - for f in me.faces: - f.material_index = mat - f.use_smooth = smooth - return - - -# -# parseUvTexture(args, tokens, me): -# parseUvTexData(args, tokens, uvdata): -# - -def parseUvTexture(args, tokens, me): - name = args[0] - uvtex = me.uv_textures.new(name) - loadedData['MeshTextureFaceLayer'][name] = uvtex - for (key, val, sub) in tokens: - if key == 'Data': - parseUvTexData(val, sub, uvtex.data) - else: - defaultKey(key, val, sub, "uvtex", [], globals(), locals()) - return - -def parseUvTexData(args, tokens, data): - n = 0 - for (key, val, sub) in tokens: - if key == 'vt': - data[n].uv1 = (float(val[0]), float(val[1])) - data[n].uv2 = (float(val[2]), float(val[3])) - data[n].uv3 = (float(val[4]), float(val[5])) - if len(val) > 6: - data[n].uv4 = (float(val[6]), float(val[7])) - n += 1 - else: - pass - #for i in range(n): - # defaultKey(key, val, sub, "data[i]", [], globals(), locals()) - return - -# -# parseVertColorLayer(args, tokens, me): -# parseVertColorData(args, tokens, data): -# - -def parseVertColorLayer(args, tokens, me): - name = args[0] - print("VertColorLayer", name) - vcol = me.vertex_colors.new(name) - loadedData['MeshColorLayer'][name] = vcol - for (key, val, sub) in tokens: - if key == 'Data': - parseVertColorData(val, sub, vcol.data) - else: - defaultKey(key, val, sub, "vcol", [], globals(), locals()) - return - -def parseVertColorData(args, tokens, data): - n = 0 - for (key, val, sub) in tokens: - if key == 'cv': - data[n].color1 = eval(val[0]) - data[n].color2 = eval(val[1]) - data[n].color3 = eval(val[2]) - data[n].color4 = eval(val[3]) - n += 1 - return - - -# -# parseVertexGroup(ob, me, args, tokens): -# - -def parseVertexGroup(ob, me, args, tokens): - global toggle - if verbosity > 2: - print( "Parsing vertgroup %s" % args ) - grpName = args[0] - try: - res = eval(args[1]) - except: - res = True - if not res: - return - - if (toggle & T_Armature) or (grpName in ['Eye_L', 'Eye_R', 'Gums', 'Head', 'Jaw', 'Left', 'Middle', 'Right', 'Scalp']): - group = ob.vertex_groups.new(grpName) - group.name = grpName - loadedData['VertexGroup'][grpName] = group - ob.vertex_groups.assign([int(val[0]) for (key, val, sub) in tokens if key == 'wv'], group, float(val[1]), 'REPLACE') - return - - -# -# parseShapeKeys(ob, me, args, tokens): -# parseShapeKey(ob, me, args, tokens): -# addShapeKey(ob, name, vgroup, tokens): -# doShape(name): -# - -def doShape(name): - if (toggle & T_Shape+T_Face) and (name == 'Basis'): - return True - else: - return (toggle & T_Face) - -def parseShapeKeys(ob, me, args, tokens): - if bpy.context.object == None: - return - for (key, val, sub) in tokens: - if key == 'ShapeKey': - parseShapeKey(ob, me, val, sub) - elif key == 'AnimationData': - if me.shape_keys: - parseAnimationData(me.shape_keys, sub) - return - - -def parseShapeKey(ob, me, args, tokens): - if verbosity > 0: - print( "Parsing ob %s shape %s" % (bpy.context.object, args[0] )) - name = args[0] - lr = args[1] - if invalid(args[2]): - return - - if lr == 'Sym' or toggle & T_Symm: - addShapeKey(ob, name, None, tokens) - elif lr == 'LR': - addShapeKey(ob, name+'_L', 'Left', tokens) - addShapeKey(ob, name+'_R', 'Right', tokens) - else: - raise NameError("ShapeKey L/R %s" % lr) - return - -def addShapeKey(ob, name, vgroup, tokens): - bpy.ops.object.shape_key_add(False) - skey = ob.active_shape_key - if name != 'Basis': - skey.relative_key = loadedData['ShapeKey']['Basis'] - skey.name = name - if vgroup: - skey.vertex_group = vgroup - loadedData['ShapeKey'][name] = skey - - for (key, val, sub) in tokens: - if key == 'sv': - index = int(val[0]) - pt = skey.data[index].co - pt[0] += float(val[1]) - pt[1] += float(val[2]) - pt[2] += float(val[3]) - else: - defaultKey(key, val, sub, "skey", [], globals(), locals()) - - return - - -# -# parseArmature (obName, args, tokens) -# - -def parseArmature (args, tokens): - global toggle, theScale - if verbosity > 2: - print( "Parsing armature %s" % args ) - - amtname = args[0] - obname = args[1] - mode = args[2] - - if mode == 'Rigify': - toggle |= T_Rigify - theScale = 0.1 - return parseRigify(amtname, obname, tokens) - - toggle &= ~T_Rigify - theScale = 1.0 - amt = bpy.data.armatures.new(amtname) - ob = createObject('Armature', obname, amt, amtname) - - linkObject(ob, amt) - print("Linked") - - bpy.ops.object.mode_set(mode='OBJECT') - bpy.ops.object.mode_set(mode='EDIT') - - heads = {} - tails = {} - for (key, val, sub) in tokens: - if key == 'Bone': - bname = val[0] - if not invalid(val[1]): - bone = amt.edit_bones.new(bname) - parseBone(bone, amt.edit_bones, sub, heads, tails) - loadedData['Bone'][bname] = bone - else: - defaultKey(key, val, sub, "amt", ['MetaRig'], globals(), locals()) - bpy.ops.object.mode_set(mode='OBJECT') - return amt - -# -# parseRigify(amtname, obname, tokens): -# - -def parseRigify(amtname, obname, tokens): - (key,val,sub) = tokens[0] - if key != 'MetaRig': - raise NameError("Expected MetaRig") - typ = val[0] - if typ == "human": - bpy.ops.object.armature_human_advanced_add() - else: - bpy.ops.pose.metarig_sample_add(type = typ) - ob = bpy.context.scene.objects.active - amt = ob.data - loadedData['Rigify'][obname] = ob - loadedData['Armature'][amtname] = amt - loadedData['Object'][obname] = ob - print("Rigify object", ob, amt) - - bpy.ops.object.mode_set(mode='OBJECT') - bpy.ops.object.mode_set(mode='EDIT') - - heads = {} - tails = {} - for (bname, bone) in amt.edit_bones.items(): - heads[bname] = 10*theScale*bone.head - tails[bname] = 10*theScale*bone.tail - - for (key, val, sub) in tokens: - if key == 'Bone': - bname = val[0] - print("Bone", bname) - try: - bone = amt.edit_bones[bname] - except: - print("Did not find bone %s" % bname) - bone = None - print(" -> ", bone) - if bone: - parseBone(bone, amt.edit_bones, sub, heads, tails) - else: - defaultKey(key, val, sub, "amt", ['MetaRig'], globals(), locals()) - bpy.ops.object.mode_set(mode='OBJECT') - return amt - -# -# parseBone(bone, bones, tokens, heads, tails): -# - -def parseBone(bone, bones, tokens, heads, tails): - global todo - - for (key, val, sub) in tokens: - if key == "head": - bone.head = (float(val[0]), float(val[1]), float(val[2])) - elif key == "tail": - bone.tail = (float(val[0]), float(val[1]), float(val[2])) - elif key == "head-as": - target = val[0] - if val[1] == 'head': - bone.head = heads[bone.name] + bones[target].head - heads[target] - elif val[1] == 'tail': - bone.head = heads[bone.name] + bones[target].tail - tails[target] - else: - raise NameError("head-as %s" % val) - elif key == "tail-as": - target = val[0] - if val[1] == 'head': - bone.tail = tails[bone.name] + bones[target].head - heads[target] - elif val[1] == 'tail': - bone.tail = tails[bone.name] + bones[target].tail - tails[target] - else: - raise NameError("tail-as %s" % val) - elif key == 'hide_select': - pass - else: - defaultKey(key, val, sub, "bone", [], globals(), locals()) - - return bone - -# -# parsePose (args, tokens): -# - -def parsePose (args, tokens): - global todo - if toggle & T_Rigify: - return - name = args[0] - ob = loadedData['Object'][name] - bpy.context.scene.objects.active = ob - bpy.ops.object.mode_set(mode='POSE') - pbones = ob.pose.bones - nGrps = 0 - for (key, val, sub) in tokens: - if key == 'Posebone': - parsePoseBone(pbones, ob, val, sub) - elif key == 'BoneGroup': - parseBoneGroup(ob.pose, nGrps, val, sub) - nGrps += 1 - elif key == 'SetProp': - bone = val[0] - prop = val[1] - value = eval(val[2]) - pb = pbones[bone] - print("Setting", pb, prop, val) - pb[prop] = value - print("Prop set", pb[prop]) - else: - defaultKey(key, val, sub, "ob.pose", [], globals(), locals()) - bpy.ops.object.mode_set(mode='OBJECT') - return ob - - -# -# parsePoseBone(pbones, args, tokens): -# parseArray(data, exts, args): -# - -def parseBoneGroup(pose, nGrps, args, tokens): - global todo - return - print( "Parsing bonegroup %s" % args ) - name = args[0] - print(dir(pose.bone_groups)) - bg = pose.bone_groups.add() - print("Created", bg) - loadedData['BoneGroup'][name] = bg - for (key, val, sub) in tokens: - defaultKey(key, val, sub, "bg", [], globals(), locals()) - return - -def parsePoseBone(pbones, ob, args, tokens): - global todo - #print( "Parsing posebone %s" % args ) - if invalid(args[1]): - return - name = args[0] - pb = pbones[name] - - # Make posebone active - don't know how to do this in pose mode - bpy.ops.object.mode_set(mode='OBJECT') - ob.data.bones.active = pb.bone - bpy.ops.object.mode_set(mode='POSE') - - for (key, val, sub) in tokens: - if key == 'Constraint': - cns = parseConstraint(pb.constraints, val, sub) - elif key == 'bpyops': - expr = "bpy.ops.%s" % val[0] - print(expr) - print("ob", bpy.context.active_object) - print("b", bpy.context.active_bone) - print("pb", bpy.context.active_pose_bone) - print("md", bpy.context.mode) - exec(expr) - print("show_alive") - elif key == 'ik_dof': - parseArray(pb, ["lock_ik_x", "lock_ik_y", "lock_ik_z"], val) - elif key == 'ik_limit': - parseArray(pb, ["use_ik_limit_x", "use_ik_limit_y", "use_ik_limit_z"], val) - elif key == 'ik_max': - parseArray(pb, ["ik_max_x", "ik_max_y", "ik_max_z"], val) - elif key == 'ik_min': - parseArray(pb, ["ik_min_x", "ik_min_y", "ik_min_z"], val) - elif key == 'ik_stiffness': - parseArray(pb, ["ik_stiffness_x", "ik_stiffness_y", "ik_stiffness_z"], val) - else: - defaultKey(key, val, sub, "pb", [], globals(), locals()) - #print("pb %s done" % name) - return - -def parseArray(data, exts, args): - n = 1 - for ext in exts: - expr = "data.%s = %s" % (ext, args[n]) - # print(expr) - exec(expr) - n += 1 - return - -# -# parseConstraint(constraints, args, tokens) -# - -def parseConstraint(constraints, args, tokens): - if invalid(args[2]): - return None - cns = constraints.new(args[1]) - #bpy.ops.pose.constraint_add(type=args[1]) - #cns = pb.constraints[-1] - - cns.name = args[0] - #print("cns", cns.name) - for (key,val,sub) in tokens: - if key == 'invert': - parseArray(cns, ["invert_x", "invert_y", "invert_z"], val) - elif key == 'use': - parseArray(cns, ["use_x", "use_y", "use_z"], val) - elif key == 'pos_lock': - parseArray(cns, ["lock_location_x", "lock_location_y", "lock_location_z"], val) - elif key == 'rot_lock': - parseArray(cns, ["lock_rotation_x", "lock_rotation_y", "lock_rotation_z"], val) - else: - defaultKey(key, val, sub, "cns", [], globals(), locals()) - #print("cns %s done" % cns.name) - return cns - -def insertInfluenceIpo(cns, bone): - global todo - if bone != 'PArmIK_L' and bone != 'PArmIK_R' and bone != 'PLegIK_L' and bone != 'PLegIK_R': - return False - - if (toggle & T_FKIK): - fcurve = cns.driver_add("influence", 0) - fcurve.driver.type = 'AVERAGE' - - var = fcurve.driver.variables.new() - var.name = bone - var.targets[0].id_type = 'OBJECT' - var.targets[0].id = getObject('HumanRig', 'var.targets[0].id', globals(), locals()) - var.targets[0].bone_target = bone - var.targets[0].transform_type = 'LOC_X' - # controller_path = fk_chain.arm_p.path_to_id() - #var.targets[0].data_path = controller_path + '["use_hinge"]' - - mod = fcurve.modifiers[0] - mod.poly_order = 2 - mod.coefficients[0] = 0.0 - mod.coefficients[1] = 1.0 - elif bone == 'PArmIK_L' or bone == 'PArmIK_R': - if toggle & T_ArmIK: - cns.influence = 1.0 - else: - cns.influence = 0.0 - elif bone == 'PLegIK_L' or bone == 'PLegIK_R': - if toggle & T_LegIK: - cns.influence = 1.0 - else: - cns.influence = 0.0 - - return True - -# -# parseCurve (args, tokens): -# parseNurb(cu, nNurbs, args, tokens): -# parseBezier(nurb, n, args, tokens): -# - -def parseCurve (args, tokens): - global todo - if verbosity > 2: - print( "Parsing curve %s" % args ) - cu = createObjectAndData(args, 'Curve') - - nNurbs = 0 - for (key, val, sub) in tokens: - if key == 'Nurb': - parseNurb(cu, nNurbs, val, sub) - nNurbs += 1 - else: - defaultKey(key, val, sub, "cu", [], globals(), locals()) - return - -def parseNurb(cu, nNurbs, args, tokens): - if nNurbs > 0: - bpy.ops.object.curve_add(type='BEZIER_CURVE') - print(cu.splines, list(cu.splines), nNurbs) - nurb = cu.splines[nNurbs] - nPoints = int(args[0]) - print(nurb, nPoints) - for n in range(2, nPoints): - bpy.ops.curve.extrude(mode=1) - - n = 0 - for (key, val, sub) in tokens: - if key == 'bz': - parseBezier(nurb, n, val, sub) - n += 1 - elif key == 'pt': - parsePoint(nurb, n, val, sub) - n += 1 - else: - defaultKey(key, val, sub, "nurb", [], globals(), locals()) - return - -def parseBezier(nurb, n, args, tokens): - bez = nurb[n] - bez.co = eval(args[0]) - bez.handle_left = eval(args[1]) - bez.handle_left_type = args[2] - bez.handle_right = eval(args[3]) - bez.handle_right_type = args[4] - return - -def parsePoint(nurb, n, args, tokens): - pt = nurb[n] - pt.co = eval(args[0]) - return - -# -# parseLattice (args, tokens): -# - -def parseLattice (args, tokens): - global todo - if verbosity > 2: - print( "Parsing lattice %s" % args ) - lat = createObjectAndData(args, 'Lattice') - for (key, val, sub) in tokens: - if key == 'Points': - parseLatticePoints(val, sub, lat.points) - else: - defaultKey(key, val, sub, "lat", [], globals(), locals()) - return - -def parseLatticePoints(args, tokens, points): - global todo - n = 0 - for (key, val, sub) in tokens: - if key == 'pt': - v = points[n].co - (x,y,z) = eval(val[0]) - v.x = x - v.y = y - v.z = z - - v = points[n].co_deform - (x,y,z) = eval(val[1]) - v.x = x - v.y = y - v.z = z - - n += 1 - return - -# -# parseGroup (args, tokens): -# - -def parseGroup (args, tokens): - global todo - if verbosity > 2: - print( "Parsing group %s" % args ) - - grpName = args[0] - grp = bpy.data.groups.new(grpName) - loadedData['Group'][grpName] = grp - for (key, val, sub) in tokens: - if key == 'Objects': - parseGroupObjects(val, sub, grp) - else: - defaultKey(key, val, sub, "grp", [], globals(), locals()) - return - -def parseGroupObjects(args, tokens, grp): - global todo - for (key, val, sub) in tokens: - if key == 'ob': - try: - ob = loadedData['Object'][val[0]] - grp.objects.link(ob) - except: - pass - return - -# -# postProcess() -# setInfluence(bones, cnsName, w): -# - -def postProcess(): - if not toggle & T_MHX: - return - if toggle & T_Rigify: - return - for rig in loadedData['Rigify'].values(): - bpy.context.scene.objects.active = rig - print("Rigify", rig) - bpy.ops.pose.metarig_generate() - print("Metarig generated") - #bpy.context.scene.objects.unlink(rig) - rig = bpy.context.scene.objects.active - print("Rigged", rig, bpy.context.object) - ob = loadedData['Object']['Human'] - mod = ob.modifiers[0] - print(ob, mod, mod.object) - mod.object = rig - print("Rig changed", mod.object) - return - -# -# parseProcess(args, tokens): -# - -def parseProcess(args, tokens): - return - rig = loadedData['Object'][args[0]] - parents = {} - objects = [] - - for (key, val, sub) in tokens: - if key == 'Reparent': - bname = val[0] - try: - eb = ebones[bname] - parents[bname] = eb.parent.name - eb.parent = ebones[val[1]] - except: - pass - elif key == 'Bend': - print(val) - axis = val[1] - angle = float(val[2]) - mat = mathutils.Matrix.Rotation(angle, 4, axis) - try: - pb = pbones[val[0]] - prod = pb.matrix_local * mat - for i in range(4): - for j in range(4): - pb.matrix_local[i][j] = prod[i][j] - print("Done", pb.matrix_local) - except: - pass - elif key == 'Pose': - bpy.context.scene.objects.active = rig - bpy.ops.object.mode_set(mode='POSE') - pbones = rig.pose.bones - elif key == 'Edit': - bpy.context.scene.objects.active = rig - bpy.ops.object.mode_set(mode='EDIT') - ebones = rig.data.edit_bones - elif key == 'Object': - bpy.ops.object.mode_set(mode='OBJECT') - try: - ob = loadedData['Object'][val[0]] - objects.append((ob,sub)) - except: - ob = None - if ob: - bpy.context.scene.objects.active = ob - mod = ob.modifiers[0] - ob.modifiers.remove(mod) - for (key1, val1, sub1) in sub: - if key1 == 'Modifier': - parseModifier(ob, val1, sub1) - - for (ob,tokens) in objects: - bpy.context.scene.objects.active = ob - bpy.ops.object.visual_transform_apply() - #print("vis", list(ob.modifiers)) - bpy.ops.object.modifier_apply(apply_as='DATA', modifier='Armature') - #print("app", list(ob.modifiers)) - - bpy.context.scene.objects.active = rig - bpy.ops.object.mode_set(mode='POSE') - bpy.ops.pose.armature_apply() - bpy.ops.object.mode_set(mode='EDIT') - ebones = rig.data.edit_bones - for (bname, pname) in parents.items(): - eb = ebones[bname] - par = ebones[pname] - if eb.use_connect: - par.tail = eb.head - eb.parent = par - bpy.ops.object.mode_set(mode='OBJECT') - - for (ob,tokens) in objects: - bpy.context.scene.objects.active = ob - for (key, val, sub) in tokens: - if key == 'Modifier': - parseModifier(ob, val, sub) - - return - -# -# defaultKey(ext, args, tokens, var, exclude, glbals, lcals): -# - -def defaultKey(ext, args, tokens, var, exclude, glbals, lcals): - global todo - - if ext == 'Property': - expr = "%s['%s'] = %s" % (var, args[0], args[1]) - print("Property", expr) - exec(expr, glbals, lcals) - #print("execd") - return - - nvar = "%s.%s" % (var, ext) - # print(ext) - if ext in exclude: - return - #print("D", nvar) - - if len(args) == 0: - raise NameError("Key length 0: %s" % ext) - - rnaType = args[0] - if rnaType == 'Add': - print("*** Cannot Add yet ***") - return - - elif rnaType == 'Refer': - typ = args[1] - name = args[2] - data = "loadedData['%s']['%s']" % (typ, name) - - elif rnaType == 'Struct' or rnaType == 'Define': - typ = args[1] - name = args[2] - try: - data = eval(nvar, glbals, lcals) - except: - data = None - # print("Old structrna", nvar, data) - - if data == None: - try: - creator = args[3] - except: - creator = None - # print("Creator", creator, eval(var,glbals,lcals)) - - try: - rna = eval(var,glbals,lcals) - data = eval(creator) - except: - data = None - # print("New struct", nvar, typ, data) - - if rnaType == 'Define': - loadedData[typ][name] = data - - if data: - for (key, val, sub) in tokens: - defaultKey(key, val, sub, "data", [], globals(), locals()) - - print("Struct done", nvar) - return - - elif rnaType == 'PropertyRNA': - raise NameError("PropertyRNA!") - #print("PropertyRNA ", ext, var) - for (key, val, sub) in tokens: - defaultKey(ext, val, sub, nvar, [], glbals, lcals) - return - - elif rnaType == 'Array': - for n in range(1, len(args)): - expr = "%s[%d] = %s" % (nvar, n-1, args[n]) - exec(expr, glbals, lcals) - if len(args) > 0: - expr = "%s[0] = %s" % (nvar, args[1]) - exec(expr, glbals, lcals) - return - - elif rnaType == 'List': - data = [] - for (key, val, sub) in tokens: - elt = eval(val[1], glbals, lcals) - data.append(elt) - - elif rnaType == 'Matrix': - return - i = 0 - n = len(tokens) - for (key, val, sub) in tokens: - if key == 'row': - for j in range(n): - expr = "%s[%d][%d] = %g" % (nvar, i, j, float(val[j])) - exec(expr, glbals, lcals) - i += 1 - return - - else: - try: - data = loadedData[rnaType][args[1]] - #print("From loaded", rnaType, args[1], data) - return data - except: - data = rnaType - - #print(var, ext, data) - expr = "%s = %s" % (nvar, data) - try: - exec(expr, glbals, lcals) - except: - #print("Failed ",expr) - todo.append((expr, glbals, lcals)) - return - -# -# parseBoolArray(mask): -# - -def parseBoolArray(mask): - list = [] - for c in mask: - if c == '0': - list.append(False) - else: - list.append(True) - return list - -# parseMatrix(args, tokens) -# - -def parseMatrix(args, tokens): - matrix = Matrix( [1,0,0,0], [0,1,0,0], [0,0,1,0], [0,0,0,1] ) - i = 0 - for (key, val, sub) in tokens: - if key == 'row': - matrix[i][0] = float(val[0]) - matrix[i][1] = float(val[1]) - matrix[i][2] = float(val[2]) - matrix[i][3] = float(val[3]) - i += 1 - return matrix - -# -# parseDefault(data, tokens, exclude): -# - -def parseDefault(data, tokens): - for (key, val, sub) in tokens: - defaultKey(key, val, sub, "data", exclude, globals(), locals()) - - -# -# Utilities -# - -# -# extractBpyType(data): -# - -def extractBpyType(data): - typeSplit = str(type(data)).split("'") - if typeSplit[0] != ' Import ", - "description": "Import Unreal Engine (.psk)", - "warning": "", - "wiki_url": "http://wiki.blender.org/index.php/Extensions:2.5/Py/" - "Scripts/File_I-O/Unreal_psk_psa", - "tracker_url": "https://projects.blender.org/tracker/index.php?"\ - "func=detail&aid=21366&group_id=153&atid=469", - "category": "Import/Export"} - -""" -Version': '2.0' ported by Darknet - -Unreal Tournament PSK file to Blender mesh converter V1.0 -Author: D.M. Sturgeon (camg188 at the elYsium forum), ported by Darknet -Imports a *psk file to a new mesh - --No UV Texutre --No Weight --No Armature Bones --No Material ID --Export Text Log From Current Location File (Bool ) -""" - -import bpy -import mathutils -import os -import sys -import string -import math -import re -from string import * -from struct import * -from math import * - -#from bpy.props import * - -import mathutils - -#output log in to txt file -DEBUGLOG = False - -scale = 1.0 -bonesize = 1.0 -md5_bones=[] - -def unpack_list(list_of_tuples): - l = [] - for t in list_of_tuples: - l.extend(t) - return l -""" -class md5_bone: - bone_index=0 - name="" - bindpos=[] - bindmat = mathutils.Quaternion() - parent="" - parent_index=0 - blenderbone=None - roll=0 - - def __init__(self): - self.bone_index=0 - self.name="" - self.bindpos=[0.0]*3 - self.bindmat=[None]*3 #is this how you initilize a 2d-array - for i in range(3): self.bindmat[i] = [0.0]*3 - self.parent="" - self.parent_index=0 - self.blenderbone=None - - def dump(self): - print ("bone index: ", self.bone_index) - print ("name: ", self.name) - print ("bind position: ", self.bindpos) - print ("bind translation matrix: ", self.bindmat) - print ("parent: ", self.parent) - print ("parent index: ", self.parent_index) - print ("blenderbone: ", self.blenderbone) -""" -class md5_bone: - bone_index=0 - name="" - bindpos=[] - bindmat=[] - scale = [] - parent="" - parent_index=0 - blenderbone=None - roll=0 - - def __init__(self): - self.bone_index=0 - self.name="" - self.bindpos=[0.0]*3 - self.scale=[0.0]*3 - self.bindmat=[None]*3 #is this how you initilize a 2d-array - for i in range(3): self.bindmat[i] = [0.0]*3 - self.parent="" - self.parent_index=0 - self.blenderbone=None - - def dump(self): - print ("bone index: ", self.bone_index) - print ("name: ", self.name) - print ("bind position: ", self.bindpos) - print ("bind translation matrix: ", self.bindmat) - print ("parent: ", self.parent) - print ("parent index: ", self.parent_index) - print ("blenderbone: ", self.blenderbone) - -#http://www.blender.org/forum/viewtopic.php?t=13340&sid=8b17d5de07b17960021bbd72cac0495f -def fixRollZ(b): - v = (b.tail-b.head)/b.length - b.roll -= math.degrees(math.atan2(v[0]*v[2]*(1 - v[1]),v[0]*v[0] + v[1]*v[2]*v[2])) -def fixRoll(b): - v = (b.tail-b.head)/b.length - if v[2]*v[2] > .5: - #align X-axis - b.roll += math.degrees(math.atan2(v[0]*v[2]*(1 - v[1]),v[2]*v[2] + v[1]*v[0]*v[0])) - else: - #align Z-axis - b.roll -= math.degrees(math.atan2(v[0]*v[2]*(1 - v[1]),v[0]*v[0] + v[1]*v[2]*v[2])) - -def pskimport(infile): - global DEBUGLOG - print ("--------------------------------------------------") - print ("---------SCRIPT EXECUTING PYTHON IMPORTER---------") - print ("--------------------------------------------------") - print ("Importing file: ", infile) - - md5_bones=[] - pskfile = open(infile,'rb') - if (DEBUGLOG): - logpath = infile.replace(".psk", ".txt") - print("logpath:",logpath) - logf = open(logpath,'w') - - def printlog(strdata): - if (DEBUGLOG): - logf.write(strdata) - - objName = infile.split('\\')[-1].split('.')[0] - - me_ob = bpy.data.meshes.new(objName) - print("objName:",objName) - printlog(("New Mesh = " + me_ob.name + "\n")) - #read general header - indata = unpack('20s3i',pskfile.read(32)) - #not using the general header at this time - #================================================================================================== - # vertex point - #================================================================================================== - #read the PNTS0000 header - indata = unpack('20s3i',pskfile.read(32)) - recCount = indata[3] - printlog(( "Nbr of PNTS0000 records: " + str(recCount) + "\n")) - counter = 0 - verts = [] - while counter < recCount: - counter = counter + 1 - indata = unpack('3f',pskfile.read(12)) - #print(indata[0],indata[1],indata[2]) - verts.extend([(indata[0],indata[1],indata[2])]) - #Tmsh.vertices.append(NMesh.Vert(indata[0],indata[1],indata[2])) - - #================================================================================================== - # UV - #================================================================================================== - #read the VTXW0000 header - indata = unpack('20s3i',pskfile.read(32)) - recCount = indata[3] - printlog( "Nbr of VTXW0000 records: " + str(recCount)+ "\n") - counter = 0 - UVCoords = [] - #UVCoords record format = [index to PNTS, U coord, v coord] - while counter < recCount: - counter = counter + 1 - indata = unpack('hhffhh',pskfile.read(16)) - UVCoords.append([indata[0],indata[2],indata[3]]) - #print([indata[0],indata[2],indata[3]]) - #print([indata[1],indata[2],indata[3]]) - - #================================================================================================== - # Face - #================================================================================================== - #read the FACE0000 header - indata = unpack('20s3i',pskfile.read(32)) - recCount = indata[3] - printlog( "Nbr of FACE0000 records: "+ str(recCount) + "\n") - #PSK FACE0000 fields: WdgIdx1|WdgIdx2|WdgIdx3|MatIdx|AuxMatIdx|SmthGrp - #associate MatIdx to an image, associate SmthGrp to a material - SGlist = [] - counter = 0 - faces = [] - faceuv = [] - while counter < recCount: - counter = counter + 1 - indata = unpack('hhhbbi',pskfile.read(12)) - #the psk values are: nWdgIdx1|WdgIdx2|WdgIdx3|MatIdx|AuxMatIdx|SmthGrp - #indata[0] = index of UVCoords - #UVCoords[indata[0]]=[index to PNTS, U coord, v coord] - #UVCoords[indata[0]][0] = index to PNTS - PNTSA = UVCoords[indata[0]][0] - PNTSB = UVCoords[indata[1]][0] - PNTSC = UVCoords[indata[2]][0] - #print(PNTSA,PNTSB,PNTSC) #face id vertex - #faces.extend([0,1,2,0]) - faces.extend([PNTSA,PNTSB,PNTSC,0]) - uv = [] - u0 = UVCoords[indata[0]][1] - v0 = UVCoords[indata[0]][2] - uv.append([u0,v0]) - u1 = UVCoords[indata[1]][1] - v1 = UVCoords[indata[1]][2] - uv.append([u1,v1]) - u2 = UVCoords[indata[2]][1] - v2 = UVCoords[indata[2]][2] - uv.append([u2,v2]) - faceuv.append(uv) - #print("UV: ",u0,v0) - #update the uv var of the last item in the Tmsh.faces list - # which is the face just added above - ##Tmsh.faces[-1].uv = [(u0,v0),(u1,v1),(u2,v2)] - #print("smooth:",indata[5]) - #collect a list of the smoothing groups - if SGlist.count(indata[5]) == 0: - SGlist.append(indata[5]) - print("smooth:",indata[5]) - #assign a material index to the face - #Tmsh.faces[-1].materialIndex = SGlist.index(indata[5]) - printlog( "Using Materials to represent PSK Smoothing Groups...\n") - #========== - # skip something... - #========== - - #================================================================================================== - # Material - #================================================================================================== - ## - #read the MATT0000 header - indata = unpack('20s3i',pskfile.read(32)) - recCount = indata[3] - printlog("Nbr of MATT0000 records: " + str(recCount) + "\n" ) - printlog(" - Not importing any material data now. PSKs are texture wrapped! \n") - counter = 0 - while counter < recCount: - counter = counter + 1 - indata = unpack('64s6i',pskfile.read(88)) - ## - - #================================================================================================== - # Bones (Armature) - #================================================================================================== - #read the REFSKEL0 header - indata = unpack('20s3i',pskfile.read(32)) - recCount = indata[3] - printlog( "Nbr of REFSKEL0 records: " + str(recCount) + "\n") - Bns = [] - bone = [] - nobone = 0 - #================================================================================================== - # Bone Data - #================================================================================================== - counter = 0 - print ("---PRASE--BONES---") - while counter < recCount: - indata = unpack('64s3i11f',pskfile.read(120)) - #print( "DATA",str(indata)) - bone.append(indata) - - createbone = md5_bone() - #temp_name = indata[0][:30] - temp_name = indata[0] - - temp_name = bytes.decode(temp_name) - temp_name = temp_name.lstrip(" ") - temp_name = temp_name.rstrip(" ") - temp_name = temp_name.strip() - temp_name = temp_name.strip( bytes.decode(b'\x00')) - print ("temp_name:", temp_name, "||") - createbone.name = temp_name - createbone.bone_index = counter - createbone.parent_index = indata[3] - createbone.bindpos[0] = indata[8] - createbone.bindpos[1] = indata[9] - createbone.bindpos[2] = indata[10] - createbone.scale[0] = indata[12] - createbone.scale[1] = indata[13] - createbone.scale[2] = indata[14] - - #w,x,y,z - if (counter == 0):#main parent - print("no parent bone") - createbone.bindmat = mathutils.Quaternion((indata[7],indata[4],indata[5],indata[6])) - #createbone.bindmat = mathutils.Quaternion((indata[7],-indata[4],-indata[5],-indata[6])) - else:#parent - print("parent bone") - createbone.bindmat = mathutils.Quaternion((indata[7],-indata[4],-indata[5],-indata[6])) - #createbone.bindmat = mathutils.Quaternion((indata[7],indata[4],indata[5],indata[6])) - - md5_bones.append(createbone) - counter = counter + 1 - bnstr = (str(indata[0])) - Bns.append(bnstr) - - for pbone in md5_bones: - pbone.parent = md5_bones[pbone.parent_index].name - - bonecount = 0 - for armbone in bone: - temp_name = armbone[0][:30] - #print ("BONE NAME: ",len(temp_name)) - temp_name=str((temp_name)) - #temp_name = temp_name[1] - #print ("BONE NAME: ",temp_name) - bonecount +=1 - print ("-------------------------") - print ("----Creating--Armature---") - print ("-------------------------") - - #================================================================================================ - #Check armature if exist if so create or update or remove all and addnew bone - #================================================================================================ - #bpy.ops.object.mode_set(mode='OBJECT') - meshname ="ArmObject" - objectname = "armaturedata" - bfound = False - arm = None - for obj in bpy.data.objects: - if (obj.name == meshname): - bfound = True - arm = obj - break - - if bfound == False: - armdata = bpy.data.armatures.new(objectname) - ob_new = bpy.data.objects.new(meshname, armdata) - #ob_new = bpy.data.objects.new(meshname, 'ARMATURE') - #ob_new.data = armdata - bpy.context.scene.objects.link(ob_new) - #bpy.ops.object.mode_set(mode='OBJECT') - for i in bpy.context.scene.objects: i.select = False #deselect all objects - ob_new.select = True - #set current armature to edit the bone - bpy.context.scene.objects.active = ob_new - #set mode to able to edit the bone - bpy.ops.object.mode_set(mode='EDIT') - #newbone = ob_new.data.edit_bones.new('test') - #newbone.tail.y = 1 - print("creating bone(s)") - for bone in md5_bones: - #print(dir(bone)) - newbone = ob_new.data.edit_bones.new(bone.name) - #parent the bone - parentbone = None - print("bone name:",bone.name) - #note bone location is set in the real space or global not local - if bone.name != bone.parent: - - pos_x = bone.bindpos[0] - pos_y = bone.bindpos[1] - pos_z = bone.bindpos[2] - - #print( "LINKING:" , bone.parent ,"j") - parentbone = ob_new.data.edit_bones[bone.parent] - newbone.parent = parentbone - rotmatrix = bone.bindmat.to_matrix().resize4x4().rotation_part() - - #parent_head = parentbone.head * parentbone.matrix.to_quat().inverse() - #parent_tail = parentbone.tail * parentbone.matrix.to_quat().inverse() - #location=Vector(pos_x,pos_y,pos_z) - #set_position = (parent_tail - parent_head) + location - #print("tmp head:",set_position) - - #pos_x = set_position.x - #pos_y = set_position.y - #pos_z = set_position.z - - newbone.head.x = parentbone.head.x + pos_x - newbone.head.y = parentbone.head.y + pos_y - newbone.head.z = parentbone.head.z + pos_z - print("head:",newbone.head) - newbone.tail.x = parentbone.head.x + (pos_x + bonesize * rotmatrix[1][0]) - newbone.tail.y = parentbone.head.y + (pos_y + bonesize * rotmatrix[1][1]) - newbone.tail.z = parentbone.head.z + (pos_z + bonesize * rotmatrix[1][2]) - else: - rotmatrix = bone.bindmat.to_matrix().resize4x4().rotation_part() - newbone.head.x = bone.bindpos[0] - newbone.head.y = bone.bindpos[1] - newbone.head.z = bone.bindpos[2] - newbone.tail.x = bone.bindpos[0] + bonesize * rotmatrix[1][0] - newbone.tail.y = bone.bindpos[1] + bonesize * rotmatrix[1][1] - newbone.tail.z = bone.bindpos[2] + bonesize * rotmatrix[1][2] - #print("no parent") - - bpy.context.scene.update() - - #================================================================================================== - #END BONE DATA BUILD - #================================================================================================== - VtxCol = [] - for x in range(len(Bns)): - #change the overall darkness of each material in a range between 0.1 and 0.9 - tmpVal = ((float(x)+1.0)/(len(Bns))*0.7)+0.1 - tmpVal = int(tmpVal * 256) - tmpCol = [tmpVal,tmpVal,tmpVal,0] - #Change the color of each material slightly - if x % 3 == 0: - if tmpCol[0] < 128: tmpCol[0] += 60 - else: tmpCol[0] -= 60 - if x % 3 == 1: - if tmpCol[1] < 128: tmpCol[1] += 60 - else: tmpCol[1] -= 60 - if x % 3 == 2: - if tmpCol[2] < 128: tmpCol[2] += 60 - else: tmpCol[2] -= 60 - #Add the material to the mesh - VtxCol.append(tmpCol) - - #================================================================================================== - # Bone Weight - #================================================================================================== - #read the RAWW0000 header - indata = unpack('20s3i',pskfile.read(32)) - recCount = indata[3] - printlog( "Nbr of RAWW0000 records: " + str(recCount) +"\n") - #RAWW0000 fields: Weight|PntIdx|BoneIdx - RWghts = [] - counter = 0 - while counter < recCount: - counter = counter + 1 - indata = unpack('fii',pskfile.read(12)) - RWghts.append([indata[1],indata[2],indata[0]]) - #RWghts fields = PntIdx|BoneIdx|Weight - RWghts.sort() - printlog( "len(RWghts)=" + str(len(RWghts)) + "\n") - #Tmsh.update() - - #set the Vertex Colors of the faces - #face.v[n] = RWghts[0] - #RWghts[1] = index of VtxCol - """ - for x in range(len(Tmsh.faces)): - for y in range(len(Tmsh.faces[x].v)): - #find v in RWghts[n][0] - findVal = Tmsh.faces[x].v[y].index - n = 0 - while findVal != RWghts[n][0]: - n = n + 1 - TmpCol = VtxCol[RWghts[n][1]] - #check if a vertex has more than one influence - if n != len(RWghts)-1: - if RWghts[n][0] == RWghts[n+1][0]: - #if there is more than one influence, use the one with the greater influence - #for simplicity only 2 influences are checked, 2nd and 3rd influences are usually very small - if RWghts[n][2] < RWghts[n+1][2]: - TmpCol = VtxCol[RWghts[n+1][1]] - Tmsh.faces[x].col.append(NMesh.Col(TmpCol[0],TmpCol[1],TmpCol[2],0)) - """ - if (DEBUGLOG): - logf.close() - #================================================================================================== - #Building Mesh - #================================================================================================== - print("vertex:",len(verts),"faces:",len(faces)) - me_ob.vertices.add(len(verts)) - me_ob.faces.add(len(faces)//4) - - me_ob.vertices.foreach_set("co", unpack_list(verts)) - - me_ob.faces.foreach_set("vertices_raw", faces) - me_ob.faces.foreach_set("use_smooth", [False] * len(me_ob.faces)) - me_ob.update() - - #=================================================================================================== - #UV Setup - #=================================================================================================== - texture = [] - texturename = "text1" - #print(dir(bpy.data)) - if (len(faceuv) > 0): - uvtex = me_ob.uv_textures.new() #add one uv texture - for i, face in enumerate(me_ob.faces): - blender_tface= uvtex.data[i] #face - blender_tface.uv1 = faceuv[i][0] #uv = (0,0) - blender_tface.uv2 = faceuv[i][1] #uv = (0,0) - blender_tface.uv3 = faceuv[i][2] #uv = (0,0) - texture.append(uvtex) - - #for tex in me_ob.uv_textures: - #print("mesh tex:",dir(tex)) - #print((tex.name)) - - #=================================================================================================== - #Material Setup - #=================================================================================================== - materialname = "mat" - materials = [] - - matdata = bpy.data.materials.new(materialname) - #color is 0 - 1 not in 0 - 255 - #matdata.mirror_color=(float(0.04),float(0.08),float(0.44)) - matdata.diffuse_color=(float(0.04),float(0.08),float(0.44))#blue color - #print(dir(me_ob.uv_textures[0].data)) - texdata = None - texdata = bpy.data.textures[len(bpy.data.textures)-1] - if (texdata != None): - #print(texdata.name) - #print(dir(texdata)) - texdata.name = "texturelist1" - matdata.active_texture = texdata - materials.append(matdata) - #matdata = bpy.data.materials.new(materialname) - #materials.append(matdata) - #= make sure the list isnt too big - for material in materials: - #add material to the mesh list of materials - me_ob.materials.append(material) - #=================================================================================================== - # - #=================================================================================================== - obmesh = bpy.data.objects.new(objName,me_ob) - #check if there is a material to set to - if len(materials) > 0: - obmesh.active_material = materials[0] #material setup tmp - - bpy.context.scene.objects.link(obmesh) - - bpy.context.scene.update() - - print ("PSK2Blender completed") -#End of def pskimport######################### - -def getInputFilename(filename): - checktype = filename.split('\\')[-1].split('.')[1] - print ("------------",filename) - if checktype.upper() != 'PSK': - print (" Selected file = ",filename) - raise (IOError, "The selected input file is not a *.psk file") - pskimport(filename) - -from bpy.props import * - -class IMPORT_OT_psk(bpy.types.Operator): - '''Load a skeleton mesh psk File''' - bl_idname = "import_scene.psk" - bl_label = "Import PSK" - - # List of operator properties, the attributes will be assigned - # to the class instance from the operator settings before calling. - filepath = StringProperty(name="File Path", description="Filepath used for importing the OBJ file", maxlen= 1024, default= "") - - def execute(self, context): - getInputFilename(self.properties.filepath) - return {'FINISHED'} - - def invoke(self, context, event): - wm = context.window_manager - wm.add_fileselect(self) - return {'RUNNING_MODAL'} - -def menu_func(self, context): - self.layout.operator(IMPORT_OT_psk.bl_idname, text="Skeleton Mesh (.psk)") - - -def register(): - bpy.types.INFO_MT_file_import.append(menu_func) - -def unregister(): - bpy.types.INFO_MT_file_import.remove(menu_func) - -if __name__ == "__main__": - register() - -#note this only read the data and will not be place in the scene -#getInputFilename('C:\\blenderfiles\\BotA.psk') -#getInputFilename('C:\\blenderfiles\\AA.PSK') diff --git a/io_mesh_raw/__init__.py b/io_mesh_raw/__init__.py deleted file mode 100644 index d52a5808..00000000 --- a/io_mesh_raw/__init__.py +++ /dev/null @@ -1,69 +0,0 @@ -# ##### 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -# ##### END GPL LICENSE BLOCK ##### - -bl_addon_info = { - "name": "Raw mesh", - "author": "Anthony D,Agostino (Scorpius), Aurel Wildfellner", - "version": (0,2), - "blender": (2, 5, 3), - "api": 31667, - "location": "File > Import/Export > Raw faces ", - "description": "Import Raw Faces (.raw format)", - "warning": "", - "wiki_url": "http://wiki.blender.org/index.php/Extensions:2.5/Py/"\ - "Scripts/File_I-O/Raw_Mesh_IO", - "tracker_url": "https://projects.blender.org/tracker/index.php?"\ - "func=detail&aid=21733&group_id=153&atid=469", - "category": "Import/Export"} - -import bpy - - -try: - init_data - - reload(import_raw) - reload(export_raw) -except: - from io_mesh_raw import import_raw - from io_mesh_raw import export_raw - -init_data = True - -def menu_import(self, context): - from io_mesh_raw import import_raw - self.layout.operator(import_raw.RawImporter.bl_idname, text="Raw Faces (.raw)").filepath = "*.raw" - - -def menu_export(self, context): - from io_mesh_raw import export_raw - import os - default_path = os.path.splitext(bpy.data.filepath)[0] + ".raw" - self.layout.operator(export_raw.RawExporter.bl_idname, text="Raw Faces (.raw)").filepath = default_path - - -def register(): - bpy.types.INFO_MT_file_import.append(menu_import) - bpy.types.INFO_MT_file_export.append(menu_export) - -def unregister(): - bpy.types.INFO_MT_file_import.remove(menu_import) - bpy.types.INFO_MT_file_export.remove(menu_export) - -if __name__ == "__main__": - register() diff --git a/io_mesh_raw/export_raw.py b/io_mesh_raw/export_raw.py deleted file mode 100644 index 59f06f9d..00000000 --- a/io_mesh_raw/export_raw.py +++ /dev/null @@ -1,112 +0,0 @@ -# ##### 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -# ##### END GPL LICENSE BLOCK ##### - -__author__ = ["Aurel Wildfellner"] -__version__ = '0.2' -__bpydoc__ = """\ -This script exports a Mesh to a RAW triangle format file. - -The raw triangle format is very simple; it has no verts or faces lists. -It's just a simple ascii text file with the vertices of each triangle -listed on each line. In addition, also quads can be exported as a line -of 12 values (this was the default before blender 2.5). Now default -settings will triangulate the mesh. - -Usage:
- Execute this script from the "File->Export" menu. You can select -whether modifiers should be applied and if the mesh is triangulated. - -""" - -import bpy - - -def faceToTriangles(face): - triangles = [] - if (len(face) == 4): #quad - triangles.append( [ face[0], face[1], face[2] ] ) - triangles.append( [ face[2], face[3], face[0] ] ) - else: - triangles.append(face) - - return triangles - - -def faceValues(face, mesh, matrix): - fv = [] - for verti in face.vertices_raw: - fv.append(matrix * mesh.vertices[verti].co) - return fv - - -def faceToLine(face): - line = "" - for v in face: - line += str(v[0]) + " " + str(v[1]) + " " + str(v[2]) + " " - return line[:-1] + "\n" - - -def export_raw(filepath, applyMods, triangulate): - faces = [] - for obj in bpy.context.selected_objects: - if obj.type == 'MESH': - matrix = obj.matrix_world - - if (applyMods): - me = obj.create_mesh(bpy.context.scene, True, "PREVIEW") - else: - me = obj.data - - for face in me.faces: - fv = faceValues(face, me, matrix) - if triangulate: - faces.extend(faceToTriangles(fv)) - else: - faces.append(fv) - - # write the faces to a file - file = open(filepath, "w") - for face in faces: - file.write(faceToLine(face)) - file.close() - - -from bpy.props import * - - -class RawExporter(bpy.types.Operator): - '''Save Raw triangle mesh data''' - bl_idname = "export_mesh.raw" - bl_label = "Export RAW" - - filepath = StringProperty(name="File Path", description="Filepath used for exporting the RAW file", maxlen= 1024, default= "") - check_existing = BoolProperty(name="Check Existing", description="Check and warn on overwriting existing files", default=True, options={'HIDDEN'}) - - apply_modifiers = BoolProperty(name="Apply Modifiers", description="Use transformed mesh data from each object", default=True) - triangulate = BoolProperty(name="Triangulate", description="Triangulate quads.", default=True) - - def execute(self, context): - export_raw(self.properties.filepath, self.properties.apply_modifiers, self.properties.triangulate) - return {'FINISHED'} - - def invoke(self, context, event): - wm = context.window_manager - wm.add_fileselect(self) - return {'RUNNING_MODAL'} - -# package manages registering diff --git a/io_mesh_raw/import_raw.py b/io_mesh_raw/import_raw.py deleted file mode 100644 index d6b70e0b..00000000 --- a/io_mesh_raw/import_raw.py +++ /dev/null @@ -1,143 +0,0 @@ -# ##### 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -# ##### END GPL LICENSE BLOCK ##### - -__author__ = ["Anthony D'Agostino (Scorpius)", "Aurel Wildfellner"] -__version__ = '0.2' -__bpydoc__ = """\ -This script imports Raw Triangle File format files to Blender. - -The raw triangle format is very simple; it has no verts or faces lists. -It's just a simple ascii text file with the vertices of each triangle -listed on each line. In addition, a line with 12 values will be -imported as a quad. This may be in conflict with some other -applications, which use a raw format, but this is how it was -implemented back in blender 2.42. - -Usage:
- Execute this script from the "File->Import" menu and choose a Raw file to -open. - -Notes:
- Generates the standard verts and faces lists, but without duplicate -verts. Only *exact* duplicates are removed, there is no way to specify a -tolerance. -""" - - - -import bpy - -# move those to a utility modul -from io_utils import unpack_face_list, unpack_list # TODO, make generic - - -def readMesh(filename, objName): - file = open(filename, "rb") - - def line_to_face(line): - # Each triplet is an xyz float - line_split = [] - try: - line_split = list(map(float, line.split())) - except: - return None - - if len(line_split) == 9: # Tri - f1, f2, f3, f4, f5, f6, f7, f8, f9 = line_split - return [(f1, f2, f3), (f4, f5, f6), (f7, f8, f9)] - elif len(line_split) == 12: # Quad - f1, f2, f3, f4, f5, f6, f7, f8, f9, A, B, C = line_split - return [(f1, f2, f3), (f4, f5, f6), (f7, f8, f9), (A, B, C)] - else: - return None - - - faces = [] - for line in file.readlines(): - face = line_to_face(line) - if face: - faces.append(face) - - file.close() - - # Generate verts and faces lists, without duplicates - verts = [] - coords = {} - index_tot = 0 - - for f in faces: - for i, v in enumerate(f): - index = coords.get(v) - - if index is None: - index = coords[v] = index_tot - index_tot += 1 - verts.append(v) - - fi[i] = index - - mesh = bpy.data.meshes.new(objName) - mesh.vertices.add(len(verts)) - mesh.faces.add(len(faces)) - mesh.vertices.foreach_set("co", unpack_list(verts)) - mesh.faces.foreach_set("vertices_raw", unpack_face_list(faces)) - - return mesh - - -def addMeshObj(mesh, objName): - scn = bpy.context.scene - - for o in scn.objects: - o.select = False - - mesh.update() - nobj = bpy.data.objects.new(objName, mesh) - scn.objects.link(nobj) - nobj.select = True - - if scn.objects.active == None or scn.objects.active.mode == 'OBJECT': - scn.objects.active = nobj - - -from bpy.props import * - -class RawImporter(bpy.types.Operator): - '''Load Raw triangle mesh data''' - bl_idname = "import_mesh.raw" - bl_label = "Import RAW" - - filepath = StringProperty(name="File Path", description="Filepath used for importing the RAW file", maxlen=1024, default="") - filename = StringProperty(name="File Name", description="Name of the file.") - - def execute(self, context): - - #convert the filename to an object name - objName = bpy.path.display_name(self.properties.filename) - - mesh = readMesh(self.properties.filepath, objName) - addMeshObj(mesh, objName) - - return {'FINISHED'} - - def invoke(self, context, event): - wm = context.window_manager - wm.add_fileselect(self) - return {'RUNNING_MODAL'} - -# package manages registering diff --git a/io_mesh_stl/__init__.py b/io_mesh_stl/__init__.py deleted file mode 100644 index 96e8fc32..00000000 --- a/io_mesh_stl/__init__.py +++ /dev/null @@ -1,163 +0,0 @@ -# ##### 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -# ##### END GPL LICENSE BLOCK ##### - -bl_addon_info = { - "name": "STL format", - "author": "Guillaume Bouchard (Guillaum)", - "version": (1,), - "blender": (2, 5, 3), - "api": 31667, - "location": "File > Import/Export > Stl", - "description": "Import/Export STL files", - "warning": "", - "wiki_url": "http://wiki.blender.org/index.php/Extensions:2.5/Py/"\ - "Scripts/File I-O/STL", - "tracker_url": "https://projects.blender.org/tracker/index.php?" - "func=detail&aid=22837&group_id=153&atid=469", - "category": "Import/Export"} - -# @todo write the wiki page - -""" -Import/Export STL files (binary or ascii) - -- Import automatically remove the doubles. -- Export can export with/without modifiers applied - -Issues: - -Import: - - Does not handle the normal of the triangles - - Does not handle endien -""" - -import itertools -import os - -import bpy -from bpy.props import * - - -try: - init_data - - reload(stl_utils) - reload(blender_utils) -except: - from io_mesh_stl import stl_utils - from io_mesh_stl import blender_utils - -init_data = True - - -class StlImporter(bpy.types.Operator): - ''' - Load STL triangle mesh data - ''' - bl_idname = "import_mesh.stl" - bl_label = "Import STL" - - files = CollectionProperty(name="File Path", - description="File path used for importing " - "the STL file", - type=bpy.types.OperatorFileListElement) - - directory = StringProperty() - - def execute(self, context): - paths = (os.path.join(self.properties.directory, name.name) for name in self.properties.files) - - for path in paths: - objName = bpy.path.display_name(path.split("\\")[-1].split("/")[-1]) - tris, pts = stl_utils.read_stl(path) - - blender_utils.create_and_link_mesh(objName, tris, pts) - - return {'FINISHED'} - - def invoke(self, context, event): - wm = context.window_manager - wm.add_fileselect(self) - - return {'RUNNING_MODAL'} - - -class StlExporter(bpy.types.Operator): - ''' - Save STL triangle mesh data from the active object - ''' - bl_idname = "export_mesh.stl" - bl_label = "Export STL" - - filepath = StringProperty(name="File Path", - description="File path used for exporting " - "the active object to STL file", - maxlen=1024, - default="") - check_existing = BoolProperty(name="Check Existing", - description="Check and warn on " - "overwriting existing files", - default=True, - options={'HIDDEN'}) - - ascii = BoolProperty(name="Ascii", - description="Save the file in ASCII file format", - default=False) - apply_modifiers = BoolProperty(name="Apply Modifiers", - description="Apply the modifiers " - "before saving", - default=True) - - def execute(self, context): - faces = itertools.chain.from_iterable( - blender_utils.faces_from_mesh(ob, self.properties.apply_modifiers) - for ob in context.selected_objects) - - stl_utils.write_stl(self.properties.filepath, faces, self.properties.ascii) - - return {'FINISHED'} - - def invoke(self, context, event): - wm = context.window_manager - wm.add_fileselect(self) - return {'RUNNING_MODAL'} - - -def menu_import(self, context): - self.layout.operator(StlImporter.bl_idname, - text="Stl (.stl)").filepath = "*.stl" - - -def menu_export(self, context): - default_path = os.path.splitext(bpy.data.filepath)[0] + ".stl" - self.layout.operator(StlExporter.bl_idname, - text="Stl (.stl)").filepath = default_path - - -def register(): - bpy.types.INFO_MT_file_import.append(menu_import) - bpy.types.INFO_MT_file_export.append(menu_export) - - -def unregister(): - bpy.types.INFO_MT_file_import.remove(menu_import) - bpy.types.INFO_MT_file_export.remove(menu_export) - - -if __name__ == "__main__": - register() diff --git a/io_mesh_stl/blender_utils.py b/io_mesh_stl/blender_utils.py deleted file mode 100644 index 76dc86b9..00000000 --- a/io_mesh_stl/blender_utils.py +++ /dev/null @@ -1,53 +0,0 @@ -import bpy - - -def create_and_link_mesh(name, faces, points): - ''' - Create a blender mesh and object called name from a list of - *points* and *faces* and link it in the current scene. - ''' - - mesh = bpy.data.meshes.new(name) - mesh.from_pydata(points, [], faces) - - ob = bpy.data.objects.new(name, mesh) - bpy.context.scene.objects.link(ob) - - # update mesh to allow proper display - mesh.update() - - -def faces_from_mesh(ob, apply_modifier=False, triangulate=True): - ''' - From an object, return a generator over a list of faces. - - Each faces is a list of his vertexes. Each vertex is a tuple of - his coordinate. - - apply_modifier - Apply the preview modifier to the returned liste - - triangulate - Split the quad into two triangles - ''' - - # get the modifiers - try: - mesh = ob.create_mesh(bpy.context.scene, - apply_modifier, "PREVIEW") - except SystemError: - return () - - def iter_face_index(): - ''' - From a list of faces, return the face triangulated if needed. - ''' - for face in mesh.faces: - if triangulate and len(face.vertices) == 4: - yield face.vertices[:3] - yield face.vertices[2:] + [face.vertices[0]] - else: - yield list(face.vertices) - - return ([tuple(ob.matrix_world * mesh.vertices[index].co) - for index in indexes] for indexes in iter_face_index()) diff --git a/io_mesh_stl/stl_utils.py b/io_mesh_stl/stl_utils.py deleted file mode 100644 index 92723e98..00000000 --- a/io_mesh_stl/stl_utils.py +++ /dev/null @@ -1,228 +0,0 @@ -''' -Import and export STL files - -Used as a blender script, it load all the stl files in the scene: - -blender -P stl_utils.py -- file1.stl file2.stl file3.stl ... -''' - -import struct -import mmap -import contextlib -import itertools - -# TODO: endien - - -@contextlib.contextmanager -def mmap_file(filename): - ''' - Context manager over the data of an mmap'ed file (Read ONLY). - - - Example: - - with mmap_file(filename) as m: - m.read() - print m[10:50] - ''' - with open(filename, 'rb') as file: - # check http://bugs.python.org/issue8046 to have mmap context - # manager fixed in python - map = mmap.mmap(file.fileno(), 0, access=mmap.ACCESS_READ) - yield map - map.close() - - -class ListDict(dict): - ''' - Set struct with order. - - You can: - - insert data into without doubles - - get the list of data in insertion order with self.list - - Like collections.OrderedDict, but quicker, can be replaced if - ODict is optimised. - ''' - - def __init__(self): - dict.__init__(self) - self.list = [] - self._len = 0 - - def add(self, item): - ''' - Add a value to the Set, return its position in it. - ''' - value = self.setdefault(item, self._len) - if value == self._len: - self.list.append(item) - self._len += 1 - - return value - - -def _binary_read(data): - # an stl binary file is - # - 80 bytes of description - # - 2 bytes of size (unsigned int) - # - size triangles : - # - # - 12 bytes of normal - # - 9 * 4 bytes of coordinate (3*3 floats) - # - 2 bytes of garbage (usually 0) - - # OFFSET for the first byte of coordinate (headers + first normal bytes) - # STRIDE between each triangle (first normal + coordinates + garbage) - OFFSET, STRIDE = 84 + 12, 12 * 4 + 2 - - # read header size, ignore description - size = struct.unpack_from('>> tris, pts = read_stl(filename, lambda x:) - >>> pts = list(pts) - >>> - >>> # print the coordinate of the triangle n - >>> print([pts[i] for i in tris[n]]) - ''' - - tris, pts = [], ListDict() - - with mmap_file(filename) as data: - # check for ascii or binary - gen = _ascii_read if data.read(5) == b'solid' else _binary_read - - for pt in gen(data): - # Add the triangle and the point. - # If the point is allready in the list of points, the - # index returned by pts.add() will be the one from the - # first equal point inserted. - tris.append([pts.add(p) for p in pt]) - - return tris, pts.list - - -if __name__ == '__main__': - import sys - import bpy - from io_mesh_stl import blender_utils - - filenames = sys.argv[sys.argv.index('--') + 1:] - - for filename in filenames: - objName = bpy.path.display_name(filename) - tris, pts = read_stl(filename) - - blender_utils.create_and_link_mesh(objName, tris, pts) diff --git a/mesh_relax.py b/mesh_relax.py deleted file mode 100644 index 1a971a93..00000000 --- a/mesh_relax.py +++ /dev/null @@ -1,128 +0,0 @@ -# mesh_relax.py Copyright (C) 2010, Fabian Fricke -# -# Relaxes selected vertices while retaining the shape as much as possible -# -# ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -# ***** END GPL LICENCE BLOCK ***** - -bl_addon_info = { - "name": "Relax", - "author": "Fabian Fricke", - "version": (1,1), - "blender": (2, 5, 3), - "api": 31667, - "location": "View3D > Specials > Relax ", - "description": "Relax the selected verts while retaining the shape", - "warning": "", - "wiki_url": "http://wiki.blender.org/index.php/Extensions:2.5/Py/"\ - "Scripts/Modeling/Relax", - "tracker_url": "https://projects.blender.org/tracker/index.php?"\ - "func=detail&aid=21421&group_id=153&atid=469", - "category": "Mesh"} - -""" -Usage: - -Launch from "W-menu" or from "Mesh -> Vertices -> Relax" - - -Additional links: - Author Site: http://frigi.designdevil.de - e-mail: frigi.f {at} gmail {dot} com -""" - - -import bpy -from bpy.props import IntProperty - -def relax_mesh(context): - - # deselect everything that's not related - for obj in context.selected_objects: - obj.select = False - - # get active object - obj = context.active_object - - # duplicate the object so it can be used for the shrinkwrap modifier - obj.select = True # make sure the object is selected! - bpy.ops.object.mode_set(mode='OBJECT') - bpy.ops.object.duplicate() - target = context.active_object - - # remove all other modifiers from the target - for m in range(0, len(target.modifiers)): - target.modifiers.remove(target.modifiers[0]) - - context.scene.objects.active = obj - - sw = obj.modifiers.new(type='SHRINKWRAP', name='relax_target') - sw.target = target - - # run smooth operator to relax the mesh - bpy.ops.object.mode_set(mode='EDIT') - bpy.ops.mesh.vertices_smooth() - bpy.ops.object.mode_set(mode='OBJECT') - - # apply the modifier - bpy.ops.object.modifier_apply(modifier='relax_target') - - # delete the target object - obj.select = False - target.select = True - bpy.ops.object.delete() - - # go back to initial state - obj.select = True - bpy.ops.object.mode_set(mode='EDIT') - -class Relax(bpy.types.Operator): - '''Relaxes selected vertices while retaining the shape as much as possible''' - bl_idname = 'mesh.relax' - bl_label = 'Relax' - bl_options = {'REGISTER', 'UNDO'} - - iterations = IntProperty(name="Relax iterations", - default=1, min=0, max=100, soft_min=0, soft_max=10) - - @classmethod - def poll(cls, context): - obj = context.active_object - return (obj and obj.type == 'MESH') - - def execute(self, context): - for i in range(0,self.properties.iterations): - relax_mesh(context) - return {'FINISHED'} - - -def menu_func(self, context): - self.layout.operator(Relax.bl_idname, text="Relax") - - -def register(): - bpy.types.VIEW3D_MT_edit_mesh_specials.append(menu_func) - bpy.types.VIEW3D_MT_edit_mesh_vertices.append(menu_func) - -def unregister(): - bpy.types.VIEW3D_MT_edit_mesh_specials.remove(menu_func) - bpy.types.VIEW3D_MT_edit_mesh_vertices.remove(menu_func) - -if __name__ == "__main__": - register() diff --git a/mesh_surface_sketch.py b/mesh_surface_sketch.py deleted file mode 100644 index 41bc79c7..00000000 --- a/mesh_surface_sketch.py +++ /dev/null @@ -1,819 +0,0 @@ -# ##### 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -# ##### END GPL LICENSE BLOCK ##### - -bl_addon_info = { - "name": "Surface Sketch", - "author": "Eclectiel", - "version": (0,8), - "blender": (2, 5, 3), - "api": 31667, - "location": "View3D > EditMode > ToolShelf", - "description": "Draw meshes and re-topologies with Grease Pencil", - "warning": "Beta", - "wiki_url": "http://wiki.blender.org/index.php/Extensions:2.5/Py/"\ - "Scripts/Mesh/Surface_Sketch", - "tracker_url": "https://projects.blender.org/tracker/index.php?"\ - "func=detail&aid=22062&group_id=153&atid=469", - "category": "Mesh"} - - -import bpy -import math - -from math import * - - -class VIEW3D_PT_tools_SURF_SKETCH(bpy.types.Panel): - bl_space_type = 'VIEW_3D' - bl_region_type = 'TOOLS' - - bl_context = "mesh_edit" - bl_label = "Surface Sketching" - - @classmethod - def poll(cls, context): - return context.active_object - - def draw(self, context): - layout = self.layout - - scn = context.scene - ob = context.object - - col = layout.column(align=True) - row = layout.row() - row.separator() - col.operator("GPENCIL_OT_SURFSK_add_surface", text="Add Surface") - col.prop(scn, "SURFSK_edges_U") - col.prop(scn, "SURFSK_edges_V") - row.separator() - col.prop(scn, "SURFSK_keep_strokes") - col.separator() - row.separator() - col.operator("GPENCIL_OT_SURFSK_strokes_to_curves", text="Strokes to curves") - - - -class GPENCIL_OT_SURFSK_add_surface(bpy.types.Operator): - bl_idname = "GPENCIL_OT_SURFSK_add_surface" - bl_label = "Surface generation from grease pencil strokes" - bl_description = "Surface generation from grease pencil strokes" - - - #### Get an ordered list of a chain of vertices. - def get_ordered_verts(self, ob, all_selected_edges_idx, all_selected_verts_idx, first_vert_idx, middle_vertex_idx): - # Order selected vertexes. - verts_ordered = [] - verts_ordered.append(self.main_object.data.vertices[first_vert_idx]) - prev_v = first_vert_idx - prev_ed = None - finish_while = False - while True: - edges_non_matched = 0 - for i in all_selected_edges_idx: - if ob.data.edges[i] != prev_ed and ob.data.edges[i].vertices[0] == prev_v and ob.data.edges[i].vertices[1] in all_selected_verts_idx: - verts_ordered.append(self.main_object.data.vertices[ob.data.edges[i].vertices[1]]) - prev_v = ob.data.edges[i].vertices[1] - prev_ed = ob.data.edges[i] - elif ob.data.edges[i] != prev_ed and ob.data.edges[i].vertices[1] == prev_v and ob.data.edges[i].vertices[0] in all_selected_verts_idx: - verts_ordered.append(self.main_object.data.vertices[ob.data.edges[i].vertices[0]]) - prev_v = ob.data.edges[i].vertices[0] - prev_ed = ob.data.edges[i] - else: - edges_non_matched += 1 - - if edges_non_matched == len(all_selected_edges_idx): - finish_while = True - - if finish_while: - break - - if middle_vertex_idx != None: - verts_ordered.append(self.main_object.data.vertices[middle_vertex_idx]) - verts_ordered.reverse() - - return verts_ordered - - - #### Calculates length of a chain of points. - def get_chain_length(self, verts_ordered): - edges_lengths = [] - edges_lengths_sum = 0 - for i in range(0, len(verts_ordered)): - if i == 0: - prev_v = verts_ordered[i] - else: - v = verts_ordered[i] - - v_difs = [prev_v.co[0] - v.co[0], prev_v.co[1] - v.co[1], prev_v.co[2] - v.co[2]] - edge_length = abs(sqrt(v_difs[0] * v_difs[0] + v_difs[1] * v_difs[1] + v_difs[2] * v_difs[2])) - - edges_lengths.append(edge_length) - edges_lengths_sum += edge_length - - prev_v = v - - return edges_lengths, edges_lengths_sum - - - #### Calculates the proportion of the edges of a chain of edges, relative to the full chain length. - def get_edges_proportions(self, edges_lengths, edges_lengths_sum, use_boundaries, fixed_edges_num): - edges_proportions = [] - if use_boundaries: - verts_count = 1 - for l in edges_lengths: - edges_proportions.append(l / edges_lengths_sum) - verts_count += 1 - else: - verts_count = 1 - for n in range(0, fixed_edges_num): - edges_proportions.append(1 / fixed_edges_num) - verts_count += 1 - - return edges_proportions - - - #### Calculates the angle between two pairs of points in space. - def orientation_difference(self, points_A_co, points_B_co): # each parameter should be a list with two elements, and each element should be a x,y,z coordinate. - vec_A = points_A_co[0] - points_A_co[1] - vec_B = points_B_co[0] - points_B_co[1] - - angle = vec_A.angle(vec_B) - - if angle > 0.5 * math.pi: - angle = abs(angle - math.pi) - - return angle - - - #### Calculate distance between two points - def pts_distance(self, p1_co, p2_co): - p_difs = [p1_co[0] - p2_co[0], p1_co[1] - p2_co[1], p1_co[2] - p2_co[2]] - distance = abs(sqrt(p_difs[0] * p_difs[0] + p_difs[1] * p_difs[1] + p_difs[2] * p_difs[2])) - - return distance - - - def execute(self, context): - #### Selected edges. - all_selected_edges_idx = [] - all_selected_verts = [] - all_verts_idx = [] - for ed in self.main_object.data.edges: - if ed.select: - all_selected_edges_idx.append(ed.index) - - # Selected vertexes. - if not ed.vertices[0] in all_selected_verts: - all_selected_verts.append(self.main_object.data.vertices[ed.vertices[0]]) - if not ed.vertices[1] in all_selected_verts: - all_selected_verts.append(self.main_object.data.vertices[ed.vertices[1]]) - - # All verts (both from each edge) to determine later which are at the tips (those not repeated twice). - all_verts_idx.append(ed.vertices[0]) - all_verts_idx.append(ed.vertices[1]) - - - #### Identify the tips and "middle-vertex" that separates U from V, if there is one. - all_chains_tips_idx = [] - for v_idx in all_verts_idx: - if all_verts_idx.count(v_idx) < 2: - all_chains_tips_idx.append(v_idx) - - edges_connected_to_tips = [] - for ed in self.main_object.data.edges: - if (ed.vertices[0] in all_chains_tips_idx or ed.vertices[1] in all_chains_tips_idx) and not (ed.vertices[0] in all_verts_idx and ed.vertices[1] in all_verts_idx): - edges_connected_to_tips.append(ed) - - middle_vertex_idx = None - tips_to_discard_idx = [] - for ed_tips in edges_connected_to_tips: - for ed_tips_b in edges_connected_to_tips: - if (ed_tips != ed_tips_b): - if ed_tips.vertices[0] in all_verts_idx and (((ed_tips.vertices[1] == ed_tips_b.vertices[0]) or ed_tips.vertices[1] == ed_tips_b.vertices[1])): - middle_vertex_idx = ed_tips.vertices[1] - tips_to_discard_idx.append(ed_tips.vertices[0]) - elif ed_tips.vertices[1] in all_verts_idx and (((ed_tips.vertices[0] == ed_tips_b.vertices[0]) or ed_tips.vertices[0] == ed_tips_b.vertices[1])): - middle_vertex_idx = ed_tips.vertices[0] - tips_to_discard_idx.append(ed_tips.vertices[1]) - - - #### List with pairs of verts that belong to the tips of each selection chain (row). - verts_tips_same_chain_idx = [] - if len(all_chains_tips_idx) >= 2: - checked_v = [] - for i in range(0, len(all_chains_tips_idx)): - if all_chains_tips_idx[i] not in checked_v: - v_chain = self.get_ordered_verts(self.main_object, all_selected_edges_idx, all_verts_idx, all_chains_tips_idx[i], middle_vertex_idx) - - verts_tips_same_chain_idx.append([v_chain[0].index, v_chain[len(v_chain) - 1].index]) - - checked_v.append(v_chain[0].index) - checked_v.append(v_chain[len(v_chain) - 1].index) - - - #### Selection tips (vertices) - verts_tips_parsed_idx = [] - if len(all_chains_tips_idx) >= 2: - for spec_v_idx in all_chains_tips_idx: - if (spec_v_idx not in tips_to_discard_idx): - verts_tips_parsed_idx.append(spec_v_idx) - - - #### Identify the type of selection made by the user. - if middle_vertex_idx != None: - if len(all_chains_tips_idx) == 4: # If there are 4 tips (two selection chains) - selection_type = "TWO_CONNECTED" - else: - # The type of the selection was not identified, so the script stops. - return - else: - if len(all_chains_tips_idx) == 2: # If there are 2 tips (one selection chain) - selection_type = "SINGLE" - elif len(all_chains_tips_idx) == 4: # If there are 4 tips (two selection chains) - selection_type = "TWO_NOT_CONNECTED" - elif len(all_chains_tips_idx) == 0: - selection_type = "NO_SELECTION" - else: - # The type of the selection was not identified, so the script stops. - return - - - #### Check if it will be used grease pencil strokes or curves. - selected_objs = bpy.context.selected_objects - if len(selected_objs) > 1: - for ob in selected_objs: - if ob != bpy.context.scene.objects.active: - ob_gp_strokes = ob - using_external_curves = True - - bpy.ops.object.editmode_toggle() - else: - #### Convert grease pencil strokes to curve. - bpy.ops.gpencil.convert(type='CURVE') - ob_gp_strokes = bpy.context.object - using_external_curves = False - - bpy.ops.object.editmode_toggle() - - ob_gp_strokes.name = "SURFSK_temp_strokes" - - bpy.ops.object.select_name(name = ob_gp_strokes.name) - bpy.context.scene.objects.active = bpy.context.scene.objects[ob_gp_strokes.name] - - - #### If "Keep strokes" is active make a duplicate of the original strokes, which will be intact - if bpy.context.scene.SURFSK_keep_strokes: - bpy.ops.object.duplicate_move() - bpy.context.object.name = "SURFSK_used_strokes" - bpy.ops.object.editmode_toggle() - bpy.ops.curve.smooth() - bpy.ops.curve.smooth() - bpy.ops.curve.smooth() - bpy.ops.curve.smooth() - bpy.ops.curve.smooth() - bpy.ops.curve.smooth() - bpy.ops.object.editmode_toggle() - - bpy.ops.object.select_name(name = ob_gp_strokes.name) - bpy.context.scene.objects.active = bpy.context.scene.objects[ob_gp_strokes.name] - - - #### Enter editmode for the new curve (converted from grease pencil strokes). - bpy.ops.object.editmode_toggle() - bpy.ops.curve.smooth() - bpy.ops.curve.smooth() - bpy.ops.curve.smooth() - bpy.ops.curve.smooth() - bpy.ops.curve.smooth() - bpy.ops.curve.smooth() - bpy.ops.object.editmode_toggle() - - - selection_U_exists = False - selection_U2_exists = False - selection_V_exists = False - selection_V2_exists = False - #### Define what vertexes are at the tips of each selection and are not the middle-vertex. - if selection_type == "TWO_CONNECTED": - selection_U_exists = True - selection_V_exists = True - - # Determine which selection is Selection-U and which is Selection-V. - points_A = [] - points_B = [] - points_first_stroke_tips = [] - - points_A.append(self.main_object.data.vertices[verts_tips_parsed_idx[0]].co) - points_A.append(self.main_object.data.vertices[middle_vertex_idx].co) - - points_B.append(self.main_object.data.vertices[verts_tips_parsed_idx[1]].co) - points_B.append(self.main_object.data.vertices[middle_vertex_idx].co) - - points_first_stroke_tips.append(ob_gp_strokes.data.splines[0].bezier_points[0].co) - points_first_stroke_tips.append(ob_gp_strokes.data.splines[0].bezier_points[len(ob_gp_strokes.data.splines[0].bezier_points) - 1].co) - - angle_A = self.orientation_difference(points_A, points_first_stroke_tips) - angle_B = self.orientation_difference(points_B, points_first_stroke_tips) - - if angle_A < angle_B: - first_vert_U_idx = verts_tips_parsed_idx[0] - first_vert_V_idx = verts_tips_parsed_idx[1] - else: - first_vert_U_idx = verts_tips_parsed_idx[1] - first_vert_V_idx = verts_tips_parsed_idx[0] - - elif selection_type == "SINGLE" or selection_type == "TWO_NOT_CONNECTED": - first_sketched_point_first_stroke_co = ob_gp_strokes.data.splines[0].bezier_points[0].co - last_sketched_point_first_stroke_co = ob_gp_strokes.data.splines[0].bezier_points[len(ob_gp_strokes.data.splines[0].bezier_points) - 1].co - - first_sketched_point_last_stroke_co = ob_gp_strokes.data.splines[len(ob_gp_strokes.data.splines) - 1].bezier_points[0].co - - # The tip of the selected vertices nearest to the first point of the first sketched stroke. - prev_dist = 999999999999 - for i in range(0, len(verts_tips_same_chain_idx)): - for v_idx in range(0, len(verts_tips_same_chain_idx[i])): - dist = self.pts_distance(first_sketched_point_first_stroke_co, self.main_object.data.vertices[verts_tips_same_chain_idx[i][v_idx]].co) - if dist < prev_dist: - prev_dist = dist - - nearest_tip_first_st_first_pt_idx = i - - nearest_tip_first_pair_first_pt_idx = v_idx - - # Shortest distance to the first point of the first stroke - shortest_distance_to_first_stroke = dist - - - # The tip of the selected vertices nearest to the last point of the first sketched stroke. - prev_dist = 999999999999 - for i in range(0, len(verts_tips_same_chain_idx)): - for v_idx in range(0, len(verts_tips_same_chain_idx[i])): - dist = self.pts_distance(last_sketched_point_first_stroke_co, self.main_object.data.vertices[verts_tips_same_chain_idx[i][v_idx]].co) - if dist < prev_dist: - prev_dist = dist - - nearest_tip_first_st_last_pt_pair_idx = i - nearest_tip_first_st_last_pt_point_idx = v_idx - - - # The tip of the selected vertices nearest to the first point of the last sketched stroke. - prev_dist = 999999999999 - for i in range(0, len(verts_tips_same_chain_idx)): - for v_idx in range(0, len(verts_tips_same_chain_idx[i])): - dist = self.pts_distance(first_sketched_point_last_stroke_co, self.main_object.data.vertices[verts_tips_same_chain_idx[i][v_idx]].co) - if dist < prev_dist: - prev_dist = dist - - nearest_tip_last_st_first_pt_pair_idx = i - nearest_tip_last_st_first_pt_point_idx = v_idx - - - points_tips = [] - points_first_stroke_tips = [] - - # Determine if the single selection will be treated as U or as V. - edges_sum = 0 - for i in all_selected_edges_idx: - edges_sum += self.pts_distance(self.main_object.data.vertices[self.main_object.data.edges[i].vertices[0]].co, self.main_object.data.vertices[self.main_object.data.edges[i].vertices[1]].co) - - average_edge_length = edges_sum / len(all_selected_edges_idx) - - - - # If the beginning of the first stroke is near enough to interpret things as an "extrude along strokes" instead of "extrude through strokes" - if shortest_distance_to_first_stroke < average_edge_length / 3: - selection_U_exists = False - selection_V_exists = True - - first_vert_V_idx = verts_tips_same_chain_idx[nearest_tip_first_st_first_pt_idx][nearest_tip_first_pair_first_pt_idx] - - if selection_type == "TWO_NOT_CONNECTED": - selection_V2_exists = True - - first_vert_V2_idx = verts_tips_same_chain_idx[nearest_tip_first_st_last_pt_pair_idx][nearest_tip_first_st_last_pt_point_idx] - - else: - selection_V2_exists = False - - else: - selection_U_exists = True - selection_V_exists = False - - points_tips.append(self.main_object.data.vertices[verts_tips_same_chain_idx[nearest_tip_first_st_first_pt_idx][0]].co) - points_tips.append(self.main_object.data.vertices[verts_tips_same_chain_idx[nearest_tip_first_st_first_pt_idx][1]].co) - - points_first_stroke_tips.append(ob_gp_strokes.data.splines[0].bezier_points[0].co) - points_first_stroke_tips.append(ob_gp_strokes.data.splines[0].bezier_points[len(ob_gp_strokes.data.splines[0].bezier_points) - 1].co) - - vec_A = points_tips[0] - points_tips[1] - vec_B = points_first_stroke_tips[0] - points_first_stroke_tips[1] - - # Compare the direction of the selection and the first grease pencil stroke to determine which is the "first" vertex of the selection. - if vec_A.dot(vec_B) < 0: - first_vert_U_idx = verts_tips_same_chain_idx[nearest_tip_first_st_first_pt_idx][1] - else: - first_vert_U_idx = verts_tips_same_chain_idx[nearest_tip_first_st_first_pt_idx][0] - - if selection_type == "TWO_NOT_CONNECTED": - selection_U2_exists = True - - first_vert_U2_idx = verts_tips_same_chain_idx[nearest_tip_last_st_first_pt_pair_idx][nearest_tip_last_st_first_pt_point_idx] - else: - selection_U2_exists = False - - elif selection_type == "NO_SELECTION": - selection_U_exists = False - selection_V_exists = False - - - #### Get an ordered list of the vertices of Selection-U. - if selection_U_exists: - verts_ordered_U = self.get_ordered_verts(self.main_object, all_selected_edges_idx, all_verts_idx, first_vert_U_idx, middle_vertex_idx) - - #### Get an ordered list of the vertices of Selection-U. - if selection_U2_exists: - verts_ordered_U2 = self.get_ordered_verts(self.main_object, all_selected_edges_idx, all_verts_idx, first_vert_U2_idx, middle_vertex_idx) - - #### Get an ordered list of the vertices of Selection-V. - if selection_V_exists: - verts_ordered_V = self.get_ordered_verts(self.main_object, all_selected_edges_idx, all_verts_idx, first_vert_V_idx, middle_vertex_idx) - - #### Get an ordered list of the vertices of Selection-U. - if selection_V2_exists: - verts_ordered_V2 = self.get_ordered_verts(self.main_object, all_selected_edges_idx, all_verts_idx, first_vert_V2_idx, middle_vertex_idx) - - - #### Calculate edges U proportions. - - # Sum selected edges U lengths. - edges_lengths_U = [] - edges_lengths_sum_U = 0 - - if selection_U_exists: - edges_lengths_U, edges_lengths_sum_U = self.get_chain_length(verts_ordered_U) - - # Sum selected edges V lengths. - edges_lengths_V = [] - edges_lengths_sum_V = 0 - - if selection_V_exists: - edges_lengths_V, edges_lengths_sum_V = self.get_chain_length(verts_ordered_V) - - bpy.ops.object.editmode_toggle() - for i in range(0, int(bpy.context.scene.SURFSK_precision)): - bpy.ops.curve.subdivide() - bpy.ops.object.editmode_toggle() - - # Proportions U. - edges_proportions_U = [] - edges_proportions_U = self.get_edges_proportions(edges_lengths_U, edges_lengths_sum_U, selection_U_exists, bpy.context.scene.SURFSK_edges_U) - verts_count_U = len(edges_proportions_U) + 1 - - # Proportions V. - edges_proportions_V = [] - edges_proportions_V = self.get_edges_proportions(edges_lengths_V, edges_lengths_sum_V, selection_V_exists, bpy.context.scene.SURFSK_edges_V) - verts_count_V = len(edges_proportions_V) + 1 - - - - #### Get ordered lists of points on each sketched curve that mimics the proportions of the edges in the vertex selection. - sketched_splines = ob_gp_strokes.data.splines - sketched_splines_lengths = [] - sketched_splines_parsed = [] - for sp_idx in range(0, len(sketched_splines)): - # Calculate spline length - sketched_splines_lengths.append(0) - for i in range(0, len(sketched_splines[sp_idx].bezier_points)): - if i == 0: - prev_p = sketched_splines[sp_idx].bezier_points[i] - else: - p = sketched_splines[sp_idx].bezier_points[i] - - p_difs = [prev_p.co[0] - p.co[0], prev_p.co[1] - p.co[1], prev_p.co[2] - p.co[2]] - edge_length = abs(sqrt(p_difs[0] * p_difs[0] + p_difs[1] * p_difs[1] + p_difs[2] * p_difs[2])) - - sketched_splines_lengths[sp_idx] += edge_length - - prev_p = p - - # Calculate vertex positions with apropriate edge proportions, and ordered, for each spline. - sketched_splines_parsed.append([]) - partial_spline_length = 0 - related_edge_U = 0 - edges_proportions_sum_U = 0 - edges_lengths_sum_U = 0 - for i in range(0, len(sketched_splines[sp_idx].bezier_points)): - if i == 0: - prev_p = sketched_splines[sp_idx].bezier_points[i] - sketched_splines_parsed[sp_idx].append(prev_p.co) - elif i != len(sketched_splines[sp_idx].bezier_points) - 1: - p = sketched_splines[sp_idx].bezier_points[i] - - p_difs = [prev_p.co[0] - p.co[0], prev_p.co[1] - p.co[1], prev_p.co[2] - p.co[2]] - edge_length = abs(sqrt(p_difs[0] * p_difs[0] + p_difs[1] * p_difs[1] + p_difs[2] * p_difs[2])) - - - if edges_proportions_sum_U + edges_proportions_U[related_edge_U] - ((edges_lengths_sum_U + partial_spline_length + edge_length) / sketched_splines_lengths[sp_idx]) > 0: # comparing proportions to see if the proportion in the selection is found in the spline. - partial_spline_length += edge_length - elif related_edge_U < len(edges_proportions_U) - 1: - sketched_splines_parsed[sp_idx].append(prev_p.co) - - edges_proportions_sum_U += edges_proportions_U[related_edge_U] - related_edge_U += 1 - - edges_lengths_sum_U += partial_spline_length - partial_spline_length = edge_length - - prev_p = p - else: # last point of the spline for the last edge - p = sketched_splines[sp_idx].bezier_points[len(sketched_splines[sp_idx].bezier_points) - 1] - sketched_splines_parsed[sp_idx].append(p.co) - - - #### If the selection type is "TWO_NOT_CONNECTED" replace the last point of each spline with the points in the "target" selection. - if selection_type == "TWO_NOT_CONNECTED": - if selection_U2_exists: - for i in range(0, len(sketched_splines_parsed[len(sketched_splines_parsed) - 1])): - sketched_splines_parsed[len(sketched_splines_parsed) - 1][i] = verts_ordered_U2[i].co - - - #### Create temporary curves along the "control-points" found on the sketched curves and the mesh selection. - mesh_ctrl_pts_name = "SURFSK_ctrl_pts" - me = bpy.data.meshes.new(mesh_ctrl_pts_name) - ob_ctrl_pts = bpy.data.objects.new(mesh_ctrl_pts_name, me) - ob_ctrl_pts.data = me - bpy.context.scene.objects.link(ob_ctrl_pts) - - - for i in range(0, verts_count_U): - vert_num_in_spline = 1 - - if selection_U_exists: - ob_ctrl_pts.data.vertices.add(1) - last_v = ob_ctrl_pts.data.vertices[len(ob_ctrl_pts.data.vertices) - 1] - last_v.co = verts_ordered_U[i].co - - vert_num_in_spline += 1 - - for sp in sketched_splines_parsed: - ob_ctrl_pts.data.vertices.add(1) - v = ob_ctrl_pts.data.vertices[len(ob_ctrl_pts.data.vertices) - 1] - v.co = sp[i] - - if vert_num_in_spline > 1: - ob_ctrl_pts.data.edges.add(1) - ob_ctrl_pts.data.edges[len(ob_ctrl_pts.data.edges) - 1].vertices[0] = len(ob_ctrl_pts.data.vertices) - 2 - ob_ctrl_pts.data.edges[len(ob_ctrl_pts.data.edges) - 1].vertices[1] = len(ob_ctrl_pts.data.vertices) - 1 - - last_v = v - - vert_num_in_spline += 1 - - bpy.ops.object.select_name(name = ob_ctrl_pts.name) - bpy.context.scene.objects.active = bpy.data.objects[ob_ctrl_pts.name] - - - # Create curves from control points. - bpy.ops.object.convert(target='CURVE', keep_original=False) - ob_curves_surf = bpy.context.scene.objects.active - bpy.ops.object.editmode_toggle() - bpy.ops.curve.spline_type_set(type='BEZIER') - bpy.ops.curve.handle_type_set(type='AUTOMATIC') - for i in range(0, int(bpy.context.scene.SURFSK_precision)): - bpy.ops.curve.subdivide() - bpy.ops.object.editmode_toggle() - - - # Calculate the length of each final surface spline. - surface_splines = ob_curves_surf.data.splines - surface_splines_lengths = [] - surface_splines_parsed = [] - for sp_idx in range(0, len(surface_splines)): - # Calculate spline length - surface_splines_lengths.append(0) - for i in range(0, len(surface_splines[sp_idx].bezier_points)): - if i == 0: - prev_p = surface_splines[sp_idx].bezier_points[i] - else: - p = surface_splines[sp_idx].bezier_points[i] - - edge_length = self.pts_distance(prev_p.co, p.co) - - surface_splines_lengths[sp_idx] += edge_length - - prev_p = p - - bpy.ops.object.editmode_toggle() - for i in range(0, int(bpy.context.scene.SURFSK_precision)): - bpy.ops.curve.subdivide() - bpy.ops.object.editmode_toggle() - - for sp_idx in range(0, len(surface_splines)): - # Calculate vertex positions with apropriate edge proportions, and ordered, for each spline. - surface_splines_parsed.append([]) - partial_spline_length = 0 - related_edge_V = 0 - edges_proportions_sum_V = 0 - edges_lengths_sum_V = 0 - for i in range(0, len(surface_splines[sp_idx].bezier_points)): - if i == 0: - prev_p = surface_splines[sp_idx].bezier_points[i] - surface_splines_parsed[sp_idx].append(prev_p.co) - elif i != len(surface_splines[sp_idx].bezier_points) - 1: - p = surface_splines[sp_idx].bezier_points[i] - - edge_length = self.pts_distance(prev_p.co, p.co) - - if edges_proportions_sum_V + edges_proportions_V[related_edge_V] - ((edges_lengths_sum_V + partial_spline_length + edge_length) / surface_splines_lengths[sp_idx]) > 0: # comparing proportions to see if the proportion in the selection is found in the spline. - partial_spline_length += edge_length - elif related_edge_V < len(edges_proportions_V) - 1: - surface_splines_parsed[sp_idx].append(prev_p.co) - - edges_proportions_sum_V += edges_proportions_V[related_edge_V] - related_edge_V += 1 - - edges_lengths_sum_V += partial_spline_length - partial_spline_length = edge_length - - prev_p = p - else: # last point of the spline for the last edge - p = surface_splines[sp_idx].bezier_points[len(surface_splines[sp_idx].bezier_points) - 1] - surface_splines_parsed[sp_idx].append(p.co) - - # Set the first and last verts of each spline to the locations of the respective verts in the selections. - if selection_V_exists: - for i in range(0, len(surface_splines_parsed[0])): - surface_splines_parsed[len(surface_splines_parsed) - 1][i] = verts_ordered_V[i].co - - if selection_type == "TWO_NOT_CONNECTED": - if selection_V2_exists: - for i in range(0, len(surface_splines_parsed[0])): - surface_splines_parsed[0][i] = verts_ordered_V2[i].co - - - #### Delete object with control points and object from grease pencil convertion. - bpy.ops.object.select_name(name = ob_ctrl_pts.name) - bpy.context.scene.objects.active = bpy.data.objects[ob_ctrl_pts.name] - bpy.ops.object.delete() - - bpy.ops.object.select_name(name = ob_gp_strokes.name) - bpy.context.scene.objects.active = bpy.data.objects[ob_gp_strokes.name] - bpy.ops.object.delete() - - - - #### Generate surface. - - # Get all verts coords. - all_surface_verts_co = [] - for i in range(0, len(surface_splines_parsed)): - # Get coords of all verts and make a list with them - for pt_co in surface_splines_parsed[i]: - all_surface_verts_co.append(pt_co) - - - # Define verts for each face. - all_surface_faces = [] - for i in range(0, len(all_surface_verts_co) - len(surface_splines_parsed[0])): - if ((i + 1) / len(surface_splines_parsed[0]) != int((i + 1) / len(surface_splines_parsed[0]))): - all_surface_faces.append([i+1, i , i + len(surface_splines_parsed[0]), i + len(surface_splines_parsed[0]) + 1]) - - - # Build the mesh. - surf_me_name = "SURFSK_surface" - me_surf = bpy.data.meshes.new(surf_me_name) - - me_surf.from_pydata(all_surface_verts_co, [], all_surface_faces) - - me_surf.update() - - ob_surface = bpy.data.objects.new(surf_me_name, me_surf) - bpy.context.scene.objects.link(ob_surface) - - - #### Join the new mesh to the main object. - ob_surface.select = True - self.main_object.select = True - bpy.context.scene.objects.active = bpy.data.objects[self.main_object.name] - bpy.ops.object.join() - bpy.ops.object.editmode_toggle() - bpy.ops.mesh.select_all(action='SELECT') - bpy.ops.mesh.remove_doubles(limit=0.0001) - bpy.ops.mesh.normals_make_consistent(inside=False) - bpy.ops.mesh.select_all(action='DESELECT') - - #### Delete grease pencil strokes - bpy.ops.gpencil.active_frame_delete() - - - def invoke (self, context, event): - bpy.ops.object.editmode_toggle() - bpy.ops.object.editmode_toggle() - self.main_object = bpy.context.scene.objects.active - - self.execute(context) - - return {"FINISHED"} - - - - -class GPENCIL_OT_SURFSK_strokes_to_curves(bpy.types.Operator): - bl_idname = "GPENCIL_OT_SURFSK_strokes_to_curves" - bl_label = "Convert grease pencil strokes into curves and enter edit mode" - bl_description = "Convert grease pencil strokes into curves and enter edit mode" - - - def execute(self, context): - #### Convert grease pencil strokes to curve. - bpy.ops.gpencil.convert(type='CURVE') - ob_gp_strokes = bpy.context.object - ob_gp_strokes.name = "SURFSK_strokes" - - #### Delete grease pencil strokes. - bpy.ops.object.select_name(name = self.main_object.name) - bpy.context.scene.objects.active = bpy.data.objects[self.main_object.name] - bpy.ops.gpencil.active_frame_delete() - - - bpy.ops.object.select_name(name = ob_gp_strokes.name) - bpy.context.scene.objects.active = bpy.data.objects[ob_gp_strokes.name] - - - bpy.ops.object.editmode_toggle() - bpy.ops.object.editmode_toggle() - bpy.ops.curve.smooth() - bpy.ops.curve.smooth() - bpy.ops.curve.smooth() - bpy.ops.curve.smooth() - bpy.ops.curve.smooth() - bpy.ops.curve.smooth() - bpy.ops.curve.smooth() - bpy.ops.curve.smooth() - bpy.ops.curve.smooth() - bpy.ops.curve.smooth() - bpy.ops.curve.smooth() - bpy.ops.curve.smooth() - - curve_crv = ob_gp_strokes.data - bpy.ops.curve.spline_type_set(type="BEZIER") - bpy.ops.curve.handle_type_set(type="AUTOMATIC") - bpy.data.curves[curve_crv.name].show_handles = False - bpy.data.curves[curve_crv.name].show_normal_face = False - - - def invoke (self, context, event): - self.main_object = bpy.context.object - - - self.execute(context) - - return {"FINISHED"} - - -def register(): - bpy.types.Scene.SURFSK_edges_U = bpy.props.IntProperty(name="Cross", description="Number of edge rings crossing the strokes (perpendicular to strokes direction)", default=10, min=0, max=100000) - bpy.types.Scene.SURFSK_edges_V = bpy.props.IntProperty(name="Follow", description="Number of edge rings following the strokes (parallel to strokes direction)", default=10, min=0, max=100000) - bpy.types.Scene.SURFSK_precision = bpy.props.IntProperty(name="Precision", description="Precision level of the surface calculation", default=4, min=0, max=100000) - bpy.types.Scene.SURFSK_keep_strokes = bpy.props.BoolProperty(name="Keep strokes", description="Keeps the sketched strokes after adding the surface", default=False) - - keymap_item_add_surf = bpy.data.window_managers[0].keyconfigs.active.keymaps["3D View"].items.new("GPENCIL_OT_SURFSK_add_surface","E","PRESS", key_modifier="D") - keymap_item_stroke_to_curve = bpy.data.window_managers[0].keyconfigs.active.keymaps["3D View"].items.new("GPENCIL_OT_SURFSK_strokes_to_curves","C","PRESS", key_modifier="D") - - -def unregister(): - del bpy.types.Scene.SURFSK_edges_U - del bpy.types.Scene.SURFSK_edges_V - del bpy.types.Scene.SURFSK_precision - del bpy.types.Scene.SURFSK_keep_strokes - - km = bpy.data.window_managers[0].keyconfigs.active.keymaps["3D View"] - for kmi in km.items: - if kmi.idname == 'wm.call_menu': - if kmi.properties.name == "GPENCIL_OT_SURFSK_add_surface": - km.items.remove(kmi) - elif kmi.properties.name == "GPENCIL_OT_SURFSK_strokes_to_curves": - km.items.remove(kmi) - else: - continue - - -if __name__ == "__main__": - register() - diff --git a/object_add_chain.py b/object_add_chain.py deleted file mode 100644 index 0cc997b9..00000000 --- a/object_add_chain.py +++ /dev/null @@ -1,150 +0,0 @@ -# ##### 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -# ##### END GPL LICENSE BLOCK ##### - -bl_addon_info = { - "name": "Add Chain", - "author": "Brian Hinton (Nichod)", - "version": (0,1), - "blender": (2, 5, 3), - "api": 31667, - "location": "View3D > Add > Mesh > Chain", - "description": "Adds Chain with curve guide for easy creation", - "warning": "", - "wiki_url": "http://wiki.blender.org/index.php/Extensions:2.5/Py/"\ - "Scripts/Object/Add_Chain", - "tracker_url": "https://projects.blender.org/tracker/index.php?"\ - "func=detail&aid=22203&group_id=153&atid=469", - "category": "Object"} - -import bpy - -def Add_Chain(): - - - ##Adds Empty to scene - bpy.ops.object.add(type='EMPTY', view_align=False, enter_editmode=False, location=(0, 0, 0), -rotation=(0, 0, 0), layers=(True, False, False, False, False, False, -False, False, False, False, False, False, False, False, False, False, False, False, False, -False)) - - ##Changes name of Empty to rot_link adds variable emp - emp = bpy.context.object - emp.name = "rot_link" - - ##Rotate emp ~ 90 degrees - emp.rotation_euler = [1.570796, 0, 0] - - ##Adds Curve Path to scene - bpy.ops.curve.primitive_nurbs_path_add( view_align=False, enter_editmode=False, location=(0, 0, 0), -rotation=(0, 0, 0), layers=(True, False, False, False, False, False, -False, False, False, False, False, False, False, False, False, False, False, False, False, -False)) - - ##Change Curve name to deform adds variable curv - curv = bpy.context.object - curv.name = "deform" - - ##Inserts Torus primitive - bpy.ops.mesh.primitive_torus_add(major_radius=1, minor_radius=0.25, -major_segments=12, minor_segments=4, use_abso=False, abso_major_rad=1, -abso_minor_rad=0.5) - - ##Positions Torus primitive to center of scene - bpy.context.active_object.location = [0, 0, 0] - - ##Changes Torus name to chain adds variable tor - tor = bpy.context.object - tor.name = "chain" - - ##Adds Array Modifier to tor - bpy.ops.object.modifier_add(type='ARRAY') - - ##Adds subsurf modifier tor - bpy.ops.object.modifier_add(type='SUBSURF') - - ##Smooths tor - bpy.ops.object.shade_smooth() - - ##Select curv - sce = bpy.context.scene - sce.objects.active = curv - - ##Toggle into editmode - bpy.ops.object.editmode_toggle() - - ##Translate curve object - bpy.ops.transform.translate(value=(2, 0, 0), constraint_axis=(True, False, False), -constraint_orientation='GLOBAL', mirror=False, proportional='DISABLED', -proportional_edit_falloff='SMOOTH', proportional_size=1, snap=False, -snap_target='CLOSEST', snap_point=(0, 0, 0), snap_align=False, snap_normal=(0, 0, 0), -release_confirm=False) - - ##Toggle into objectmode - bpy.ops.object.editmode_toggle() - - ##Select tor or chain - sce.objects.active = tor - - ##Selects Array Modifier for editing - array = tor.modifiers['Array'] - - ##Change Array Modifier Parameters - array.fit_type = ('FIT_CURVE') - array.curve = curv - array.offset_object = emp - array.use_object_offset = True - array.relative_offset_displace = [ 0.549, 0, 0 ] - - ##Add curve modifier - bpy.ops.object.modifier_add(type='CURVE') - - ##Selects Curve Modifier for editing - cur = tor.modifiers['Curve'] - - ##Change Curve Modifier Parameters - cur.object = curv - -#makes AddChain an operator -class AddChain(bpy.types.Operator): - '''Add a Chain.''' - bl_idname = "mesh.primitive_chain_add" - bl_label = "Add Chain" - bl_options = {'REGISTER', 'UNDO'} - - - def execute(self, context): - Add_Chain() - - return {'FINISHED'} - -# Register the operator -def menu_func(self, context): - self.layout.operator(AddChain.bl_idname, text="Chain", icon='PLUGIN') - - -def register(): - # Add "Chain" menu to the "Add Mesh" menu. - bpy.types.INFO_MT_mesh_add.append(menu_func) - - -def unregister(): - # Remove "Chain" menu from the "Add Mesh" menu. - bpy.types.INFO_MT_mesh_add.remove(menu_func) - -if __name__ == "__main__": - register() diff --git a/object_cloud_gen.py b/object_cloud_gen.py deleted file mode 100644 index 9d9ee1e2..00000000 --- a/object_cloud_gen.py +++ /dev/null @@ -1,674 +0,0 @@ -# ##### 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -# ##### END GPL LICENSE BLOCK ##### - -bl_addon_info = { - "name": "Cloud Generator", - "author": "Nick Keeline(nrk)", - "version": (0,7), - "blender": (2, 5, 3), - "api": 31667, - "location": "Tool Shelf ", - "description": "Creates Volumetric Clouds", - "warning": "", - "wiki_url": "http://wiki.blender.org/index.php/Extensions:2.5/Py/"\ - "Scripts/Object/Cloud_Gen", - "tracker_url": "https://projects.blender.org/tracker/index.php?"\ - "func=detail&aid=22015&group_id=153&atid=469", - "category": "Object"} - -""" -Place this file in the .blender/scripts/addons dir -You have to activated the script in the "Add-Ons" tab (user preferences). -The functionality can then be accessed via the Tool shelf when objects -are selected - -Rev 0 initial release -Rev 0.1 added scene to create_mesh per python api change. -Rev 0.2 Added Point Density turbulence and fixed degenerate -Rev 0.3 Fixed bug in degenerate -Rev 0.4 updated for api change/changed to new apply modifier technique -Rev 0.5 made particle count equation with radius so radius increases with cloud volume -Rev 0.6 added poll function to operator, fixing crash with no selected objects -Rev 0.7 added particles option and Type of Cloud wanted selector -""" - -import bpy -import mathutils -from math import * -from bpy.props import * - - -# This routine takes an object and deletes all of the geometry in it -# and adds a bounding box to it. -# It will add or subtract the bound box size by the variable sizeDifference. -def makeObjectIntoBoundBox(object, sizeDifference): - # Deselect All - bpy.ops.object.select_all(action='DESELECT') - - # Select the object - object.select = True - - # Go into Edit Mode - bpy.ops.object.mode_set(mode='EDIT') - - mesh = object.data - verts = mesh.vertices - - #Set the max and min verts to the first vertex on the list - maxVert = [verts[0].co[0], verts[0].co[1], verts[0].co[2]] - minVert = [verts[0].co[0], verts[0].co[1], verts[0].co[2]] - - #Create Max and Min Vertex array for the outer corners of the box - for vert in verts: - #Max vertex - if vert.co[0] > maxVert[0]: - maxVert[0] = vert.co[0] - if vert.co[1] > maxVert[1]: - maxVert[1] = vert.co[1] - if vert.co[2] > maxVert[2]: - maxVert[2] = vert.co[2] - - #Min Vertex - if vert.co[0] < minVert[0]: - minVert[0] = vert.co[0] - if vert.co[1] < minVert[1]: - minVert[1] = vert.co[1] - if vert.co[2] < minVert[2]: - minVert[2] = vert.co[2] - - #Add the size difference to the max size of the box - maxVert[0] = maxVert[0] + sizeDifference - maxVert[1] = maxVert[1] + sizeDifference - maxVert[2] = maxVert[2] + sizeDifference - - #subtract the size difference to the min size of the box - minVert[0] = minVert[0] - sizeDifference - minVert[1] = minVert[1] - sizeDifference - minVert[2] = minVert[2] - sizeDifference - - #Create arrays of verts and faces to be added to the mesh - addVerts = [] - - #X high loop - addVerts.append([maxVert[0], maxVert[1], maxVert[2]]) - addVerts.append([maxVert[0], maxVert[1], minVert[2]]) - addVerts.append([maxVert[0], minVert[1], minVert[2]]) - addVerts.append([maxVert[0], minVert[1], maxVert[2]]) - - #x low loop - addVerts.append([minVert[0], maxVert[1], maxVert[2]]) - addVerts.append([minVert[0], maxVert[1], minVert[2]]) - addVerts.append([minVert[0], minVert[1], minVert[2]]) - addVerts.append([minVert[0], minVert[1], maxVert[2]]) - - # Make the faces of the bounding box. - addFaces = [] - - # Draw a box on paper and number the vertices. - # Use right hand rule to come up with number orders for faces on - # the box (with normals pointing out). - addFaces.append([0, 3, 2, 1]) - addFaces.append([4, 5, 6, 7]) - addFaces.append([0, 1, 5, 4]) - addFaces.append([1, 2, 6, 5]) - addFaces.append([2, 3, 7, 6]) - addFaces.append([0, 4, 7, 3]) - - # Delete all geometry from the object. - bpy.ops.mesh.select_all(action='SELECT') - bpy.ops.mesh.delete(type='ALL') - - # Must be in object mode for from_pydata to work - bpy.ops.object.mode_set(mode='OBJECT') - - # Add the mesh data. - mesh.from_pydata(addVerts, [], addFaces) - - # Update the mesh - mesh.update() - - -def applyScaleRotLoc(scene, obj): - # Deselect All - bpy.ops.object.select_all(action='DESELECT') - - # Select the object - obj.select = True - scene.objects.active = obj - - #bpy.ops.object.rotation_apply() - bpy.ops.object.location_apply() - bpy.ops.object.scale_apply() - - -def totallyDeleteObject(scene, obj): - #To Do this section to be updated when - #Ability to completely delet objects added to blender - # Deselect All - bpy.ops.object.select_all(action='DESELECT') - - # Select the object and delete it. - obj.select = True - scene.objects.active = obj - - # Delete all material slots in obj - for i in range(len(obj.material_slots)): - #textureSlots = cloudMaterial.texture_slots - obj.active_material_index = i - 1 - bpy.ops.object.material_slot_remove() - - #bpy.ops.object.parent_clear(type='CLEAR') - - # Delete the Main Object - bpy.ops.object.delete() - #bpy.data.objects.remove(obj) - - -def makeParent(parentobj, childobj, scene): - - applyScaleRotLoc(scene, parentobj) - - applyScaleRotLoc(scene, childobj) - - childobj.parent = parentobj - - #childobj.location = childobj.location - parentobj.location - - -def addNewObject(scene, name, copyobj): - ''' - Add an object and do other silly stuff. - ''' - # Create new mesh - mesh = bpy.data.meshes.new(name) - - # Create a new object. - ob_new = bpy.data.objects.new(name, mesh) - tempme = copyobj.data - ob_new.data = tempme.copy() - ob_new.scale = copyobj.scale - ob_new.location = copyobj.location - - # Link new object to the given scene and select it. - scene.objects.link(ob_new) - ob_new.select = True - - return ob_new - - -def combineObjects(scene, combined, listobjs): - # scene is the current scene - # combined is the object we want to combine everything into - # listobjs is the list of objects to stick into combined - - # Deselect All - bpy.ops.object.select_all(action='DESELECT') - - # Select the new object. - combined.select = True - scene.objects.active = combined - - # Add data - if (len(listobjs) > 0): - for i in listobjs: - # Add a modifier - bpy.ops.object.modifier_add(type='BOOLEAN') - - union = combined.modifiers - union[0].name = "AddEmUp" - union[0].object = i - union[0].operation = 'UNION' - - # Apply modifier - bpy.ops.object.modifier_apply(apply_as='DATA', modifier=union[0].name) - - -# Returns True if we want to degenerate -# and False if we want to generate a new cloud. -def degenerateCloud(obj): - if not obj: - return False - - if "CloudMember" in obj: - if obj["CloudMember"] != None: - if obj.parent: - if "CloudMember" not in obj.parent: - return False - - else: - return True - - return False - - -class VIEW3D_PT_tools_cloud(bpy.types.Panel): - bl_space_type = 'VIEW_3D' - bl_region_type = 'TOOLS' - - bl_label = "Cloud Generator" - bl_context = "objectmode" - - def draw(self, context): - active_obj = context.active_object - layout = self.layout - col = layout.column(align=True) - - degenerate = degenerateCloud(active_obj) - - if active_obj and degenerate: - - col.operator("cloud.generate_cloud", text="DeGenerate") - - elif active_obj is None: - - col.label(text="Select one or more") - col.label(text="objects to generate") - col.label(text="a cloud.") - - elif "CloudMember" in active_obj: - - col.label(text="Must select") - col.label(text="bound box") - - elif active_obj and active_obj.type == 'MESH': - - col.operator("cloud.generate_cloud", text="Generate Cloud") - - col.prop(context.scene, "cloudparticles") - col.prop(context.scene, "cloud_type") - else: - col.label(text="Select one or more") - col.label(text="objects to generate") - col.label(text="a cloud.") - -cloudTypes = [] - -cloudTypes.append(("0","Stratus","Generate Stratus_foggy Cloud")) -cloudTypes.append(("1","Cumulous","Generate Cumulous_puffy Cloud")) -cloudTypes.append(("2","Cirrus","Generate Cirrus_wispy Cloud")) -#cloudTypes.append(("3","Nimbus","Generate Nimbus Cloud")) - - -bpy.types.Scene.cloudparticles = BoolProperty( - name="Particles", - description="Generate Cloud as Particle System", - default=False) - -bpy.types.Scene.cloud_type = EnumProperty( - name="Type", - description="Select the type of cloud to create with material settings", - items = cloudTypes, default = '0') - -class GenerateCloud(bpy.types.Operator): - bl_idname = "cloud.generate_cloud" - bl_label = "Generate Cloud" - bl_description = "Create a Cloud." - bl_register = True - bl_undo = True - - @classmethod - def poll(cls, context): - if not context.active_object: - return False - else: - return (context.active_object.type=='MESH') - - def execute(self, context): - # Make variable that is the current .blend file main data blocks - blend_data = context.blend_data - - # Make variable that is the active object selected by user - active_object = context.active_object - - # Make variable scene that is current scene - scene = context.scene - - # Parameters the user may want to change: - # Number of points this number is multiplied by the volume to get - # the number of points the scripts will put in the volume. - numOfPoints = 1.0 - maxNumOfPoints = 100000 - scattering = 2.5 - pointDensityRadiusFactor = 1.0 - densityScale = 1.5 - - # Should we degnerate? - degenerate = degenerateCloud(active_object) - - if degenerate: - # Degenerate Cloud - mainObj = active_object - - cloudMembers = active_object.children - - createdObjects = [] - definitionObjects = [] - for member in cloudMembers: - applyScaleRotLoc(scene, member) - if (member["CloudMember"] == "CreatedObj"): - createdObjects.append(member) - else: - definitionObjects.append(member) - - for defObj in definitionObjects: - #Delete cloudmember data from objects - if "CloudMember" in defObj: - del(defObj["CloudMember"]) - - for createdObj in createdObjects: - totallyDeleteObject(scene, createdObj) - - # Delete the blend_data object - totallyDeleteObject(scene, mainObj) - - # Select all of the left over boxes so people can immediately - # press generate again if they want. - for eachMember in definitionObjects: - eachMember.draw_type = 'SOLID' - eachMember.select = True - #scene.objects.active = eachMember - - #TODO Delete this when render bug caused by degenerate is fixed. - self.report({'WARNING'}, "Please save file exit and reenter blender before rendering to clean memory and prevent crash") - - else: - # Generate Cloud - - ###############Create Combined Object bounds################## - # Make a list of all Selected objects. - selectedObjects = bpy.context.selected_objects - if not selectedObjects: - selectedObjects = [bpy.context.active_object] - - # Create a new object bounds - bounds = addNewObject(scene, - "CloudBounds", - selectedObjects[0]) - - bounds.draw_type = 'BOUNDS' - bounds.hide_render = False - - # Just add a Definition Property designating this - # as the blend_data object. - bounds["CloudMember"] = "MainObj" - - # Since we used iteration 0 to copy with object we - # delete it off the list. - firstObject = selectedObjects[0] - del selectedObjects[0] - - # Apply location Rotation and Scale to all objects involved. - applyScaleRotLoc(scene, bounds) - for each in selectedObjects: - applyScaleRotLoc(scene, each) - - # Let's combine all of them together. - combineObjects(scene, bounds, selectedObjects) - - # Let's add some property info to the objects. - for selObj in selectedObjects: - selObj["CloudMember"] = "DefinitioinObj" - selObj.name = "DefinitioinObj" - selObj.draw_type = 'WIRE' - selObj.hide_render = True - makeParent(bounds, selObj, scene) - - # Do the same to the 1. object since it is no longer in list. - firstObject["CloudMember"] = "DefinitioinObj" - firstObject.name = "DefinitioinObj" - firstObject.draw_type = 'WIRE' - firstObject.hide_render = True - makeParent(bounds, firstObject, scene) - - ###############Create Cloud for putting Cloud Mesh############ - # Create a new object cloud. - cloud = addNewObject(scene, "CloudMesh", bounds) - cloud["CloudMember"] = "CreatedObj" - cloud.draw_type = 'WIRE' - cloud.hide_render = True - - makeParent(bounds, cloud, scene) - - bpy.ops.object.editmode_toggle() - bpy.ops.mesh.select_all(action='SELECT') - bpy.ops.mesh.subdivide(number_cuts=2, fractal=0, smoothness=1) - bpy.ops.object.location_apply() - bpy.ops.mesh.vertices_smooth(repeat=20) - bpy.ops.mesh.tris_convert_to_quads() - bpy.ops.mesh.faces_shade_smooth() - bpy.ops.object.editmode_toggle() - - ###############Create Particles in cloud obj################## - # Turn off gravity. - scene.use_gravity = False - - # Set time to 0. - scene.frame_current = 0 - - # Add a new particle system. - bpy.ops.object.particle_system_add() - - #Particle settings setting it up! - cloudParticles = cloud.particle_systems.active - cloudParticles.name = "CloudParticles" - cloudParticles.settings.frame_start = 0 - cloudParticles.settings.frame_end = 0 - cloudParticles.settings.emit_from = 'VOLUME' - cloudParticles.settings.draw_method = 'DOT' - cloudParticles.settings.render_type = 'NONE' - cloudParticles.settings.normal_factor = 0 - cloudParticles.settings.distribution = 'RAND' - cloudParticles.settings.physics_type = 'NO' - - ####################Create Volume Material#################### - # Deselect All - bpy.ops.object.select_all(action='DESELECT') - - # Select the object. - bounds.select = True - scene.objects.active = bounds - - # Turn bounds object into a box. - makeObjectIntoBoundBox(bounds, .6) - - # Delete all material slots in bounds object. - for i in range(len(bounds.material_slots)): - bounds.active_material_index = i - 1 - bpy.ops.object.material_slot_remove() - - # Add a new material. - cloudMaterial = blend_data.materials.new("CloudMaterial") - bpy.ops.object.material_slot_add() - bounds.material_slots[0].material = cloudMaterial - - # Set Up the Cloud Material - cloudMaterial.name = "CloudMaterial" - cloudMaterial.type = 'VOLUME' - mVolume = cloudMaterial.volume - mVolume.scattering = scattering - mVolume.density = 0 - mVolume.density_scale = densityScale - mVolume.transmission_color = [3, 3, 3] - mVolume.step_size = 0.1 - mVolume.use_light_cache = True - mVolume.cache_resolution = 75 - - # Add a texture - vMaterialTextureSlots = cloudMaterial.texture_slots - cloudtex = blend_data.textures.new("CloudTex", type='CLOUDS') - cloudtex.noise_type = 'HARD_NOISE' - cloudtex.noise_scale = 2 - mtex = cloudMaterial.texture_slots.add() - mtex.texture = cloudtex - mtex.texture_coords = 'ORCO' - mtex.use_map_color_diffuse = True - - # Add a force field to the points. - cloudField = bounds.field - cloudField.type = 'TEXTURE' - cloudField.strength = 2 - cloudField.texture = cloudtex - - # Set time - #for i in range(12): - # scene.current_frame = i - # scene.update() - scene.frame_current = 1 - - #bpy.ops.ptcache.bake(bake=False) - - # Add a Point Density texture - pDensity = blend_data.textures.new("CloudPointDensity", 'POINT_DENSITY') - - mtex = cloudMaterial.texture_slots.add() - mtex.texture = pDensity - mtex.texture_coords = 'GLOBAL' - mtex.use_map_density = True - mtex.use_rgb_to_intensity = True - mtex.texture_coords = 'GLOBAL' - - pDensity.point_density.vertex_cache_space = 'WORLD_SPACE' - pDensity.point_density.use_turbulence = True - pDensity.point_density.noise_basis = 'VORONOI_F2' - pDensity.point_density.turbulence_depth = 3 - - pDensity.use_color_ramp = True - pRamp = pDensity.color_ramp - #pRamp.use_interpolation = 'LINEAR' - pRampElements = pRamp.elements - #pRampElements[1].position = .9 - #pRampElements[1].color = [.18,.18,.18,.8] - bpy.ops.texture.slot_move(type='UP') - - - # Estimate the number of particles for the size of bounds. - volumeBoundBox = (bounds.dimensions[0] * bounds.dimensions[1]* bounds.dimensions[2]) - numParticles = int((2.4462 * volumeBoundBox + 430.4) * numOfPoints) - if numParticles > maxNumOfPoints: - numParticles = maxNumOfPoints - if numParticles < 10000: - numParticles = int(numParticles + 15 * volumeBoundBox) - print(numParticles) - - # Set the number of particles according to the volume - # of bounds. - cloudParticles.settings.count = numParticles - - pDensity.point_density.radius = (.00013764 * volumeBoundBox + .3989) * pointDensityRadiusFactor - - # Set time to 1. - scene.frame_current = 1 - - if not scene.cloudparticles: - ###############Create CloudPnts for putting points in######### - # Create a new object cloudPnts - cloudPnts = addNewObject(scene, "CloudPoints", bounds) - cloudPnts["CloudMember"] = "CreatedObj" - cloudPnts.draw_type = 'WIRE' - cloudPnts.hide_render = True - - makeParent(bounds, cloudPnts, scene) - - bpy.ops.object.editmode_toggle() - bpy.ops.mesh.select_all(action='SELECT') - - bpy.ops.mesh.delete(type='ALL') - - meshPnts = cloudPnts.data - - listCloudParticles = cloudParticles.particles - - listMeshPnts = [] - for pTicle in listCloudParticles: - listMeshPnts.append(pTicle.location) - - # Must be in object mode fro from_pydata to work. - bpy.ops.object.mode_set(mode='OBJECT') - - # Add in the mesh data. - meshPnts.from_pydata(listMeshPnts, [], []) - - # Update the mesh. - meshPnts.update() - - # Add a modifier. - bpy.ops.object.modifier_add(type='DISPLACE') - - cldPntsModifiers = cloudPnts.modifiers - cldPntsModifiers[0].name = "CloudPnts" - cldPntsModifiers[0].texture = cloudtex - cldPntsModifiers[0].texture_coords = 'OBJECT' - cldPntsModifiers[0].texture_coordinate_object = cloud - cldPntsModifiers[0].strength = -1.4 - - # Apply modifier - bpy.ops.object.modifier_apply(apply_as='DATA', modifier=cldPntsModifiers[0].name) - - pDensity.point_density.point_source = 'OBJECT' - pDensity.point_density.object = cloudPnts - - # Deselect All - bpy.ops.object.select_all(action='DESELECT') - - # Select the object. - cloud.select = True - scene.objects.active = cloud - - bpy.ops.object.particle_system_remove() - - # Deselect All - bpy.ops.object.select_all(action='DESELECT') - - else: - - pDensity.point_density.point_source = 'PARTICLE_SYSTEM' - pDensity.point_density.object = cloud - pDensity.point_density.particle_system = cloudParticles - - if scene.cloud_type == '1': # Cumulous - print("Cumulous") - mVolume.density_scale = 2.22 - pDensity.point_density.turbulence_depth = 10 - pDensity.point_density.turbulence_strength = 6.3 - pDensity.point_density.turbulence_scale = 2.9 - pRampElements[1].position = .606 - pDensity.point_density.radius = pDensity.point_density.radius + .1 - - elif scene.cloud_type == '2': # Cirrus - print("Cirrus") - pDensity.point_density.turbulence_strength = 22 - mVolume.transmission_color = [3.5, 3.5, 3.5] - mVolume.scattering = .13 - - # Select the object. - bounds.select = True - scene.objects.active = bounds - - return {'FINISHED'} - - -def register(): - pass - - -def unregister(): - pass - - -if __name__ == "__main__": - register() diff --git a/object_fracture/__init__.py b/object_fracture/__init__.py deleted file mode 100644 index 182298fa..00000000 --- a/object_fracture/__init__.py +++ /dev/null @@ -1,80 +0,0 @@ -# ##### 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -# ##### END GPL LICENSE BLOCK ##### - -bl_addon_info = { - "name": "Fracture Tools", - "author": "pildanovak", - "version": (2,0), - "blender": (2, 5, 3), - "api": 31667, - "location": "Fracture tools (Search > Fracture Object & Add -> Fracture Helper Objects", - "description": "Fractured Object, Bomb, Projectile, Recorder", - "warning": "script is returning errors", - "wiki_url": "http://wiki.blender.org/index.php/Extensions:2.5/Py/"\ - "Scripts/Object/Fracture", - "tracker_url": "https://projects.blender.org/tracker/index.php?"\ - "func=detail&aid=21793&group_id=153&atid=469", - "category": "Object"} - - -import bpy - -try: - init_data - - reload(fracture_ops) - reload(fracture_setup) -except: - from object_fracture import fracture_ops - from object_fracture import fracture_setup - -init_data = True - -class INFO_MT_add_fracture_objects(bpy.types.Menu): - bl_idname = "INFO_MT_add_fracture_objects" - bl_label = "Fracture Helper Objects" - - def draw(self, context): - layout = self.layout - layout.operator_context = 'INVOKE_REGION_WIN' - - layout.operator("object.import_fracture_bomb", - text="Bomb") - layout.operator("object.import_fracture_projectile", - text="Projectile") - layout.operator("object.import_fracture_recorder", - text="Rigidbody Recorder") - -import space_info - - -def menu_func(self, context): - self.layout.menu("INFO_MT_add_fracture_objects", icon="PLUGIN") - - -def register(): - # Add the "add fracture objects" menu to the "Add" menu - space_info.INFO_MT_add.append(menu_func) - - -def unregister(): - # Remove "add fracture objects" menu from the "Add" menu. - space_info.INFO_MT_add.remove(menu_func) - -if __name__ == "__main__": - register() diff --git a/object_fracture/data.blend b/object_fracture/data.blend deleted file mode 100644 index e0e72dcf..00000000 Binary files a/object_fracture/data.blend and /dev/null differ diff --git a/object_fracture/fracture_ops.py b/object_fracture/fracture_ops.py deleted file mode 100644 index 19cd4bce..00000000 --- a/object_fracture/fracture_ops.py +++ /dev/null @@ -1,490 +0,0 @@ -# ##### 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -# ##### END GPL LICENSE BLOCK ##### - -import bpy -from bpy.props import * -import os -import random -import mathutils -from mathutils import * - - -def create_cutter(context, crack_type, scale, roughness): - ncuts = 12 - if crack_type == 'FLAT' or crack_type == 'FLAT_ROUGH': - bpy.ops.mesh.primitive_cube_add( - view_align=False, - enter_editmode=False, - location=(0, 0, 0), - rotation=(0, 0, 0), - layers=(True, False, False, False, - False, False, False, False, - False, False, False, False, - False, False, False, False, - False, False, False, False)) - - for v in context.scene.objects.active.data.vertices: - v.co[0] += 1 - v.co[0] *= scale - v.co[1] *= scale - v.co[2] *= scale - - bpy.ops.object.editmode_toggle() - bpy.ops.mesh.faces_shade_smooth() - bpy.ops.uv.reset() - - if crack_type == 'FLAT_ROUGH': - bpy.ops.mesh.subdivide( - number_cuts=ncuts, - fractal=roughness * 7 * scale, - smoothness=0) - - bpy.ops.mesh.vertices_smooth(repeat=5) - - bpy.ops.object.editmode_toggle() - - if crack_type == 'SPHERE' or crack_type == 'SPHERE_ROUGH': - bpy.ops.mesh.primitive_ico_sphere_add(subdivisions=4, - size=1, - view_align=False, - enter_editmode=False, - location=(0, 0, 0), - rotation=(0, 0, 0), - layers=(True, False, False, False, - False, False, False, False, - False, False, False, False, - False, False, False, False, - False, False, False, False, - False, False, False, False, - False, False, False, False, - False, False, False, False)) - - bpy.ops.object.editmode_toggle() - bpy.ops.mesh.faces_shade_smooth() - bpy.ops.uv.smart_project(angle_limit=66, island_margin=0) - - bpy.ops.object.editmode_toggle() - for v in context.scene.objects.active.data.vertices: - v.co[0] += 1 - v.co[0] *= scale - v.co[1] *= scale - v.co[2] *= scale - - if crack_type == 'SPHERE_ROUGH': - for v in context.scene.objects.active.data.vertices: - v.co[0] += roughness * scale * 0.2 * (random.random() - 0.5) - v.co[1] += roughness * scale * 0.1 * (random.random() - 0.5) - v.co[2] += roughness * scale * 0.1 * (random.random() - 0.5) - - bpy.context.scene.objects.active.select = True - - ''' - # Adding fracture material - # @todo Doesn't work at all yet. - sce = bpy.context.scene - if bpy.data.materials.get('fracture')==None: - bpy.ops.material.new() - bpy.ops.object.material_slot_add() - sce.objects.active.material_slots[0].material.name = 'fracture' - else: - bpy.ops.object.material_slot_add() - sce.objects.active.material_slots[0].material - = bpy.data.materials['fracture'] - ''' - - -#UNWRAP -def getsizefrommesh(ob): - bb = ob.bound_box - return ( - bb[5][0] - bb[0][0], - bb[3][1] - bb[0][1], - bb[1][2] - bb[0][2]) - - -def getIslands(shard): - sm = shard.data - islands = [] - vgroups = [] - fgroups = [] - - vgi = [] - for v in sm.vertices: - vgi.append(-1) - - gindex = 0 - for i in range(len(vgi)): - if vgi[i] == -1: - gproc = [i] - vgroups.append([i]) - fgroups.append([]) - - while len(gproc) > 0: - i = gproc.pop(0) - for f in sm.faces: - #if i in f.vertices: - for v in f.vertices: - if v == i: - for v1 in f.vertices: - if vgi[v1] == -1: - vgi[v1] = gindex - vgroups[gindex].append(v1) - gproc.append(v1) - - fgroups[gindex].append(f.index) - - gindex += 1 - - #print( gindex) - - if gindex == 1: - shards = [shard] - - else: - shards = [] - for gi in range(0, gindex): - bpy.ops.object.select_all(action='DESELECT') - bpy.context.scene.objects.active = shard - shard.select = True - bpy.ops.object.duplicate(linked=False, mode=1) - a = bpy.context.scene.objects.active - sm = a.data - print (a.name) - - bpy.ops.object.editmode_toggle() - bpy.ops.mesh.select_all(action='DESELECT') - bpy.ops.object.editmode_toggle() - - for x in range(len(sm.vertices) - 1, -1, -1): - if vgi[x] != gi: - #print('getIslands: selecting') - #print('getIslands: ' + str(x)) - a.data.vertices[x].select = True - - print(bpy.context.scene.objects.active.name) - - bpy.ops.object.editmode_toggle() - bpy.ops.mesh.delete() - bpy.ops.object.editmode_toggle() - - bpy.ops.object.origin_set(type='ORIGIN_GEOMETRY') - - shards.append(a) - - bpy.context.scene.objects.unlink(shard) - - return shards - - -def boolop(ob, cutter, op): - sce = bpy.context.scene - - fault = 0 - new_shards = [] - - sizex, sizey, sizez = getsizefrommesh(ob) - gsize = sizex + sizey + sizez - - bpy.ops.object.select_all() - ob.select = True - sce.objects.active = ob - cutter.select = False - - bpy.ops.object.modifier_add(type='BOOLEAN') - a = sce.objects.active - a.modifiers['Boolean'].object = cutter - a.modifiers['Boolean'].operation = op - - nmesh = a.create_mesh(sce, apply_modifiers=True, settings='PREVIEW') - - if len(nmesh.vertices) > 0: - a.modifiers.remove(a.modifiers['Boolean']) - bpy.ops.object.duplicate(linked=False, mode=1) - - new_shard = sce.objects.active - new_shard.data = nmesh - #scene.objects.link(new_shard) - - new_shard.location = a.location - bpy.ops.object.origin_set(type='ORIGIN_GEOMETRY') - - sizex, sizey, sizez = getsizefrommesh(new_shard) - gsize2 = sizex + sizey + sizez - - if gsize2 > gsize * 1.01: # Size check - print (gsize2, gsize, ob.name, cutter.name) - fault = 1 - #print ('boolop: sizeerror') - - elif min(nmesh.edge_face_count) < 2: # Manifold check - fault = 1 - - if not fault: - new_shards = getIslands(new_shard) - - else: - sce.objects.unlink(new_shard) - - else: - fault = 2 - - return fault, new_shards - - -def splitobject(context, ob, crack_type, roughness): - scene = context.scene - - size = getsizefrommesh(ob) - shards = [] - scale = max(size) * 1.3 - - create_cutter(context, crack_type, scale, roughness) - cutter = context.active_object - cutter.location = ob.location - - cutter.location[0] += random.random() * size[0] * 0.1 - cutter.location[1] += random.random() * size[1] * 0.1 - cutter.location[2] += random.random() * size[2] * 0.1 - cutter.rotation_euler = [ - random.random() * 5000.0, - random.random() * 5000.0, - random.random() * 5000.0] - - scene.objects.active = ob - operations = ['INTERSECT', 'DIFFERENCE'] - - for op in operations: - fault, newshards = boolop(ob, cutter, op) - - shards.extend(newshards) - if fault > 0: - # Delete all shards in case of fault from previous operation. - for s in shards: - scene.objects.unlink(s) - - scene.objects.unlink(cutter) - #print('splitobject: fault') - - return [ob] - - if shards[0] != ob: - bpy.context.scene.objects.unlink(ob) - - bpy.context.scene.objects.unlink(cutter) - - return shards - - -def fracture_basic(context, nshards, crack_type, roughness): - tobesplit = [] - shards = [] - - for ob in context.scene.objects: - if ob.select: - tobesplit.append(ob) - - i = 1 # I counts shards, starts with 1 - the original object - iter = 0 # counts iterations, to prevent eternal loops in case - # of boolean faults - - maxshards = nshards * len(tobesplit) - - while i < maxshards and len(tobesplit) > 0 and iter < maxshards * 10: - ob = tobesplit.pop(0) - newshards = splitobject(context, ob, crack_type, roughness) - - tobesplit.extend(newshards) - - if len(newshards) > 1: - shards.extend(newshards) - #shards.remove(ob) - - i += (len(newshards) - 1) - - #print('fracture_basic: ' + str(i)) - #print('fracture_basic: lenobs', len(context.scene.objects)) - - iter += 1 - - -def fracture_group(context, group): - tobesplit = [] - shards = [] - - for ob in context.scene.objects: - if (ob.select - and (len(ob.users_group) == 0 or ob.users_group[0].name != group)): - tobesplit.append(ob) - - cutters = bpy.data.groups[group].objects - - # @todo This can be optimized. - # Avoid booleans on obs where bbox doesn't intersect. - i = 0 - for ob in tobesplit: - for cutter in cutters: - fault, newshards = boolop(ob, cutter, 'INTERSECT') - shards.extend(newshards) - - if fault == 1: - # Delete all shards in case of fault from previous operation. - for s in shards: - bpy.context.scene.objects.unlink(s) - - #print('fracture_group: fault') - #print('fracture_group: ' + str(i)) - - return - - i += 1 - - -class FractureSimple(bpy.types.Operator): - '''Split object with boolean operations for simulation, uses an object.''' - bl_idname = "object.fracture_simple" - bl_label = "Fracture Object" - bl_options = {'REGISTER', 'UNDO'} - - exe = BoolProperty(name="Execute", - description="If it shall actually run, for optimal performance...", - default=False) - - hierarchy = BoolProperty(name="Generate hierarchy", - description="Hierarchy is usefull for simulation of objects" \ - " breaking in motion.", - default=False) - - nshards = IntProperty(name="Number of shards", - description="Number of shards the object should be split into.", - min=2, - default=5) - - crack_type = EnumProperty(name='Crack type', - items=( - ('FLAT', 'Flat', 'a'), - ('FLAT_ROUGH', 'Flat rough', 'a'), - ('SPHERE', 'Spherical', 'a'), - ('SPHERE_ROUGH', 'Spherical rough', 'a')), - description='Look of the fracture surface', - default='FLAT') - - roughness = FloatProperty(name="Roughness", - description="Roughness of the fracture surface", - min=0.0, - max=3.0, - default=0.5) - - def execute(self, context): - #getIslands(context.object) - if self.exe: - fracture_basic(context, - self.nshards, - self.crack_type, - self.roughness) - - return {'FINISHED'} - - -class FractureGroup(bpy.types.Operator): - '''Split object with boolean operations for simulation, uses a group.''' - bl_idname = "object.fracture_group" - bl_label = "Fracture Object (Group)" - bl_options = {'REGISTER', 'UNDO'} - - exe = BoolProperty(name="Execute", - description="If it shall actually run, for optimal performance...", - default=False) - - e = [] - for i, g in enumerate(bpy.data.groups): - e.append((g.name, g.name, '')) - - group = EnumProperty(name='Group (hit F8 to refresh list)', - items=e, - description='Specify the group used for fracturing') - - def execute(self, context): - #getIslands(context.object) - - if self.properties.exe: - fracture_group(context, self.properties.group) - - return {'FINISHED'} - - -##################################################################### -# Import Functions - -def import_object(obname): - opath = "//data.blend\\Object\\" + obname - s = os.sep - dpath = bpy.utils.script_paths()[0] + \ - '%saddons%sobject_fracture%sdata.blend\\Object\\' % (s, s, s) - - # DEBUG - #print('import_object: ' + opath) - - bpy.ops.wm.link_append( - filepath=opath, - filename=obname, - directory=dpath, - filemode=1, - link=False, - autoselect=True, - active_layer=True, - instance_groups=True, - relative_path=True) - - for ob in bpy.context.selected_objects: - ob.location = bpy.context.scene.cursor_location - - -class ImportFractureRecorder(bpy.types.Operator): - '''Imports a rigidbody recorder''' - bl_idname = "object.import_fracture_recorder" - bl_label = "Add Rigidbody Recorder (Fracture)" - bl_options = {'REGISTER', 'UNDO'} - - def execute(self, context): - import_object("RECORDER") - - return {'FINISHED'} - - -class ImportFractureBomb(bpy.types.Operator): - '''Import a bomb''' - bl_idname = "object.import_fracture_bomb" - bl_label = "Add Bomb (Fracture)" - bl_options = {'REGISTER', 'UNDO'} - - def execute(self, context): - import_object("BOMB") - - return {'FINISHED'} - - -class ImportFractureProjectile(bpy.types.Operator, ): - '''Imports a projectile''' - bl_idname = "object.import_fracture_projectile" - bl_label = "Add Projectile (Fracture)" - bl_options = {'REGISTER', 'UNDO'} - - def execute(self, context): - import_object("PROJECTILE") - - return {'FINISHED'} diff --git a/object_fracture/fracture_setup.py b/object_fracture/fracture_setup.py deleted file mode 100644 index 3ab93821..00000000 --- a/object_fracture/fracture_setup.py +++ /dev/null @@ -1,74 +0,0 @@ -# ##### 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -# ##### END GPL LICENSE BLOCK ##### - -import bpy -from bpy.props import * - - -def getsizefrommesh(ob): - bb = ob.bound_box - return( - bb[5][0] - bb[0][0], - bb[3][1] - bb[0][1], - bb[1][2] - bb[0][2]) - - -def setupshards(context): - sce = context.scene - #print(dir(context)) - #bpy.data.scenes[0].game_settings.all_frames - - tobeprocessed = [] - for ob in sce.objects: - if ob.select: - tobeprocessed.append(ob) - - for ob in tobeprocessed: - g = ob.game - - g.physics_type = 'RIGID_BODY' - g.use_collision_bounds = 1 - g.collision_bounds_type = 'CONVEX_HULL' - g.rotation_damping = 0.9 - - sizex, sizey, sizez = getsizefrommesh(ob) - approxvolume = sizex * sizey * sizez - g.mass = approxvolume - - sce.objects.active = ob - - bpy.ops.object.game_property_new() - g.properties['prop'].name = 'shard' - #sm=FloatProperty(name='shard',description='shardprop',default=0.0) - #print (sm) - #np=bpy.types.GameFloatProperty(sm) - #name='shard',type='BOOL', value=1 - #print(ob) - - -class SetupFractureShards(bpy.types.Operator): - '''''' - bl_idname = "object.setup_fracture_shards" - bl_label = "Setup Fracture Shards" - bl_options = {'REGISTER', 'UNDO'} - - #def poll(self, context): - - def execute(self, context): - setupshards(context) - return {'FINISHED'} diff --git a/render_povray/__init__.py b/render_povray/__init__.py deleted file mode 100644 index 4adcbf07..00000000 --- a/render_povray/__init__.py +++ /dev/null @@ -1,131 +0,0 @@ -# ##### 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -# ##### END GPL LICENSE BLOCK ##### - -bl_addon_info = { - "name": "PovRay", - "author": "Campbell Barton", - "version": (0,1), - "blender": (2, 5, 4), - "api": 31667, - "location": "Info Header (engine dropdown)", - "description": "Basic povray integration for blender", - "warning": "", - "wiki_url": "http://wiki.blender.org/index.php/Extensions:2.5/Py/"\ - "Scripts/Render/PovRay", - "tracker_url": "https://projects.blender.org/tracker/index.php?"\ - "func=detail&aid=23145&group_id=153&atid=469", - "category": "Render"} - - -if "bpy" in locals(): - reload(render) - reload(ui) - -else: - import bpy - from bpy.props import * - from render_povray import render - from render_povray import ui - - -def register(): - Scene = bpy.types.Scene - - # Not a real pov option, just to know if we should write - Scene.pov_radio_enable = BoolProperty( - name="Enable Radiosity", - description="Enable povrays radiosity calculation", - default=False) - Scene.pov_radio_display_advanced = BoolProperty( - name="Advanced Options", - description="Show advanced options", - default=False) - - # Real pov options - Scene.pov_radio_adc_bailout = FloatProperty( - name="ADC Bailout", description="The adc_bailout for radiosity rays. Use adc_bailout = 0.01 / brightest_ambient_object for good results", - min=0.0, max=1000.0, soft_min=0.0, soft_max=1.0, default=0.01) - - Scene.pov_radio_always_sample = BoolProperty( - name="Always Sample", description="Only use the data from the pretrace step and not gather any new samples during the final radiosity pass", - default=True) - - Scene.pov_radio_brightness = FloatProperty( - name="Brightness", description="Amount objects are brightened before being returned upwards to the rest of the system", - min=0.0, max=1000.0, soft_min=0.0, soft_max=10.0, default=1.0) - - Scene.pov_radio_count = IntProperty( - name="Ray Count", description="Number of rays that are sent out whenever a new radiosity value has to be calculated", - min=1, max=1600, default=35) - - Scene.pov_radio_error_bound = FloatProperty( - name="Error Bound", description="One of the two main speed/quality tuning values, lower values are more accurate", - min=0.0, max=1000.0, soft_min=0.1, soft_max=10.0, default=1.8) - - Scene.pov_radio_gray_threshold = FloatProperty( - name="Gray Threshold", description="One of the two main speed/quality tuning values, lower values are more accurate", - min=0.0, max=1.0, soft_min=0, soft_max=1, default=0.0) - - Scene.pov_radio_low_error_factor = FloatProperty( - name="Low Error Factor", description="If you calculate just enough samples, but no more, you will get an image which has slightly blotchy lighting", - min=0.0, max=1.0, soft_min=0.0, soft_max=1.0, default=0.5) - - # max_sample - not available yet - Scene.pov_radio_media = BoolProperty( - name="Media", description="Radiosity estimation can be affected by media", - default=False) - - Scene.pov_radio_minimum_reuse = FloatProperty( - name="Minimum Reuse", description="Fraction of the screen width which sets the minimum radius of reuse for each sample point (At values higher than 2% expect errors)", - min=0.0, max=1.0, soft_min=0.1, soft_max=0.1, default=0.015) - - Scene.pov_radio_nearest_count = IntProperty( - name="Nearest Count", description="Number of old ambient values blended together to create a new interpolated value", - min=1, max=20, default=5) - - Scene.pov_radio_normal = BoolProperty( - name="Normals", description="Radiosity estimation can be affected by normals", - default=False) - - Scene.pov_radio_recursion_limit = IntProperty( - name="Recursion Limit", description="how many recursion levels are used to calculate the diffuse inter-reflection", - min=1, max=20, default=3) - - -def unregister(): - import bpy - Scene = bpy.types.Scene - - del Scene.pov_radio_enable - del Scene.pov_radio_display_advanced - del Scene.pov_radio_adc_bailout - del Scene.pov_radio_always_sample - del Scene.pov_radio_brightness - del Scene.pov_radio_count - del Scene.pov_radio_error_bound - del Scene.pov_radio_gray_threshold - del Scene.pov_radio_low_error_factor - del Scene.pov_radio_media - del Scene.pov_radio_minimum_reuse - del Scene.pov_radio_nearest_count - del Scene.pov_radio_normal - del Scene.pov_radio_recursion_limit - - -if __name__ == "__main__": - register() diff --git a/render_povray/render.py b/render_povray/render.py deleted file mode 100644 index 936ddc3b..00000000 --- a/render_povray/render.py +++ /dev/null @@ -1,790 +0,0 @@ -# ##### 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -# ##### END GPL LICENSE BLOCK ##### - -import bpy -import subprocess -import os -import sys -import time -import math - -import platform as pltfrm -if pltfrm.architecture()[0] == '64bit': - bitness = 64 -else: - bitness = 32 - - -def write_pov(filename, scene=None, info_callback=None): - file = open(filename, 'w') - - # Only for testing - if not scene: - scene = bpy.data.scenes[0] - - render = scene.render - world = scene.world - - def uniqueName(name, nameSeq): - - if name not in nameSeq: - return name - - name_orig = name - i = 1 - while name in nameSeq: - name = '%s_%.3d' % (name_orig, i) - i += 1 - - return name - - def writeMatrix(matrix): - file.write('\tmatrix <%.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f>\n' %\ - (matrix[0][0], matrix[0][1], matrix[0][2], matrix[1][0], matrix[1][1], matrix[1][2], matrix[2][0], matrix[2][1], matrix[2][2], matrix[3][0], matrix[3][1], matrix[3][2])) - - def writeObjectMaterial(material): - if material and material.transparency_method == 'RAYTRACE': - file.write('\tinterior { ior %.6f }\n' % material.raytrace_transparency.ior) - - # Other interior args - # fade_distance 2 - # fade_power [Value] - # fade_color - - # dispersion - # dispersion_samples - - materialNames = {} - DEF_MAT_NAME = 'Default' - - def writeMaterial(material): - # Assumes only called once on each material - - if material: - name_orig = material.name - else: - name_orig = DEF_MAT_NAME - - name = materialNames[name_orig] = uniqueName(bpy.path.clean_name(name_orig), materialNames) - - file.write('#declare %s = finish {\n' % name) - - if material: - file.write('\tdiffuse %.3g\n' % material.diffuse_intensity) - file.write('\tspecular %.3g\n' % material.specular_intensity) - - file.write('\tambient %.3g\n' % material.ambient) - #file.write('\tambient rgb <%.3g, %.3g, %.3g>\n' % tuple([c*material.ambient for c in world.ambient_color])) # povray blends the global value - - # map hardness between 0.0 and 1.0 - roughness = ((1.0 - ((material.specular_hardness - 1.0) / 510.0))) - # scale from 0.0 to 0.1 - roughness *= 0.1 - # add a small value because 0.0 is invalid - roughness += (1 / 511.0) - - file.write('\troughness %.3g\n' % roughness) - - # 'phong 70.0 ' - - if material.raytrace_mirror.use: - raytrace_mirror = material.raytrace_mirror - if raytrace_mirror.reflect_factor: - file.write('\treflection {\n') - file.write('\t\trgb <%.3g, %.3g, %.3g>' % tuple(material.mirror_color)) - file.write('\t\tfresnel 1 falloff %.3g exponent %.3g metallic %.3g} ' % (raytrace_mirror.fresnel, raytrace_mirror.fresnel_factor, raytrace_mirror.reflect_factor)) - - else: - file.write('\tdiffuse 0.8\n') - file.write('\tspecular 0.2\n') - - - # This is written into the object - ''' - if material and material.transparency_method=='RAYTRACE': - 'interior { ior %.3g} ' % material.raytrace_transparency.ior - ''' - - #file.write('\t\t\tcrand 1.0\n') # Sand granyness - #file.write('\t\t\tmetallic %.6f\n' % material.spec) - #file.write('\t\t\tphong %.6f\n' % material.spec) - #file.write('\t\t\tphong_size %.6f\n' % material.spec) - #file.write('\t\t\tbrilliance %.6f ' % (material.specular_hardness/256.0) # Like hardness - - file.write('}\n') - - def exportCamera(): - camera = scene.camera - matrix = camera.matrix_world - - # compute resolution - Qsize = float(render.resolution_x) / float(render.resolution_y) - - file.write('camera {\n') - file.write('\tlocation <0, 0, 0>\n') - file.write('\tlook_at <0, 0, -1>\n') - file.write('\tright <%s, 0, 0>\n' % - Qsize) - file.write('\tup <0, 1, 0>\n') - file.write('\tangle %f \n' % (360.0 * math.atan(16.0 / camera.data.lens) / math.pi)) - - file.write('\trotate <%.6f, %.6f, %.6f>\n' % tuple([math.degrees(e) for e in matrix.rotation_part().to_euler()])) - file.write('\ttranslate <%.6f, %.6f, %.6f>\n' % (matrix[3][0], matrix[3][1], matrix[3][2])) - file.write('}\n') - - def exportLamps(lamps): - # Get all lamps - for ob in lamps: - lamp = ob.data - - matrix = ob.matrix_world - - color = tuple([c * lamp.energy for c in lamp.color]) # Colour is modified by energy - - file.write('light_source {\n') - file.write('\t< 0,0,0 >\n') - file.write('\tcolor rgb<%.3g, %.3g, %.3g>\n' % color) - - if lamp.type == 'POINT': # Point Lamp - pass - elif lamp.type == 'SPOT': # Spot - file.write('\tspotlight\n') - - # Falloff is the main radius from the centre line - file.write('\tfalloff %.2f\n' % (math.degrees(lamp.spot_size) / 2.0)) # 1 TO 179 FOR BOTH - file.write('\tradius %.6f\n' % ((math.degrees(lamp.spot_size) / 2.0) * (1.0 - lamp.spot_blend))) - - # Blender does not have a tightness equivilent, 0 is most like blender default. - file.write('\ttightness 0\n') # 0:10f - - file.write('\tpoint_at <0, 0, -1>\n') - elif lamp.type == 'SUN': - file.write('\tparallel\n') - file.write('\tpoint_at <0, 0, -1>\n') # *must* be after 'parallel' - - elif lamp.type == 'AREA': - - size_x = lamp.size - samples_x = lamp.shadow_ray_samples_x - if lamp.shape == 'SQUARE': - size_y = size_x - samples_y = samples_x - else: - size_y = lamp.size_y - samples_y = lamp.shadow_ray_samples_y - - file.write('\tarea_light <%d,0,0>,<0,0,%d> %d, %d\n' % (size_x, size_y, samples_x, samples_y)) - if lamp.shadow_ray_sample_method == 'CONSTANT_JITTERED': - if lamp.jitter: - file.write('\tjitter\n') - else: - file.write('\tadaptive 1\n') - file.write('\tjitter\n') - - if lamp.shadow_method == 'NOSHADOW': - file.write('\tshadowless\n') - - file.write('\tfade_distance %.6f\n' % lamp.distance) - file.write('\tfade_power %d\n' % 1) # Could use blenders lamp quad? - writeMatrix(matrix) - - file.write('}\n') - - def exportMeta(metas): - - # TODO - blenders 'motherball' naming is not supported. - - for ob in metas: - meta = ob.data - - file.write('blob {\n') - file.write('\t\tthreshold %.4g\n' % meta.threshold) - - try: - material = meta.materials[0] # lame! - blender cant do enything else. - except: - material = None - - for elem in meta.elements: - - if elem.type not in ('BALL', 'ELLIPSOID'): - continue # Not supported - - loc = elem.co - - stiffness = elem.stiffness - if elem.use_negative: - stiffness = - stiffness - - if elem.type == 'BALL': - - file.write('\tsphere { <%.6g, %.6g, %.6g>, %.4g, %.4g ' % (loc.x, loc.y, loc.z, elem.radius, stiffness)) - - # After this wecould do something simple like... - # "pigment {Blue} }" - # except we'll write the color - - elif elem.type == 'ELLIPSOID': - # location is modified by scale - file.write('\tsphere { <%.6g, %.6g, %.6g>, %.4g, %.4g ' % (loc.x / elem.size_x, loc.y / elem.size_y, loc.z / elem.size_z, elem.radius, stiffness)) - file.write('scale <%.6g, %.6g, %.6g> ' % (elem.size_x, elem.size_y, elem.size_z)) - - if material: - diffuse_color = material.diffuse_color - - if material.use_transparency and material.transparency_method == 'RAYTRACE': - trans = 1.0 - material.raytrace_transparency.filter - else: - trans = 0.0 - - file.write('pigment {rgbft<%.3g, %.3g, %.3g, %.3g, %.3g>} finish {%s} }\n' % \ - (diffuse_color[0], diffuse_color[1], diffuse_color[2], 1.0 - material.alpha, trans, materialNames[material.name])) - - else: - file.write('pigment {rgb<1 1 1>} finish {%s} }\n' % DEF_MAT_NAME) # Write the finish last. - - writeObjectMaterial(material) - - writeMatrix(ob.matrix_world) - - file.write('}\n') - - def exportMeshs(scene, sel): - - ob_num = 0 - - for ob in sel: - ob_num += 1 - - if ob.type in ('LAMP', 'CAMERA', 'EMPTY', 'META', 'ARMATURE', 'LATTICE'): - continue - - me = ob.data - me_materials = me.materials - - me = ob.create_mesh(scene, True, 'RENDER') - - if not me or not me.faces: - continue - - if info_callback: - info_callback('Object %2.d of %2.d (%s)' % (ob_num, len(sel), ob.name)) - - #if ob.type!='MESH': - # continue - # me = ob.data - - matrix = ob.matrix_world - try: - uv_layer = me.uv_textures.active.data - except: - uv_layer = None - - try: - vcol_layer = me.vertex_colors.active.data - except: - vcol_layer = None - - faces_verts = [f.vertices[:] for f in me.faces] - faces_normals = [tuple(f.normal) for f in me.faces] - verts_normals = [tuple(v.normal) for v in me.vertices] - - # quads incur an extra face - quadCount = len([f for f in faces_verts if len(f) == 4]) - - file.write('mesh2 {\n') - file.write('\tvertex_vectors {\n') - file.write('\t\t%s' % (len(me.vertices))) # vert count - for v in me.vertices: - file.write(',\n\t\t<%.6f, %.6f, %.6f>' % tuple(v.co)) # vert count - file.write('\n }\n') - - - # Build unique Normal list - uniqueNormals = {} - for fi, f in enumerate(me.faces): - fv = faces_verts[fi] - # [-1] is a dummy index, use a list so we can modify in place - if f.use_smooth: # Use vertex normals - for v in fv: - key = verts_normals[v] - uniqueNormals[key] = [-1] - else: # Use face normal - key = faces_normals[fi] - uniqueNormals[key] = [-1] - - file.write('\tnormal_vectors {\n') - file.write('\t\t%d' % len(uniqueNormals)) # vert count - idx = 0 - for no, index in uniqueNormals.items(): - file.write(',\n\t\t<%.6f, %.6f, %.6f>' % no) # vert count - index[0] = idx - idx += 1 - file.write('\n }\n') - - - # Vertex colours - vertCols = {} # Use for material colours also. - - if uv_layer: - # Generate unique UV's - uniqueUVs = {} - - for fi, uv in enumerate(uv_layer): - - if len(faces_verts[fi]) == 4: - uvs = uv.uv1, uv.uv2, uv.uv3, uv.uv4 - else: - uvs = uv.uv1, uv.uv2, uv.uv3 - - for uv in uvs: - uniqueUVs[tuple(uv)] = [-1] - - file.write('\tuv_vectors {\n') - #print unique_uvs - file.write('\t\t%s' % (len(uniqueUVs))) # vert count - idx = 0 - for uv, index in uniqueUVs.items(): - file.write(',\n\t\t<%.6f, %.6f>' % uv) - index[0] = idx - idx += 1 - ''' - else: - # Just add 1 dummy vector, no real UV's - file.write('\t\t1') # vert count - file.write(',\n\t\t<0.0, 0.0>') - ''' - file.write('\n }\n') - - - if me.vertex_colors: - - for fi, f in enumerate(me.faces): - material_index = f.material_index - material = me_materials[material_index] - - if material and material.use_vertex_color_paint: - - col = vcol_layer[fi] - - if len(faces_verts[fi]) == 4: - cols = col.color1, col.color2, col.color3, col.color4 - else: - cols = col.color1, col.color2, col.color3 - - for col in cols: - key = col[0], col[1], col[2], material_index # Material index! - vertCols[key] = [-1] - - else: - if material: - diffuse_color = tuple(material.diffuse_color) - key = diffuse_color[0], diffuse_color[1], diffuse_color[2], material_index - vertCols[key] = [-1] - - - else: - # No vertex colours, so write material colours as vertex colours - for i, material in enumerate(me_materials): - - if material: - diffuse_color = tuple(material.diffuse_color) - key = diffuse_color[0], diffuse_color[1], diffuse_color[2], i # i == f.mat - vertCols[key] = [-1] - - - # Vert Colours - file.write('\ttexture_list {\n') - file.write('\t\t%s' % (len(vertCols))) # vert count - idx = 0 - for col, index in vertCols.items(): - - if me_materials: - material = me_materials[col[3]] - material_finish = materialNames[material.name] - - if material.use_transparency and material.transparency_method == 'RAYTRACE': - trans = 1.0 - material.raytrace_transparency.filter - else: - trans = 0.0 - - else: - material_finish = DEF_MAT_NAME # not working properly, - trans = 0.0 - - #print material.apl - file.write(',\n\t\ttexture { pigment {rgbft<%.3g, %.3g, %.3g, %.3g, %.3g>} finish {%s}}' % - (col[0], col[1], col[2], 1.0 - material.alpha, trans, material_finish)) - - index[0] = idx - idx += 1 - - file.write('\n }\n') - - # Face indicies - file.write('\tface_indices {\n') - file.write('\t\t%d' % (len(me.faces) + quadCount)) # faces count - for fi, f in enumerate(me.faces): - fv = faces_verts[fi] - material_index = f.material_index - if len(fv) == 4: - indicies = (0, 1, 2), (0, 2, 3) - else: - indicies = ((0, 1, 2),) - - if vcol_layer: - col = vcol_layer[fi] - - if len(fv) == 4: - cols = col.color1, col.color2, col.color3, col.color4 - else: - cols = col.color1, col.color2, col.color3 - - - if not me_materials or me_materials[material_index] == None: # No materials - for i1, i2, i3 in indicies: - file.write(',\n\t\t<%d,%d,%d>' % (fv[i1], fv[i2], fv[i3])) # vert count - else: - material = me_materials[material_index] - for i1, i2, i3 in indicies: - if me.vertex_colors and material.use_vertex_color_paint: - # Colour per vertex - vertex colour - - col1 = cols[i1] - col2 = cols[i2] - col3 = cols[i3] - - ci1 = vertCols[col1[0], col1[1], col1[2], material_index][0] - ci2 = vertCols[col2[0], col2[1], col2[2], material_index][0] - ci3 = vertCols[col3[0], col3[1], col3[2], material_index][0] - else: - # Colour per material - flat material colour - diffuse_color = material.diffuse_color - ci1 = ci2 = ci3 = vertCols[diffuse_color[0], diffuse_color[1], diffuse_color[2], f.material_index][0] - - file.write(',\n\t\t<%d,%d,%d>, %d,%d,%d' % (fv[i1], fv[i2], fv[i3], ci1, ci2, ci3)) # vert count - - - file.write('\n }\n') - - # normal_indices indicies - file.write('\tnormal_indices {\n') - file.write('\t\t%d' % (len(me.faces) + quadCount)) # faces count - for fi, fv in enumerate(faces_verts): - - if len(fv) == 4: - indicies = (0, 1, 2), (0, 2, 3) - else: - indicies = ((0, 1, 2),) - - for i1, i2, i3 in indicies: - if f.use_smooth: - file.write(',\n\t\t<%d,%d,%d>' %\ - (uniqueNormals[verts_normals[fv[i1]]][0],\ - uniqueNormals[verts_normals[fv[i2]]][0],\ - uniqueNormals[verts_normals[fv[i3]]][0])) # vert count - else: - idx = uniqueNormals[faces_normals[fi]][0] - file.write(',\n\t\t<%d,%d,%d>' % (idx, idx, idx)) # vert count - - file.write('\n }\n') - - if uv_layer: - file.write('\tuv_indices {\n') - file.write('\t\t%d' % (len(me.faces) + quadCount)) # faces count - for fi, fv in enumerate(faces_verts): - - if len(fv) == 4: - indicies = (0, 1, 2), (0, 2, 3) - else: - indicies = ((0, 1, 2),) - - uv = uv_layer[fi] - if len(faces_verts[fi]) == 4: - uvs = tuple(uv.uv1), tuple(uv.uv2), tuple(uv.uv3), tuple(uv.uv4) - else: - uvs = tuple(uv.uv1), tuple(uv.uv2), tuple(uv.uv3) - - for i1, i2, i3 in indicies: - file.write(',\n\t\t<%d,%d,%d>' %\ - (uniqueUVs[uvs[i1]][0],\ - uniqueUVs[uvs[i2]][0],\ - uniqueUVs[uvs[i2]][0])) # vert count - file.write('\n }\n') - - if me.materials: - material = me.materials[0] # dodgy - writeObjectMaterial(material) - - writeMatrix(matrix) - file.write('}\n') - - bpy.data.meshes.remove(me) - - def exportWorld(world): - if not world: - return - - mist = world.mist_settings - - if mist.use_mist: - file.write('fog {\n') - file.write('\tdistance %.6f\n' % mist.depth) - file.write('\tcolor rgbt<%.3g, %.3g, %.3g, %.3g>\n' % (tuple(world.horizon_color) + (1 - mist.intensity,))) - #file.write('\tfog_offset %.6f\n' % mist.start) - #file.write('\tfog_alt 5\n') - #file.write('\tturbulence 0.2\n') - #file.write('\tturb_depth 0.3\n') - file.write('\tfog_type 1\n') - file.write('}\n') - - def exportGlobalSettings(scene): - - file.write('global_settings {\n') - - if scene.pov_radio_enable: - file.write('\tradiosity {\n') - file.write("\t\tadc_bailout %.4g\n" % scene.pov_radio_adc_bailout) - file.write("\t\talways_sample %d\n" % scene.pov_radio_always_sample) - file.write("\t\tbrightness %.4g\n" % scene.pov_radio_brightness) - file.write("\t\tcount %d\n" % scene.pov_radio_count) - file.write("\t\terror_bound %.4g\n" % scene.pov_radio_error_bound) - file.write("\t\tgray_threshold %.4g\n" % scene.pov_radio_gray_threshold) - file.write("\t\tlow_error_factor %.4g\n" % scene.pov_radio_low_error_factor) - file.write("\t\tmedia %d\n" % scene.pov_radio_media) - file.write("\t\tminimum_reuse %.4g\n" % scene.pov_radio_minimum_reuse) - file.write("\t\tnearest_count %d\n" % scene.pov_radio_nearest_count) - file.write("\t\tnormal %d\n" % scene.pov_radio_normal) - file.write("\t\trecursion_limit %d\n" % scene.pov_radio_recursion_limit) - file.write('\t}\n') - - if world: - file.write("\tambient_light rgb<%.3g, %.3g, %.3g>\n" % tuple(world.ambient_color)) - - file.write('}\n') - - - # Convert all materials to strings we can access directly per vertex. - writeMaterial(None) # default material - - for material in bpy.data.materials: - writeMaterial(material) - - exportCamera() - #exportMaterials() - sel = scene.objects - exportLamps([l for l in sel if l.type == 'LAMP']) - exportMeta([l for l in sel if l.type == 'META']) - exportMeshs(scene, sel) - exportWorld(scene.world) - exportGlobalSettings(scene) - - file.close() - - - -def write_pov_ini(filename_ini, filename_pov, filename_image): - scene = bpy.data.scenes[0] - render = scene.render - - x = int(render.resolution_x * render.resolution_percentage * 0.01) - y = int(render.resolution_y * render.resolution_percentage * 0.01) - - file = open(filename_ini, 'w') - - file.write('Input_File_Name="%s"\n' % filename_pov) - file.write('Output_File_Name="%s"\n' % filename_image) - - file.write('Width=%d\n' % x) - file.write('Height=%d\n' % y) - - # Needed for border render. - ''' - file.write('Start_Column=%d\n' % part.x) - file.write('End_Column=%d\n' % (part.x+part.w)) - - file.write('Start_Row=%d\n' % (part.y)) - file.write('End_Row=%d\n' % (part.y+part.h)) - ''' - - file.write('Display=0\n') - file.write('Pause_When_Done=0\n') - file.write('Output_File_Type=T\n') # TGA, best progressive loading - file.write('Output_Alpha=1\n') - - if render.use_antialiasing: - aa_mapping = {'5': 2, '8': 3, '11': 4, '16': 5} # method 1 assumed - file.write('Antialias=1\n') - file.write('Antialias_Depth=%d\n' % aa_mapping[render.antialiasing_samples]) - else: - file.write('Antialias=0\n') - - file.close() - - -class PovrayRender(bpy.types.RenderEngine): - bl_idname = 'POVRAY_RENDER' - bl_label = "Povray" - DELAY = 0.02 - - def _export(self, scene): - import tempfile - - self._temp_file_in = tempfile.mktemp(suffix='.pov') - self._temp_file_out = tempfile.mktemp(suffix='.tga') - self._temp_file_ini = tempfile.mktemp(suffix='.ini') - ''' - self._temp_file_in = '/test.pov' - self._temp_file_out = '/test.tga' - self._temp_file_ini = '/test.ini' - ''' - - def info_callback(txt): - self.update_stats("", "POVRAY: " + txt) - - write_pov(self._temp_file_in, scene, info_callback) - - def _render(self): - - try: - os.remove(self._temp_file_out) # so as not to load the old file - except: - pass - - write_pov_ini(self._temp_file_ini, self._temp_file_in, self._temp_file_out) - - print ("***-STARTING-***") - - pov_binary = "povray" - - if sys.platform == 'win32': - import winreg - regKey = winreg.OpenKey(winreg.HKEY_CURRENT_USER, 'Software\\POV-Ray\\v3.6\\Windows') - - if bitness == 64: - pov_binary = winreg.QueryValueEx(regKey, 'Home')[0] + '\\bin\\pvengine64' - else: - pov_binary = winreg.QueryValueEx(regKey, 'Home')[0] + '\\bin\\pvengine' - - if 1: - # TODO, when povray isnt found this gives a cryptic error, would be nice to be able to detect if it exists - try: - self._process = subprocess.Popen([pov_binary, self._temp_file_ini]) # stdout=subprocess.PIPE, stderr=subprocess.PIPE - except OSError: - # TODO, report api - print("POVRAY: could not execute '%s', possibly povray isn't installed" % pov_binary) - import traceback - traceback.print_exc() - print ("***-DONE-***") - return False - - else: - # This works too but means we have to wait until its done - os.system('%s %s' % (pov_binary, self._temp_file_ini)) - - print ("***-DONE-***") - return True - - def _cleanup(self): - for f in (self._temp_file_in, self._temp_file_ini, self._temp_file_out): - try: - os.remove(f) - except: - pass - - self.update_stats("", "") - - def render(self, scene): - - self.update_stats("", "POVRAY: Exporting data from Blender") - self._export(scene) - self.update_stats("", "POVRAY: Parsing File") - - if not self._render(): - self.update_stats("", "POVRAY: Not found") - return - - r = scene.render - - # compute resolution - x = int(r.resolution_x * r.resolution_percentage * 0.01) - y = int(r.resolution_y * r.resolution_percentage * 0.01) - - # Wait for the file to be created - while not os.path.exists(self._temp_file_out): - if self.test_break(): - try: - self._process.terminate() - except: - pass - break - - if self._process.poll() != None: - self.update_stats("", "POVRAY: Failed") - break - - time.sleep(self.DELAY) - - if os.path.exists(self._temp_file_out): - - self.update_stats("", "POVRAY: Rendering") - - prev_size = -1 - - def update_image(): - result = self.begin_result(0, 0, x, y) - lay = result.layers[0] - # possible the image wont load early on. - try: - lay.load_from_file(self._temp_file_out) - except: - pass - self.end_result(result) - - # Update while povray renders - while True: - - # test if povray exists - if self._process.poll() is not None: - update_image() - break - - # user exit - if self.test_break(): - try: - self._process.terminate() - except: - pass - - break - - # Would be nice to redirect the output - # stdout_value, stderr_value = self._process.communicate() # locks - - - # check if the file updated - new_size = os.path.getsize(self._temp_file_out) - - if new_size != prev_size: - update_image() - prev_size = new_size - - time.sleep(self.DELAY) - - self._cleanup() - - diff --git a/render_povray/ui.py b/render_povray/ui.py deleted file mode 100644 index 2d2a6d62..00000000 --- a/render_povray/ui.py +++ /dev/null @@ -1,136 +0,0 @@ -# ##### 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -# ##### END GPL LICENSE BLOCK ##### - -import bpy - -# Use some of the existing buttons. -import properties_render -properties_render.RENDER_PT_render.COMPAT_ENGINES.add('POVRAY_RENDER') -properties_render.RENDER_PT_dimensions.COMPAT_ENGINES.add('POVRAY_RENDER') -properties_render.RENDER_PT_antialiasing.COMPAT_ENGINES.add('POVRAY_RENDER') -properties_render.RENDER_PT_output.COMPAT_ENGINES.add('POVRAY_RENDER') -del properties_render - -# Use only a subset of the world panels -import properties_world -properties_world.WORLD_PT_preview.COMPAT_ENGINES.add('POVRAY_RENDER') -properties_world.WORLD_PT_context_world.COMPAT_ENGINES.add('POVRAY_RENDER') -properties_world.WORLD_PT_world.COMPAT_ENGINES.add('POVRAY_RENDER') -properties_world.WORLD_PT_mist.COMPAT_ENGINES.add('POVRAY_RENDER') -del properties_world - -# Example of wrapping every class 'as is' -import properties_material -for member in dir(properties_material): - subclass = getattr(properties_material, member) - try: - subclass.COMPAT_ENGINES.add('POVRAY_RENDER') - except: - pass -del properties_material - -import properties_data_mesh -for member in dir(properties_data_mesh): - subclass = getattr(properties_data_mesh, member) - try: - subclass.COMPAT_ENGINES.add('POVRAY_RENDER') - except: - pass -del properties_data_mesh - -import properties_texture -for member in dir(properties_texture): - subclass = getattr(properties_texture, member) - try: - subclass.COMPAT_ENGINES.add('POVRAY_RENDER') - except: - pass -del properties_texture - -import properties_data_camera -for member in dir(properties_data_camera): - subclass = getattr(properties_data_camera, member) - try: - subclass.COMPAT_ENGINES.add('POVRAY_RENDER') - except: - pass -del properties_data_camera - - - -class RenderButtonsPanel(): - bl_space_type = 'PROPERTIES' - bl_region_type = 'WINDOW' - bl_context = "render" - # COMPAT_ENGINES must be defined in each subclass, external engines can add themselves here - - @classmethod - def poll(cls, context): - rd = context.scene.render - return (rd.use_game_engine == False) and (rd.engine in cls.COMPAT_ENGINES) - - -class RENDER_PT_povray_radiosity(RenderButtonsPanel, bpy.types.Panel): - bl_label = "Radiosity" - COMPAT_ENGINES = {'POVRAY_RENDER'} - - def draw_header(self, context): - scene = context.scene - - self.layout.prop(scene, "pov_radio_enable", text="") - - def draw(self, context): - layout = self.layout - - scene = context.scene - rd = scene.render - - layout.active = scene.pov_radio_enable - - split = layout.split() - - col = split.column() - col.prop(scene, "pov_radio_count", text="Rays") - col.prop(scene, "pov_radio_recursion_limit", text="Recursions") - col = split.column() - col.prop(scene, "pov_radio_error_bound", text="Error") - - layout.prop(scene, "pov_radio_display_advanced") - - if scene.pov_radio_display_advanced: - split = layout.split() - - col = split.column() - col.prop(scene, "pov_radio_adc_bailout", slider=True) - col.prop(scene, "pov_radio_gray_threshold", slider=True) - col.prop(scene, "pov_radio_low_error_factor", slider=True) - - col = split.column() - col.prop(scene, "pov_radio_brightness") - col.prop(scene, "pov_radio_minimum_reuse", text="Min Reuse") - col.prop(scene, "pov_radio_nearest_count") - - split = layout.split() - - col = split.column() - col.label(text="Estimation Influence:") - col.prop(scene, "pov_radio_media") - col.prop(scene, "pov_radio_normal") - - col = split.column() - col.prop(scene, "pov_radio_always_sample") diff --git a/render_renderfarmfi.py b/render_renderfarmfi.py deleted file mode 100644 index 34998a8e..00000000 --- a/render_renderfarmfi.py +++ /dev/null @@ -1,820 +0,0 @@ -# ##### 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -# ##### END GPL LICENSE BLOCK ##### - -bl_addon_info = { - "name": "Renderfarm.fi", - "author": "Nathan Letwory , Jesse Kaukonen ", - "version": (3,), - "blender": (2, 5, 3), - "api": 31667, - "location": "Render > Engine > Renderfarm.fi", - "description": "Send .blend as session to http://www.renderfarm.fi to render", - "warning": "", - "wiki_url": "http://wiki.blender.org/index.php/Extensions:2.5/Py/"\ - "Scripts/Render/Renderfarm.fi", - "tracker_url": "https://projects.blender.org/tracker/index.php?"\ - "func=detail&aid=22927&group_id=153&atid=469", - "category": "Render"} - -""" -Copyright 2009-2010 Laurea University of Applied Sciences -Authors: Nathan Letwory, Jesse Kaukonen -""" - -import bpy -import hashlib -import http.client -import xmlrpc.client -import math -from os.path import abspath, isabs, join, isfile - -from bpy.props import PointerProperty, StringProperty, BoolProperty, EnumProperty, IntProperty, CollectionProperty - -bpy.CURRENT_VERSION = bl_addon_info["version"][0] -bpy.found_newer_version = False -bpy.up_to_date = False -bpy.download_location = 'http://www.renderfarm.fi/blender' - -bpy.errorMessages = { - 'missing_desc': 'You need to enter a title, short and long description', - 'missing_creds': 'You haven\'t entered your credentials yet' -} - -bpy.statusMessage = { - 'title': 'TRIA_RIGHT', - 'shortdesc': 'TRIA_RIGHT', - 'longdesc': 'TRIA_RIGHT', - 'username': 'TRIA_RIGHT', - 'password': 'TRIA_RIGHT' -} - -bpy.errors = [] -bpy.ore_sessions = [] -bpy.queue_selected = -1 - -def renderEngine(render_engine): - bpy.types.register(render_engine) - return render_engine - - -class ORESession(bpy.types.IDPropertyGroup): - pass - -class ORESettings(bpy.types.IDPropertyGroup): - pass - -# entry point for settings collection -bpy.types.Scene.ore_render = PointerProperty(type=ORESettings, name='ORE Render', description='ORE Render Settings') - -# fill the new struct -ORESettings.username = StringProperty(name='E-mail', description='E-mail for Renderfarm.fi', maxlen=256, default='') -ORESettings.password = StringProperty(name='Password', description='Renderfarm.fi password', maxlen=256, default='') -ORESettings.hash = StringProperty(name='Hash', description='hash calculated out of credentials', maxlen=33, default='') - -ORESettings.shortdesc = StringProperty(name='Short description', description='A short description of the scene (100 characters)', maxlen=101, default='') -ORESettings.longdesc = StringProperty(name='Long description', description='A more elaborate description of the scene (2k)', maxlen=2048, default='') -ORESettings.title = StringProperty(name='Title', description='Title for this session (128 characters)', maxlen=128, default='') -ORESettings.url = StringProperty(name='Project URL', description='Project URL. Leave empty if not applicable', maxlen=256, default='') - -ORESettings.parts = IntProperty(name='Parts/Frame', description='', min=1, max=1000, soft_min=1, soft_max=64, default=1) -ORESettings.resox = IntProperty(name='Resolution X', description='X of render', min=1, max=10000, soft_min=1, soft_max=10000, default=1920) -ORESettings.resoy = IntProperty(name='Resolution Y', description='Y of render', min=1, max=10000, soft_min=1, soft_max=10000, default=1080) -ORESettings.memusage = IntProperty(name='Memory Usage', description='Estimated maximum memory usage during rendering in MB', min=1, max=6*1024, soft_min=1, soft_max=3*1024, default=256) -ORESettings.start = IntProperty(name='Start Frame', description='Start Frame', default=1) -ORESettings.end = IntProperty(name='End Frame', description='End Frame', default=250) -ORESettings.fps = IntProperty(name='FPS', description='FPS', min=1, max=256, default=25) - -ORESettings.prepared = BoolProperty(name='Prepared', description='Set to True if preparation has been run', default=False) -ORESettings.debug = BoolProperty(name='Debug', description='Verbose output in console', default=False) -ORESettings.selected_session = IntProperty(name='Selected Session', description='The selected session', default=0) - -# session struct -ORESession.name = StringProperty(name='Name', description='Name of the session', maxlen=128, default='[session]') - -licenses = ( - ('1', 'CC by-nc-nd', 'Creative Commons: Attribution Non-Commercial No Derivatives'), - ('2', 'CC by-nc-sa', 'Creative Commons: Attribution Non-Commercial Share Alike'), - ('3', 'CC by-nd', 'Creative Commons: Attribution No Derivatives'), - ('4', 'CC by-nc', 'Creative Commons: Attribution Non-Commercial'), - ('5', 'CC by-sa', 'Creative Commons: Attribution Share Alike'), - ('6', 'CC by', 'Creative Commons: Attribution'), - ('7', 'Copyright', 'Copyright, no license specified'), - ) -ORESettings.inlicense = EnumProperty(items=licenses, name='source license', description='license speficied for the source files', default='1') -ORESettings.outlicense = EnumProperty(items=licenses, name='output license', description='license speficied for the output files', default='1') - -ORESettings.sessions = CollectionProperty(type=ORESession, name='Sessions', description='Sessions on Renderfarm.fi') - -# all panels, except render panel -# Example of wrapping every class 'as is' -import properties_scene -for member in dir(properties_scene): - subclass = getattr(properties_scene, member) - try: subclass.COMPAT_ENGINES.add('RENDERFARMFI_RENDER') - except: pass -del properties_scene - -import properties_world -for member in dir(properties_world): - subclass = getattr(properties_world, member) - try: subclass.COMPAT_ENGINES.add('RENDERFARMFI_RENDER') - except: pass -del properties_world - -import properties_material -for member in dir(properties_material): - subclass = getattr(properties_material, member) - try: subclass.COMPAT_ENGINES.add('RENDERFARMFI_RENDER') - except: pass -del properties_material - -import properties_object -for member in dir(properties_object): - subclass = getattr(properties_object, member) - try: subclass.COMPAT_ENGINES.add('RENDERFARMFI_RENDER') - except: pass -del properties_object - -class RenderButtonsPanel(): - bl_space_type = 'PROPERTIES' - bl_region_type = 'WINDOW' - bl_context = "render" - # COMPAT_ENGINES must be defined in each subclass, external engines can add themselves here - - -class RENDERFARM_MT_Session(bpy.types.Menu): - bl_label = "Show Session" - - def draw(self, context): - layout = self.layout - - layout.operator('ore.completed_sessions') - layout.operator('ore.accept_sessions') - layout.operator('ore.active_sessions') - layout.separator() - layout.operator('ore.cancelled_sessions') - -class LOGIN_PT_RenderfarmFi(RenderButtonsPanel, bpy.types.Panel): - bl_label = 'Login to Renderfarm.fi' - COMPAT_ENGINES = set(['RENDERFARMFI_RENDER']) - - @classmethod - def poll(cls, context): - rd = context.scene.render - return (rd.use_game_engine==False) and (rd.engine in cls.COMPAT_ENGINES) - - def draw(self, context): - layout = self.layout - # XXX layout.operator('ore.check_update') - ore = context.scene.ore_render - updateSessionList(ore) - checkStatus(ore) - - if ore.hash=='': - col = layout.column() - if ore.hash=='': - col.prop(ore, 'username', icon=bpy.statusMessage['username']) - col.prop(ore, 'password', icon=bpy.statusMessage['password']) - layout.operator('ore.login') - else: - layout.label(text='E-mail and password entered.', icon='INFO') - layout.operator('ore.change_user') - -class CHECK_PT_RenderfarmFi(RenderButtonsPanel, bpy.types.Panel): - bl_label = 'Check for updates' - COMPAT_ENGINES = set(['RENDERFARMFI_RENDER']) - - @classmethod - def poll(cls, context): - rd = context.scene.render - return (rd.use_game_engine==False) and (rd.engine in cls.COMPAT_ENGINES) - - def draw(self, context): - layout = self.layout - ore = context.scene.ore_render - - if bpy.found_newer_version == True: - layout.operator('ore.open_download_location') - else: - if bpy.up_to_date == True: - layout.label(text='You have the latest version') - layout.operator('ore.check_update') - -class SESSIONS_PT_RenderfarmFi(RenderButtonsPanel, bpy.types.Panel): - bl_label = 'Sessions' - COMPAT_ENGINES = set(['RENDERFARMFI_RENDER']) - - @classmethod - def poll(cls, context): - rd = context.scene.render - return (rd.use_game_engine==False) and (rd.engine in cls.COMPAT_ENGINES) - - def draw(self, context): - layout = self.layout - ore = context.scene.ore_render - - layout.menu("RENDERFARM_MT_Session") - if bpy.queue_selected == 1: - layout.label(text='Completed Sessions') - elif bpy.queue_selected == 2: - layout.label(text='Rendering Sessions') - elif bpy.queue_selected == 3: - layout.label(text='Pending Sessions') - elif bpy.queue_selected == 4: - layout.label(text='Cancelled and Rejected Sessions') - layout.template_list(ore, 'sessions', ore, 'selected_session', rows=2) - if bpy.queue_selected == 3: - layout.operator('ore.cancel_session') - -class RENDER_PT_RenderfarmFi(RenderButtonsPanel, bpy.types.Panel): - bl_label = "Scene Settings" - COMPAT_ENGINES = set(['RENDERFARMFI_RENDER']) - - @classmethod - def poll(cls, context): - rd = context.scene.render - return (rd.use_game_engine==False) and (rd.engine in cls.COMPAT_ENGINES) - - def draw(self, context): - layout = self.layout - sce = context.scene - ore = sce.ore_render - - if ore.prepared and ore.hash!='': - layout.prop(ore, 'memusage') - - layout.separator() - row = layout.row() - row.label(text='Resolution: '+str(ore.resox)+'x'+str(ore.resoy)) - - layout.separator() - row = layout.row() - row.prop(ore, 'inlicense') - row.prop(ore, 'outlicense') - - layout.separator() - row = layout.row() - row.operator('ore.upload') - row.operator('ore.reset', icon='FILE_REFRESH') - else: - layout.prop(ore, 'title', icon=bpy.statusMessage['title']) - layout.prop(ore, 'shortdesc', icon=bpy.statusMessage['shortdesc']) - layout.prop(ore, 'longdesc', icon=bpy.statusMessage['longdesc']) - layout.prop(ore, 'url') - layout.separator() - layout.operator('ore.use_scene_settings', icon='HAND') - row = layout.row() - row.prop(ore, 'resox') - row.prop(ore, 'resoy') - layout.separator() - layout.prop(ore, 'parts') - row = layout.row() - row.prop(ore, 'start') - row.prop(ore, 'end') - layout.prop(ore, 'fps') - - layout.separator() - layout.operator('ore.prepare', icon='INFO') - -def random_string(length): - import string - import random - return ''.join(random.choice(string.ascii_letters) for ii in range(length + 1)) - -def encode_multipart_data(data, files): - boundary = random_string(30) - - def get_content_type(filename): - return 'application/octet-stream' # default this - - def encode_field(field_name): - return ('--' + boundary, - 'Content-Disposition: form-data; name="%s"' % field_name, - '', str(data[field_name])) - - def encode_file(field_name): - import codecs - filename = files [field_name] - return ('--' + boundary, - 'Content-Disposition: form-data; name="%s"; filename="%s"' % (field_name, filename), - 'Content-Type: %s' % get_content_type(filename), - '', str(open(filename, 'rb').read(), encoding='iso-8859-1')) - - lines = [] - for name in data: - lines.extend(encode_field(name)) - for name in files: - lines.extend(encode_file(name)) - lines.extend(('--%s--' % boundary, '')) - body = '\r\n'.join(lines) - - headers = {'content-type': 'multipart/form-data; boundary=' + boundary, - 'content-length': str(len(body))} - - return body, headers - -def send_post(url, data, files): - connection = http.client.HTTPConnection('xmlrpc.renderfarm.fi') - connection.request('POST', '/file', *encode_multipart_data(data, files)) - response = connection.getresponse() - res = response.read() - return res - -def md5_for_file(filepath): - md5hash = hashlib.md5() - blocksize = 0x10000 - f = open(filepath, "rb") - while True: - data = f.read(blocksize) - if not data: - break - md5hash.update(data) - return md5hash.hexdigest() - -def upload_file(key, userid, sessionid, server, path): - assert isabs(path) - assert isfile(path) - - data = { - 'userId': str(userid), - 'sessionKey': key, - 'sessionId': sessionid, - 'md5sum': md5_for_file(path) - } - files = { - 'blenderfile': path - } - - r = send_post(server, data, files) - - #print 'Uploaded %r' % (path) - - return r - -def run_upload(key, userid, sessionid, path): - #print('Upload', path) - r = upload_file(key, userid, sessionid, r'http://xmlrpc.renderfarm.fi/file', path) - o = xmlrpc.client.loads(r) - #print('Done!') - - return o[0][0] - -def ore_upload(op, context): - sce = context.scene - ore = sce.ore_render - if not ore.prepared: - op.report(set(['ERROR']), 'Your user or scene information is not complete') - return {'CANCELLED'} - try: - authproxy = xmlrpc.client.ServerProxy(r'https://xmlrpc.renderfarm.fi/auth') - res = authproxy.auth.getSessionKey(ore.username, ore.hash) - key = res['key'] - userid = res['userId'] - - proxy = xmlrpc.client.ServerProxy(r'http://xmlrpc.renderfarm.fi/session') - proxy._ServerProxy__transport.user_agent = 'Renderfarm.fi Uploader/%s' % (bpy.CURRENT_VERSION) - res = proxy.session.createSession(userid, key) - sessionid = res['sessionId'] - key = res['key'] - res = run_upload(key, userid, sessionid, bpy.data.filepath) - fileid = int(res['fileId']) - - res = proxy.session.setTitle(userid, res['key'], sessionid, ore.title) - res = proxy.session.setLongDescription(userid, res['key'], sessionid, ore.longdesc) - res = proxy.session.setShortDescription(userid, res['key'], sessionid, ore.shortdesc) - if len(ore.url)>0: - res = proxy.session.setExternalURLs(userid, res['key'], sessionid, ore.url) - res = proxy.session.setStartFrame(userid, res['key'], sessionid, ore.start) - res = proxy.session.setEndFrame(userid, res['key'], sessionid, ore.end) - res = proxy.session.setSplit(userid, res['key'], sessionid, ore.parts) - res = proxy.session.setMemoryLimit(userid, res['key'], sessionid, ore.memusage) - res = proxy.session.setXSize(userid, res['key'], sessionid, ore.resox) - res = proxy.session.setYSize(userid, res['key'], sessionid, ore.resoy) - res = proxy.session.setFrameRate(userid, res['key'], sessionid, ore.fps) - res = proxy.session.setOutputLicense(userid, res['key'], sessionid, int(ore.outlicense)) - res = proxy.session.setInputLicense(userid, res['key'], sessionid, int(ore.inlicense)) - res = proxy.session.setPrimaryInputFile(userid, res['key'], sessionid, fileid) - res = proxy.session.submit(userid, res['key'], sessionid) - op.report(set(['INFO']), 'Submission sent to Renderfarm.fi') - except xmlrpc.client.Error as v: - print('ERROR:', v) - op.report(set(['ERROR']), 'An error occurred while sending submission to Renderfarm.fi') - except Exception as e: - print('Unhandled error:', e) - op.report(set(['ERROR']), 'An error occurred while sending submission to Renderfarm.fi') - - return {'FINISHED'} - -def setStatus(property, status): - if status: - bpy.statusMessage[property] = 'ERROR' - else: - bpy.statusMessage[property] = 'TRIA_RIGHT' - -def showStatus(layoutform, property, message): - if bpy.statusMessage[property] == 'ERROR': - layoutform.label(text='', icon='ERROR') - -def checkStatus(ore): - bpy.errors = [] - - if ore.hash=='' and (ore.username=='' or ore.password==''): - bpy.errors.append('missing_creds') - - if '' in (ore.title, ore.longdesc, ore.shortdesc): - bpy.errors.append('missing_desc') - - setStatus('username', ore.hash=='' and ore.username=='') - setStatus('password', ore.hash=='' and ore.password=='') - - setStatus('title', ore.title=='') - setStatus('longdesc', ore.longdesc=='') - setStatus('shortdesc', ore.shortdesc=='') - -class OreSession: - - def __init__(self, id, title): - self.id = id - self.title = title - self.frames = 0 - self.startframe = 0 - self.endframe = 0 - self.rendertime = 0 - self.percentage = 0 - - def percentageComplete(self): - totFrames = self.endframe - self.startframe - done = math.floor((self.frames / totFrames)*100) - if done > 100: done = 100 - return done - -def xmlSessionsToOreSessions(sessions, queue): - bpy.ore_sessions = [] - completed = sessions[queue] - for sid in completed: - s = completed[sid]['title'] - t = completed[sid]['timestamps'] - sinfo = OreSession(sid, s) - if queue in ('completed', 'active'): - sinfo.frames = completed[sid]['framesRendered'] - sinfo.startframe = completed[sid]['startFrame'] - sinfo.endframe = completed[sid]['endFrame'] - bpy.ore_sessions.append(sinfo) - -def updateSessionList(ore): - while(len(ore.sessions) > 0): - ore.sessions.remove(0) - - for s in bpy.ore_sessions: - ore.sessions.add() - session = ore.sessions[-1] - session.name = s.title + ' [' + str(s.percentageComplete()) + '% complete]' - -class ORE_OpenDownloadLocation(bpy.types.Operator): - bl_idname = 'ore.open_download_location' - bl_label = 'Download new version for your platform' - - def execute(self, context): - import webbrowser - webbrowser.open(bpy.download_location) - return {'FINISHED'} - -class ORE_CancelSession(bpy.types.Operator): - bl_idname = 'ore.cancel_session' - bl_label = 'Cancel Session' - - def execute(self, context): - sce = context.scene - ore = sce.ore_render - userproxy = xmlrpc.client.ServerProxy(r'https://xmlrpc.renderfarm.fi/user') - if len(bpy.ore_sessions)>0: - s = bpy.ore_sessions[ore.selected_session] - try: - res = userproxy.user.cancelSession(ore.username, ore.hash, int(s.id)) - self.report(set(['INFO']), 'Session ' + s.title + ' with id ' + s.id + ' cancelled') - except: - self.report(set(['ERROR']), 'Could not cancel session ' + s.title + ' with id ' + s.id) - - return {'FINISHED'} - -class ORE_GetCompletedSessions(bpy.types.Operator): - bl_idname = 'ore.completed_sessions' - bl_label = 'Complete' - - def execute(self, context): - sce = context.scene - ore = sce.ore_render - bpy.queue_selected = 1 - userproxy = xmlrpc.client.ServerProxy(r'https://xmlrpc.renderfarm.fi/user') - - sessions = userproxy.user.getAllSessions(ore.username, ore.hash, 'completed') - - xmlSessionsToOreSessions(sessions, 'completed') - - updateSessionList(ore) - - return {'FINISHED'} - -class ORE_GetCancelledSessions(bpy.types.Operator): - bl_idname = 'ore.cancelled_sessions' - bl_label = 'Cancelled' - - def execute(self, context): - sce = context.scene - ore = sce.ore_render - bpy.queue_selected = 4 - userproxy = xmlrpc.client.ServerProxy(r'https://xmlrpc.renderfarm.fi/user') - - sessions = userproxy.user.getAllSessions(ore.username, ore.hash, 'completed') - - xmlSessionsToOreSessions(sessions, 'canceled') - - updateSessionList(ore) - - return {'FINISHED'} - -class ORE_GetActiveSessions(bpy.types.Operator): - bl_idname = 'ore.active_sessions' - bl_label = 'Rendering' - - def execute(self, context): - sce = context.scene - ore = sce.ore_render - bpy.queue_selected = 2 - userproxy = xmlrpc.client.ServerProxy(r'https://xmlrpc.renderfarm.fi/user') - - sessions = userproxy.user.getAllSessions(ore.username, ore.hash, 'active') - - xmlSessionsToOreSessions(sessions, 'active') - - updateSessionList(ore) - - return {'FINISHED'} - -class ORE_GetPendingSessions(bpy.types.Operator): - bl_idname = 'ore.accept_sessions' # using ORE lingo in API. acceptQueue is session waiting for admin approval - bl_label = 'Pending' - - def execute(self, context): - sce = context.scene - ore = sce.ore_render - bpy.queue_selected = 3 - userproxy = xmlrpc.client.ServerProxy(r'https://xmlrpc.renderfarm.fi/user') - - sessions = userproxy.user.getAllSessions(ore.username, ore.hash, 'accept') - - xmlSessionsToOreSessions(sessions, 'accept') - - updateSessionList(ore) - - return {'FINISHED'} - -class ORE_CheckUpdate(bpy.types.Operator): - bl_idname = 'ore.check_update' - bl_label = 'Check for new version' - - def execute(self, context): - sce = context.scene - ore = sce.ore_render - blenderproxy = xmlrpc.client.ServerProxy(r'http://xmlrpc.renderfarm.fi/blender') - try: - self.report(set(['INFO']), 'Checking for newer version on Renderfarm.fi') - dl_url = blenderproxy.blender.getCurrentVersion(bpy.CURRENT_VERSION) - if len(dl_url['url']) > 0: - self.report(set(['INFO']), 'Found a newer version on Renderfarm.fi ' + dl_url['url']) - bpy.download_location = dl_url['url'] - bpy.found_newer_version = True - else: - bpy.up_to_date = True - self.report(set(['INFO']), 'Done checking for newer version on Renderfarm.fi') - except xmlrpc.client.Fault as f: - print('ERROR:', f) - self.report(set(['ERROR']), 'An error occurred while checking for newer version on Renderfarm.fi') - - return {'FINISHED'} - -class ORE_LoginOp(bpy.types.Operator): - bl_idname = 'ore.login' - bl_label = 'Confirm credentials' - - def execute(self, context): - sce = context.scene - ore = sce.ore_render - - if ore.hash=='': - if ore.password != '' and ore.username != '': - ore.hash = hashlib.md5(ore.password.encode() + ore.username.encode()).hexdigest() - ore.password = '' - - checkStatus(ore) - - if len(bpy.errors) > 0: - ore.prepared = False - return {'CANCELLED'} - - return {'FINISHED'} - -class ORE_PrepareOp(bpy.types.Operator): - '''Checking the scene will also save to the current file when successful!''' - bl_idname = 'ore.prepare' - bl_label = 'Check scene' - - def execute(self, context): - def hasSSSMaterial(): - for m in bpy.data.materials: - if m.subsurface_scattering.enabled: - return True - return False - - def hasParticleSystem(): - if len(bpy.data.particles) > 0: - self.report({'WARNING'}, "Found particle system") - print("Found particle system") - return True - return False - - def hasSimulation(t): - for o in bpy.data.objects: - for m in o.modifiers: - if isinstance(m, t): - self.report({'WARNING'}, "Found simulation: " + str(t)) - print("Found simulation: " + str(t)) - return True - return False - - def hasFluidSimulation(): - return hasSimulation(bpy.types.FluidSimulationModifier) - - def hasSmokeSimulation(): - return hasSimulation(bpy.types.SmokeModifier) - - def hasClothSimulation(): - return hasSimulation(bpy.types.ClothModifier) - - def hasCollisionSimulation(): - return hasSimulation(bpy.types.CollisionModifier) - - def hasSoftbodySimulation(): - return hasSimulation(bpy.types.SoftBodyModifier) - - def hasUnsupportedSimulation(): - return hasSoftbodySimulation() or hasCollisionSimulation() or hasClothSimulation() or hasSmokeSimulation or hasFluidSimulation() or hasParticleSystem() - - def isFilterNode(node): - t = type(node) - return t==bpy.types.CompositorNodeBlur or t==bpy.types.CompositorNodeDBlur - - def hasCompositingErrors(use_nodes, nodetree, parts): - if not use_nodes: # no nodes in use, ignore check - return False - - for node in nodetree.nodes: - # output file absolutely forbidden - if type(node)==bpy.types.CompositorNodeOutputFile: - self.report({'ERROR'}, 'File output node is disallowed, remove them from your compositing nodetrees.') - return True - # blur et al are problematic when rendering ore.parts>1 - if isFilterNode(node) and parts>1: - self.report({'WARNING'}, 'A filtering node found and parts > 1. This combination will give bad output.') - return True - - return False - - sce = context.scene - ore = sce.ore_render - - errors = False - - checkStatus(ore) - - if len(bpy.errors) > 0: - ore.prepared = False - return {'CANCELLED'} - - rd = sce.render - print("=============================================") - rd.threads_mode = 'FIXED' - rd.threads = 1 - rd.resolution_x = ore.resox - rd.resolution_y = ore.resoy - if (rd.resolution_percentage != 100): - print("Resolution percentage is not 100. Changing to 100%") - self.report({'WARNING'}, "Resolution percentage is not 100. Changing to 100%") - errors = True - rd.resolution_percentage = 100 - if rd.file_format != 'PNG': - print("Renderfarm.fi always uses PNG for output. Changing to PNG.") - self.report({'WARNING'}, "Renderfarm.fi always uses PNG for output. Changing to PNG.") - errors = True - rd.file_format = 'PNG' - if (rd.use_sss == True or hasSSSMaterial()) and ore.parts > 1: - print("Subsurface Scattering is not supported when rendering with parts > 1. Disabling") - self.report({'WARNING'}, "Subsurface Scattering is not supported when rendering with parts > 1. Disabling") - rd.use_sss = False # disabling because ore.parts > 1. It's ok to use SSS with 1part/frame - errors = True - if hasUnsupportedSimulation() == True: - print("An unsupported simulation was detected. Please check your settings and remove them") - self.report({'WARNING'}, "An unsupported simulation was detected. Please check your settings and remove them") - errors = True - rd.use_save_buffers = False - rd.use_free_image_textures = True - if rd.use_compositing: - if hasCompositingErrors(sce.use_nodes, sce.nodetree, ore.parts): - print("Found disallowed nodes or problematic setup") - self.report({'WARNING'}, "Found disallowed nodes or problematic setup") - errors = True - print("Done checking the scene. Now do a test render") - self.report({'INFO'}, "Done checking the scene. Now do a test render") - print("=============================================") - - # if errors found, don't allow to upload, instead have user - # go through this until everything is ok - if errors: - self.report({'WARNING'}, "Settings were changed or other issues found. Check console and do a test render to make sure everything works.") - ore.prepared = False - else: - ore.prepared = True - rd.engine = 'BLENDER_RENDER' - bpy.ops.wm.save_mainfile() - rd.engine = 'RENDERFARMFI_RENDER' - - return {'FINISHED'} - -class ORE_ResetOp(bpy.types.Operator): - bl_idname = "ore.reset" - bl_label = "Reset Preparation" - - def execute(self, context): - sce = context.scene - sce.ore_render.prepared = False - return {'FINISHED'} - -class ORE_UploaderOp(bpy.types.Operator): - bl_idname = "ore.upload" - bl_label = "Render on Renderfarm.fi" - - def execute(self, context): - rd = context.scene.render - rd.engine = 'BLENDER_RENDER' - bpy.ops.wm.save_mainfile() - return ore_upload(self, context) - -class ORE_UseBlenderReso(bpy.types.Operator): - bl_idname = "ore.use_scene_settings" - bl_label = "Use Scene resolution" - - def execute(self, context): - sce = context.scene - ore = sce.ore_render - - ore.resox = sce.render.resolution_x - ore.resoy = sce.render.resolution_y - - return {'FINISHED'} - -class ORE_ChangeUser(bpy.types.Operator): - bl_idname = "ore.change_user" - bl_label = "Change user" - - def execute(self, context): - ore = context.scene.ore_render - ore.password = '' - ore.hash = '' - - return {'FINISHED'} - -class RenderfarmFi(bpy.types.RenderEngine): - bl_idname = 'RENDERFARMFI_RENDER' - bl_label = "Renderfarm.fi" - - def render(self, scene): - print('Do test renders with Blender Render') - -def menu_export(self, context): - import os - default_path = os.path.splitext(bpy.data.filepath)[0] + ".py" - self.layout.operator(RenderfarmFi.bl_idname, text=RenderfarmFi.bl_label) - -def register(): - bpy.types.INFO_MT_render.append(menu_export) - -def unregister(): - bpy.types.INFO_MT_render.remove(menu_export) - -if __name__ == "__main__": - register() diff --git a/space_view3d_align_tools.py b/space_view3d_align_tools.py deleted file mode 100644 index 4ed56b35..00000000 --- a/space_view3d_align_tools.py +++ /dev/null @@ -1,338 +0,0 @@ -# AlingTools.py (c) 2009, 2010 Gabriel Beaudin (gabhead) -# -# ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -# ***** END GPL LICENCE BLOCK ***** - -bl_addon_info = { - "name": "Align Tools", - "author": "Gabriel Beaudin (gabhead)", - "version": (0,1), - "blender": (2, 5, 3), - "api": 31854, - "location": "Tool Shelf", - "description": "Align selected objects to the active object", - "warning": "", - "wiki_url": "http://wiki.blender.org/index.php/Extensions:2.5/Py/"\ - "Scripts/3D interaction/Align_Tools", - "tracker_url": "https://projects.blender.org/tracker/index.php?"\ - "func=detail&aid==22389&group_id=153&atid=468", - "category": "3D View"} - -"""Align Selected Objects""" - -import bpy - - -class AlignUi(bpy.types.Panel): - bl_space_type = 'VIEW_3D' - bl_region_type = 'TOOLS' - - bl_label = "Align Tools" - bl_context = "objectmode" - - def draw(self, context): - layout = self.layout - obj = context.object - - if obj != None: - row = layout.row() - row.label(text="Active object is: ", icon='OBJECT_DATA') - row = layout.row() - row.label(obj.name, icon='EDITMODE_HLT') - - box = layout.separator() - - col = layout.column() - col.label(text="Align Loc + Rot:", icon='MANIPUL') - - - col = layout.column(align=False) - col.operator("object.AlignObjects",text="XYZ") - - col = layout.column() - col.label(text="Align Location:", icon='MAN_TRANS') - - col = layout.column_flow(columns=5,align=True) - col.operator("object.AlignObjectsLocationX",text="X") - col.operator("object.AlignObjectsLocationY",text="Y") - col.operator("object.AlignObjectsLocationZ",text="Z") - col.operator("object.AlignObjectsLocationAll",text="All") - - col = layout.column() - col.label(text="Align Rotation:", icon='MAN_ROT') - - col = layout.column_flow(columns=5,align=True) - col.operator("object.AlignObjectsRotationX",text="X") - col.operator("object.AlignObjectsRotationY",text="Y") - col.operator("object.AlignObjectsRotationZ",text="Z") - col.operator("object.AlignObjectsRotationAll",text="All") - - col = layout.column() - col.label(text="Align Scale:", icon='MAN_SCALE') - - col = layout.column_flow(columns=5,align=True) - col.operator("object.AlignObjectsScaleX",text="X") - col.operator("object.AlignObjectsScaleY",text="Y") - col.operator("object.AlignObjectsScaleZ",text="Z") - col.operator("object.AlignObjectsScaleAll",text="All") - - -##Align all -def main(context): - for i in bpy.context.selected_objects: - i.location = bpy.context.active_object.location - i.rotation_euler = bpy.context.active_object.rotation_euler - -## Align Location - -def LocAll(context): - for i in bpy.context.selected_objects: - i.location = bpy.context.active_object.location - -def LocX(context): - for i in bpy.context.selected_objects: - i.location.x = bpy.context.active_object.location.x - -def LocY(context): - for i in bpy.context.selected_objects: - i.location.y = bpy.context.active_object.location.y - -def LocZ(context): - for i in bpy.context.selected_objects: - i.location.z = bpy.context.active_object.location.z - -## Aling Rotation -def RotAll(context): - for i in bpy.context.selected_objects: - i.rotation_euler = bpy.context.active_object.rotation_euler - -def RotX(context): - for i in bpy.context.selected_objects: - i.rotation_euler.x = bpy.context.active_object.rotation_euler.x - -def RotY(context): - for i in bpy.context.selected_objects: - i.rotation_euler.y = bpy.context.active_object.rotation_euler.y - -def RotZ(context): - for i in bpy.context.selected_objects: - i.rotation_euler.z = bpy.context.active_object.rotation_euler.z -## Aling Scale -def ScaleAll(context): - for i in bpy.context.selected_objects: - i.scale = bpy.context.active_object.scale - -def ScaleX(context): - for i in bpy.context.selected_objects: - i.scale.x = bpy.context.active_object.scale.x - -def ScaleY(context): - for i in bpy.context.selected_objects: - i.scale.y = bpy.context.active_object.scale.y - -def ScaleZ(context): - for i in bpy.context.selected_objects: - i.scale.z = bpy.context.active_object.scale.z - -## Classes - -## Align All Rotation And Location -class AlignOperator(bpy.types.Operator): - '''''' - bl_idname = "object.AlignObjects" - bl_label = "Align Selected To Active" - - @classmethod - def poll(cls, context): - return context.active_object != None - - def execute(self, context): - main(context) - return {'FINISHED'} - -#######################Align Location######################## -## Align LocationAll -class AlignLocationOperator(bpy.types.Operator): - '''''' - bl_idname = "object.AlignObjectsLocationAll" - bl_label = "Align Selected Location To Active" - - @classmethod - def poll(cls, context): - return context.active_object != None - - def execute(self, context): - LocAll(context) - return {'FINISHED'} -## Align LocationX -class AlignLocationXOperator(bpy.types.Operator): - '''''' - bl_idname = "object.AlignObjectsLocationX" - bl_label = "Align Selected Location X To Active" - - @classmethod - def poll(cls, context): - return context.active_object != None - - def execute(self, context): - LocX(context) - return {'FINISHED'} -## Align LocationY -class AlignLocationYOperator(bpy.types.Operator): - '''''' - bl_idname = "object.AlignObjectsLocationY" - bl_label = "Align Selected Location Y To Active" - - @classmethod - def poll(cls, context): - return context.active_object != None - - def execute(self, context): - LocY(context) - return {'FINISHED'} -## Align LocationZ -class AlignLocationZOperator(bpy.types.Operator): - '''''' - bl_idname = "object.AlignObjectsLocationZ" - bl_label = "Align Selected Location Z To Active" - - @classmethod - def poll(cls, context): - return context.active_object != None - - def execute(self, context): - LocZ(context) - return {'FINISHED'} - -#######################Align Rotation######################## -## Align RotationAll -class AlignRotationOperator(bpy.types.Operator): - '''''' - bl_idname = "object.AlignObjectsRotationAll" - bl_label = "Align Selected Rotation To Active" - - @classmethod - def poll(cls, context): - return context.active_object != None - - def execute(self, context): - RotAll(context) - return {'FINISHED'} -## Align RotationX -class AlignRotationXOperator(bpy.types.Operator): - '''''' - bl_idname = "object.AlignObjectsRotationX" - bl_label = "Align Selected Rotation X To Active" - - @classmethod - def poll(cls, context): - return context.active_object != None - - def execute(self, context): - RotX(context) - return {'FINISHED'} -## Align RotationY -class AlignRotationYOperator(bpy.types.Operator): - '''''' - bl_idname = "object.AlignObjectsRotationY" - bl_label = "Align Selected Rotation Y To Active" - - @classmethod - def poll(cls, context): - return context.active_object != None - - def execute(self, context): - RotY(context) - return {'FINISHED'} -## Align RotationZ -class AlignRotationZOperator(bpy.types.Operator): - '''''' - bl_idname = "object.AlignObjectsRotationZ" - bl_label = "Align Selected Rotation Z To Active" - - @classmethod - def poll(cls, context): - return context.active_object != None - - def execute(self, context): - RotZ(context) - return {'FINISHED'} -#######################Align Scale######################## -## Scale All -class AlignScaleOperator(bpy.types.Operator): - '''''' - bl_idname = "object.AlignObjectsScaleAll" - bl_label = "Align Selected Scale To Active" - - @classmethod - def poll(cls, context): - return context.active_object != None - - def execute(self, context): - ScaleAll(context) - return {'FINISHED'} -## Align ScaleX -class AlignScaleXOperator(bpy.types.Operator): - '''''' - bl_idname = "object.AlignObjectsScaleX" - bl_label = "Align Selected Scale X To Active" - - @classmethod - def poll(cls, context): - return context.active_object != None - - def execute(self, context): - ScaleX(context) - return {'FINISHED'} -## Align ScaleY -class AlignScaleYOperator(bpy.types.Operator): - '''''' - bl_idname = "object.AlignObjectsScaleY" - bl_label = "Align Selected Scale Y To Active" - - @classmethod - def poll(cls, context): - return context.active_object != None - - def execute(self, context): - ScaleY(context) - return {'FINISHED'} -## Align ScaleZ -class AlignScaleZOperator(bpy.types.Operator): - '''''' - bl_idname = "object.AlignObjectsScaleZ" - bl_label = "Align Selected Scale Z To Active" - - @classmethod - def poll(cls, context): - return context.active_object != None - - def execute(self, context): - ScaleZ(context) - return {'FINISHED'} - -## registring -def register(): - pass - -def unregister(): - pass - -if __name__ == "__main__": - register() diff --git a/space_view3d_materials_utils.py b/space_view3d_materials_utils.py deleted file mode 100644 index 5d680eae..00000000 --- a/space_view3d_materials_utils.py +++ /dev/null @@ -1,689 +0,0 @@ -#(c) 2010 Michael Williamson (michaelw) -#ported from original by Michael Williamsn -# -#tested r28370 -# -# -# ##### 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -# ##### END GPL LICENSE BLOCK ##### - -bl_addon_info = { - "name": "Material Utils", - "author": "michaelw", - "version": (1,3), - "blender": (2, 5, 3), - "api": 31854, - "location": "View3D > Q key", - "description": "Menu of material tools (assign, select by etc) in the 3D View", - "warning": "", - "wiki_url": "http://wiki.blender.org/index.php/Extensions:2.5/Py/"\ - "Scripts/3D interaction/Materials Utils", - "tracker_url": "https://projects.blender.org/tracker/index.php?"\ - "func=detail&aid=22140&group_id=153&atid=469", - "category": "3D View"} - -""" -This script has several functions and operators... grouped for convenience -* assign material: - offers the user a list of ALL the materials in the blend file and an additional "new" entry - the chosen material will be assigned to all the selected objects in object mode. - - in edit mode the selected faces get the selected material applied. - - if the user chose "new" the new material can be renamed using the "last operator" section of the toolbox - After assigning the material "clean material slots" and "material to texface" are auto run to keep things tidy (see description bellow) - - -* select by material - in object mode this offers the user a menu of all materials in the blend file - any objects using the selected material will become selected, any objects without the material will be removed from selection. - - in edit mode: the menu offers only the materials attached to the current object. It will select the faces that use the material and deselect those that do not. - -* clean material slots - for all selected objects any empty material slots or material slots with materials that are not used by the mesh faces will be removed. - -* Any un-used materials and slots will be removed -""" - - -import bpy -from bpy.props import* - - -def replace_material(m1 , m2, all_objects = False): - #replace material named m1 with material named m2 - #m1 is the name of original material - #m2 is the name of the material to replace it with - #'all' will replace throughout the blend file - try: - matorg = bpy.data.materials[m1] - matrep = bpy.data.materials[m2] - - - #store active object - scn = bpy.context.scene - ob_active = bpy.context.active_object - - if all_objects: - objs = bpy.data.objects - - else: - objs = bpy.context.selected_editable_objects - - for ob in objs: - if ob.type == 'MESH': - scn.objects.active = ob - print(ob.name) - ms = ob.material_slots.values() - - for m in ms: - if m.material == matorg: - m.material = matrep - #don't break the loop as the material can be - # ref'd more than once - - #restore active object - scn.objects.active = ob_active - except: - print('no match to replace') - -def select_material_by_name(find_mat): - #in object mode selects all objects with material find_mat - #in edit mode selects all faces with material find_mat - - #check for editmode - editmode = False - - scn = bpy.context.scene - actob = bpy.context.active_object - if actob.mode == 'EDIT': - editmode =True - bpy.ops.object.mode_set() - - - if not editmode: - objs = bpy.data.objects - for ob in objs: - if ob.type == 'MESH': - ms = ob.material_slots.values() - for m in ms: - if m.material.name == find_mat: - ob.select = True - #the active object may not have the mat! - #set it to one that does! - scn.objects.active = ob - break - else: - ob.select = False - - #deselect non-meshes - else: - ob.select = False - - else: - #it's editmode, so select the faces - ob = actob - ms = ob.material_slots.values() - - #same material can be on multiple slots - slot_indeces =[] - i = 0 - found = False - for m in ms: - if m.material.name == find_mat: - slot_indeces.append(i) - found = True - i += 1 - me = ob.data - for f in me.faces: - if f.material_index in slot_indeces: - f.select = True - else: - f.select = False - me.update - if editmode: - bpy.ops.object.mode_set(mode = 'EDIT') - -def mat_to_texface(): - #assigns the first image in each material to the faces in the active uvlayer - #for all selected objects - - #check for editmode - editmode = False - - actob = bpy.context.active_object - if actob.mode == 'EDIT': - editmode =True - bpy.ops.object.mode_set() - - for ob in bpy.context.selected_editable_objects: - #get the materials from slots - ms = ob.material_slots.values() - - #build a list of images, one per material - images=[] - #get the textures from the mats - for m in ms: - gotimage = False - textures = m.material.texture_slots.values() - if len(textures) >= 1: - for t in textures: - if t != None: - tex = t.texture - if tex.type == 'IMAGE': - img = tex.image - images.append(img) - gotimage =True - break - - if not gotimage: - print('noimage on', m.name) - images.append(None) - - #now we have the images - #applythem to the uvlayer - - - me = ob.data - #got uvs? - if not me.uv_textures: - scn = bpy.context.scene - scn.objects.active = ob - bpy.ops.mesh.uv_texture_add() - scn.objects.active = actob - - #get active uvlayer - for t in me.uv_textures: - if t.active: - uvtex = t.data.values() - for f in me.faces: - #check that material had an image! - if images[f.material_index] != None: - uvtex[f.index].image = images[f.material_index] - uvtex[f.index].use_image = True - else: - uvtex[f.index].use_image = False - - me.update() - - - if editmode: - bpy.ops.object.mode_set(mode = 'EDIT') - - - -def assignmatslots(ob, matlist): - #given an object and a list of material names - #removes all material slots form the object - #adds new ones for each material in matlist - #adds the materials to the slots as well. - - scn = bpy.context.scene - ob_active = bpy.context.active_object - scn.objects.active = ob - - for s in ob.material_slots: - bpy.ops.object.material_slot_remove() - - - #re-add them and assign material - i = 0 - for m in matlist: - mat = bpy.data.materials[m] - bpy.ops.object.material_slot_add() - ob.material_slots.values()[i].material = mat - i += 1 - - #restore active object: - scn.objects.active = ob_active - - -def cleanmatslots(): - #check for edit mode - editmode = False - actob = bpy.context.active_object - if actob.mode == 'EDIT': - editmode =True - bpy.ops.object.mode_set() - - - objs = bpy.context.selected_editable_objects - - for ob in objs: - print(ob.name) - mats = ob.material_slots.keys() - - #check the faces on the mesh to build a list of used materials - usedMatIndex =[] #we'll store used materials indices here - faceMats =[] - me = ob.data - for f in me.faces: - #get the material index for this face... - faceindex = f.material_index - - #indices will be lost: Store face mat use by name - currentfacemat = mats[faceindex] - faceMats.append(currentfacemat) - - - #check if index is already listed as used or not - found = 0 - for m in usedMatIndex: - if m == faceindex: - found = 1 - #break - - if found == 0: - #add this index to the list - usedMatIndex.append(faceindex) - - #re-assign the used mats to the mesh and leave out the unused - ml = [] - mnames = [] - for u in usedMatIndex: - ml.append( mats[u] ) - #we'll need a list of names to get the face indices... - mnames.append(mats[u]) - - assignmatslots(ob, ml) - - - #restore face indices: - i = 0 - for f in me.faces: - matindex = mnames.index(faceMats[i]) - f.material_index = matindex - i += 1 - print('Done') - if editmode: - bpy.ops.object.mode_set(mode = 'EDIT') - - - - - -def assign_mat(matname="Default"): - #get active object so we can restore it later - actob = bpy.context.active_object - - #check if material exists, if it doesn't then create it - mats =bpy.data.materials - found = False - for m in mats: - if m.name == matname: - target = m - found = True - break - if not found: - target = bpy.data.materials.new(matname) - - - #if objectmodeset all faces - editmode = False - allfaces = True - if actob.mode == 'EDIT': - editmode =True - allfaces = False - bpy.ops.object.mode_set() - - objs = bpy.context.selected_editable_objects - - for ob in objs: - #set the active object to our object - scn = bpy.context.scene - scn.objects.active = ob - - - #check if the material is on the object already - if ob.type =='MESH': - #check material slots for matname material - found=False - i = 0 - mats = ob.material_slots - for m in mats: - if m.name == matname: - found =True - index = i - #make slot active - ob.active_material_index = i - break - i += 1 - - if not found: - index=i - #the material is not attached to the object - #so attach it! - - #add a material slot - bpy.ops.object.material_slot_add() - - #make slot active - ob.active_material_index = i - - #and assign material to slot - ob.material_slots.values()[i].material = target - #now assign the material: - me =ob.data - if allfaces: - for f in me.faces: - f.material_index = index - elif allfaces == False: - for f in me.faces: - if f.select: - f.material_index = index - me.update - - #restore the active object - bpy.context.scene.objects.active = actob - if editmode: - bpy.ops.object.mode_set(mode = 'EDIT') - - - -def check_texture(img,mat): - #finds a texture from an image - #makes a texture if needed - #adds it to the material if it isn't there already - - tex = bpy.data.textures.get(img.name) - - if tex is None: - tex = bpy.data.textures.new(name=img.name, type='IMAGE') - - tex.image = img - - #see if the material already uses this tex - #add it if needed - found = False - for m in mat.texture_slots: - if m and m.texture == tex: - found = True - break - if not found and mat: - mtex = mat.texture_slots.add() - mtex.texture = tex - mtex.texture_coords = 'UV' - mtex.use_map_color_diffuse = True - -def texface_to_mat(): - # editmode check here! - editmode = False - ob = bpy.context.object - if ob.mode =='EDIT': - editmode = True - bpy.ops.object.mode_set() - - for ob in bpy.context.selected_editable_objects: - - faceindex = [] - unique_images = [] - - # get the texface images and store indices - if (ob.data.uv_textures): - for f in ob.data.uv_textures.active.data: - if f.image: - img = f.image - #build list of unique images - if img not in unique_images: - unique_images.append(img) - faceindex.append(unique_images.index(img)) - - else: - img = None - faceindex.append(None) - - - - #check materials for images exist; create if needed - matlist = [] - for i in unique_images: - if i: - print(i.name) - try: - m = bpy.data.materials[i.name] - - except: - m = bpy.data.materials.new(name = i.name) - continue - - finally: - matlist.append(m.name) - # add textures if needed - check_texture(i,m) - - #set up the object material slots - assignmatslots(ob, matlist) - - #set texface indices to material slot indices.. - me = ob.data - - i = 0 - for f in faceindex: - if f != None: - me.faces[i].material_index = f - i += 1 - if editmode: - bpy.ops.object.mode_set(mode = 'EDIT') - - -#operator classes: -#--------------------------------------------------------------------- - -class VIEW3D_OT_texface_to_material(bpy.types.Operator): - '''''' - bl_idname = "texface_to_material" - bl_label = "MW Texface Images to Material/Texture" - bl_options = {'REGISTER', 'UNDO'} - - @classmethod - def poll(cls, context): - return context.active_object != None - - def execute(self, context): - if context.selected_editable_objects: - texface_to_mat() - return {'FINISHED'} - else: - self.report({'WARNING'}, "No editable selected objects, could not finish") - return {'CANCELLED'} - -class VIEW3D_OT_assign_material(bpy.types.Operator): - '''assign a material to the selection''' - bl_idname = "assign_material" - bl_label = "MW Assign Material" - bl_options = {'REGISTER', 'UNDO'} - - matname = StringProperty(name = 'Material Name', - description = 'Name of Material to Assign', - default = "", maxlen = 21) - - @classmethod - def poll(cls, context): - return context.active_object != None - - def execute(self, context): - mn = self.properties.matname - print(mn) - assign_mat(mn) - cleanmatslots() - mat_to_texface() - return {'FINISHED'} - -class VIEW3D_OT_clean_material_slots(bpy.types.Operator): - '''removes any material slots from the - selected objects that are not used by the mesh''' - bl_idname = "clean_material_slots" - bl_label = "MW Clean Material Slots" - bl_options = {'REGISTER', 'UNDO'} - - @classmethod - def poll(cls, context): - return context.active_object != None - - def execute(self, context): - cleanmatslots() - return {'FINISHED'} - -class VIEW3D_OT_material_to_texface(bpy.types.Operator): - '''''' - bl_idname = "material_to_texface" - bl_label = "MW Material Images to Texface" - bl_options = {'REGISTER', 'UNDO'} - - @classmethod - def poll(cls, context): - return context.active_object != None - - def execute(self, context): - mat_to_texface() - return {'FINISHED'} - -class VIEW3D_OT_select_material_by_name(bpy.types.Operator): - '''''' - bl_idname = "select_material_by_name" - bl_label = "MW Select Material By Name" - bl_options = {'REGISTER', 'UNDO'} - matname = StringProperty(name = 'Material Name', - description = 'Name of Material to Select', - default = "", maxlen = 21) - - @classmethod - def poll(cls, context): - return context.active_object != None - - def execute(self, context): - mn = self.properties.matname - select_material_by_name(mn) - return {'FINISHED'} - - -class VIEW3D_OT_replace_material(bpy.types.Operator): - '''assign a material to the selection''' - bl_idname = "replace_material" - bl_label = "MW Replace Material" - bl_options = {'REGISTER', 'UNDO'} - - matorg = StringProperty(name = 'Material to Replace', - description = 'Name of Material to Assign', - default = "", maxlen = 21) - - matrep = StringProperty(name = 'Replacement material', - description = 'Name of Material to Assign', - default = "", maxlen = 21) - - all_objects = BoolProperty(name ='all_objects', - description="replace for all objects in this blend file", - default = True) - - @classmethod - def poll(cls, context): - return context.active_object != None - - def execute(self, context): - m1 = self.properties.matorg - m2 = self.properties.matrep - all = self.properties.all_objects - replace_material(m1,m2,all) - return {'FINISHED'} - -#menu classes -#------------------------------------------------------------------------------- -class VIEW3D_MT_master_material(bpy.types.Menu): - bl_label = "Master Material Menu" - - def draw(self, context): - layout = self.layout - layout.operator_context = 'INVOKE_REGION_WIN' - - layout.menu("VIEW3D_MT_assign_material", icon='ZOOMIN') - layout.menu("VIEW3D_MT_select_material", icon='HAND') - layout.separator() - layout.operator("clean_material_slots", - text = 'Clean Material Slots', icon='CANCEL') - layout.operator("material_to_texface", - text = 'Material to Texface',icon='FACESEL_HLT') - layout.operator("texface_to_material", - text = 'Texface to Material',icon='FACESEL_HLT') - - layout.separator() - layout.operator("replace_material", - text = 'Replace Material', icon='ARROW_LEFTRIGHT') - - - -class VIEW3D_MT_assign_material(bpy.types.Menu): - bl_label = "Assign Material" - - def draw(self, context): - layout = self.layout - layout.operator_context = 'INVOKE_REGION_WIN' - - ob = context - layout.label - for i in range (len(bpy.data.materials)): - - layout.operator("assign_material", - text=bpy.data.materials[i].name, - icon='MATERIAL_DATA').matname = bpy.data.materials[i].name - - layout.operator("assign_material",text="Add New", - icon='ZOOMIN') - -class VIEW3D_MT_select_material(bpy.types.Menu): - bl_label = "Select by Material" - - def draw(self, context): - layout = self.layout - layout.operator_context = 'INVOKE_REGION_WIN' - - ob = context.object - layout.label - if ob.mode == 'OBJECT': - #show all materials in entire blend file - for i in range (len(bpy.data.materials)): - - layout.operator("select_material_by_name", - text=bpy.data.materials[i].name, - icon='MATERIAL_DATA').matname = bpy.data.materials[i].name - - - elif ob.mode == 'EDIT': - #show only the materials on this object - mats = ob.material_slots.keys() - for m in mats: - layout.operator("select_material_by_name", - text=m, - icon='MATERIAL_DATA').matname = m - - -def register(): - km = bpy.context.window_manager.keyconfigs.active.keymaps['3D View'] - kmi = km.items.new('wm.call_menu', 'Q', 'PRESS') - kmi.properties.name = "VIEW3D_MT_master_material" - -def unregister(): - km = bpy.context.window_manager.keyconfigs.active.keymaps['3D View'] - for kmi in km.items: - if kmi.idname == 'wm.call_menu': - if kmi.properties.name == "VIEW3D_MT_master_material": - km.items.remove(kmi) - break - -if __name__ == "__main__": - register() diff --git a/space_view3d_panel_measure.py b/space_view3d_panel_measure.py deleted file mode 100644 index c5df0a03..00000000 --- a/space_view3d_panel_measure.py +++ /dev/null @@ -1,1065 +0,0 @@ -# ##### 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -# ##### END GPL LICENSE BLOCK ##### - -bl_addon_info = { - "name": "Measure Panel", - "author": "Buerbaum Martin (Pontiac)", - "version": (0, 7, 9), - "blender": (2, 5, 3), - "api": 31854, - "location": "View3D > Properties > Measure", - "description": "Measure distances between objects", - "warning": "", - "wiki_url": "http://wiki.blender.org/index.php/Extensions:2.5/Py/" \ - "Scripts/3D_interaction/Panel_Measure", - "tracker_url": "https://projects.blender.org/tracker/index.php?" \ - "func=detail&aid=21445&group_id=153&atid=469", - "category": "3D View"} - -""" -Measure panel - -This script displays in OBJECT MODE: -* The distance of the 3D cursor to the origin of the - 3D space (if NOTHING is selected). -* The distance of the 3D cursor to the center of an object - (if exactly ONE object is selected). -* The distance between 2 object centers - (if exactly TWO objects are selected). -* The surface area of any selected mesh object. - -Display in EDIT MODE (Local and Global space supported): -* The distance of the 3D cursor to the origin - (in Local space it is the object center instead). -* The distance of the 3D cursor to a selected vertex. -* The distance between 2 selected vertices. - -Usage: - -This functionality can be accessed via the -"Properties" panel in 3D View ([N] key). - -It's very helpful to use one or two "Empty" objects with -"Snap during transform" enabled for fast measurement. - -Version history: -v0.7.9 - Updated scene properties for changes in property API. - See http://lists.blender.org/pipermail/bf-committers/ - 2010-September/028654.html - Synced API changes in7from local copy. -v0.7.8 - Various Py API changes by Campbell ... - bl_default_closed -> bl_options = {'DEFAULT_CLOSED'} - x.verts -> x.vertices - @classmethod def poll(cls, context) - No "location" in bl_addon_info->name - bl_addon_info->api -v0.7.7 - One more change to the callback registration code. - Now it should finally work as intended. -v0.7.6 - API changes (r885, r886) - register & unregister function -v0.7.5.3 - Small fix for bug in v0.7.5.1 - (location was off when object was moved) -v0.7.5.2 - Changed callback registration back to original code & - fixed bug in there (use bl_idname instead of bl_label) -v0.7.5.1 - Global mode is now taking rotation into account properly. -v0.7.5 - Fixed lagging and drawing issues. -v0.7.4 - Fixed the add_modal_handler and callback_add code. - Thanks to jesterKing for pointing that out :-) -v0.7.3.1 - Fixed bug that made all lines in Blender stippled :-) -v0.7.3 - Added display of delta x/y/z value in 3d view. - * Inspired by warpi's patch here: - http://blenderartists.org/forum/showpost.php?p=1671033&postcount=47 - * Also added display of dx,dy,dz lines - * Changed the "dist" colors to something not already used - by x/y/z axes. -v0.7.2 - Merged changes from trunk (scripts_addons r847): - * obj.matrix -> obj.matrix_world - * vert.selected -> vert.select - * face.selected -> face.select - * bl_addon_info: warning, wiki_url, tracker_url - * removed __bpydoc__ - * Use fontid=0 for blf functions. 0 is the default font. -v0.7.1 - Merged changes by Campbell: - * Fix for API change: Collections like context.selected_objects - no longer return None for empty lists. - * Update for mathutils, also stripped some redundant - conversions (Mostly "Vector()" stuff) -v0.7 - Initial support for drawing lines. - (Thanks to Algorith for applying my perspective_matrix patch.) - The distance value (in BUs) is also drawn in the 3D view now. - Also fixed some wrong calculations of global/local distances. - Now it's really "what you see is what is calculated". - Use bl_addon_info for Add-On information. - Use "3D View" in category & name - Renamed reenter_editmode to view3d.reenter_editmode. - Renamed panel_measure.py into space_view3d_panel_measure.py - Active object is only used for edit-mode now. Measurement - with exactly one sel. (but not necessarily active) object - now gets the obj via the sel-object array. - API change Mathutils -> mathutils (r557) - Deselecting 1 of 2 objects now works correctly (active object is ignored). - Force a redraw of the area so disabling the "measure_panel_draw" - checkbox will clear the line/text. - Only calculate area (CPU heavy) if a "area" checkbox is enabled. -v0.6.4 - Fixed unneeded meshdata duplication (sometimes crashes Blender). - The script now correctly calculated the surface area (faceAreaGlobal) - of scaled meshes. - http://projects.blender.org/tracker/ - ?func=detail&atid=453&aid=21913&group_id=153 -v0.6.3 - Added register & unregister functions. -v0.6.2 - Fixed precision of second area property. - Reduced display precision to 5 (instead of 6). - Added (commented out code) for shortcut [F5] for - updating EditMode selection & calculation. - Changed the script so it can be managed from the "Add-Ons" tab - in the user preferences. - Corrected FSF address. -v0.6.1 - Updated reenter_editmode operator description. - Fixed search for selected mesh objects. - Added "BU^2" after values that are not yet translated via "unit". -v0.6 - *) Fix: Removed EditMode/ObjectMode toggle stuff. This causes all the - crashes and is generally not stable. - Instead I've added a manual "refresh" button. - I registered a new operator OBJECT_OT_reenter_editmode for this. - *) Use "unit" settings (i.e. none/metric/imperial) - *) Fix: Only display surface area (>=3 objects) if return value is >=0. - *) Minor: Renamed objectFaceArea to objectSurfaceArea - *) Updated Vector() and tuple() usage. - *) Fixed some comments. -v0.5 - Global surface area (object mode) is now calculated as well. - Support area calculation for face selection. - Also made measurement panel closed by default. (Area calculation - may use up a lot of CPU/RAM in extreme cases) -v0.4.1 - Various cleanups. - Using the shorter "scene" instead of "context.scene" - New functions measureGlobal() and measureLocal() for - user-friendly access to the "space" setting. -v0.4 - Calculate & display the surface area of mesh - objects (local space only right now). - Expanded global/local switch. - Made "local" option for 3Dcursor-only in edit mode actually work. - Fixed local/global calculation for 3Dcursor<->vertex in edit mode. -v0.3.2 - Fixed calculation & display of local/global coordinates. - The user can now select via dropdown which space is wanted/needed - Basically this is a bugfix and new feature at the same time :-) -v0.3.1 - Fixed bug where "measure_panel_dist" wasn't defined - before it was used. - Also added the distance calculation "origin -> 3D cursor" for edit mode. -v0.3 - Support for mesh edit mode (1 or 2 selected vertices) -v0.2.1 - Small fix (selecting nothing didn't calculate the distance - of the cursor from the origin anymore) -v0.2 - Distance value is now displayed via a FloatProperty widget (and - therefore saved to file too right now [according to ideasman42]. - The value is save inside the scene right now.) - Thanks goes to ideasman42 (Campbell Barton) for helping me out on this. -v0.1 - Initial revision. Seems to work fine for most purposes. - -More links: -http://gitorious.org/blender-scripts/blender-measure-panel-script -http://blenderartists.org/forum/showthread.php?t=177800 -""" - -import bpy -from bpy.props import * -from mathutils import Vector, Matrix -import bgl -import blf - - -# Precicion for display of float values. -PRECISION = 4 - -# Name of the custom properties as stored in the scene. -COLOR_LOCAL = (1.0, 0.5, 0.0, 0.8) -COLOR_GLOBAL = (0.5, 0.0, 1.0, 0.8) - - -# Returns a single selected object. -# Returns None if more than one (or nothing) is selected. -# Note: Ignores the active object. -def getSingleObject(context): - if len(context.selected_objects) == 1: - return context.selected_objects[0] - - return None - - -# Returns a list with 2 3D points (Vector) and a color (RGBA) -# depending on the current view mode and the selection. -def getMeasurePoints(context): - sce = context.scene - - # Get a single selected object (or nothing). - obj = getSingleObject(context) - - if (context.mode == 'EDIT_MESH'): - obj = context.active_object - - if (obj and obj.type == 'MESH' and obj.data): - # Get mesh data from Object. - mesh = obj.data - - # Get transformation matrix from object. - ob_mat = obj.matrix_world - # Also make an inversed copy! of the matrix. - ob_mat_inv = ob_mat.copy().invert() - # And a transposed one... - ob_mat_trans = ob_mat.copy().transpose() - - # Get the selected vertices. - # @todo: Better (more efficient) way to do this? - verts_selected = [v for v in mesh.vertices if v.select == 1] - - if len(verts_selected) == 0: - # Nothing selected. - # We measure the distance from... - # local ... the object center to the 3D cursor. - # global ... the origin to the 3D cursor. - cur_loc = sce.cursor_location - obj_loc = obj.location.copy() - - # Convert to local space, if needed. - if measureLocal(sce): - p1 = cur_loc - p2 = obj_loc - return (p1, p2, COLOR_GLOBAL) - - else: - p1 = Vector((0.0, 0.0, 0.0)) - p2 = cur_loc - return (p1, p2, COLOR_GLOBAL) - - elif len(verts_selected) == 1: - # One vertex selected. - # We measure the distance from the - # selected vertex object to the 3D cursor. - cur_loc = sce.cursor_location - vert_loc = verts_selected[0].co.copy() - obj_loc = obj.location.copy() - - # Convert to local or global space. - if measureLocal(sce): - p1 = obj_loc + vert_loc - p2 = cur_loc - return (p1, p2, COLOR_LOCAL) - - else: - p1 = vert_loc * ob_mat_trans - p2 = cur_loc - return (p1, p2, COLOR_GLOBAL) - - elif len(verts_selected) == 2: - # Two vertices selected. - # We measure the distance between the - # two selected vertices. - obj_loc = obj.location.copy() - vert1_loc = verts_selected[0].co.copy() - vert2_loc = verts_selected[1].co.copy() - - # Convert to local or global space. - if measureLocal(sce): - p1 = obj_loc + vert1_loc - p2 = obj_loc + vert2_loc - return (p1, p2, COLOR_LOCAL) - - else: - p1 = vert1_loc * ob_mat_trans - p2 = vert2_loc * ob_mat_trans - return (p1, p2, COLOR_GLOBAL) - - else: - return None - - elif (context.mode == 'OBJECT'): - # We are working on object mode. - - if len(context.selected_objects) > 2: - return None - elif len(context.selected_objects) == 2: - # 2 objects selected. - # We measure the distance between the 2 selected objects. - obj1, obj2 = context.selected_objects - obj1_loc = obj1.location.copy() - obj2_loc = obj2.location.copy() - return (obj1_loc, obj2_loc, COLOR_GLOBAL) - - elif (obj): - # One object selected. - # We measure the distance from the object to the 3D cursor. - cur_loc = sce.cursor_location - obj_loc = obj.location.copy() - return (obj_loc, cur_loc, COLOR_GLOBAL) - - elif not context.selected_objects: - # Nothing selected. - # We measure the distance from the origin to the 3D cursor. - p1 = Vector((0.0, 0.0, 0.0)) - p2 = sce.cursor_location - return (p1, p2, COLOR_GLOBAL) - - else: - return None - - -# Return the area of a face (in global space). -# @note Copies the functionality of the following functions, -# but also respects the scaling (via the "obj.matrix_world" parameter): -# @sa: rna_mesh.c:rna_MeshFace_area_get -# @sa: math_geom.c:area_quad_v3 -# @sa: math_geom.c:area_tri_v3 -def faceAreaGlobal(face, obj): - area = 0.0 - - mat = obj.matrix_world - - if len(face.vertices) == 4: - # Quad - - # Get vertex indices - v1, v2, v3, v4 = face.vertices - - # Get vertex data - v1 = obj.data.vertices[v1] - v2 = obj.data.vertices[v2] - v3 = obj.data.vertices[v3] - v4 = obj.data.vertices[v4] - - # Apply transform matrix to vertex coordinates. - v1 = v1.co * mat - v2 = v2.co * mat - v3 = v3.co * mat - v4 = v4.co * mat - - vec1 = v2 - v1 - vec2 = v4 - v1 - - n = vec1.cross(vec2) - - area = n.length / 2.0 - - vec1 = v4 - v3 - vec2 = v2 - v3 - - n = vec1.cross(vec2) - - area += n.length / 2.0 - - elif len(face.vertices) == 3: - # Triangle - - # Get vertex indices - v1, v2, v3 = face.vertices - - # Get vertex data - v1 = obj.data.vertices[v1] - v2 = obj.data.vertices[v2] - v3 = obj.data.vertices[v3] - - # Apply transform matrix to vertex coordinates. - v1 = v1.co * mat - v2 = v2.co * mat - v3 = v3.co * mat - - vec1 = v3 - v2 - vec2 = v1 - v2 - - n = vec1.cross(vec2) - - area = n.length / 2.0 - - return area - - -# Calculate the surface area of a mesh object. -# *) Set selectedOnly=1 if you only want to count selected faces. -# *) Set globalSpace=1 if you want to calculate -# the global surface area (object mode). -# Note: Be sure you have updated the mesh data before -# running this with selectedOnly=1! -# @todo Support other object types (surfaces, etc...)? -def objectSurfaceArea(obj, selectedOnly, globalSpace): - if (obj and obj.type == 'MESH' and obj.data): - areaTotal = 0 - - mesh = obj.data - - # Count the area of all the faces. - for face in mesh.faces: - if not selectedOnly or face.select: - if globalSpace: - areaTotal += faceAreaGlobal(face, obj) - else: - areaTotal += face.area - - return areaTotal - - # We can not calculate an area for this object. - return -1 - - -# User friendly access to the "space" setting. -def measureGlobal(sce): - return (sce.measure_panel_transform == "measure_global") - - -# User friendly access to the "space" setting. -def measureLocal(sce): - return (sce.measure_panel_transform == "measure_local") - - -# Converts 3D coordinates in a 3DRegion -# into 2D screen coordinates for that region. -def region3d_get_2d_coordinates(context, loc_3d): - # Get screen information - mid_x = context.region.width / 2.0 - mid_y = context.region.height / 2.0 - width = context.region.width - height = context.region.height - - # Get matrices - view_mat = context.space_data.region_3d.perspective_matrix - total_mat = view_mat - - # order is important - vec = total_mat * Vector((loc_3d[0], loc_3d[1], loc_3d[2], 1.0)) - - # dehomogenise - vec = Vector(( - vec[0] / vec[3], - vec[1] / vec[3], - vec[2] / vec[3])) - - x = int(mid_x + vec[0] * width / 2.0) - y = int(mid_y + vec[1] * height / 2.0) - - return Vector((x, y, 0)) - - -def draw_measurements_callback(self, context): - sce = context.scene - - draw = 0 - if hasattr(sce, "measure_panel_draw"): - draw = sce.measure_panel_draw - - # 2D drawing code example - #bgl.glBegin(bgl.GL_LINE_STRIP) - #bgl.glVertex2i(0, 0) - #bgl.glVertex2i(80, 100) - #bgl.glEnd() - - # Get measured 3D points and colors. - line = getMeasurePoints(context) - if (line and draw): - p1, p2, color = line - - # Get and convert the Perspective Matrix of the current view/region. - view3d = bpy.context.space_data - region = view3d.region_3d - perspMatrix = region.perspective_matrix - tempMat = [perspMatrix[i][j] for i in range(4) for j in range(4)] - perspBuff = bgl.Buffer(bgl.GL_FLOAT, 16, tempMat) - - # --- - # Store previous OpenGL settings. - # Store MatrixMode - MatrixMode_prev = bgl.Buffer(bgl.GL_INT, [1]) - bgl.glGetIntegerv(bgl.GL_MATRIX_MODE, MatrixMode_prev) - MatrixMode_prev = MatrixMode_prev[0] - - # Store projection matrix - ProjMatrix_prev = bgl.Buffer(bgl.GL_DOUBLE, [16]) - bgl.glGetFloatv(bgl.GL_PROJECTION_MATRIX, ProjMatrix_prev) - - # Store Line width - lineWidth_prev = bgl.Buffer(bgl.GL_FLOAT, [1]) - bgl.glGetFloatv(bgl.GL_LINE_WIDTH, lineWidth_prev) - lineWidth_prev = lineWidth_prev[0] - - # Store GL_BLEND - blend_prev = bgl.Buffer(bgl.GL_BYTE, [1]) - bgl.glGetFloatv(bgl.GL_BLEND, blend_prev) - blend_prev = blend_prev[0] - - line_stipple_prev = bgl.Buffer(bgl.GL_BYTE, [1]) - bgl.glGetFloatv(bgl.GL_LINE_STIPPLE, line_stipple_prev) - line_stipple_prev = line_stipple_prev[0] - - # Store glColor4f - color_prev = bgl.Buffer(bgl.GL_FLOAT, [4]) - bgl.glGetFloatv(bgl.GL_COLOR, color_prev) - - # --- - # Prepare for 3D drawing - bgl.glLoadIdentity() - bgl.glMatrixMode(bgl.GL_PROJECTION) - bgl.glLoadMatrixf(perspBuff) - - bgl.glEnable(bgl.GL_BLEND) - bgl.glEnable(bgl.GL_LINE_STIPPLE) - - # --- - # Draw 3D stuff. - width = 1 - bgl.glLineWidth(width) - # X - bgl.glColor4f(1, 0, 0, 0.8) - bgl.glBegin(bgl.GL_LINE_STRIP) - bgl.glVertex3f(p1[0], p1[1], p1[2]) - bgl.glVertex3f(p2[0], p1[1], p1[2]) - bgl.glEnd() - # Y - bgl.glColor4f(0, 1, 0, 0.8) - bgl.glBegin(bgl.GL_LINE_STRIP) - bgl.glVertex3f(p1[0], p1[1], p1[2]) - bgl.glVertex3f(p1[0], p2[1], p1[2]) - bgl.glEnd() - # Z - bgl.glColor4f(0, 0, 1, 0.8) - bgl.glBegin(bgl.GL_LINE_STRIP) - bgl.glVertex3f(p1[0], p1[1], p1[2]) - bgl.glVertex3f(p1[0], p1[1], p2[2]) - bgl.glEnd() - - # Dist - width = 2 - bgl.glLineWidth(width) - bgl.glColor4f(color[0], color[1], color[2], color[3]) - bgl.glBegin(bgl.GL_LINE_STRIP) - bgl.glVertex3f(p1[0], p1[1], p1[2]) - bgl.glVertex3f(p2[0], p2[1], p2[2]) - bgl.glEnd() - - # --- - # Restore previous OpenGL settings - bgl.glLoadIdentity() - bgl.glMatrixMode(MatrixMode_prev) - bgl.glLoadMatrixf(ProjMatrix_prev) - bgl.glLineWidth(lineWidth_prev) - if not blend_prev: - bgl.glDisable(bgl.GL_BLEND) - if not line_stipple_prev: - bgl.glDisable(bgl.GL_LINE_STIPPLE) - bgl.glColor4f(color_prev[0], - color_prev[1], - color_prev[2], - color_prev[3]) - - # --- - # Draw (2D) text - # We do this after drawing the lines so - # we can draw it OVER the line. - coord_2d = region3d_get_2d_coordinates(context, p2 + (p1 - p2) * 0.5) - OFFSET_LINE = 10 # Offset the text a bit to the right. - OFFSET_Y = 15 # Offset of the lines. - OFFSET_VALUE = 30 # Offset of value(s) from the text. - dist = (p1 - p2).length - - texts = [("Dist:", round(dist, PRECISION)), - ("X:", round(abs(p1[0] - p2[0]), PRECISION)), - ("Y:", round(abs(p1[1] - p2[1]), PRECISION)), - ("Z:", round(abs(p1[2] - p2[2]), PRECISION))] - - # Draw all texts - # @todo Get user pref for text color in 3D View - bgl.glColor4f(1.0, 1.0, 1.0, 1.0) - blf.size(0, 12, 72) # Prevent font size to randomly change. - - loc_x = coord_2d[0] + OFFSET_LINE - loc_y = coord_2d[1] - for t in texts: - text = t[0] - value = str(t[1]) + " BU" - - blf.position(0, loc_x, loc_y, 0) - blf.draw(0, text) - blf.position(0, loc_x + OFFSET_VALUE, loc_y, 0) - blf.draw(0, value) - - loc_y -= OFFSET_Y - - -class VIEW3D_OT_display_measurements(bpy.types.Operator): - '''Display the measurements made in the 'Measure' panel''' - # Do not use bl_idname here (class name is used instead), - # so the callback can be added easily. - #bl_idname = "view3d.display_measurements" - bl_label = "Display the measurements made in the" \ - " 'Measure' panel in the 3D View." - bl_options = {'REGISTER'} - - def modal(self, context, event): - context.area.tag_redraw() - - return {'FINISHED'} - - def execute(self, context): - if context.area.type == 'VIEW_3D': - mgr_ops = context.window_manager.operators.values() - if not self.bl_idname in [op.bl_idname for op in mgr_ops]: - # Add the region OpenGL drawing callback - for WINregion in context.area.regions: - if WINregion.type == 'WINDOW': - context.window_manager.add_modal_handler(self) - self._handle = WINregion.callback_add( - draw_measurements_callback, - (self, context), - 'POST_PIXEL') - - print("Measure panel display callback added") - - return {'RUNNING_MODAL'} - - return {'CANCELLED'} - - else: - self.report({'WARNING'}, "View3D not found, cannot run operator") - return {'CANCELLED'} - - -class VIEW3D_OT_reenter_editmode(bpy.types.Operator): - bl_label = "Re-enter EditMode" - bl_idname = "view3d.reenter_editmode" - bl_description = "Update mesh data of an active mesh object." \ - " This is done by exiting and re-entering mesh edit mode." - bl_options = {'REGISTER'} - - def invoke(self, context, event): - - # Get the active object. - obj = context.active_object - - if (obj and obj.type == 'MESH' and context.mode == 'EDIT_MESH'): - # Exit and re-enter mesh EditMode. - bpy.ops.object.mode_set(mode='OBJECT') - bpy.ops.object.mode_set(mode='EDIT') - return {'FINISHED'} - - return {'CANCELLED'} - - -class VIEW3D_PT_measure(bpy.types.Panel): - bl_space_type = 'VIEW_3D' - bl_region_type = 'UI' - bl_label = "Measure" - bl_options = {'DEFAULT_CLOSED'} - - @classmethod - def poll(cls, context): - # Only display this panel in the object and edit mode 3D view. - if (context.area.type == 'VIEW_3D' and - (context.mode == 'EDIT_MESH' - or context.mode == 'OBJECT')): - return 1 - - return 0 - - def draw_header(self, context): - layout = self.layout - sce = context.scene - - # Force a redraw. - # This prevents the lines still be drawn after - # disabling the "measure_panel_draw" checkbox. - # @todo Better solution? - context.area.tag_redraw() - - # Execute operator (this adds the callback) - # if it wasn't done yet. - bpy.ops.view3d.display_measurements() - - # Define property for the draw setting. - bpy.types.Scene.measure_panel_draw = bpy.props.BoolProperty( - description="Draw distances in 3D View", - default=1) - - # Define property for the calc-area setting. - # @todo prevent double calculations for each refresh automatically? - bpy.types.Scene.measure_panel_calc_area = bpy.props.BoolProperty( - description="Calculate mesh surface area (heavy CPU" \ - " usage on bigger meshes)", - default=0) - - layout.prop(sce, "measure_panel_draw") - - def draw(self, context): - layout = self.layout - sce = context.scene - - # Get a single selected object (or nothing). - obj = getSingleObject(context) - - # Define a temporary attribute for the distance value - bpy.types.Scene.measure_panel_dist = bpy.props.FloatProperty( - name="Distance", - attr="measure_panel_dist", - precision=PRECISION, - unit="LENGTH") - bpy.types.Scene.measure_panel_area1 = bpy.props.FloatProperty( - attr="measure_panel_area1", - precision=PRECISION, - unit="AREA") - bpy.types.Scene.measure_panel_area2 = bpy.props.FloatProperty( - attr="measure_panel_area2", - precision=PRECISION, - unit="AREA") - - TRANSFORM = [ - ("measure_global", "Global", - "Calculate values in global space."), - ("measure_local", "Local", - "Calculate values inside the local object space.")] - - # Define dropdown for the global/local setting - bpy.types.Scene.measure_panel_transform = bpy.props.EnumProperty( - name="Space", - description="Choose in which space you want to measure.", - items=TRANSFORM, - default='measure_global') - - if (context.mode == 'EDIT_MESH'): - obj = context.active_object - - if (obj and obj.type == 'MESH' and obj.data): - # "Note: a Mesh will return the selection state of the mesh - # when EditMode was last exited. A Python script operating - # in EditMode must exit EditMode before getting the current - # selection state of the mesh." - # http://www.blender.org/documentation/249PythonDoc/ - # /Mesh.MVert-class.html#sel - # We can only provide this by existing & re-entering EditMode. - # @todo: Better way to do this? - - # Get mesh data from Object. - mesh = obj.data - - # Get transformation matrix from object. - ob_mat = obj.matrix_world - # Also make an inversed copy! of the matrix. - ob_mat_inv = ob_mat.copy() - Matrix.invert(ob_mat_inv) - - # Get the selected vertices. - # @todo: Better (more efficient) way to do this? - verts_selected = [v for v in mesh.vertices if v.select == 1] - - if len(verts_selected) == 0: - # Nothing selected. - # We measure the distance from... - # local ... the object center to the 3D cursor. - # global ... the origin to the 3D cursor. - - # Get the 2 measure points - line = getMeasurePoints(context) - if line != 0: - dist_vec = line[0] - line[1] - - sce.measure_panel_dist = dist_vec.length - - row = layout.row() - row.prop(sce, "measure_panel_dist") - - row = layout.row() - row.label(text="", icon='CURSOR') - row.label(text="", icon='ARROW_LEFTRIGHT') - if measureLocal(sce): - row.label(text="Obj. Center") - else: - row.label(text="Origin [0,0,0]") - - row = layout.row() - row.operator("view3d.reenter_editmode", - text="Update selection & distance") -# @todo -# description="The surface area value can" \ -# " not be updated in mesh edit mode" \ -# " automatically. Press this button" \ -# " to do this manually, after you changed" \ -# " the selection.") - - row = layout.row() - row.prop(sce, - "measure_panel_transform", - expand=True) - - elif len(verts_selected) == 1: - # One vertex selected. - # We measure the distance from the - # selected vertex object to the 3D cursor. - - # Get the 2 measure points - line = getMeasurePoints(context) - if line != 0: - dist_vec = line[0] - line[1] - - sce.measure_panel_dist = dist_vec.length - - row = layout.row() - row.prop(sce, "measure_panel_dist") - - row = layout.row() - row.label(text="", icon='CURSOR') - row.label(text="", icon='ARROW_LEFTRIGHT') - row.label(text="", icon='VERTEXSEL') - - row = layout.row() - row.operator("view3d.reenter_editmode", - text="Update selection & distance") - - row = layout.row() - row.prop(sce, - "measure_panel_transform", - expand=True) - - elif len(verts_selected) == 2: - # Two vertices selected. - # We measure the distance between the - # two selected vertices. - - # Get the 2 measure points - line = getMeasurePoints(context) - if line != 0: - dist_vec = line[0] - line[1] - - sce.measure_panel_dist = dist_vec.length - - row = layout.row() - row.prop(sce, "measure_panel_dist") - - row = layout.row() - row.label(text="", icon='VERTEXSEL') - row.label(text="", icon='ARROW_LEFTRIGHT') - row.label(text="", icon='VERTEXSEL') - - row = layout.row() - row.operator("view3d.reenter_editmode", - text="Update selection & distance") - - row = layout.row() - row.prop(sce, - "measure_panel_transform", - expand=True) - - else: - row = layout.row() - row.prop(sce, "measure_panel_calc_area", - text="Surface area (selected faces):") - - if (sce.measure_panel_calc_area): - # Get selected faces - # @todo: Better (more efficient) way to do this? - faces_selected = [f for f in mesh.faces - if f.select == 1] - - if len(faces_selected) > 0: - area = objectSurfaceArea(obj, True, - measureGlobal(sce)) - if (area >= 0): - row = layout.row() - row.label( - text=str(len(faces_selected)), - icon='FACESEL') - sce.measure_panel_area1 = area - row.prop(sce, "measure_panel_area1") - - row = layout.row() - row.operator("view3d.reenter_editmode", - text="Update selection & area") - - row = layout.row() - row.prop(sce, - "measure_panel_transform", - expand=True) - - else: - row = layout.row() - row.label(text="Selection not supported.", - icon='INFO') - - row = layout.row() - row.operator("view3d.reenter_editmode", - text="Update selection") - - else: - row = layout.row() - row.operator("view3d.reenter_editmode", - text="Update selection") - - elif (context.mode == 'OBJECT'): - # We are working on object mode. - - if len(context.selected_objects) > 2: - # We have more that 2 objects selected... - - row = layout.row() - row.prop(sce, "measure_panel_calc_area", - text="Surface area (selected faces):") - - if (sce.measure_panel_calc_area): - - mesh_objects = [o for o in context.selected_objects - if (o.type == 'MESH')] - - if (len(mesh_objects) > 0): - # ... and at least one of them is a mesh. - - # Calculate and display surface area of the objects. - # @todo: Convert to scene units! We do not have a - # FloatProperty field here for automatic conversion. - - row = layout.row() - for o in mesh_objects: - area = objectSurfaceArea(o, False, - measureGlobal(sce)) - if (area >= 0): - row = layout.row() - row.label(text=o.name, icon='OBJECT_DATA') - row.label(text=str(round(area, PRECISION)) - + " BU^2") - - row = layout.row() - row.prop(sce, - "measure_panel_transform", - expand=True) - - elif len(context.selected_objects) == 2: - # 2 objects selected. - # We measure the distance between the 2 selected objects. - - obj1, obj2 = context.selected_objects - - # Get the 2 measure points - line = getMeasurePoints(context) - if line != 0: - dist_vec = line[0] - line[1] - - sce.measure_panel_dist = dist_vec.length - - row = layout.row() - row.prop(sce, "measure_panel_dist") - - row = layout.row() - row.label(text="", icon='OBJECT_DATA') - row.prop(obj1, "name", text="") - - row.label(text="", icon='ARROW_LEFTRIGHT') - - row.label(text="", icon='OBJECT_DATA') - row.prop(obj2, "name", text="") - - row = layout.row() - row.prop(sce, "measure_panel_calc_area", - text="Surface area:") - - if (sce.measure_panel_calc_area): - # Calculate and display surface area of the objects. - area1 = objectSurfaceArea(obj1, False, measureGlobal(sce)) - area2 = objectSurfaceArea(obj2, False, measureGlobal(sce)) - if (area1 >= 0 or area2 >= 0): - if (area1 >= 0): - row = layout.row() - row.label(text=obj1.name, icon='OBJECT_DATA') - sce.measure_panel_area1 = area1 - row.prop(sce, "measure_panel_area1") - - if (area2 >= 0): - row = layout.row() - row.label(text=obj2.name, icon='OBJECT_DATA') - sce.measure_panel_area2 = area2 - row.prop(sce, "measure_panel_area2") - - row = layout.row() - row.prop(sce, - "measure_panel_transform", - expand=True) - - elif (obj): - # One object selected. - # We measure the distance from the object to the 3D cursor. - - # Get the 2 measure points - line = getMeasurePoints(context) - if line != 0: - dist_vec = line[0] - line[1] - - sce.measure_panel_dist = dist_vec.length - - row = layout.row() - #row.label(text=str(dist_vec.length)) - row.prop(sce, "measure_panel_dist") - - row = layout.row() - row.label(text="", icon='CURSOR') - - row.label(text="", icon='ARROW_LEFTRIGHT') - - row.label(text="", icon='OBJECT_DATA') - row.prop(obj, "name", text="") - - row = layout.row() - row.prop(sce, "measure_panel_calc_area", - text="Surface area:") - - if (sce.measure_panel_calc_area): - # Calculate and display surface area of the object. - area = objectSurfaceArea(obj, False, measureGlobal(sce)) - if (area >= 0): - row = layout.row() - row.label(text=obj.name, icon='OBJECT_DATA') - sce.measure_panel_area1 = area - row.prop(sce, "measure_panel_area1") - - row = layout.row() - row.prop(sce, - "measure_panel_transform", - expand=True) - - elif not context.selected_objects: - # Nothing selected. - # We measure the distance from the origin to the 3D cursor. - - # Get the 2 measure points - line = getMeasurePoints(context) - if line != 0: - dist_vec = line[0] - line[1] - - sce.measure_panel_dist = dist_vec.length - - row = layout.row() - row.prop(sce, "measure_panel_dist") - - row = layout.row() - row.label(text="", icon='CURSOR') - row.label(text="", icon='ARROW_LEFTRIGHT') - row.label(text="Origin [0,0,0]") - - else: - row = layout.row() - row.label(text="Selection not supported.", - icon='INFO') - - -def register(): - pass - - -def unregister(): - pass - -if __name__ == "__main__": - register() diff --git a/space_view3d_property_chart.py b/space_view3d_property_chart.py deleted file mode 100644 index 290b2941..00000000 --- a/space_view3d_property_chart.py +++ /dev/null @@ -1,230 +0,0 @@ -# -# ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -# ***** END GPL LICENCE BLOCK ***** - -bl_addon_info = { - "name": "Object Property Chart", - "author": "Campbell Barton (ideasman42)", - "version": (0,1), - "blender": (2, 5, 3), - "api": 31667, - "location": "Tool Shelf", - "description": "Edit arbitrary selected properties for objects of the same type", - "warning": "", - "wiki_url": "http://wiki.blender.org/index.php/Extensions:2.5/Py/"\ - "Scripts/3D interaction/Object Property Chart", - "tracker_url": "https://projects.blender.org/tracker/index.php?"\ - "func=detail&aid=22701&group_id=153&atid=469", - "category": "3D View"} - -"""List properties of selected objects""" - -import bpy - -def _property_chart_data_get(self, context): - # eg. context.active_object - obj = eval("context.%s" % self.context_data_path_active) - - if obj is None: - return None, None - - # eg. context.selected_objects[:] - selected_objects = eval("context.%s" % self.context_data_path_selected)[:] - - if not selected_objects: - return None, None - - return obj, selected_objects - - -def _property_chart_draw(self, context): - ''' - This function can run for different types. - ''' - obj, selected_objects = _property_chart_data_get(self, context) - - if not obj: - return - - # active first - try: - active_index = selected_objects.index(obj) - except ValueError: - active_index = -1 - - if active_index > 0: # not the first alredy - selected_objects[0], selected_objects[active_index] = selected_objects[active_index], selected_objects[0] - - id_storage = context.scene - - strings = id_storage.get(self._PROP_STORAGE_ID) - - if strings is None: - strings = id_storage[self._PROP_STORAGE_ID] = "data data.name" - - if strings: - - def obj_prop_get(obj, attr_string): - """return a pair (rna_base, "rna_property") to give to the rna UI property function""" - attrs = attr_string.split(".") - val_new = obj - for i, attr in enumerate(attrs): - val_old = val_new - val_new = getattr(val_old, attr, Ellipsis) - - if val_new == Ellipsis: - return None, None - return val_old, attrs[-1] - - strings = strings.split() - - prop_all = [] - - for obj in selected_objects: - prop_pairs = [] - prop_found = False - for attr_string in strings: - prop_pairs.append(obj_prop_get(obj, attr_string)) - if prop_found == False and prop_pairs[-1] != (None, None): - prop_found = True - - if prop_found: - prop_all.append((obj, prop_pairs)) - - - # Collected all props, now display them all - layout = self.layout - - row = layout.row(align=True) - - col = row.column() - col.label(text="name") - for obj, prop_pairs in prop_all: - col.prop(obj, "name", text="") - - for i in range(len(strings)): - col = row.column() - - # name and copy button - rowsub = col.row(align=False) - rowsub.label(text=strings[i].rsplit(".", 1)[-1]) - props = rowsub.operator("wm.chart_copy", text="", icon='PASTEDOWN', emboss=False) - props.data_path_active = self.context_data_path_active - props.data_path_selected = self.context_data_path_selected - props.data_path = strings[i] - - for obj, prop_pairs in prop_all: - data, attr = prop_pairs[i] - if data: - col.prop(data, attr, text="")# , emboss=obj==active_object - else: - col.label(text="") - - # edit the display props - col = layout.column() - col.label(text="Object Properties") - col.prop(id_storage, '["%s"]' % self._PROP_STORAGE_ID, text="") - - -class View3DEditProps(bpy.types.Panel): - bl_space_type = 'VIEW_3D' - bl_region_type = 'UI' - - bl_label = "Property Chart" - bl_context = "objectmode" - - _PROP_STORAGE_ID = "view3d_edit_props" - - # _property_chart_draw needs these - context_data_path_active = "active_object" - context_data_path_selected = "selected_objects" - - draw = _property_chart_draw - - -class SequencerEditProps(bpy.types.Panel): - bl_space_type = 'SEQUENCE_EDITOR' - bl_region_type = 'UI' - - bl_label = "Property Chart" - - _PROP_STORAGE_ID = "sequencer_edit_props" - - # _property_chart_draw needs these - context_data_path_active = "scene.sequence_editor.active_strip" - context_data_path_selected = "selected_sequences" - - draw = _property_chart_draw - - @classmethod - def poll(cls, context): - return context.scene.sequence_editor is not None - -# Operator to copy properties - - -def _property_chart_copy(self, context): - obj, selected_objects = _property_chart_data_get(self, context) - - if not obj: - return - - data_path = self.properties.data_path - - # quick & nasty method! - for obj_iter in selected_objects: - if obj != obj_iter: - try: - exec("obj_iter.%s = obj.%s" % (data_path, data_path)) - except: - # just incase we need to know what went wrong! - import traceback - traceback.print_exc() - -from bpy.props import StringProperty - - -class CopyPropertyChart(bpy.types.Operator): - "Open a path in a file browser" - bl_idname = "wm.chart_copy" - bl_label = "Copy properties from active to selected" - - data_path_active = StringProperty() - data_path_selected = StringProperty() - data_path = StringProperty() - - def execute(self, context): - # so attributes are found for '_property_chart_data_get()' - self.context_data_path_active = self.properties.data_path_active - self.context_data_path_selected = self.properties.data_path_selected - - _property_chart_copy(self, context) - - return {'FINISHED'} - - -def register(): - pass - - -def unregister(): - pass - -if __name__ == "__main__": - register() diff --git a/space_view3d_spacebar_menu.py b/space_view3d_spacebar_menu.py deleted file mode 100644 index 6feffb1d..00000000 --- a/space_view3d_spacebar_menu.py +++ /dev/null @@ -1,1471 +0,0 @@ -#3d_cursor_menu.py (c) 2010 Jonathan Smith (JayDez) -#Original Script by: Mariano Hidalgo (uselessdreamer) -#contributed to by: Crouch, sim88, sam, meta-androcto -# -#Tested with r28146 -# -# ##### 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -# ##### END GPL LICENSE BLOCK ##### - -bl_addon_info = { - "name": "Dynamic Spacebar Menu", - "author": "JayDez, sim88, meta-androcto", "sam" - "version": (1,5), - "blender": (2, 5, 3), - "api": 31854, - "location": "View3D > Spacebar", - "description": "Context sensitive spacebar menu", - "warning": "", - "wiki_url": "http://wiki.blender.org/index.php/Extensions:2.5/Py/"\ - "Scripts/3D_interaction/Dynamic_Spacebar_Menu", - "tracker_url": "https://projects.blender.org/tracker/index.php?"\ - "func=detail&aid=22060&group_id=153&atid=469", - "category": "3D View"} - -""" -Dynamic Menu -This adds a the Dynamic Spacebar Menu in the View3D. - -Usage: -* This script gives a basic menu with common simple tools for easy access. -* Very similar to the Spacebar menu in 2.49 -* Context sensitive for Object. Edit, Sculpt, Pose, Weight/Texture/Vertex Paint. -* Object sensitive based on object selected in edit mode. - -Version history: -v1.5 - (meta-androcto) - adding context sensitive menus. -v1.3 - (JayDez) - Changed toggle editmode to an if statement, so that - if you are in editmode it will show change to object mode but - otherwise it shows change to edit mode. Also added separate icons - for change to edit mode and to object mode. -v1.2 - (JayDez) - Editing docs, changing 3D cursor to dynamic menu, - reorganizing menu. -v1.1 - (meta-androcto) - added editmode menu -v1.0 - (meta-androcto) - initial final revision (commited to contrib) -v0.1 through 0.9 - various tests/contributions by various people and scripts - Devs: JayDez, Crouch, sim88, meta-androcto, Sam - Scripts: 3D Cursor Menu, Original Dynamic Menu -""" - -import bpy -from bpy import * -from mathutils import Vector, Matrix -import math - -# Dynamic Menu -class VIEW3D_MT_Space_Dynamic_Menu(bpy.types.Menu): - bl_label = "Dynamic Spacebar Menu" - - def draw(self, context): - layout = self.layout - settings = context.tool_settings - layout.operator_context = 'INVOKE_REGION_WIN' - - ob = context - if ob.mode == 'OBJECT': - # Object mode - - # Search Menu - layout.operator("wm.search_menu", text="Search", icon='VIEWZOOM') - layout.separator() - - # Add Menu block - layout.menu("VIEW3D_MT_AddMenu", icon='OBJECT_DATAMODE') - layout.separator() - - # Transform block - layout.menu("VIEW3D_MT_TransformMenu", icon='MANIPUL') - - # Mirror block - layout.menu("VIEW3D_MT_MirrorMenu", icon='MOD_MIRROR') - layout.separator() - - # Parent block - layout.menu("VIEW3D_MT_ParentMenu", icon='ROTACTIVE') - - # Group block - layout.menu("VIEW3D_MT_GroupMenu", icon='GROUP') - layout.separator() - - # Modifier block - layout.operator_menu_enum("object.modifier_add", "type" , icon='MODIFIER') - layout.separator() - - # Cursor Block - layout.menu("VIEW3D_MT_CursorMenu", icon='CURSOR') - layout.separator() - - # Align block - layout.menu("VIEW3D_MT_AlignMenu", icon='ALIGN') - layout.separator() - - # Select block - layout.menu("VIEW3D_MT_SelectMenu", icon='RESTRICT_SELECT_OFF') - - # Toolshelf block - layout.operator("view3d.toolshelf", icon='MENU_PANEL') - layout.separator() - - # Properties block - layout.operator("view3d.properties", icon='MENU_PANEL') - layout.separator() - - # Toggle Editmode - layout.operator("object.editmode_toggle", text="Enter Edit Mode", - icon='EDITMODE_HLT') - - # Delete block - layout.operator("object.delete", text="Delete Object", - icon='CANCEL') - - - elif ob.mode == 'EDIT_MESH': - # Edit mode - - # Search Menu - layout.operator("wm.search_menu", text="Search", icon='VIEWZOOM') - - # Add block - bl_label = "Create" - layout.menu("INFO_MT_mesh_add", text="Add Mesh", - icon='EDITMODE_HLT') - layout.separator() - - # Transform block - layout.menu("VIEW3D_MT_TransformMenu", icon='MANIPUL') - layout.separator() - - # Mirror block - layout.menu("VIEW3D_MT_MirrorMenu", icon='MOD_MIRROR') - layout.separator() - - # Cursor block - layout.menu("VIEW3D_MT_EditCursorMenu", icon='CURSOR') - layout.separator() - - # Edit block - layout.menu("VIEW3D_MT_edit_TK", icon='OUTLINER_OB_MESH') - layout.separator() - - # Multi Select - layout.menu("VIEW3D_MT_edit_multi", icon='VERTEXSEL') - layout.separator() - - # Extrude block - layout.menu("VIEW3D_MT_edit_mesh_extrude", icon='EDITMODE_HLT') - layout.separator() - - # Tools block - layout.menu("VIEW3D_MT_edit_mesh_specials", icon='MODIFIER') - layout.menu("VIEW3D_MT_uv_map", icon='MOD_UVPROJECT') - - # Select block - layout.menu("VIEW3D_MT_SelectMenu", icon='RESTRICT_SELECT_OFF') - - # Toolshelf block - layout.operator("view3d.toolshelf", icon='MENU_PANEL') - layout.separator() - - # Properties block - layout.operator("view3d.properties", icon='MENU_PANEL') - layout.separator() - - # Toggle Object Mode - layout.operator("object.editmode_toggle", text="Enter Object Mode", - icon='OBJECT_DATAMODE') - - # Delete Block - layout.operator("mesh.delete", icon='CANCEL') - - if ob.mode == 'EDIT_CURVE': - # Curve menu - - # Search Menu - layout.operator("wm.search_menu", text="Search", icon='VIEWZOOM') - - # Transform block - layout.menu("VIEW3D_MT_TransformMenu", icon='MANIPUL') - layout.separator() - - # Mirror block - layout.menu("VIEW3D_MT_MirrorMenu", icon='MOD_MIRROR') - layout.separator() - - # Proportional block - layout.prop_menu_enum(settings, "proportional_edit", icon= "PROP_CON") - layout.prop_menu_enum(settings, "proportional_edit_falloff", icon= "SMOOTHCURVE") - layout.separator() - - # Edit Control Points - layout.menu("VIEW3D_MT_EditCurveCtrlpoints", - icon='CURVE_BEZCURVE') - layout.separator() - - # Edit Curve Specials - layout.menu("VIEW3D_MT_EditCurveSpecials", - icon='MODIFIER') - layout.separator() - - # Cursor block - layout.menu("VIEW3D_MT_CursorMenu", icon='CURSOR') - layout.separator() - - # Select Curve Block - layout.menu("VIEW3D_MT_SelectCurveMenu", icon='RESTRICT_SELECT_OFF') - layout.separator() - - # Toolshelf block - layout.operator("view3d.toolshelf", icon='MENU_PANEL') - layout.separator() - - # Properties block - layout.operator("view3d.properties", icon='MENU_PANEL') - layout.separator() - - # Toggle Objectmode - layout.operator("object.editmode_toggle", text="Enter Object Mode", - icon='OBJECT_DATA') - - # Delete block - layout.operator("object.delete", text="Delete Object", - icon='CANCEL') - - if ob.mode == 'EDIT_SURFACE': - # Surface menu - - # Search Menu - layout.operator("wm.search_menu", text="Search", icon='VIEWZOOM') - - # Transform block - layout.menu("VIEW3D_MT_TransformMenu", icon='MANIPUL') - layout.separator() - - # Mirror block - layout.menu("VIEW3D_MT_MirrorMenu", icon='MOD_MIRROR') - layout.separator() - - # Proportional block - layout.prop_menu_enum(settings, "proportional_edit", icon= "PROP_CON") - layout.prop_menu_enum(settings, "proportional_edit_falloff", icon= "SMOOTHCURVE") - - # Edit Curve Specials - layout.menu("VIEW3D_MT_EditCurveSpecials", - icon='MODIFIER') - layout.separator() - - # Cursor block - layout.menu("VIEW3D_MT_CursorMenu", icon='CURSOR') - layout.separator() - - # Select Surface - layout.menu("VIEW3D_MT_SelectSurface", icon='RESTRICT_SELECT_OFF') - layout.separator() - - # Toolshelf block - layout.operator("view3d.toolshelf", icon='MENU_PANEL') - layout.separator() - - # Properties block - layout.operator("view3d.properties", icon='MENU_PANEL') - layout.separator() - - # Toggle Objectmode - layout.operator("object.editmode_toggle", text="Enter Object Mode", - icon='OBJECT_DATA') - - # Delete block - layout.operator("object.delete", text="Delete Object", - icon='CANCEL') - - if ob.mode == 'EDIT_METABALL': - # Metaball menu - - #Search Menu - layout.operator("wm.search_menu", text="Search", icon='VIEWZOOM') - - # Transform block - layout.menu("VIEW3D_MT_TransformMenu", icon='MANIPUL') - layout.separator() - - # Mirror block - layout.menu("VIEW3D_MT_MirrorMenu", icon='MOD_MIRROR') - layout.separator() - - # Proportional block - layout.prop_menu_enum(settings, "proportional_edit", icon= "PROP_CON") - layout.prop_menu_enum(settings, "proportional_edit_falloff", icon= "SMOOTHCURVE") - - # Cursor block - layout.menu("VIEW3D_MT_CursorMenu", icon='CURSOR') - layout.separator() - - #Select Metaball - layout.menu("VIEW3D_MT_SelectMetaball", icon='RESTRICT_SELECT_OFF') - layout.separator() - - # Toolshelf block - layout.operator("view3d.toolshelf", icon='MENU_PANEL') - layout.separator() - - # Properties block - layout.operator("view3d.properties", icon='MENU_PANEL') - layout.separator() - - # Toggle Objectmode - layout.operator("object.editmode_toggle", text="Enter Object Mode", - icon='OBJECT_DATA') - - # Delete block - layout.operator("object.delete", text="Delete Object", - icon='CANCEL') - - elif ob.mode == 'EDIT_LATTICE': - # Lattice menu - - #Search Menu - layout.operator("wm.search_menu", text="Search", icon='VIEWZOOM') - - # Transform block - layout.menu("VIEW3D_MT_TransformMenu", icon='MANIPUL') - layout.separator() - - # Mirror block - layout.menu("VIEW3D_MT_MirrorMenu", icon='MOD_MIRROR') - layout.separator() - - # Proportional block - layout.prop_menu_enum(settings, "proportional_edit", icon= "PROP_CON") - layout.prop_menu_enum(settings, "proportional_edit_falloff", icon= "SMOOTHCURVE") - - # Cursor block - layout.menu("VIEW3D_MT_CursorMenu", icon='CURSOR') - layout.separator() - - #Select Lattice - layout.menu("VIEW3D_MT_select_edit_lattice", icon='RESTRICT_SELECT_OFF') - layout.separator() - - layout.operator("lattice.make_regular") - layout.separator() - - # Toolshelf block - layout.operator("view3d.toolshelf", icon='MENU_PANEL') - layout.separator() - - # Properties block - layout.operator("view3d.properties", icon='MENU_PANEL') - layout.separator() - - # Toggle Objectmode - layout.operator("object.editmode_toggle", text="Enter Object Mode", - icon='OBJECT_DATA') - - # Delete block - layout.operator("object.delete", text="Delete Object", - icon='CANCEL') - - - if context.mode == 'PARTICLE': - # Particle menu - - #Search Menu - layout.operator("wm.search_menu", text="Search", icon='VIEWZOOM') - - # Transform block - layout.menu("VIEW3D_MT_TransformMenu", icon='MANIPUL') - layout.separator() - - # Mirror block - layout.menu("VIEW3D_MT_MirrorMenu", icon='MOD_MIRROR') - layout.separator() - - # Proportional block - layout.prop_menu_enum(settings, "proportional_edit", icon= "PROP_CON") - layout.prop_menu_enum(settings, "proportional_edit_falloff", icon= "SMOOTHCURVE") - - # Cursor block - layout.menu("VIEW3D_MT_CursorMenu", icon='CURSOR') - layout.separator() - - # Toolshelf block - layout.operator("view3d.toolshelf", icon='MENU_PANEL') - layout.separator() - - # Properties block - layout.operator("view3d.properties", icon='MENU_PANEL') - layout.separator() - - # Toggle Objectmode - layout.operator("object.editmode_toggle", text="Enter Object Mode", - icon='OBJECT_DATA') - - # Delete block - layout.operator("object.delete", text="Delete Object", - icon='CANCEL') - - ob = context - if ob.mode == 'PAINT_WEIGHT': - # Weight paint menu - - # Search Menu - layout.operator("wm.search_menu", text="Search", icon='VIEWZOOM') - - # Transform block - layout.menu("VIEW3D_MT_TransformMenu", icon='MANIPUL') - layout.separator() - - # Cursor block - layout.menu("VIEW3D_MT_CursorMenu", icon='CURSOR') - layout.separator() - - # Weight Paint block - layout.menu("VIEW3D_MT_paint_weight", icon='WPAINT_HLT') - layout.separator() - - # History/Cursor Block - layout.menu("VIEW3D_MT_undoS", icon='ARROW_LEFTRIGHT') - - # Toolshelf block - layout.operator("view3d.toolshelf", icon='MENU_PANEL') - layout.separator() - - # Properties block - layout.operator("view3d.properties", icon='MENU_PANEL') - layout.separator() - - # Toggle Objectmode - layout.operator("object.mode_set", text="Enter Object Mode", - icon='OBJECT_DATA') - - - - elif ob.mode == 'PAINT_VERTEX': - # Vertex paint menu - - # Search Menu - layout.operator("wm.search_menu", text="Search", icon='VIEWZOOM') - - # Transform block - layout.menu("VIEW3D_MT_TransformMenu", icon='MANIPUL') - layout.separator() - - # Cursor block - layout.menu("VIEW3D_MT_CursorMenu", icon='CURSOR') - layout.separator() - - # Vertex Paint block - layout.operator("paint.vertex_color_set", icon='VPAINT_HLT') - layout.separator() - - # History/Cursor Block - layout.menu("VIEW3D_MT_undoS", icon='ARROW_LEFTRIGHT') - - # Toolshelf block - layout.operator("view3d.toolshelf", icon='MENU_PANEL') - layout.separator() - - # Properties block - layout.operator("view3d.properties", icon='MENU_PANEL') - layout.separator() - - # Toggle Objectmode - layout.operator("object.mode_set", text="Enter Object Mode", - icon='OBJECT_DATA') - - elif ob.mode == 'PAINT_TEXTURE': - # Texture paint menu - - # Search Menu - layout.operator("wm.search_menu", text="Search", icon='VIEWZOOM') - - # Transform block - layout.menu("VIEW3D_MT_TransformMenu", icon='MANIPUL') - layout.separator() - - # Cursor block - layout.menu("VIEW3D_MT_CursorMenu", icon='CURSOR') - layout.separator() - - # History/Cursor Block - layout.menu("VIEW3D_MT_undoS", icon='ARROW_LEFTRIGHT') - - # Toolshelf block - layout.operator("view3d.toolshelf", icon='MENU_PANEL') - layout.separator() - - # Properties block - layout.operator("view3d.properties", icon='MENU_PANEL') - layout.separator() - - # Toggle Objectmode - layout.operator("object.mode_set", text="Enter Object Mode", - icon='OBJECT_DATA') - - elif ob.mode == 'SCULPT': - # Sculpt menu - - # Search Menu - layout.operator("wm.search_menu", text="Search", icon='VIEWZOOM') - - # Transform block - layout.menu("VIEW3D_MT_TransformMenu", icon='MANIPUL') - layout.separator() - - # Mirror block - layout.menu("VIEW3D_MT_MirrorMenu", icon='MOD_MIRROR') - layout.separator() - - # Sculpt block - layout.menu("VIEW3D_MT_sculpt", icon='SCULPTMODE_HLT') - layout.separator() - - # Cursor block - layout.menu("VIEW3D_MT_CursorMenu", icon='CURSOR') - layout.separator() - - # History/Cursor Block - layout.menu("VIEW3D_MT_undoS", icon='ARROW_LEFTRIGHT') - - # Toolshelf block - layout.operator("view3d.toolshelf", icon='MENU_PANEL') - layout.separator() - - # Properties block - layout.operator("view3d.properties", icon='MENU_PANEL') - layout.separator() - - # Toggle Editmode - layout.operator("object.editmode_toggle", text="Enter Edit Mode", - icon='EDITMODE_HLT') - - elif ob.mode == 'EDIT_ARMATURE': - # Armature menu - - # Search Menu - layout.operator("wm.search_menu", text="Search", icon='VIEWZOOM') - - # Transform block - layout.menu("VIEW3D_MT_TransformMenu", icon='MANIPUL') - layout.separator() - - # Mirror block - layout.menu("VIEW3D_MT_MirrorMenu", icon='MOD_MIRROR') - layout.separator() - - # Cursor block - layout.menu("VIEW3D_MT_CursorMenu", icon='CURSOR') - layout.separator() - - # Edit Armature roll - layout.menu("VIEW3D_MT_edit_armature_roll", - icon='BONE_DATA') - layout.separator() - - # Edit Armature Toolkit - layout.menu("VIEW3D_MT_EditArmatureTK", - icon='ARMATURE_DATA') - layout.separator() - - # Edit Armature Name - layout.menu("VIEW3D_MT_ArmatureName", - icon='NEW') - layout.separator() - - # Parent block - layout.menu("VIEW3D_MT_ParentMenu", icon='ROTACTIVE') - - layout.separator() - layout.operator_menu_enum("armature.flags_set", "mode", text="Bone Settings") - - # Edit Armature Select - layout.menu("VIEW3D_MT_SelectArmatureMenu", - icon='RESTRICT_SELECT_OFF') - layout.separator() - - # Edit Armature Specials - layout.menu("VIEW3D_MT_armature_specials", icon='MODIFIER') - layout.separator() - - # Toggle Posemode - layout.operator("object.posemode_toggle", text="Enter Pose Mode", - icon='EDITMODE_HLT') - - # Toggle Posemode - layout.operator("object.editmode_toggle", text="Enter Object Mode", - icon='OBJECT_DATA') - - # Delete block - layout.operator("object.delete", text="Delete Object", - icon='CANCEL') - - - if context.mode == 'POSE': - # Pose mode menu - arm = context.active_object.data - - # Search Menu - layout.operator("wm.search_menu", text="Search", icon='VIEWZOOM') - - # Transform Menu - layout.menu("VIEW3D_MT_TransformMenu", icon='MANIPUL') - - # Clear Transform - layout.menu("VIEW3D_MT_pose_transform") - - # Cursor Menu - layout.menu("VIEW3D_MT_CursorMenu", icon='CURSOR') - layout.separator() - - # Select Pose Block - layout.menu("VIEW3D_MT_SelectPoseMenu", icon='RESTRICT_SELECT_OFF') - layout.separator() - - # Pose Copy Block - layout.menu("VIEW3D_MT_PoseCopy", icon='FILE') - layout.separator() - - - if arm.drawtype in ('BBONE', 'ENVELOPE'): - layout.operator("transform.transform", - text="Scale Envelope Distance").mode = 'BONESIZE' - - layout.menu("VIEW3D_MT_pose_apply") - layout.separator() - - layout.operator("pose.relax") - layout.separator() - - layout.menu("VIEW3D_MT_KeyframeMenu") - layout.separator() - - layout.menu("VIEW3D_MT_pose_pose") - layout.menu("VIEW3D_MT_pose_motion") - layout.menu("VIEW3D_MT_pose_group") - layout.separator() - - layout.menu("VIEW3D_MT_pose_ik") - layout.menu("VIEW3D_MT_PoseNames") - layout.separator() - - layout.menu("VIEW3D_MT_pose_constraints") - layout.separator() - - - - layout.operator("pose.quaternions_flip") - layout.separator() - - layout.operator_context = 'INVOKE_AREA' - layout.operator("pose.armature_layers", - text="Change Armature Layers...") - layout.operator("pose.bone_layers", text="Change Bone Layers...") - layout.separator() - - layout.menu("VIEW3D_MT_pose_showhide") - layout.operator_menu_enum("pose.flags_set", 'mode', - text="Bone Settings") - - # Toggle Editmode - layout.operator("object.editmode_toggle", text="Enter Edit Mode", - icon='EDITMODE_HLT') - - -class VIEW3D_MT_AddMenu(bpy.types.Menu): - bl_label = "Add Object Menu" - - def draw(self, context): - layout = self.layout - layout.operator_context = 'INVOKE_REGION_WIN' - - layout.menu("INFO_MT_mesh_add", text="Add Mesh", - icon='OUTLINER_OB_MESH') - layout.menu("INFO_MT_curve_add", text="Add Curve", - icon='OUTLINER_OB_CURVE') - layout.menu("INFO_MT_surface_add", text="Add Surface", - icon='OUTLINER_OB_SURFACE') - layout.operator_menu_enum("object.metaball_add", "type", - icon='OUTLINER_OB_META') - layout.operator("object.text_add", text="Add Text", - icon='OUTLINER_OB_FONT') - layout.separator() - layout.menu("INFO_MT_armature_add", text="Add Armature", - icon='OUTLINER_OB_ARMATURE') - layout.operator("object.add", text="Lattice", - icon='OUTLINER_OB_LATTICE').type = 'LATTICE' - layout.separator() - layout.operator("object.add", text="Add Empty", - icon='OUTLINER_OB_EMPTY') - layout.separator() - - layout.operator("object.camera_add", text="Camera", - icon='OUTLINER_OB_CAMERA') - layout.operator_menu_enum("object.lamp_add", "type", - icon="OUTLINER_OB_LAMP") - layout.separator() - - layout.operator_menu_enum("object.effector_add", "type", - text="Force Field", - icon='OUTLINER_OB_EMPTY') - layout.operator_menu_enum("object.group_instance_add", "group", - text="Group Instance", - icon='OUTLINER_OB_EMPTY') - - -class VIEW3D_MT_TransformMenu(bpy.types.Menu): - bl_label = "Transform Menu" - - # TODO: get rid of the custom text strings? - def draw(self, context): - layout = self.layout - - layout.operator("transform.translate", text="Grab/Move") - # TODO: sub-menu for grab per axis - layout.operator("transform.rotate", text="Rotate") - # TODO: sub-menu for rot per axis - layout.operator("transform.resize", text="Scale") - # TODO: sub-menu for scale per axis - layout.separator() - - layout.operator("transform.tosphere", text="To Sphere") - layout.operator("transform.shear", text="Shear") - layout.operator("transform.warp", text="Warp") - layout.operator("transform.push_pull", text="Push/Pull") - if context.edit_object and context.edit_object.type == 'ARMATURE': - layout.operator("armature.align") - else: - layout.operator_context = 'EXEC_REGION_WIN' - # @todo vvv See alignmenu() in edit.c of b2.4x to get this working. - layout.operator("transform.transform", - text="Align to Transform Orientation").mode = 'ALIGN' - layout.separator() - - layout.operator_context = 'EXEC_AREA' - - layout.operator("object.origin_set", - text="Geometry to Origin").type = 'GEOMETRY_ORIGIN' - layout.operator("object.origin_set", - text="Origin to Geometry").type = 'ORIGIN_GEOMETRY' - layout.operator("object.origin_set", - text="Origin to 3D Cursor").type = 'ORIGIN_CURSOR' - - -class VIEW3D_MT_MirrorMenu(bpy.types.Menu): - bl_label = "Mirror Menu" - - def draw(self, context): - layout = self.layout - - layout.operator("transform.mirror", text="Interactive Mirror") - layout.separator() - - layout.operator_context = 'INVOKE_REGION_WIN' - - props = layout.operator("transform.mirror", text="X Global") - props.constraint_axis = (True, False, False) - props.constraint_orientation = 'GLOBAL' - props = layout.operator("transform.mirror", text="Y Global") - props.constraint_axis = (False, True, False) - props.constraint_orientation = 'GLOBAL' - props = layout.operator("transform.mirror", text="Z Global") - props.constraint_axis = (False, False, True) - props.constraint_orientation = 'GLOBAL' - - if context.edit_object: - layout.separator() - - props = layout.operator("transform.mirror", text="X Local") - props.constraint_axis = (True, False, False) - props.constraint_orientation = 'LOCAL' - props = layout.operator("transform.mirror", text="Y Local") - props.constraint_axis = (False, True, False) - props.constraint_orientation = 'LOCAL' - props = layout.operator("transform.mirror", text="Z Local") - props.constraint_axis = (False, False, True) - props.constraint_orientation = 'LOCAL' - - layout.operator("object.vertex_group_mirror") - -class VIEW3D_MT_ParentMenu(bpy.types.Menu): - bl_label = "Parent Menu" - - def draw(self, context): - layout = self.layout - - layout.operator("object.parent_set", text="Set") - layout.operator("object.parent_clear", text="Clear") - -class VIEW3D_MT_GroupMenu(bpy.types.Menu): - bl_label = "Group Menu" - - def draw(self, context): - layout = self.layout - - layout.operator("group.create") - layout.operator("group.objects_remove") - - layout.separator() - - layout.operator("group.objects_add_active") - layout.operator("group.objects_remove_active") - -class VIEW3D_MT_AlignMenu(bpy.types.Menu): - bl_label = "Align Menu" - - def draw(self, context): - layout = self.layout - - layout.menu("VIEW3D_MT_view_align_selected") - - layout.separator() - - layout.operator("view3d.view_all", text="Center Cursor and View All").center = True - layout.operator("view3d.camera_to_view", text="Align Active Camera to View") - layout.operator("view3d.view_selected") - layout.operator("view3d.view_center_cursor") - -class VIEW3D_MT_SelectMenu(bpy.types.Menu): - bl_label = "Select Menu" - - def draw(self, context): - layout = self.layout - layout.operator_context = 'INVOKE_REGION_WIN' - - layout.operator("view3d.select_border") - layout.operator("view3d.select_circle") - layout.separator() - layout.operator("object.select_all", text="Select/Deselect All") - layout.operator("object.select_inverse", text="Inverse") - layout.operator("object.select_random", text="Random") - layout.operator("object.select_mirror", text="Mirror") - layout.operator("object.select_by_layer", text="Select All by Layer") - layout.operator_menu_enum("object.select_by_type", "type", text="Select All by Type...") - layout.operator("object.select_camera", text="Select Camera") - layout.separator() - layout.operator_menu_enum("object.select_grouped", "type", text="Grouped") - layout.operator_menu_enum("object.select_linked", "type", text="Linked") - layout.operator("object.select_pattern", text="Select Pattern...") - -class VIEW3D_MT_SelectEditMenu(bpy.types.Menu): - bl_label = "Select Menu" - - def draw(self, context): - layout = self.layout - - layout.operator("view3d.select_border") - layout.operator("view3d.select_circle") - - layout.separator() - - layout.operator("mesh.select_all", text="Select/Deselect All") - layout.operator("mesh.select_inverse", text="Inverse") - - layout.separator() - - layout.operator("mesh.select_random", text="Random") - layout.operator("mesh.select_nth", text="Every N Number of Verts") - layout.operator("mesh.edges_select_sharp", text="Sharp Edges") - layout.operator("mesh.faces_select_linked_flat", text="Linked Flat Faces") - layout.operator("mesh.faces_select_interior", text="Interior Faces") - layout.operator("mesh.select_axis", text="Side of Active") - - layout.separator() - - layout.operator("mesh.select_by_number_vertices", text="Triangles").type = 'TRIANGLES' - layout.operator("mesh.select_by_number_vertices", text="Quads").type = 'QUADS' - if context.scene.tool_settings.mesh_select_mode[2] == False: - layout.operator("mesh.select_non_manifold", text="Non Manifold") - layout.operator("mesh.select_by_number_vertices", text="Loose Verts/Edges").type = 'OTHER' - layout.operator("mesh.select_similar", text="Similar") - - layout.separator() - - layout.operator("mesh.select_less", text="Less") - layout.operator("mesh.select_more", text="More") - - layout.separator() - - layout.operator("mesh.select_mirror", text="Mirror") - - layout.operator("mesh.select_linked", text="Linked") - layout.operator("mesh.select_vertex_path", text="Vertex Path") - layout.operator("mesh.loop_multi_select", text="Edge Loop") - layout.operator("mesh.loop_multi_select", text="Edge Ring").ring = True - - layout.separator() - - layout.operator("mesh.loop_to_region") - layout.operator("mesh.region_to_loop") - -class VIEW3D_MT_SelectCurveMenu(bpy.types.Menu): - bl_label = "Select Menu" - - def draw(self, context): - layout = self.layout - - layout.operator("view3d.select_border") - layout.operator("view3d.select_circle") - - layout.separator() - - layout.operator("curve.select_all", text="Select/Deselect All") - layout.operator("curve.select_inverse") - layout.operator("curve.select_random") - layout.operator("curve.select_every_nth") - - layout.separator() - - layout.operator("curve.de_select_first") - layout.operator("curve.de_select_last") - layout.operator("curve.select_next") - layout.operator("curve.select_previous") - - layout.separator() - - layout.operator("curve.select_more") - layout.operator("curve.select_less") - -class VIEW3D_MT_SelectArmatureMenu(bpy.types.Menu): - bl_label = "Select Menu" - - def draw(self, context): - layout = self.layout - - layout.operator("view3d.select_border") - - - layout.separator() - - layout.operator("armature.select_all", text="Select/Deselect All") - layout.operator("armature.select_inverse", text="Inverse") - - layout.separator() - - layout.operator("armature.select_hierarchy", text="Parent").direction = 'PARENT' - layout.operator("armature.select_hierarchy", text="Child").direction = 'CHILD' - - layout.separator() - - props = layout.operator("armature.select_hierarchy", text="Extend Parent") - props.extend = True - props.direction = 'PARENT' - - props = layout.operator("armature.select_hierarchy", text="Extend Child") - props.extend = True - props.direction = 'CHILD' - - layout.operator("object.select_pattern", text="Select Pattern...") - - -class VIEW3D_MT_SelectPoseMenu(bpy.types.Menu): - bl_label = "Select Menu" - - def draw(self, context): - layout = self.layout - - layout.operator("view3d.select_border") - - layout.separator() - - layout.operator("pose.select_all", text="Select/Deselect All") - layout.operator("pose.select_inverse", text="Inverse") - layout.operator("pose.select_constraint_target", text="Constraint Target") - layout.operator("pose.select_linked", text="Linked") - - layout.separator() - - layout.operator("pose.select_hierarchy", text="Parent").direction = 'PARENT' - layout.operator("pose.select_hierarchy", text="Child").direction = 'CHILD' - - layout.separator() - - props = layout.operator("pose.select_hierarchy", text="Extend Parent") - props.extend = True - props.direction = 'PARENT' - - props = layout.operator("pose.select_hierarchy", text="Extend Child") - props.extend = True - props.direction = 'CHILD' - - layout.separator() - - layout.operator_menu_enum("pose.select_grouped", "type", text="Grouped") - layout.operator("object.select_pattern", text="Select Pattern...") - -class VIEW3D_MT_PoseCopy(bpy.types.Menu): - bl_label = "Pose Copy" - - def draw(self, context): - layout = self.layout - - layout.operator("pose.copy") - layout.operator("pose.paste") - layout.operator("pose.paste", - text="Paste X-Flipped Pose").flipped = True - layout.separator() - -class VIEW3D_MT_PoseNames(bpy.types.Menu): - bl_label = "Pose Copy" - - def draw(self, context): - layout = self.layout - - layout.operator_context = 'EXEC_AREA' - layout.operator("pose.autoside_names", - text="AutoName Left/Right").axis = 'XAXIS' - layout.operator("pose.autoside_names", - text="AutoName Front/Back").axis = 'YAXIS' - layout.operator("pose.autoside_names", - text="AutoName Top/Bottom").axis = 'ZAXIS' - - layout.operator("pose.flip_names") - - -class VIEW3D_MT_SelectSurface(bpy.types.Menu): - bl_label = "Select Menu" - - def draw(self, context): - layout = self.layout - - layout.operator("view3d.select_border") - layout.operator("view3d.select_circle") - - layout.separator() - - layout.operator("curve.select_all", text="Select/Deselect All") - layout.operator("curve.select_inverse") - layout.operator("curve.select_random") - layout.operator("curve.select_every_nth") - - layout.separator() - - layout.operator("curve.select_row") - - layout.separator() - - layout.operator("curve.select_more") - layout.operator("curve.select_less") - -class VIEW3D_MT_SelectMetaball(bpy.types.Menu): - bl_label = "Select Menu" - - def draw(self, context): - layout = self.layout - - layout.operator("view3d.select_border") - - layout.separator() - - #layout.operator("mball.select_deselect_all_metaelems") - layout.operator("mball.select_inverse_metaelems") - - layout.separator() - - layout.operator("mball.select_random_metaelems") - -class VIEW3D_MT_edit_TK(bpy.types.Menu): - bl_label = "Edit Mesh Tools" - - def draw(self, context): - layout = self.layout - row = layout.row() - - layout.operator_context = 'INVOKE_REGION_WIN' - - layout.menu("VIEW3D_MT_edit_mesh_vertices", icon='VERTEXSEL') - layout.menu("VIEW3D_MT_edit_mesh_edges", icon='EDGESEL') - layout.menu("VIEW3D_MT_edit_mesh_faces", icon='FACESEL') - layout.separator() - layout.menu("VIEW3D_MT_edit_mesh_normals", icon='META_DATA') - layout.operator("mesh.loopcut_slide", - text="Loopcut", icon='EDIT_VEC') - - - -class VIEW3D_MT_edit_multi(bpy.types.Menu): - bl_label = "Multi Select" - - def draw(self, context): - layout = self.layout - layout.operator_context = 'INVOKE_REGION_WIN' - - layout.separator() - prop = layout.operator("wm.context_set_value", text="Vertex Select", icon='VERTEXSEL') - prop.value = "(True, False, False)" - prop.data_path = "tool_settings.mesh_select_mode" - - prop = layout.operator("wm.context_set_value", text="Edge Select", icon='EDGESEL') - prop.value = "(False, True, False)" - prop.data_path = "tool_settings.mesh_select_mode" - - prop = layout.operator("wm.context_set_value", text="Face Select", icon='FACESEL') - prop.value = "(False, False, True)" - prop.data_path = "tool_settings.mesh_select_mode" - layout.separator() - - prop = layout.operator("wm.context_set_value", text="Vertex & Edge Select", icon='EDITMODE_HLT') - prop.value = "(True, True, False)" - prop.data_path = "tool_settings.mesh_select_mode" - - prop = layout.operator("wm.context_set_value", text="Vertex & Face Select", icon='ORTHO') - prop.value = "(True, False, True)" - prop.data_path = "tool_settings.mesh_select_mode" - - prop = layout.operator("wm.context_set_value", text="Edge & Face Select", icon='SNAP_FACE') - prop.value = "(False, True, True)" - prop.data_path = "tool_settings.mesh_select_mode" - layout.separator() - - prop = layout.operator("wm.context_set_value", text="Vertex & Edge & Face Select", icon='SNAP_VOLUME') - prop.value = "(True, True, True)" - prop.data_path = "tool_settings.mesh_select_mode" - -class VIEW3D_MT_editM_Edge(bpy.types.Menu): - bl_label = "Edges" - - def draw(self, context): - layout = self.layout - layout.operator_context = 'INVOKE_REGION_WIN' - - layout.operator("mesh.mark_seam") - layout.operator("mesh.mark_seam", text="Clear Seam").clear = True - layout.separator() - - layout.operator("mesh.mark_sharp") - layout.operator("mesh.mark_sharp", text="Clear Sharp").clear = True - layout.operator("mesh.extrude_move_along_normals", text="Extrude") - layout.separator() - - layout.operator("mesh.edge_rotate", - text="Rotate Edge CW").direction = 'CW' - layout.operator("mesh.edge_rotate", - text="Rotate Edge CCW").direction = 'CCW' - layout.separator() - - layout.operator("TFM_OT_edge_slide", text="Edge Slide") - layout.operator("mesh.loop_multi_select", text="Edge Loop") - layout.operator("mesh.loop_multi_select", text="Edge Ring").ring = True - layout.operator("mesh.loop_to_region") - layout.operator("mesh.region_to_loop") - - -class VIEW3D_MT_EditCurveCtrlpoints(bpy.types.Menu): - bl_label = "Control Points" - - def draw(self, context): - layout = self.layout - - edit_object = context.edit_object - - if edit_object.type == 'CURVE': - layout.operator("transform.transform").mode = 'TILT' - layout.operator("curve.tilt_clear") - layout.operator("curve.separate") - - layout.separator() - - layout.operator_menu_enum("curve.handle_type_set", "type") - - layout.separator() - - layout.menu("VIEW3D_MT_hook") - - -class VIEW3D_MT_EditCurveSegments(bpy.types.Menu): - bl_label = "Curve Segments" - - def draw(self, context): - layout = self.layout - - layout.operator("curve.subdivide") - layout.operator("curve.switch_direction") - -class VIEW3D_MT_EditCurveSpecials(bpy.types.Menu): - bl_label = "Specials" - - def draw(self, context): - layout = self.layout - - layout.operator("curve.subdivide") - layout.operator("curve.switch_direction") - layout.operator("curve.spline_weight_set") - layout.operator("curve.radius_set") - layout.operator("curve.smooth") - layout.operator("curve.smooth_radius") - -class VIEW3D_MT_EditArmatureTK(bpy.types.Menu): - bl_label = "Armature Tools" - - def draw(self, context): - layout = self.layout - - # Edit Armature - - layout.operator("transform.transform", text="Scale Envelope Distance").mode = 'BONESIZE' - - layout.operator("transform.transform", text="Scale B-Bone Width").mode = 'BONESIZE' - - layout.separator() - - layout.operator("armature.extrude_move") - - layout.operator("armature.extrude_forked") - - layout.operator("armature.duplicate_move") - layout.operator("armature.merge") - layout.operator("armature.fill") - layout.operator("armature.delete") - layout.operator("armature.separate") - - layout.separator() - - layout.operator("armature.subdivide_multi", text="Subdivide") - layout.operator("armature.switch_direction", text="Switch Direction") - -class VIEW3D_MT_ArmatureName(bpy.types.Menu): - bl_label = "Armature Name" - - def draw(self, context): - layout = self.layout - - layout.operator_context = 'EXEC_AREA' - layout.operator("armature.autoside_names", text="AutoName Left/Right").type = 'XAXIS' - layout.operator("armature.autoside_names", text="AutoName Front/Back").type = 'YAXIS' - layout.operator("armature.autoside_names", text="AutoName Top/Bottom").type = 'ZAXIS' - layout.operator("armature.flip_names") - layout.separator() - -class VIEW3D_MT_KeyframeMenu(bpy.types.Menu): - bl_label = "Keyframe Menu" - - def draw(self, context): - layout = self.layout - - # Keyframe Bleck - layout.operator("anim.keyframe_insert_menu", - text="Insert Keyframe...") - layout.operator("anim.keyframe_delete_v3d", - text="Delete Keyframe...") - layout.operator("anim.keying_set_active_set", - text="Change Keying Set...") - layout.separator() - -# Classes for VIEW3D_MT_CursorMenu() -class VIEW3D_OT_pivot_cursor(bpy.types.Operator): - "Cursor as Pivot Point" - bl_idname = "view3d.pivot_cursor" - bl_label = "Cursor as Pivot Point" - - @classmethod - def poll(cls, context): - return bpy.context.space_data.pivot_point != 'CURSOR' - - def execute(self, context): - bpy.context.space_data.pivot_point = 'CURSOR' - return {'FINISHED'} - -class VIEW3D_OT_revert_pivot(bpy.types.Operator): - "Revert Pivot Point" - bl_idname = "view3d.revert_pivot" - bl_label = "Reverts Pivot Point to median" - - @classmethod - def poll(cls, context): - return bpy.context.space_data.pivot_point != 'MEDIAN_POINT' - - def execute(self, context): - bpy.context.space_data.pivot_point = 'MEDIAN_POINT' - # @todo Change this to 'BOUDNING_BOX_CENTER' if needed... - return{'FINISHED'} - -class VIEW3D_MT_CursorMenu(bpy.types.Menu): - bl_label = "Snap Cursor Menu" - - def draw(self, context): - - layout = self.layout - layout.operator_context = 'INVOKE_REGION_WIN' - layout.operator("view3d.snap_cursor_to_selected", - text="Cursor to Selected") - layout.operator("view3d.snap_cursor_to_center", - text="Cursor to Center") - layout.operator("view3d.snap_cursor_to_grid", - text="Cursor to Grid") - layout.operator("view3d.snap_cursor_to_active", - text="Cursor to Active") - layout.separator() - layout.operator("view3d.snap_selected_to_cursor", - text="Selection to Cursor") - layout.operator("view3d.snap_selected_to_grid", - text="Selection to Grid") - layout.separator() - layout.operator("view3d.pivot_cursor", - text="Set Cursor as Pivot Point") - layout.operator("view3d.revert_pivot", - text="Revert Pivot Point") - -class VIEW3D_MT_EditCursorMenu(bpy.types.Menu): - bl_label = "Snap Cursor Menu" - - def draw(self, context): - - layout = self.layout - layout.operator_context = 'INVOKE_REGION_WIN' - layout.operator("view3d.snap_cursor_to_selected", - text="Cursor to Selected") - layout.operator("view3d.snap_cursor_to_center", - text="Cursor to Center") - layout.operator("view3d.snap_cursor_to_grid", - text="Cursor to Grid") - layout.operator("view3d.snap_cursor_to_active", - text="Cursor to Active") - layout.separator() - layout.operator("view3d.snap_selected_to_cursor", - text="Selection to Cursor") - layout.operator("view3d.snap_selected_to_grid", - text="Selection to Grid") - layout.separator() - layout.operator("view3d.pivot_cursor", - text="Set Cursor as Pivot Point") - layout.operator("view3d.revert_pivot", - text="Revert Pivot Point") - layout.operator("view3d.snap_cursor_to_edge_intersection", - text="Cursor to Edge Intersection") - layout.operator("transform.snap_type", text="Snap Tools", - icon='SNAP_ON') - -def abs(val): - if val > 0: - return val - return -val - -def LineLineIntersect (p1, p2, p3, p4): - # based on Paul Bourke's Shortest Line Between 2 lines - - min = 0.0000001 - - v1 = Vector((p1.x - p3.x, p1.y - p3.y, p1.z - p3.z)) - v2 = Vector((p4.x - p3.x, p4.y - p3.y, p4.z - p3.z)) - - if abs(v2.x) < min and abs(v2.y) < min and abs(v2.z) < min: - return None - - v3 = Vector((p2.x - p1.x, p2.y - p1.y, p2.z - p1.z)) - - if abs(v3.x) < min and abs(v3.y) < min and abs(v3.z) < min: - return None - - d1 = v1.dot(v2) - d2 = v2.dot(v3) - d3 = v1.dot(v3) - d4 = v2.dot(v2) - d5 = v3.dot(v3) - - d = d5 * d4 - d2 * d2 - - if abs(d) < min: - return None - - n = d1 * d2 - d3 * d4 - - mua = n / d - mub = (d1 + d2 * (mua)) / d4 - - return [Vector((p1.x + mua * v3.x, p1.y + mua * v3.y, p1.z + mua * v3.z)), - Vector((p3.x + mub * v2.x, p3.y + mub * v2.y, p3.z + mub * v2.z))] - -def edgeIntersect(context, operator): - - obj = context.active_object - - if (obj.type != "MESH"): - operator.report({'ERROR'}, "Object must be a mesh") - return None - - edges = []; - mesh = obj.data - verts = mesh.vertices - - is_editmode = (obj.mode == 'EDIT') - if is_editmode: - bpy.ops.object.mode_set(mode='OBJECT') - - for e in mesh.edges: - if e.select: - edges.append(e) - - if is_editmode: - bpy.ops.object.mode_set(mode='EDIT') - - if len(edges) != 2: - operator.report({'ERROR'}, "Operator requires exactly 2 edges to be selected.") - return - - line = LineLineIntersect(verts[edges[0].vertices[0]].co, verts[edges[0].vertices[1]].co, verts[edges[1].vertices[0]].co, verts[edges[1].vertices[1]].co) - - if (line == None): - operator.report({'ERROR'}, "Selected edges are parallel.") - return - - tm = obj.matrix_world.copy() - point = ((line[0] + line[1]) / 2) - point = tm * point - - context.scene.cursor_location = point - - return point - -class VIEW3D_OT_CursorToEdgeIntersection(bpy.types.Operator): - "Finds the mid-point of the shortest distance between two edges" - - bl_idname = "view3d.snap_cursor_to_edge_intersection" - bl_label = "Cursor to Edge Intersection" - - @classmethod - def poll(cls, context): - obj = context.active_object - return obj != None and obj.type == 'MESH' - - def execute(self, context): - edgeIntersect(context, self) - return {'FINISHED'} - -class VIEW3D_MT_undoS(bpy.types.Menu): - bl_label = "Undo/Redo" - - def draw(self, context): - layout = self.layout - layout.operator_context = 'INVOKE_REGION_WIN' - layout.operator("ed.undo", icon='TRIA_LEFT') - layout.operator("ed.redo", icon='TRIA_RIGHT') - -def register(): - km = bpy.context.window_manager.keyconfigs.active.keymaps['3D View'] - kmi = km.items.new('wm.call_menu', 'SPACE', 'PRESS') - kmi.properties.name = "VIEW3D_MT_Space_Dynamic_Menu" - - -def unregister(): - km = bpy.context.window_manager.keyconfigs.active.keymaps['3D View'] - for kmi in km.items: - if kmi.idname == 'wm.call_menu': - if kmi.properties.name == "VIEW3D_MT_Space_Dynamic_Menu": - km.items.remove(kmi) - break - -if __name__ == "__main__": - register() diff --git a/system_blend_info.py b/system_blend_info.py deleted file mode 100644 index e9649ba3..00000000 --- a/system_blend_info.py +++ /dev/null @@ -1,207 +0,0 @@ -# scene_blend_info.py Copyright (C) 2010, Mariano Hidalgo -# -# Show Information About the Blend. -# ***** 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 ***** - -bl_addon_info = { - "name": "Scene Information", - "author": "uselessdreamer", - "version": (0,3), - "blender": (2, 5, 3), - "api": 31854, - "location": "Properties space > Scene tab > Blend Info panel", - "description": "Show information about the .blend", - "warning": "", - "wiki_url": 'http://wiki.blender.org/index.php/Extensions:2.5/Py/' \ - 'Scripts/System/Blend Info', - "tracker_url": "https://projects.blender.org/tracker/index.php?" \ - "func=detail&aid=22102&group_id=153&atid=469", - "category": "System"} - -import bpy - - -def quantity_string(quantity, text_single, text_plural, text_none=None): - sep = " " - - if not text_none: - text_none = text_plural - - if quantity == 0: - string = str(quantity) + sep + text_none - - if quantity == 1: - string = str(quantity) + sep + text_single - - if quantity >= 2: - string = str(quantity) + sep + text_plural - - if quantity < 0: - return None - - return string - - -class OBJECT_PT_blendinfo(bpy.types.Panel): - bl_label = "Blend Info" - bl_space_type = "PROPERTIES" - bl_region_type = "WINDOW" - bl_context = "scene" - - def draw(self, context): - amount = 2 - ob_cols = [] - db_cols = [] - etc_cols = [] - - objects = bpy.data.objects - - layout = self.layout - - # OBJECTS - - l_row = layout.row() - num = len(bpy.data.objects) - l_row.label(text=quantity_string(num, "Object", "Objects") - + " in the scene:", - icon='OBJECT_DATA') - - l_row = layout.row() - ob_cols.append(l_row.column()) - ob_cols.append(l_row.column()) - - row = ob_cols[0].row() - meshes = [o for o in objects.values() if o.type == 'MESH'] - num = len(meshes) - row.label(text=quantity_string(num, "Mesh", "Meshes"), - icon='MESH_DATA') - - row = ob_cols[1].row() - curves = [o for o in objects.values() if o.type == 'CURVE'] - num = len(curves) - row.label(text=quantity_string(num, "Curve", "Curves"), - icon='CURVE_DATA') - - row = ob_cols[0].row() - cameras = [o for o in objects.values() if o.type == 'CAMERA'] - num = len(cameras) - row.label(text=quantity_string(num, "Camera", "Cameras"), - icon='CAMERA_DATA') - - row = ob_cols[1].row() - lamps = [o for o in objects.values() if o.type == 'LAMP'] - num = len(lamps) - row.label(text=quantity_string(num, "Lamp", "Lamps"), - icon='LAMP_DATA') - - row = ob_cols[0].row() - armatures = [o for o in objects.values() if o.type == 'ARMATURE'] - num = len(armatures) - row.label(text=quantity_string(num, "Armature", "Armatures"), - icon='ARMATURE_DATA') - - row = ob_cols[1].row() - lattices = [o for o in objects.values() if o.type == 'LATTICE'] - num = len(lattices) - row.label(text=quantity_string(num, "Lattice", "Lattices"), - icon='LATTICE_DATA') - - row = ob_cols[0].row() - empties = [o for o in objects.values() if o.type == 'EMPTY'] - num = len(empties) - row.label(text=quantity_string(num, "Empty", "Empties"), - icon='EMPTY_DATA') - - l_row_sep = layout.separator() - - # DATABLOCKS - - l_row = layout.row() - num = len(bpy.data.objects) - l_row.label(text="Datablocks in the scene:") - - l_row = layout.row() - db_cols.append(l_row.column()) - db_cols.append(l_row.column()) - - row = db_cols[0].row() - num = len(bpy.data.meshes) - row.label(text=quantity_string(num, "Mesh", "Meshes"), - icon='MESH_DATA') - - row = db_cols[1].row() - num = len(bpy.data.curves) - row.label(text=quantity_string(num, "Curve", "Curves"), - icon='CURVE_DATA') - - row = db_cols[0].row() - num = len(bpy.data.cameras) - row.label(text=quantity_string(num, "Camera", "Cameras"), - icon='CAMERA_DATA') - - row = db_cols[1].row() - num = len(bpy.data.lamps) - row.label(text=quantity_string(num, "Lamp", "Lamps"), - icon='LAMP_DATA') - - row = db_cols[0].row() - num = len(bpy.data.armatures) - row.label(text=quantity_string(num, "Armature", "Armatures"), - icon='ARMATURE_DATA') - - row = db_cols[1].row() - num = len(bpy.data.lattices) - row.label(text=quantity_string(num, "Lattice", "Lattices"), - icon='LATTICE_DATA') - - row = db_cols[0].row() - num = len(bpy.data.materials) - row.label(text=quantity_string(num, "Material", "Materials"), - icon='MATERIAL_DATA') - - row = db_cols[1].row() - num = len(bpy.data.worlds) - row.label(text=quantity_string(num, "World", "Worlds"), - icon='WORLD_DATA') - - row = db_cols[0].row() - num = len(bpy.data.textures) - row.label(text=quantity_string(num, "Texture", "Textures"), - icon='TEXTURE_DATA') - - row = db_cols[1].row() - num = len(bpy.data.images) - row.label(text=quantity_string(num, "Image", "Images"), - icon='IMAGE_DATA') - - row = db_cols[0].row() - num = len(bpy.data.texts) - row.label(text=quantity_string(num, "Text", "Texts"), - icon='TEXT') - - -def register(): - pass - -def unregister(): - pass - -if __name__ == "__main__": - register() -- cgit v1.2.3