Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArystanbek Dyussenov <arystan.d@gmail.com>2010-09-04 22:49:07 +0400
committerArystanbek Dyussenov <arystan.d@gmail.com>2010-09-04 22:49:07 +0400
commit90b464d3728d9ed8ec26fdf59058d236b99dbcd9 (patch)
treee88cab4fb1358e962b19f658064ca8c9f8d29f5b /release/scripts/io
parent08d02dd04d836976b25793bb1d4c6a86b3f924c7 (diff)
parentb0b787ef38f9947b3176642556f5282eb3518f69 (diff)
COLLADA branch: merge from trunk -r 28015:31610.soc-2009-chingachgook
Diffstat (limited to 'release/scripts/io')
-rw-r--r--release/scripts/io/engine_render_pov.py964
-rw-r--r--release/scripts/io/export_3ds.py79
-rw-r--r--release/scripts/io/export_fbx.py281
-rw-r--r--release/scripts/io/export_mdd.py54
-rw-r--r--release/scripts/io/export_obj.py554
-rw-r--r--release/scripts/io/export_ply.py44
-rw-r--r--release/scripts/io/export_x3d.py195
-rw-r--r--release/scripts/io/import_anim_bvh.py56
-rw-r--r--release/scripts/io/import_scene_3ds.py289
-rw-r--r--release/scripts/io/import_scene_obj.py364
-rw-r--r--release/scripts/io/import_shape_mdd.py19
-rw-r--r--release/scripts/io/netrender/__init__.py41
-rw-r--r--release/scripts/io/netrender/client.py37
-rw-r--r--release/scripts/io/netrender/master.py93
-rw-r--r--release/scripts/io/netrender/master_html.py112
-rw-r--r--release/scripts/io/netrender/model.py14
-rw-r--r--release/scripts/io/netrender/netrender.css4
-rw-r--r--release/scripts/io/netrender/operators.py123
-rw-r--r--release/scripts/io/netrender/repath.py150
-rw-r--r--release/scripts/io/netrender/slave.py99
-rw-r--r--release/scripts/io/netrender/ui.py368
-rw-r--r--release/scripts/io/netrender/utils.py46
22 files changed, 1539 insertions, 2447 deletions
diff --git a/release/scripts/io/engine_render_pov.py b/release/scripts/io/engine_render_pov.py
deleted file mode 100644
index e64e3bf05fb..00000000000
--- a/release/scripts/io/engine_render_pov.py
+++ /dev/null
@@ -1,964 +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 #####
-
-# <pep8 compliant>
-
-import bpy
-
-from math import atan, pi, degrees
-import subprocess
-import os
-import sys
-import time
-
-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.utils.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.enabled:
- 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
-
- # 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 * atan(16.0 / camera.data.lens) / pi))
-
- file.write('\trotate <%.6f, %.6f, %.6f>\n' % tuple([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
-
- 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' % (degrees(lamp.spot_size) / 2.0)) # 1 TO 179 FOR BOTH
- file.write('\tradius %.6f\n' % ((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_sampling_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.location
-
- stiffness = elem.stiffness
- if elem.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.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)
-
- file.write('}\n')
-
- def exportMeshs(sel):
-
- ob_num = 0
-
- for ob in sel:
- ob_num += 1
-
- if ob.type in ('LAMP', 'CAMERA', 'EMPTY', 'META', 'ARMATURE'):
- continue
-
- me = ob.data
- me_materials = me.materials
-
- me = ob.create_mesh(True, 'RENDER')
-
- if not me:
- 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
- try:
- uv_layer = me.active_uv_texture.data
- except:
- uv_layer = None
-
- try:
- vcol_layer = me.active_vertex_color.data
- except:
- vcol_layer = None
-
- faces_verts = [f.verts for f in me.faces]
- faces_normals = [tuple(f.normal) for f in me.faces]
- verts_normals = [tuple(v.normal) for v in me.verts]
-
- # 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.verts))) # vert count
- for v in me.verts:
- 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.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.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.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.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.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
-
- if mist.enabled:
- 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(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.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()
-
-# Radiosity panel, use in the scene for now.
-FloatProperty = bpy.types.Scene.FloatProperty
-IntProperty = bpy.types.Scene.IntProperty
-BoolProperty = bpy.types.Scene.BoolProperty
-
-# Not a real pov option, just to know if we should write
-BoolProperty(attr="pov_radio_enable",
- name="Enable Radiosity",
- description="Enable povrays radiosity calculation",
- default=False)
-BoolProperty(attr="pov_radio_display_advanced",
- name="Advanced Options",
- description="Show advanced options",
- default=False)
-
-# Real pov options
-FloatProperty(attr="pov_radio_adc_bailout",
- 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)
-
-BoolProperty(attr="pov_radio_always_sample",
- 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)
-
-FloatProperty(attr="pov_radio_brightness",
- 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)
-
-IntProperty(attr="pov_radio_count",
- 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)
-
-FloatProperty(attr="pov_radio_error_bound",
- 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)
-
-FloatProperty(attr="pov_radio_gray_threshold",
- 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)
-
-FloatProperty(attr="pov_radio_low_error_factor",
- 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
-BoolProperty(attr="pov_radio_media",
- name="Media",
- description="Radiosity estimation can be affected by media",
- default=False)
-
-FloatProperty(attr="pov_radio_minimum_reuse",
- 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)
-
-IntProperty(attr="pov_radio_nearest_count",
- name="Nearest Count",
- description="Number of old ambient values blended together to create a new interpolated value",
- min=1, max=20, default=5)
-
-BoolProperty(attr="pov_radio_normal",
- name="Normals",
- description="Radiosity estimation can be affected by normals",
- default=False)
-
-IntProperty(attr="pov_radio_recursion_limit",
- name="Recursion Limit",
- description="how many recursion levels are used to calculate the diffuse inter-reflection",
- min=1, max=20, default=3)
-
-
-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
- self._process = subprocess.Popen([pov_binary, self._temp_file_ini]) # stdout=subprocess.PIPE, stderr=subprocess.PIPE
- 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-***")
-
- 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")
- self._render()
-
- 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()
-
-
-# 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
-
-
-class RenderButtonsPanel(bpy.types.Panel):
- 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
-
- def poll(self, context):
- rd = context.scene.render
- return (rd.use_game_engine == False) and (rd.engine in self.COMPAT_ENGINES)
-
-
-class RENDER_PT_povray_radiosity(RenderButtonsPanel):
- 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")
-
-
-classes = [
- PovrayRender,
- RENDER_PT_povray_radiosity]
-
-
-def register():
- register = bpy.types.register
- for cls in classes:
- register(cls)
-
-
-def unregister():
- unregister = bpy.types.unregister
- for cls in classes:
- unregister(cls)
-
-if __name__ == "__main__":
- register()
diff --git a/release/scripts/io/export_3ds.py b/release/scripts/io/export_3ds.py
index d46cc712e9a..706e7eb1516 100644
--- a/release/scripts/io/export_3ds.py
+++ b/release/scripts/io/export_3ds.py
@@ -74,15 +74,15 @@ import bpy
# also used by X3D exporter
# return a tuple (free, object list), free is True if memory should be freed later with free_derived_objects()
-def create_derived_objects(ob):
+def create_derived_objects(scene, ob):
if ob.parent and ob.parent.dupli_type != 'NONE':
return False, None
if ob.dupli_type != 'NONE':
- ob.create_dupli_list()
+ ob.create_dupli_list(scene)
return True, [(dob.object, dob.matrix) for dob in ob.dupli_list]
else:
- return False, [(ob, ob.matrix)]
+ return False, [(ob, ob.matrix_world)]
# also used by X3D exporter
def free_derived_objects(ob):
@@ -494,8 +494,7 @@ def make_material_texture_chunk(id, images):
mat_sub = _3ds_chunk(id)
def add_image(img):
- filename = os.path.basename(image.filename)
-# filename = image.filename.split('\\')[-1].split('/')[-1]
+ filename = os.path.basename(image.filepath)
mat_sub_file = _3ds_chunk(MATMAPFILE)
mat_sub_file.add_variable("mapfile", _3ds_string(sane_name(filename)))
mat_sub.add_subchunk(mat_sub_file)
@@ -565,14 +564,14 @@ def extract_triangles(mesh):
img = None
for i, face in enumerate(mesh.faces):
- f_v = face.verts
+ f_v = face.vertices
# f_v = face.v
- uf = mesh.active_uv_texture.data[i] if do_uv else None
+ uf = mesh.uv_textures.active.data[i] if do_uv else None
if do_uv:
f_uv = uf.uv
- # f_uv = (uf.uv1, uf.uv2, uf.uv3, uf.uv4) if face.verts[3] else (uf.uv1, uf.uv2, uf.uv3)
+ # f_uv = (uf.uv1, uf.uv2, uf.uv3, uf.uv4) if face.vertices[3] else (uf.uv1, uf.uv2, uf.uv3)
# f_uv = face.uv
img = uf.image if uf else None
# img = face.image
@@ -762,18 +761,18 @@ def make_mesh_chunk(mesh, materialDict):
if len(mesh.uv_textures):
# if mesh.faceUV:
# Remove the face UVs and convert it to vertex UV:
- vert_array, uv_array, tri_list = remove_face_uv(mesh.verts, tri_list)
+ vert_array, uv_array, tri_list = remove_face_uv(mesh.vertices, tri_list)
else:
# Add the vertices to the vertex array:
vert_array = _3ds_array()
- for vert in mesh.verts:
+ for vert in mesh.vertices:
vert_array.add(_3ds_point_3d(vert.co))
# If the mesh has vertex UVs, create an array of UVs:
if len(mesh.sticky):
# if mesh.vertexUV:
uv_array = _3ds_array()
for uv in mesh.sticky:
-# for vert in mesh.verts:
+# for vert in mesh.vertices:
uv_array.add(_3ds_point_uv(uv.co))
# uv_array.add(_3ds_point_uv(vert.uvco))
else:
@@ -923,7 +922,7 @@ def make_kf_obj_node(obj, name_to_id):
"""
# import BPyMessages
-def save_3ds(filename, context):
+def write(filename, context):
'''Save the Blender scene to a 3ds file.'''
# Time the export
@@ -942,7 +941,8 @@ def save_3ds(filename, context):
sce = context.scene
# sce= bpy.data.scenes.active
- bpy.ops.object.mode_set(mode='OBJECT')
+ if context.object:
+ bpy.ops.object.mode_set(mode='OBJECT')
# Initialize the main chunk (primary):
primary = _3ds_chunk(PRIMARY)
@@ -968,11 +968,12 @@ def save_3ds(filename, context):
# each material is added once):
materialDict = {}
mesh_objects = []
- for ob in [ob for ob in context.scene.objects if ob.is_visible()]:
+ scene = context.scene
+ for ob in [ob for ob in scene.objects if ob.is_visible(scene)]:
# for ob in sce.objects.context:
# get derived objects
- free, derived = create_derived_objects(ob)
+ free, derived = create_derived_objects(scene, ob)
if derived == None: continue
@@ -982,7 +983,7 @@ def save_3ds(filename, context):
if ob.type not in ('MESH', 'CURVE', 'SURFACE', 'TEXT', 'META'):
continue
- data = ob_derived.create_mesh(True, 'PREVIEW')
+ data = ob_derived.create_mesh(scene, True, 'PREVIEW')
# data = getMeshFromObject(ob_derived, None, True, False, sce)
if data:
data.transform(mat)
@@ -997,7 +998,7 @@ def save_3ds(filename, context):
if not mat_ls:
mat = mat_name = None
- for f, uf in zip(data.faces, data.active_uv_texture.data):
+ for f, uf in zip(data.faces, data.uv_textures.active.data):
if mat_ls:
mat_index = f.material_index
# mat_index = f.mat
@@ -1006,7 +1007,7 @@ def save_3ds(filename, context):
mat = mat_ls[mat_index]
if mat: mat_name = mat.name
else: mat_name = None
- # else there alredy set to none
+ # else there already set to none
img = uf.image
# img = f.image
@@ -1064,7 +1065,7 @@ def save_3ds(filename, context):
'''
if not blender_mesh.users:
bpy.data.meshes.remove(blender_mesh)
-# blender_mesh.verts = None
+# blender_mesh.vertices = None
i+=i
@@ -1106,53 +1107,47 @@ def save_3ds(filename, context):
#primary.dump()
-# if __name__=='__main__':
-# if struct:
-# Blender.Window.FileSelector(save_3ds, "Export 3DS", Blender.sys.makename(ext='.3ds'))
-# else:
-# Blender.Draw.PupMenu("Error%t|This script requires a full python installation")
-# # save_3ds('/test_b.3ds')
+# # write('/test_b.3ds')
from bpy.props import *
class Export3DS(bpy.types.Operator):
'''Export to 3DS file format (.3ds)'''
bl_idname = "export.autodesk_3ds"
bl_label = 'Export 3DS'
- # List of operator properties, the attributes will be assigned
- # to the class instance from the operator settings before calling.
-
-
- # filename = StringProperty(name="File Name", description="File name used for exporting the 3DS file", maxlen= 1024, default= ""),
- path = StringProperty(name="File Path", description="File path used for exporting the 3DS file", maxlen= 1024, default= "")
+ filepath = StringProperty(name="File Path", description="Filepath used for exporting the 3DS file", maxlen= 1024, default= "")
check_existing = BoolProperty(name="Check Existing", description="Check and warn on overwriting existing files", default=True, options={'HIDDEN'})
+ @classmethod
+ def poll(cls, context): # Poll isnt working yet
+ return context.active_object != None
+
def execute(self, context):
- save_3ds(self.properties.path, context)
+ filepath = self.properties.filepath
+ filepath = bpy.path.ensure_ext(filepath, ".3ds")
+
+ write(filepath, context)
return {'FINISHED'}
def invoke(self, context, event):
- wm = context.manager
- wm.add_fileselect(self)
- return {'RUNNING_MODAL'}
+ import os
+ if not self.properties.is_property_set("filepath"):
+ self.properties.filepath = os.path.splitext(bpy.data.filepath)[0] + ".3ds"
- def poll(self, context): # Poll isnt working yet
- return context.active_object != None
+ context.manager.add_fileselect(self)
+ return {'RUNNING_MODAL'}
# Add to a menu
def menu_func(self, context):
- default_path = bpy.data.filename.replace(".blend", ".3ds")
- self.layout.operator(Export3DS.bl_idname, text="3D Studio (.3ds)").path = default_path
+ self.layout.operator(Export3DS.bl_idname, text="3D Studio (.3ds)")
def register():
- bpy.types.register(Export3DS)
bpy.types.INFO_MT_file_export.append(menu_func)
+
def unregister():
- bpy.types.unregister(Export3DS)
bpy.types.INFO_MT_file_export.remove(menu_func)
if __name__ == "__main__":
register()
-
diff --git a/release/scripts/io/export_fbx.py b/release/scripts/io/export_fbx.py
index 9dd3a68f4da..486f7d8199b 100644
--- a/release/scripts/io/export_fbx.py
+++ b/release/scripts/io/export_fbx.py
@@ -54,50 +54,11 @@ import time
import math # math.pi
import shutil # for file copying
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-# import Blender
import bpy
-import Mathutils
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+from mathutils import Vector, Euler, Matrix
def copy_file(source, dest):
+ # XXX - remove, can use shutil
file = open(source, 'rb')
data = file.read()
file.close()
@@ -114,7 +75,7 @@ def copy_images(dest_dir, textures):
image_paths = set()
for tex in textures:
- image_paths.add(Blender.sys.expandpath(tex.filename))
+ image_paths.add(bpy.path.abspath(tex.filepath))
# Now copy images
copyCount = 0
@@ -122,7 +83,7 @@ def copy_images(dest_dir, textures):
if Blender.sys.exists(image_path):
# Make a name for the target path.
dest_image_path = dest_dir + image_path.split('\\')[-1].split('/')[-1]
- if not Blender.sys.exists(dest_image_path): # Image isnt alredy there
+ if not Blender.sys.exists(dest_image_path): # Image isnt already there
print('\tCopying "%s" > "%s"' % (image_path, dest_image_path))
try:
copy_file(image_path, dest_image_path)
@@ -135,7 +96,7 @@ def copy_images(dest_dir, textures):
# I guess FBX uses degrees instead of radians (Arystan).
# Call this function just before writing to FBX.
def eulerRadToDeg(eul):
- ret = Mathutils.Euler()
+ ret = Euler()
ret.x = 180 / math.pi * eul[0]
ret.y = 180 / math.pi * eul[1]
@@ -143,22 +104,22 @@ def eulerRadToDeg(eul):
return ret
-mtx4_identity = Mathutils.Matrix()
+mtx4_identity = Matrix()
# testing
-mtx_x90 = Mathutils.RotationMatrix( math.pi/2, 3, 'X') # used
-#mtx_x90n = RotationMatrix(-90, 3, 'x')
-#mtx_y90 = RotationMatrix( 90, 3, 'y')
-#mtx_y90n = RotationMatrix(-90, 3, 'y')
-#mtx_z90 = RotationMatrix( 90, 3, 'z')
-#mtx_z90n = RotationMatrix(-90, 3, 'z')
-
-#mtx4_x90 = RotationMatrix( 90, 4, 'x')
-mtx4_x90n = Mathutils.RotationMatrix(-math.pi/2, 4, 'X') # used
-#mtx4_y90 = RotationMatrix( 90, 4, 'y')
-mtx4_y90n = Mathutils.RotationMatrix(-math.pi/2, 4, 'Y') # used
-mtx4_z90 = Mathutils.RotationMatrix( math.pi/2, 4, 'Z') # used
-mtx4_z90n = Mathutils.RotationMatrix(-math.pi/2, 4, 'Z') # used
+mtx_x90 = Matrix.Rotation( math.pi/2, 3, 'X') # used
+#mtx_x90n = Matrix.Rotation(-90, 3, 'x')
+#mtx_y90 = Matrix.Rotation( 90, 3, 'y')
+#mtx_y90n = Matrix.Rotation(-90, 3, 'y')
+#mtx_z90 = Matrix.Rotation( 90, 3, 'z')
+#mtx_z90n = Matrix.Rotation(-90, 3, 'z')
+
+#mtx4_x90 = Matrix.Rotation( 90, 4, 'x')
+mtx4_x90n = Matrix.Rotation(-math.pi/2, 4, 'X') # used
+#mtx4_y90 = Matrix.Rotation( 90, 4, 'y')
+mtx4_y90n = Matrix.Rotation(-math.pi/2, 4, 'Y') # used
+mtx4_z90 = Matrix.Rotation( math.pi/2, 4, 'Z') # used
+mtx4_z90n = Matrix.Rotation(-math.pi/2, 4, 'Z') # used
# def strip_path(p):
# return p.split('\\')[-1].split('/')[-1]
@@ -215,7 +176,7 @@ def sane_name(data, dct):
name = 'unnamed' # blank string, ASKING FOR TROUBLE!
else:
- name = bpy.utils.clean_name(name) # use our own
+ name = bpy.path.clean_name(name) # use our own
while name in iter(dct.values()): name = increment_string(name)
@@ -239,14 +200,14 @@ def sane_groupname(data): return sane_name(data, sane_name_mapping_group)
# FORCE_CWD - dont use the basepath, just add a ./ to the filename.
# use when we know the file will be in the basepath.
# '''
-# fname = bpy.utils.expandpath(fname_orig)
+# fname = bpy.path.abspath(fname_orig)
# # fname = Blender.sys.expandpath(fname_orig)
# fname_strip = os.path.basename(fname)
# # fname_strip = strip_path(fname)
# if FORCE_CWD:
# fname_rel = '.' + os.sep + fname_strip
# else:
-# fname_rel = bpy.utils.relpath(fname, basepath)
+# fname_rel = bpy.path.relpath(fname, basepath)
# # fname_rel = Blender.sys.relpath(fname, basepath)
# if fname_rel.startswith('//'): fname_rel = '.' + os.sep + fname_rel[2:]
# return fname, fname_strip, fname_rel
@@ -260,7 +221,7 @@ def mat4x4str(mat):
def getVertsFromGroup(me, group_index):
ret = []
- for i, v in enumerate(me.verts):
+ for i, v in enumerate(me.vertices):
for g in v.groups:
if g.group == group_index:
ret.append((i, g.weight))
@@ -282,11 +243,11 @@ def BPyMesh_meshWeight2List(ob):
if not len_groupNames:
# no verts? return a vert aligned empty list
- return [[] for i in range(len(me.verts))], []
+ return [[] for i in range(len(me.vertices))], []
else:
- vWeightList= [[0.0]*len_groupNames for i in range(len(me.verts))]
+ vWeightList= [[0.0]*len_groupNames for i in range(len(me.vertices))]
- for i, v in enumerate(me.verts):
+ for i, v in enumerate(me.vertices):
for g in v.groups:
vWeightList[i][g.group] = g.weight
@@ -333,7 +294,7 @@ def write(filename, batch_objects = None, \
EXP_CAMERA = True,
EXP_EMPTY = True,
EXP_IMAGE_COPY = False,
- GLOBAL_MATRIX = Mathutils.Matrix(),
+ GLOBAL_MATRIX = Matrix(),
ANIM_ENABLE = True,
ANIM_OPTIMIZE = True,
ANIM_OPTIMIZE_PRECISSION = 6,
@@ -344,7 +305,8 @@ def write(filename, batch_objects = None, \
BATCH_OWN_DIR = False
):
- bpy.ops.object.mode_set(mode='OBJECT')
+ if bpy.context.object:
+ bpy.ops.object.mode_set(mode='OBJECT')
# ----------------- Batch support!
if BATCH_ENABLE:
@@ -392,13 +354,13 @@ def write(filename, batch_objects = None, \
new_fbxpath = fbxpath # own dir option modifies, we need to keep an original
for data in data_seq: # scene or group
- newname = BATCH_FILE_PREFIX + bpy.utils.clean_name(data.name)
-# newname = BATCH_FILE_PREFIX + BPySys.bpy.utils.clean_name(data.name)
+ newname = BATCH_FILE_PREFIX + bpy.path.clean_name(data.name)
+# newname = BATCH_FILE_PREFIX + BPySys.bpy.path.clean_name(data.name)
if BATCH_OWN_DIR:
new_fbxpath = fbxpath + newname + os.sep
- # path may alredy exist
+ # path may already exist
# TODO - might exist but be a file. unlikely but should probably account for it.
if bpy.utils.exists(new_fbxpath) == 0:
@@ -430,7 +392,7 @@ def write(filename, batch_objects = None, \
# Call self with modified args
- # Dont pass batch options since we alredy usedt them
+ # Dont pass batch options since we already usedt them
write(filename, data.objects,
context,
False,
@@ -567,7 +529,7 @@ def write(filename, batch_objects = None, \
self.fbxGroupNames = []
self.fbxParent = None # set later on IF the parent is in the selection.
if matrixWorld: self.matrixWorld = GLOBAL_MATRIX * matrixWorld
- else: self.matrixWorld = GLOBAL_MATRIX * ob.matrix
+ else: self.matrixWorld = GLOBAL_MATRIX * ob.matrix_world
# else: self.matrixWorld = ob.matrixWorld * GLOBAL_MATRIX
self.__anim_poselist = {} # we should only access this
@@ -578,8 +540,7 @@ def write(filename, batch_objects = None, \
return self.matrixWorld
def setPoseFrame(self, f):
- self.__anim_poselist[f] = self.blenObject.matrix.copy()
-# self.__anim_poselist[f] = self.blenObject.matrixWorld.copy()
+ self.__anim_poselist[f] = self.blenObject.matrix_world.copy()
def getAnimParRelMatrix(self, frame):
if self.fbxParent:
@@ -600,8 +561,8 @@ def write(filename, batch_objects = None, \
matrix_rot = matrix_rot * mtx_x90
elif type =='CAMERA':
# elif ob and type =='Camera':
- y = matrix_rot * Mathutils.Vector(0,1,0)
- matrix_rot = Mathutils.RotationMatrix(math.pi/2, 3, y) * matrix_rot
+ y = matrix_rot * Vector((0.0, 1.0, 0.0))
+ matrix_rot = Matrix.Rotation(math.pi/2, 3, y) * matrix_rot
return matrix_rot
@@ -685,7 +646,7 @@ def write(filename, batch_objects = None, \
else:
# This is bad because we need the parent relative matrix from the fbx parent (if we have one), dont use anymore
- #if ob and not matrix: matrix = ob.matrixWorld * GLOBAL_MATRIX
+ #if ob and not matrix: matrix = ob.matrix_world * GLOBAL_MATRIX
if ob and not matrix: raise Exception("error: this should never happen!")
matrix_rot = matrix
@@ -702,8 +663,8 @@ def write(filename, batch_objects = None, \
matrix_rot = matrix_rot * mtx_x90
rot = tuple(matrix_rot.to_euler())
elif ob and ob.type =='Camera':
- y = matrix_rot * Mathutils.Vector(0,1,0)
- matrix_rot = Mathutils.RotationMatrix(math.pi/2, 3, y) * matrix_rot
+ y = matrix_rot * Vector((0.0, 1.0, 0.0))
+ matrix_rot = Matrix.Rotation(math.pi/2, 3, y) * matrix_rot
rot = tuple(matrix_rot.to_euler())
else:
rot = tuple(matrix_rot.to_euler())
@@ -987,10 +948,7 @@ def write(filename, batch_objects = None, \
render = scene.render
width = render.resolution_x
height = render.resolution_y
-# render = scene.render
-# width = render.sizeX
-# height = render.sizeY
- aspect = float(width)/height
+ aspect = width / height
data = my_cam.blenObject.data
@@ -1002,11 +960,9 @@ def write(filename, batch_objects = None, \
file.write('\n\t\t\tProperty: "FieldOfView", "FieldOfView", "A+",%.6f' % math.degrees(data.angle))
file.write('\n\t\t\tProperty: "FieldOfViewX", "FieldOfView", "A+",1')
file.write('\n\t\t\tProperty: "FieldOfViewY", "FieldOfView", "A+",1')
- file.write('\n\t\t\tProperty: "FocalLength", "Real", "A+",14.0323972702026')
+ # file.write('\n\t\t\tProperty: "FocalLength", "Real", "A+",14.0323972702026')
file.write('\n\t\t\tProperty: "OpticalCenterX", "Real", "A+",%.6f' % data.shift_x) # not sure if this is in the correct units?
-# file.write('\n\t\t\tProperty: "OpticalCenterX", "Real", "A+",%.6f' % data.shiftX) # not sure if this is in the correct units?
file.write('\n\t\t\tProperty: "OpticalCenterY", "Real", "A+",%.6f' % data.shift_y) # ditto
-# file.write('\n\t\t\tProperty: "OpticalCenterY", "Real", "A+",%.6f' % data.shiftY) # ditto
file.write('\n\t\t\tProperty: "BackgroundColor", "Color", "A+",0,0,0')
file.write('\n\t\t\tProperty: "TurnTable", "Real", "A+",0')
file.write('\n\t\t\tProperty: "DisplayTurnTableIcon", "bool", "",1')
@@ -1015,7 +971,7 @@ def write(filename, batch_objects = None, \
file.write('\n\t\t\tProperty: "UseRealTimeMotionBlur", "bool", "",1')
file.write('\n\t\t\tProperty: "ResolutionMode", "enum", "",0')
file.write('\n\t\t\tProperty: "ApertureMode", "enum", "",2')
- file.write('\n\t\t\tProperty: "GateFit", "enum", "",0')
+ file.write('\n\t\t\tProperty: "GateFit", "enum", "",2')
file.write('\n\t\t\tProperty: "CameraFormat", "enum", "",0')
file.write('\n\t\t\tProperty: "AspectW", "double", "",%i' % width)
file.write('\n\t\t\tProperty: "AspectH", "double", "",%i' % height)
@@ -1088,8 +1044,8 @@ def write(filename, batch_objects = None, \
file.write('\n\t\tTypeFlags: "Camera"')
file.write('\n\t\tGeometryVersion: 124')
file.write('\n\t\tPosition: %.6f,%.6f,%.6f' % loc)
- file.write('\n\t\tUp: %.6f,%.6f,%.6f' % tuple(matrix_rot * Mathutils.Vector(0,1,0)) )
- file.write('\n\t\tLookAt: %.6f,%.6f,%.6f' % tuple(matrix_rot * Mathutils.Vector(0,0,-1)) )
+ file.write('\n\t\tUp: %.6f,%.6f,%.6f' % tuple(matrix_rot * Vector((0.0, 1.0, 0.0))))
+ file.write('\n\t\tLookAt: %.6f,%.6f,%.6f' % tuple(matrix_rot * Vector((0.0, 0.0, -1.0))))
#file.write('\n\t\tUp: 0,0,0' )
#file.write('\n\t\tLookAt: 0,0,0' )
@@ -1126,7 +1082,7 @@ def write(filename, batch_objects = None, \
else:
do_shadow = 0
- if light.only_shadow or (not light.diffuse and not light.specular):
+ if light.use_only_shadow or (not light.diffuse and not light.specular):
# if mode & Blender.Lamp.Modes.OnlyShadow or (mode & Blender.Lamp.Modes.NoDiffuse and mode & Blender.Lamp.Modes.NoSpecular):
do_light = 0
else:
@@ -1234,7 +1190,7 @@ def write(filename, batch_objects = None, \
# mat_spec = mat.spec/2.0
mat_alpha = mat.alpha
mat_emit = mat.emit
- mat_shadeless = mat.shadeless
+ mat_shadeless = mat.use_shadeless
# mat_shadeless = mat.mode & Blender.Material.Modes.SHADELESS
if mat_shadeless:
mat_shader = 'Lambert'
@@ -1294,7 +1250,7 @@ def write(filename, batch_objects = None, \
file.write('\n\t}')
def copy_image(image):
- fn = bpy.utils.expandpath(image.filename)
+ fn = bpy.path.abspath(image.filepath)
fn_strip = os.path.basename(fn)
if EXP_IMAGE_COPY:
@@ -1321,7 +1277,7 @@ def write(filename, batch_objects = None, \
Property: "Height", "int", "",0''')
if tex:
fname_rel, fname_strip = copy_image(tex)
-# fname, fname_strip, fname_rel = derived_paths(tex.filename, basepath, EXP_IMAGE_COPY)
+# fname, fname_strip, fname_rel = derived_paths(tex.filepath, basepath, EXP_IMAGE_COPY)
else:
fname = fname_strip = fname_rel = ''
@@ -1371,9 +1327,9 @@ def write(filename, batch_objects = None, \
Property: "CurrentMappingType", "enum", "",0
Property: "UVSwap", "bool", "",0''')
- file.write('\n\t\t\tProperty: "WrapModeU", "enum", "",%i' % tex.clamp_x)
+ file.write('\n\t\t\tProperty: "WrapModeU", "enum", "",%i' % tex.use_clamp_x)
# file.write('\n\t\t\tProperty: "WrapModeU", "enum", "",%i' % tex.clampX)
- file.write('\n\t\t\tProperty: "WrapModeV", "enum", "",%i' % tex.clamp_y)
+ file.write('\n\t\t\tProperty: "WrapModeV", "enum", "",%i' % tex.use_clamp_y)
# file.write('\n\t\t\tProperty: "WrapModeV", "enum", "",%i' % tex.clampY)
file.write('''
@@ -1386,7 +1342,7 @@ def write(filename, batch_objects = None, \
if tex:
fname_rel, fname_strip = copy_image(tex)
-# fname, fname_strip, fname_rel = derived_paths(tex.filename, basepath, EXP_IMAGE_COPY)
+# fname, fname_strip, fname_rel = derived_paths(tex.filepath, basepath, EXP_IMAGE_COPY)
else:
fname = fname_strip = fname_rel = ''
@@ -1442,7 +1398,7 @@ def write(filename, batch_objects = None, \
# TODO - this is a bit lazy, we could have a simple write loop
# for this case because all weights are 1.0 but for now this is ok
# Parent Bones arent used all that much anyway.
- vgroup_data = [(j, 1.0) for j in range(len(my_mesh.blenData.verts))]
+ vgroup_data = [(j, 1.0) for j in range(len(my_mesh.blenData.vertices))]
else:
# This bone is not a parent of this mesh object, no weights
vgroup_data = []
@@ -1531,7 +1487,7 @@ def write(filename, batch_objects = None, \
file.write('\n\t\tVertices: ')
i=-1
- for v in me.verts:
+ for v in me.vertices:
if i==-1:
file.write('%.6f,%.6f,%.6f' % tuple(v.co)); i=0
else:
@@ -1543,17 +1499,14 @@ def write(filename, batch_objects = None, \
file.write('\n\t\tPolygonVertexIndex: ')
i=-1
for f in me.faces:
- fi = [v for v in f.verts]
- # fi = [v_index for j, v_index in enumerate(f.verts) if v_index != 0 or j != 3]
-# fi = [v.index for v in f]
+ fi = f.vertices[:]
- # flip the last index, odd but it looks like
- # this is how fbx tells one face from another
- fi[-1] = -(fi[-1]+1)
+ # last index XORd w. -1 indicates end of face
+ fi[-1] = fi[-1] ^ -1
fi = tuple(fi)
+
if i==-1:
if len(fi) == 3: file.write('%i,%i,%i' % fi )
-# if len(f) == 3: file.write('%i,%i,%i' % fi )
else: file.write('%i,%i,%i,%i' % fi )
i=0
else:
@@ -1561,22 +1514,38 @@ def write(filename, batch_objects = None, \
file.write('\n\t\t')
i=0
if len(fi) == 3: file.write(',%i,%i,%i' % fi )
-# if len(f) == 3: file.write(',%i,%i,%i' % fi )
else: file.write(',%i,%i,%i,%i' % fi )
i+=1
+ # write loose edges as faces.
+ for ed in me.edges:
+ if ed.is_loose:
+ ed_val = ed.vertices[:]
+ ed_val = ed_val[0], ed_val[-1] ^ -1
+
+ if i==-1:
+ file.write('%i,%i' % ed_val)
+ i=0
+ else:
+ if i==13:
+ file.write('\n\t\t')
+ i=0
+ file.write(',%i,%i' % ed_val)
+ i+=1
+
+
file.write('\n\t\tEdges: ')
i=-1
for ed in me.edges:
if i==-1:
- file.write('%i,%i' % (ed.verts[0], ed.verts[1]))
+ file.write('%i,%i' % (ed.vertices[0], ed.vertices[1]))
# file.write('%i,%i' % (ed.v1.index, ed.v2.index))
i=0
else:
if i==13:
file.write('\n\t\t')
i=0
- file.write(',%i,%i' % (ed.verts[0], ed.verts[1]))
+ file.write(',%i,%i' % (ed.vertices[0], ed.vertices[1]))
# file.write(',%i,%i' % (ed.v1.index, ed.v2.index))
i+=1
@@ -1591,7 +1560,7 @@ def write(filename, batch_objects = None, \
Normals: ''')
i=-1
- for v in me.verts:
+ for v in me.vertices:
if i==-1:
file.write('%.15f,%.15f,%.15f' % tuple(v.normal)); i=0
# file.write('%.15f,%.15f,%.15f' % tuple(v.no)); i=0
@@ -1615,11 +1584,11 @@ def write(filename, batch_objects = None, \
i=-1
for f in me.faces:
if i==-1:
- file.write('%i' % f.smooth); i=0
+ file.write('%i' % f.use_smooth); i=0
else:
if i==54:
file.write('\n '); i=0
- file.write(',%i' % f.smooth)
+ file.write(',%i' % f.use_smooth)
i+=1
file.write('\n\t\t}')
@@ -1633,27 +1602,23 @@ def write(filename, batch_objects = None, \
ReferenceInformationType: "Direct"
Smoothing: ''')
-# SHARP = Blender.Mesh.EdgeFlags.SHARP
i=-1
for ed in me.edges:
if i==-1:
- file.write('%i' % (ed.sharp)); i=0
-# file.write('%i' % ((ed.flag&SHARP)!=0)); i=0
+ file.write('%i' % (ed.use_edge_sharp)); i=0
else:
if i==54:
file.write('\n '); i=0
- file.write(',%i' % (ed.sharp))
-# file.write(',%i' % ((ed.flag&SHARP)!=0))
+ file.write(',%i' % (ed.use_edge_sharp))
i+=1
file.write('\n\t\t}')
-# del SHARP
# small utility function
# returns a slice of data depending on number of face verts
# data is either a MeshTextureFace or MeshColor
def face_data(data, face):
- totvert = len(f.verts)
+ totvert = len(f.vertices)
return data[:totvert]
@@ -1665,7 +1630,7 @@ def write(filename, batch_objects = None, \
# if me.vertexColors:
collayers = me.vertex_colors
# collayers = me.getColorLayerNames()
- collayer_orig = me.active_vertex_color
+ collayer_orig = me.vertex_colors.active
# collayer_orig = me.activeColorLayer
for colindex, collayer in enumerate(collayers):
# me.activeColorLayer = collayer
@@ -1735,7 +1700,7 @@ def write(filename, batch_objects = None, \
if do_uvs:
uvlayers = me.uv_textures
# uvlayers = me.getUVLayerNames()
- uvlayer_orig = me.active_uv_texture
+ uvlayer_orig = me.uv_textures.active
# uvlayer_orig = me.activeUVLayer
for uvindex, uvlayer in enumerate(me.uv_textures):
# for uvindex, uvlayer in enumerate(uvlayers):
@@ -1869,8 +1834,8 @@ def write(filename, batch_objects = None, \
mats = my_mesh.blenMaterialList
- if me.active_uv_texture:
- uv_faces = me.active_uv_texture.data
+ if me.uv_textures.active:
+ uv_faces = me.uv_textures.active.data
else:
uv_faces = [None] * len(me.faces)
@@ -2037,9 +2002,8 @@ def write(filename, batch_objects = None, \
if ob_arms_orig_rest:
for ob_base in bpy.data.objects:
- #if ob_base.type == 'Armature':
- ob_base.make_display_list()
-# ob_base.makeDisplayList()
+ if ob_base.type == 'ARMATURE':
+ ob_base.update(scene)
# This causes the makeDisplayList command to effect the mesh
scene.set_frame(scene.frame_current)
@@ -2052,9 +2016,9 @@ def write(filename, batch_objects = None, \
if ob_base.parent and ob_base.parent.dupli_type != 'NONE':
continue
- obs = [(ob_base, ob_base.matrix)]
+ obs = [(ob_base, ob_base.matrix_world)]
if ob_base.dupli_type != 'NONE':
- ob_base.create_dupli_list()
+ ob_base.create_dupli_list(scene)
obs = [(dob.object, dob.matrix) for dob in ob_base.dupli_list]
for ob, mtx in obs:
@@ -2083,7 +2047,7 @@ def write(filename, batch_objects = None, \
if tmp_ob_type != 'MESH':
# if tmp_ob_type != 'Mesh':
# me = bpy.data.meshes.new()
- try: me = ob.create_mesh(True, 'PREVIEW')
+ try: me = ob.create_mesh(scene, True, 'PREVIEW')
# try: me.getFromObject(ob)
except: me = None
if me:
@@ -2094,7 +2058,7 @@ def write(filename, batch_objects = None, \
# Mesh Type!
if EXP_MESH_APPLY_MOD:
# me = bpy.data.meshes.new()
- me = ob.create_mesh(True, 'PREVIEW')
+ me = ob.create_mesh(scene, True, 'PREVIEW')
# me.getFromObject(ob)
# so we keep the vert groups
@@ -2104,7 +2068,7 @@ def write(filename, batch_objects = None, \
# ob.copy().link(me)
# # If new mesh has no vgroups we can try add if verts are teh same
# if not me.getVertGroupNames(): # vgroups were not kept by the modifier
-# if len(me.verts) == len(orig_mesh.verts):
+# if len(me.vertices) == len(orig_mesh.vertices):
# groupNames, vWeightDict = BPyMesh.meshWeight2Dict(orig_mesh)
# BPyMesh.dict2MeshWeight(me, groupNames, vWeightDict)
@@ -2139,7 +2103,7 @@ def write(filename, batch_objects = None, \
material_mapping_local = {}
if len(me.uv_textures) > 0:
# if me.faceUV:
- uvlayer_orig = me.active_uv_texture
+ uvlayer_orig = me.uv_textures.active
# uvlayer_orig = me.activeUVLayer
for uvlayer in me.uv_textures:
# for uvlayer in me.getUVLayerNames():
@@ -2213,9 +2177,7 @@ def write(filename, batch_objects = None, \
if ob_arms_orig_rest:
for ob_base in bpy.data.objects:
if ob_base.type == 'ARMATURE':
-# if ob_base.type == 'Armature':
- ob_base.make_display_list()
-# ob_base.makeDisplayList()
+ ob_base.update(scene)
# This causes the makeDisplayList command to effect the mesh
scene.set_frame(scene.frame_current)
# Blender.Set('curframe', Blender.Get('curframe'))
@@ -2793,7 +2755,7 @@ Takes: {''')
act_end = end
else:
# use existing name
- if blenAction == blenActionDefault: # have we alredy got the name
+ if blenAction == blenActionDefault: # have we already got the name
file.write('\n\tTake: "%s" {' % sane_name_mapping_take[blenAction.name])
else:
file.write('\n\tTake: "%s" {' % sane_takename(blenAction))
@@ -2812,7 +2774,7 @@ Takes: {''')
# Set the action active
for my_bone in ob_arms:
- if blenAction in my_bone.blenActionList:
+ if ob.animation_data and blenAction in my_bone.blenActionList:
ob.animation_data.action = blenAction
# print '\t\tSetting Action!', blenAction
# scene.update(1)
@@ -2948,7 +2910,7 @@ Takes: {''')
for val, frame in context_bone_anim_keys:
if frame != context_bone_anim_keys[0][1]: # not the first
file.write(',')
- # frame is alredy one less then blenders frame
+ # frame is already one less then blenders frame
file.write('\n\t\t\t\t\t\t\t%i,%.15f,L' % (fbx_time(frame), val ))
if i==0: file.write('\n\t\t\t\t\t\tColor: 1,0,0')
@@ -2970,7 +2932,8 @@ Takes: {''')
# end action loop. set original actions
# do this after every loop incase actions effect eachother.
for my_bone in ob_arms:
- my_bone.blenObject.animation_data.action = my_bone.blenAction
+ if my_bone.blenObject.animation_data:
+ my_bone.blenObject.animation_data.action = my_bone.blenAction
file.write('\n}')
@@ -2994,13 +2957,12 @@ Takes: {''')
# Clear mesh data Only when writing with modifiers applied
for me in meshes_to_clear:
bpy.data.meshes.remove(me)
-# me.verts = None
+# me.vertices = None
# --------------------------- Footer
if world:
m = world.mist
- has_mist = m.enabled
-# has_mist = world.mode & 1
+ has_mist = m.use_mist
mist_intense = m.intensity
mist_start = m.start
mist_end = m.depth
@@ -3068,7 +3030,7 @@ Takes: {''')
# --------------------------------------------
# UI Function - not a part of the exporter.
-# this is to seperate the user interface from the rest of the exporter.
+# this is to separate the user interface from the rest of the exporter.
# from Blender import Draw, Window
EVENT_NONE = 0
EVENT_EXIT = 1
@@ -3365,7 +3327,7 @@ class ExportFBX(bpy.types.Operator):
# to the class instance from the operator settings before calling.
- path = StringProperty(name="File Path", description="File path used for exporting the FBX file", maxlen= 1024, default="")
+ filepath = StringProperty(name="File Path", description="Filepath used for exporting the FBX file", maxlen= 1024, default="")
check_existing = BoolProperty(name="Check Existing", description="Check and warn on overwriting existing files", default=True, options={'HIDDEN'})
EXP_OBS_SELECTED = BoolProperty(name="Selected Objects", description="Export selected objects on visible layers", default=True)
@@ -3395,12 +3357,16 @@ class ExportFBX(bpy.types.Operator):
BATCH_FILE_PREFIX = StringProperty(name="Prefix", description="Prefix each file with this name", maxlen=1024, default="")
- def poll(self, context):
+ @classmethod
+ def poll(cls, context):
return context.active_object
def execute(self, context):
- if not self.properties.path:
- raise Exception("path not set")
+ if not self.properties.filepath:
+ raise Exception("filepath not set")
+
+ filepath = self.properties.filepath
+ filepath = bpy.path.ensure_ext(filepath, ".fbx")
GLOBAL_MATRIX = mtx4_identity
GLOBAL_MATRIX[0][0] = GLOBAL_MATRIX[1][1] = GLOBAL_MATRIX[2][2] = self.properties.TX_SCALE
@@ -3408,7 +3374,7 @@ class ExportFBX(bpy.types.Operator):
if self.properties.TX_YROT90: GLOBAL_MATRIX = mtx4_y90n * GLOBAL_MATRIX
if self.properties.TX_ZROT90: GLOBAL_MATRIX = mtx4_z90n * GLOBAL_MATRIX
- write(self.properties.path,
+ write(filepath,
None, # XXX
context,
self.properties.EXP_OBS_SELECTED,
@@ -3428,25 +3394,29 @@ class ExportFBX(bpy.types.Operator):
self.properties.BATCH_ENABLE,
self.properties.BATCH_GROUP,
self.properties.BATCH_FILE_PREFIX,
- self.properties.BATCH_OWN_DIR)
+ self.properties.BATCH_OWN_DIR,
+ )
return {'FINISHED'}
def invoke(self, context, event):
- wm = context.manager
- wm.add_fileselect(self)
+ import os
+ if not self.properties.is_property_set("filepath"):
+ self.properties.filepath = os.path.splitext(bpy.data.filepath)[0] + ".fbx"
+
+ context.manager.add_fileselect(self)
return {'RUNNING_MODAL'}
# if __name__ == "__main__":
-# bpy.ops.EXPORT_OT_ply(filename="/tmp/test.ply")
+# bpy.ops.EXPORT_OT_ply(filepath="/tmp/test.ply")
# NOTES (all line numbers correspond to original export_fbx.py (under release/scripts)
# - Draw.PupMenu alternative in 2.5?, temporarily replaced PupMenu with print
-# - get rid of bpy.utils.clean_name somehow
+# - get rid of bpy.path.clean_name somehow
# + fixed: isinstance(inst, bpy.types.*) doesn't work on RNA objects: line 565
# + get rid of BPyObject_getObjectArmature, move it in RNA?
# - BATCH_ENABLE and BATCH_GROUP options: line 327
@@ -3461,24 +3431,21 @@ class ExportFBX(bpy.types.Operator):
# - bpy.data.remove_scene: line 366
# - bpy.sys.time move to bpy.sys.util?
# - new scene creation, activation: lines 327-342, 368
-# - uses bpy.utils.expandpath, *.relpath - replace at least relpath
+# - uses bpy.path.abspath, *.relpath - replace at least relpath
# SMALL or COSMETICAL
# - find a way to get blender version, and put it in bpy.util?, old was Blender.Get('version')
def menu_func(self, context):
- default_path = bpy.data.filename.replace(".blend", ".fbx")
- self.layout.operator(ExportFBX.bl_idname, text="Autodesk FBX (.fbx)").path = default_path
+ self.layout.operator(ExportFBX.bl_idname, text="Autodesk FBX (.fbx)")
def register():
- bpy.types.register(ExportFBX)
bpy.types.INFO_MT_file_export.append(menu_func)
def unregister():
- bpy.types.unregister(ExportFBX)
bpy.types.INFO_MT_file_export.remove(menu_func)
if __name__ == "__main__":
diff --git a/release/scripts/io/export_mdd.py b/release/scripts/io/export_mdd.py
index be3ddbc73bd..b2eda13fc8f 100644
--- a/release/scripts/io/export_mdd.py
+++ b/release/scripts/io/export_mdd.py
@@ -48,7 +48,7 @@ Be sure not to use modifiers that change the number or order of verts in the mes
# ***** END GPL LICENCE BLOCK *****
import bpy
-import Mathutils
+import mathutils
from struct import pack
@@ -65,7 +65,7 @@ def check_vertcount(mesh, vertcount):
'''
check and make sure the vertcount is consistent throughout the frame range
'''
- if len(mesh.verts) != vertcount:
+ if len(mesh.vertices) != vertcount:
raise Exception('Error, number of verts has changed during animation, cannot export')
f.close()
zero_file(filepath)
@@ -84,17 +84,17 @@ def write(filename, sce, ob, PREF_STARTFRAME, PREF_ENDFRAME, PREF_FPS):
orig_frame = sce.frame_current
sce.set_frame(PREF_STARTFRAME)
- me = ob.create_mesh(True, 'PREVIEW')
+ me = ob.create_mesh(sce, True, 'PREVIEW')
#Flip y and z
- mat_flip = Mathutils.Matrix(\
+ mat_flip = mathutils.Matrix(\
[1.0, 0.0, 0.0, 0.0],\
[0.0, 0.0, 1.0, 0.0],\
[0.0, 1.0, 0.0, 0.0],\
[0.0, 0.0, 0.0, 1.0],\
)
- numverts = len(me.verts)
+ numverts = len(me.vertices)
numframes = PREF_ENDFRAME - PREF_STARTFRAME + 1
PREF_FPS = float(PREF_FPS)
@@ -113,8 +113,8 @@ def write(filename, sce, ob, PREF_STARTFRAME, PREF_ENDFRAME, PREF_FPS):
"""
check_vertcount(me, numverts)
- me.transform(mat_flip * ob.matrix)
- f.write(pack(">%df" % (numverts * 3), *[axis for v in me.verts for axis in v.co]))
+ me.transform(mat_flip * ob.matrix_world)
+ f.write(pack(">%df" % (numverts * 3), *[axis for v in me.vertices for axis in v.co]))
for frame in range(PREF_STARTFRAME, PREF_ENDFRAME + 1):#in order to start at desired frame
"""
@@ -123,15 +123,15 @@ def write(filename, sce, ob, PREF_STARTFRAME, PREF_ENDFRAME, PREF_FPS):
"""
sce.set_frame(frame)
- me = ob.create_mesh(True, 'PREVIEW')
+ me = ob.create_mesh(sce, True, 'PREVIEW')
check_vertcount(me, numverts)
- me.transform(mat_flip * ob.matrix)
+ me.transform(mat_flip * ob.matrix_world)
# Write the vertex data
- f.write(pack(">%df" % (numverts * 3), *[axis for v in me.verts for axis in v.co]))
+ f.write(pack(">%df" % (numverts * 3), *[axis for v in me.vertices for axis in v.co]))
"""
- me_tmp.verts= None
+ me_tmp.vertices= None
"""
f.close()
@@ -159,41 +159,49 @@ class ExportMDD(bpy.types.Operator):
# List of operator properties, the attributes will be assigned
# to the class instance from the operator settings before calling.
- path = StringProperty(name="File Path", description="File path used for exporting the MDD file", maxlen=1024)
+ filepath = StringProperty(name="File Path", description="Filepath used for exporting the MDD file", maxlen=1024)
check_existing = BoolProperty(name="Check Existing", description="Check and warn on overwriting existing files", default=True, options={'HIDDEN'})
fps = IntProperty(name="Frames Per Second", description="Number of frames/second", min=minfps, max=maxfps, default=25)
frame_start = IntProperty(name="Start Frame", description="Start frame for baking", min=minframe, max=maxframe, default=1)
frame_end = IntProperty(name="End Frame", description="End frame for baking", min=minframe, max=maxframe, default=250)
- def poll(self, context):
+ @classmethod
+ def poll(cls, context):
ob = context.active_object
return (ob and ob.type == 'MESH')
def execute(self, context):
- if not self.properties.path:
- raise Exception("filename not set")
- write(self.properties.path, context.scene, context.active_object,
- self.properties.frame_start, self.properties.frame_end, self.properties.fps)
+ filepath = self.properties.filepath
+ filepath = bpy.path.ensure_ext(filepath, ".mdd")
+
+ write(filepath,
+ context.scene,
+ context.active_object,
+ self.properties.frame_start,
+ self.properties.frame_end,
+ self.properties.fps,
+ )
+
return {'FINISHED'}
def invoke(self, context, event):
- wm = context.manager
- wm.add_fileselect(self)
+ import os
+ if not self.properties.is_property_set("filepath"):
+ self.properties.filepath = os.path.splitext(bpy.data.filepath)[0] + ".mdd"
+
+ context.manager.add_fileselect(self)
return {'RUNNING_MODAL'}
def menu_func(self, context):
- default_path = bpy.data.filename.replace(".blend", ".mdd")
- self.layout.operator(ExportMDD.bl_idname, text="Lightwave Point Cache (.mdd)").path = default_path
+ self.layout.operator(ExportMDD.bl_idname, text="Lightwave Point Cache (.mdd)")
def register():
- bpy.types.register(ExportMDD)
bpy.types.INFO_MT_file_export.append(menu_func)
def unregister():
- bpy.types.unregister(ExportMDD)
bpy.types.INFO_MT_file_export.remove(menu_func)
if __name__ == "__main__":
diff --git a/release/scripts/io/export_obj.py b/release/scripts/io/export_obj.py
index c10a698c9d3..37c6059d173 100644
--- a/release/scripts/io/export_obj.py
+++ b/release/scripts/io/export_obj.py
@@ -18,13 +18,6 @@
# <pep8 compliant>
-"""
-Name: 'Wavefront (.obj)...'
-Blender: 248
-Group: 'Export'
-Tooltip: 'Save a Wavefront OBJ File'
-"""
-
__author__ = "Campbell Barton, Jiri Hnidek, Paolo Ciccone"
__url__ = ['http://wiki.blender.org/index.php/Scripts/Manual/Export/wavefront_obj', 'www.blender.org', 'blenderartists.org']
__version__ = "1.21"
@@ -47,17 +40,7 @@ import time
import shutil
import bpy
-import Mathutils
-
-
-# Returns a tuple - path,extension.
-# 'hello.obj' > ('hello', '.obj')
-def splitExt(path):
- dotidx = path.rfind('.')
- if dotidx == -1:
- return path, ''
- else:
- return path[:dotidx], path[dotidx:]
+import mathutils
def fixName(name):
if name == None:
@@ -65,15 +48,15 @@ def fixName(name):
else:
return name.replace(' ', '_')
-def write_mtl(scene, filename, copy_images, mtl_dict):
+def write_mtl(scene, filepath, copy_images, mtl_dict):
world = scene.world
worldAmb = world.ambient_color
- dest_dir = os.path.dirname(filename)
+ dest_dir = os.path.dirname(filepath)
def copy_image(image):
- fn = bpy.utils.expandpath(image.filename)
+ fn = bpy.path.abspath(image.filepath)
fn_strip = os.path.basename(fn)
if copy_images:
rel = fn_strip
@@ -86,9 +69,9 @@ def write_mtl(scene, filename, copy_images, mtl_dict):
return rel
- file = open(filename, "w")
+ file = open(filepath, "w")
# XXX
-# file.write('# Blender MTL File: %s\n' % Blender.Get('filename').split('\\')[-1].split('/')[-1])
+# file.write('# Blender MTL File: %s\n' % Blender.Get('filepath').split('\\')[-1].split('/')[-1])
file.write('# Material Count: %i\n' % len(mtl_dict))
# Write material/image combinations we have used.
for key, (mtl_mat_name, mat, img) in mtl_dict.items():
@@ -100,7 +83,7 @@ def write_mtl(scene, filename, copy_images, mtl_dict):
if mat:
file.write('Ns %.6f\n' % ((mat.specular_hardness-1) * 1.9607843137254901) ) # Hardness, convert blenders 1-511 to MTL's
- file.write('Ka %.6f %.6f %.6f\n' % tuple([c*mat.ambient for c in worldAmb]) ) # Ambient, uses mirror colour,
+ file.write('Ka %.6f %.6f %.6f\n' % tuple([c*mat.ambient for c in worldAmb]) ) # Ambient, uses mirror colour,
file.write('Kd %.6f %.6f %.6f\n' % tuple([c*mat.diffuse_intensity for c in mat.diffuse_color]) ) # Diffuse
file.write('Ks %.6f %.6f %.6f\n' % tuple([c*mat.specular_intensity for c in mat.specular_color]) ) # Specular
if hasattr(mat, "ior"):
@@ -110,7 +93,7 @@ def write_mtl(scene, filename, copy_images, mtl_dict):
file.write('d %.6f\n' % mat.alpha) # Alpha (obj uses 'd' for dissolve)
# 0 to disable lighting, 1 for ambient & diffuse only (specular color set to black), 2 for full lighting.
- if mat.shadeless:
+ if mat.use_shadeless:
file.write('illum 0\n') # ignore lighting
elif mat.specular_intensity == 0:
file.write('illum 1\n') # no specular.
@@ -120,26 +103,26 @@ def write_mtl(scene, filename, copy_images, mtl_dict):
else:
#write a dummy material here?
file.write('Ns 0\n')
- file.write('Ka %.6f %.6f %.6f\n' % tuple([c for c in worldAmb]) ) # Ambient, uses mirror colour,
+ file.write('Ka %.6f %.6f %.6f\n' % tuple([c for c in worldAmb]) ) # Ambient, uses mirror colour,
file.write('Kd 0.8 0.8 0.8\n')
file.write('Ks 0.8 0.8 0.8\n')
file.write('d 1\n') # No alpha
file.write('illum 2\n') # light normaly
# Write images!
- if img: # We have an image on the face!
+ if img: # We have an image on the face!
# write relative image path
rel = copy_image(img)
file.write('map_Kd %s\n' % rel) # Diffuse mapping image
-# file.write('map_Kd %s\n' % img.filename.split('\\')[-1].split('/')[-1]) # Diffuse mapping image
+# file.write('map_Kd %s\n' % img.filepath.split('\\')[-1].split('/')[-1]) # Diffuse mapping image
elif mat: # No face image. if we havea material search for MTex image.
for mtex in mat.texture_slots:
if mtex and mtex.texture.type == 'IMAGE':
try:
- filename = copy_image(mtex.texture.image)
-# filename = mtex.texture.image.filename.split('\\')[-1].split('/')[-1]
- file.write('map_Kd %s\n' % filename) # Diffuse mapping image
+ filepath = copy_image(mtex.texture.image)
+# filepath = mtex.texture.image.filepath.split('\\')[-1].split('/')[-1]
+ file.write('map_Kd %s\n' % filepath) # Diffuse mapping image
break
except:
# Texture has no image though its an image type, best ignore.
@@ -164,8 +147,8 @@ def copy_file(source, dest):
def copy_images(dest_dir):
if dest_dir[-1] != os.sep:
dest_dir += os.sep
-# if dest_dir[-1] != sys.sep:
-# dest_dir += sys.sep
+# if dest_dir[-1] != sys.sep:
+# dest_dir += sys.sep
# Get unique image names
uniqueImages = {}
@@ -188,63 +171,61 @@ def copy_images(dest_dir):
# Now copy images
copyCount = 0
-# for bImage in uniqueImages.values():
-# image_path = bpy.utils.expandpath(bImage.filename)
-# if bpy.sys.exists(image_path):
-# # Make a name for the target path.
-# dest_image_path = dest_dir + image_path.split('\\')[-1].split('/')[-1]
-# if not bpy.utils.exists(dest_image_path): # Image isnt alredy there
-# print('\tCopying "%s" > "%s"' % (image_path, dest_image_path))
-# copy_file(image_path, dest_image_path)
-# copyCount+=1
+# for bImage in uniqueImages.values():
+# image_path = bpy.path.abspath(bImage.filepath)
+# if bpy.sys.exists(image_path):
+# # Make a name for the target path.
+# dest_image_path = dest_dir + image_path.split('\\')[-1].split('/')[-1]
+# if not bpy.utils.exists(dest_image_path): # Image isnt already there
+# print('\tCopying "%s" > "%s"' % (image_path, dest_image_path))
+# copy_file(image_path, dest_image_path)
+# copyCount+=1
-# paths= bpy.util.copy_images(uniqueImages.values(), dest_dir)
+# paths= bpy.util.copy_images(uniqueImages.values(), dest_dir)
print('\tCopied %d images' % copyCount)
-# print('\tCopied %d images' % copyCount)
-# XXX not converted
+
def test_nurbs_compat(ob):
- if ob.type != 'Curve':
+ if ob.type != 'CURVE':
return False
- for nu in ob.data:
- if (not nu.knotsV) and nu.type != 1: # not a surface and not bezier
+ for nu in ob.data.splines:
+ if nu.point_count_v == 1 and nu.type != 'BEZIER': # not a surface and not bezier
return True
return False
-# XXX not converted
def write_nurb(file, ob, ob_mat):
tot_verts = 0
cu = ob.data
# use negative indices
- Vector = Blender.Mathutils.Vector
- for nu in cu:
-
- if nu.type==0: DEG_ORDER_U = 1
- else: DEG_ORDER_U = nu.orderU-1 # Tested to be correct
+ for nu in cu.splines:
+ if nu.type == 'POLY':
+ DEG_ORDER_U = 1
+ else:
+ DEG_ORDER_U = nu.order_u - 1 # odd but tested to be correct
- if nu.type==1:
+ if nu.type == 'BEZIER':
print("\tWarning, bezier curve:", ob.name, "only poly and nurbs curves supported")
continue
- if nu.knotsV:
+ if nu.point_count_v > 1:
print("\tWarning, surface:", ob.name, "only poly and nurbs curves supported")
continue
- if len(nu) <= DEG_ORDER_U:
- print("\tWarning, orderU is lower then vert count, skipping:", ob.name)
+ if len(nu.points) <= DEG_ORDER_U:
+ print("\tWarning, order_u is lower then vert count, skipping:", ob.name)
continue
pt_num = 0
- do_closed = (nu.flagU & 1)
- do_endpoints = (do_closed==0) and (nu.flagU & 2)
+ do_closed = nu.use_cyclic_u
+ do_endpoints = (do_closed == 0) and nu.use_endpoint_u
- for pt in nu:
- pt = Vector(pt[0], pt[1], pt[2]) * ob_mat
+ for pt in nu.points:
+ pt = ob_mat * pt.co.copy().resize3D()
file.write('v %.6f %.6f %.6f\n' % (pt[0], pt[1], pt[2]))
pt_num += 1
tot_verts += pt_num
@@ -264,7 +245,7 @@ def write_nurb(file, ob, ob_mat):
pt_num += DEG_ORDER_U
curve_ls = curve_ls + curve_ls[0:DEG_ORDER_U]
- file.write('curv 0.0 1.0 %s\n' % (' '.join( [str(i) for i in curve_ls] ))) # Blender has no U and V values for the curve
+ file.write('curv 0.0 1.0 %s\n' % (' '.join([str(i) for i in curve_ls]))) # Blender has no U and V values for the curve
# 'parm' keyword
tot_parm = (DEG_ORDER_U + 1) + pt_num
@@ -282,7 +263,7 @@ def write_nurb(file, ob, ob_mat):
return tot_verts
-def write(filename, objects, scene,
+def write_file(filepath, objects, scene,
EXPORT_TRI=False,
EXPORT_EDGES=False,
EXPORT_NORMALS=False,
@@ -299,7 +280,7 @@ def write(filename, objects, scene,
EXPORT_POLYGROUPS=False,
EXPORT_CURVE_AS_NURBS=True):
'''
- Basic write function. The context and options must be alredy set
+ Basic write function. The context and options must be already set
This can be accessed externaly
eg.
write( 'c:\\test\\foobar.obj', Blender.Object.GetSelected() ) # Using default options.
@@ -325,10 +306,10 @@ def write(filename, objects, scene,
of vertices is the face's group
"""
weightDict = {}
- for vert_index in face.verts:
-# for vert in face:
+ for vert_index in face.vertices:
+# for vert in face:
vWeights = vWeightMap[vert_index]
-# vWeights = vWeightMap[vert]
+# vWeights = vWeightMap[vert]
for vGroupName, weight in vWeights:
weightDict[vGroupName] = weightDict.get(vGroupName, 0) + weight
@@ -343,7 +324,7 @@ def write(filename, objects, scene,
def getVertsFromGroup(me, group_index):
ret = []
- for i, v in enumerate(me.verts):
+ for i, v in enumerate(me.vertices):
for g in v.groups:
if g.group == group_index:
ret.append((i, g.weight))
@@ -351,26 +332,26 @@ def write(filename, objects, scene,
return ret
- print('OBJ Export path: "%s"' % filename)
+ print('OBJ Export path: "%s"' % filepath)
temp_mesh_name = '~tmp-mesh'
time1 = time.clock()
-# time1 = sys.time()
-# scn = Scene.GetCurrent()
+# time1 = sys.time()
+# scn = Scene.GetCurrent()
- file = open(filename, "w")
+ file = open(filepath, "w")
# Write Header
- file.write('# Blender v%s OBJ File: %s\n' % (bpy.app.version_string, bpy.data.filename.split('/')[-1].split('\\')[-1] ))
+ file.write('# Blender v%s OBJ File: %s\n' % (bpy.app.version_string, bpy.data.filepath.split('/')[-1].split('\\')[-1] ))
file.write('# www.blender.org\n')
# Tell the obj file what material file to use.
if EXPORT_MTL:
- mtlfilename = '%s.mtl' % '.'.join(filename.split('.')[:-1])
- file.write('mtllib %s\n' % ( mtlfilename.split('\\')[-1].split('/')[-1] ))
+ mtlfilepath = '%s.mtl' % '.'.join(filepath.split('.')[:-1])
+ file.write('mtllib %s\n' % ( mtlfilepath.split('\\')[-1].split('/')[-1] ))
if EXPORT_ROTX90:
- mat_xrot90= Mathutils.RotationMatrix(-math.pi/2, 4, 'X')
+ mat_xrot90= mathutils.Matrix.Rotation(-math.pi/2, 4, 'X')
# Initialize totals, these are updated each object
totverts = totuvco = totno = 1
@@ -396,48 +377,48 @@ def write(filename, objects, scene,
if ob_main.dupli_type != 'NONE':
# XXX
print('creating dupli_list on', ob_main.name)
- ob_main.create_dupli_list()
+ ob_main.create_dupli_list(scene)
obs = [(dob.object, dob.matrix) for dob in ob_main.dupli_list]
# XXX debug print
print(ob_main.name, 'has', len(obs), 'dupli children')
else:
- obs = [(ob_main, ob_main.matrix)]
+ obs = [(ob_main, ob_main.matrix_world)]
for ob, ob_mat in obs:
- # XXX postponed
-# # Nurbs curve support
-# if EXPORT_CURVE_AS_NURBS and test_nurbs_compat(ob):
-# if EXPORT_ROTX90:
-# ob_mat = ob_mat * mat_xrot90
-
-# totverts += write_nurb(file, ob, ob_mat)
-
-# continue
-# end nurbs
+ # Nurbs curve support
+ if EXPORT_CURVE_AS_NURBS and test_nurbs_compat(ob):
+ if EXPORT_ROTX90:
+ ob_mat = ob_mat * mat_xrot90
+ totverts += write_nurb(file, ob, ob_mat)
+ continue
+ # END NURBS
if ob.type != 'MESH':
continue
- me = ob.create_mesh(EXPORT_APPLY_MODIFIERS, 'PREVIEW')
+ me = ob.create_mesh(scene, EXPORT_APPLY_MODIFIERS, 'PREVIEW')
if EXPORT_ROTX90:
me.transform(mat_xrot90 * ob_mat)
else:
me.transform(ob_mat)
-# # Will work for non meshes now! :)
-# me= BPyMesh.getMeshFromObject(ob, containerMesh, EXPORT_APPLY_MODIFIERS, EXPORT_POLYGROUPS, scn)
-# if not me:
-# continue
+# # Will work for non meshes now! :)
+# me= BPyMesh.getMeshFromObject(ob, containerMesh, EXPORT_APPLY_MODIFIERS, EXPORT_POLYGROUPS, scn)
+# if not me:
+# continue
if EXPORT_UV:
faceuv = len(me.uv_textures) > 0
+ uv_layer = me.uv_textures.active.data[:]
else:
faceuv = False
+ me_verts = me.vertices[:]
+
# XXX - todo, find a better way to do triangulation
# ...removed convert_to_triface because it relies on editmesh
'''
@@ -446,7 +427,7 @@ def write(filename, objects, scene,
# Add a dummy object to it.
has_quads = False
for f in me.faces:
- if f.verts[3] != 0:
+ if f.vertices[3] != 0:
has_quads = True
break
@@ -468,7 +449,7 @@ def write(filename, objects, scene,
else:
edges = []
- if not (len(face_index_pairs)+len(edges)+len(me.verts)): # Make sure there is somthing to write
+ if not (len(face_index_pairs)+len(edges)+len(me.vertices)): # Make sure there is somthing to write
# clean up
bpy.data.meshes.remove(me)
@@ -479,13 +460,13 @@ def write(filename, objects, scene,
# High Quality Normals
if EXPORT_NORMALS and face_index_pairs:
me.calc_normals()
-# if EXPORT_NORMALS_HQ:
-# BPyMesh.meshCalcNormals(me)
-# else:
-# # transforming normals is incorrect
-# # when the matrix is scaled,
-# # better to recalculate them
-# me.calcNormals()
+# if EXPORT_NORMALS_HQ:
+# BPyMesh.meshCalcNormals(me)
+# else:
+# # transforming normals is incorrect
+# # when the matrix is scaled,
+# # better to recalculate them
+# me.calcNormals()
materials = me.materials
@@ -510,29 +491,24 @@ def write(filename, objects, scene,
if EXPORT_KEEP_VERT_ORDER:
pass
elif faceuv:
- # XXX update
- tface = me.active_uv_texture.data
-
- face_index_pairs.sort(key=lambda a: (a[0].material_index, hash(tface[a[1]].image), a[0].smooth))
+ face_index_pairs.sort(key=lambda a: (a[0].material_index, hash(uv_layer[a[1]].image), a[0].use_smooth))
elif len(materials) > 1:
- face_index_pairs.sort(key = lambda a: (a[0].material_index, a[0].smooth))
+ face_index_pairs.sort(key = lambda a: (a[0].material_index, a[0].use_smooth))
else:
# no materials
- face_index_pairs.sort(key = lambda a: a[0].smooth)
-# if EXPORT_KEEP_VERT_ORDER:
-# pass
-# elif faceuv:
-# try: faces.sort(key = lambda a: (a.mat, a.image, a.smooth))
-# except: faces.sort(lambda a,b: cmp((a.mat, a.image, a.smooth), (b.mat, b.image, b.smooth)))
-# elif len(materials) > 1:
-# try: faces.sort(key = lambda a: (a.mat, a.smooth))
-# except: faces.sort(lambda a,b: cmp((a.mat, a.smooth), (b.mat, b.smooth)))
-# else:
-# # no materials
-# try: faces.sort(key = lambda a: a.smooth)
-# except: faces.sort(lambda a,b: cmp(a.smooth, b.smooth))
-
- faces = [pair[0] for pair in face_index_pairs]
+ face_index_pairs.sort(key = lambda a: a[0].use_smooth)
+# if EXPORT_KEEP_VERT_ORDER:
+# pass
+# elif faceuv:
+# try: faces.sort(key = lambda a: (a.mat, a.image, a.use_smooth))
+# except: faces.sort(lambda a,b: cmp((a.mat, a.image, a.use_smooth), (b.mat, b.image, b.use_smooth)))
+# elif len(materials) > 1:
+# try: faces.sort(key = lambda a: (a.mat, a.use_smooth))
+# except: faces.sort(lambda a,b: cmp((a.mat, a.use_smooth), (b.mat, b.use_smooth)))
+# else:
+# # no materials
+# try: faces.sort(key = lambda a: a.use_smooth)
+# except: faces.sort(lambda a,b: cmp(a.use_smooth, b.use_smooth))
# Set the default mat to no material and no image.
contextMat = (0, 0) # Can never be this, so we will label a new material teh first chance we get.
@@ -553,28 +529,17 @@ def write(filename, objects, scene,
# Vert
- for v in me.verts:
+ for v in me_verts:
file.write('v %.6f %.6f %.6f\n' % tuple(v.co))
# UV
if faceuv:
- uv_face_mapping = [[0,0,0,0] for f in faces] # a bit of a waste for tri's :/
+ uv_face_mapping = [[0,0,0,0] for i in range(len(face_index_pairs))] # a bit of a waste for tri's :/
uv_dict = {} # could use a set() here
- uv_layer = me.active_uv_texture
+ uv_layer = me.uv_textures.active.data
for f, f_index in face_index_pairs:
-
- tface = uv_layer.data[f_index]
-
- # workaround, since tface.uv iteration is wrong atm
- uvs = tface.uv
- # uvs = [tface.uv1, tface.uv2, tface.uv3]
-
- # # add another UV if it's a quad
- # if len(f.verts) == 4:
- # uvs.append(tface.uv4)
-
- for uv_index, uv in enumerate(uvs):
+ for uv_index, uv in enumerate(uv_layer[f_index].uv):
uvkey = veckey2d(uv)
try:
uv_face_mapping[f_index][uv_index] = uv_dict[uvkey]
@@ -582,27 +547,16 @@ def write(filename, objects, scene,
uv_face_mapping[f_index][uv_index] = uv_dict[uvkey] = len(uv_dict)
file.write('vt %.6f %.6f\n' % tuple(uv))
-# uv_dict = {} # could use a set() here
-# for f_index, f in enumerate(faces):
-
-# for uv_index, uv in enumerate(f.uv):
-# uvkey = veckey2d(uv)
-# try:
-# uv_face_mapping[f_index][uv_index] = uv_dict[uvkey]
-# except:
-# uv_face_mapping[f_index][uv_index] = uv_dict[uvkey] = len(uv_dict)
-# file.write('vt %.6f %.6f\n' % tuple(uv))
-
uv_unique_count = len(uv_dict)
-# del uv, uvkey, uv_dict, f_index, uv_index
+# del uv, uvkey, uv_dict, f_index, uv_index
# Only need uv_unique_count and uv_face_mapping
# NORMAL, Smooth/Non smoothed.
if EXPORT_NORMALS:
- for f in faces:
- if f.smooth:
- for vIdx in f.verts:
- v = me.verts[vIdx]
+ for f, f_index in face_index_pairs:
+ if f.use_smooth:
+ for v_idx in f.vertices:
+ v = me_verts[v_idx]
noKey = veckey3d(v.normal)
if noKey not in globalNormals:
globalNormals[noKey] = totno
@@ -622,66 +576,66 @@ def write(filename, objects, scene,
# XXX
if EXPORT_POLYGROUPS:
# Retrieve the list of vertex groups
-# vertGroupNames = me.getVertGroupNames()
+# vertGroupNames = me.getVertGroupNames()
currentVGroup = ''
# Create a dictionary keyed by face id and listing, for each vertex, the vertex groups it belongs to
- vgroupsMap = [[] for _i in range(len(me.verts))]
-# vgroupsMap = [[] for _i in xrange(len(me.verts))]
+ vgroupsMap = [[] for _i in range(len(me_verts))]
+# vgroupsMap = [[] for _i in xrange(len(me_verts))]
for g in ob.vertex_groups:
-# for vertexGroupName in vertGroupNames:
- for vIdx, vWeight in getVertsFromGroup(me, g.index):
-# for vIdx, vWeight in me.getVertsFromGroup(vertexGroupName, 1):
- vgroupsMap[vIdx].append((g.name, vWeight))
+# for vertexGroupName in vertGroupNames:
+ for v_idx, vWeight in getVertsFromGroup(me, g.index):
+# for v_idx, vWeight in me.getVertsFromGroup(vertexGroupName, 1):
+ vgroupsMap[v_idx].append((g.name, vWeight))
- for f_index, f in enumerate(faces):
- f_v = [{"index": index, "vertex": me.verts[index]} for index in f.verts]
+ for f, f_index in face_index_pairs:
+ f_v = [me_verts[v_idx] for v_idx in f.vertices]
- # if f.verts[3] == 0:
- # f_v.pop()
+ # if f.vertices[3] == 0:
+ # f_v.pop()
-# f_v= f.v
- f_smooth= f.smooth
+# f_v= f.v
+ f_smooth= f.use_smooth
f_mat = min(f.material_index, len(materialNames)-1)
-# f_mat = min(f.mat, len(materialNames)-1)
+# f_mat = min(f.mat, len(materialNames)-1)
if faceuv:
- tface = me.active_uv_texture.data[face_index_pairs[f_index][1]]
+ tface = uv_layer[f_index]
f_image = tface.image
f_uv = tface.uv
# f_uv= [tface.uv1, tface.uv2, tface.uv3]
- # if len(f.verts) == 4:
- # f_uv.append(tface.uv4)
-# f_image = f.image
-# f_uv= f.uv
+ # if len(f.vertices) == 4:
+ # f_uv.append(tface.uv4)
+# f_image = f.image
+# f_uv= f.uv
# MAKE KEY
if faceuv and f_image: # Object is always true.
- key = materialNames[f_mat], f_image.name
+ key = materialNames[f_mat], f_image.name
else:
- key = materialNames[f_mat], None # No image, use None instead.
+ key = materialNames[f_mat], None # No image, use None instead.
# Write the vertex group
if EXPORT_POLYGROUPS:
if len(ob.vertex_groups):
# find what vertext group the face belongs to
theVGroup = findVertexGroupName(f,vgroupsMap)
- if theVGroup != currentVGroup:
+ if theVGroup != currentVGroup:
currentVGroup = theVGroup
file.write('g %s\n' % theVGroup)
-# # Write the vertex group
-# if EXPORT_POLYGROUPS:
-# if vertGroupNames:
-# # find what vertext group the face belongs to
-# theVGroup = findVertexGroupName(f,vgroupsMap)
-# if theVGroup != currentVGroup:
-# currentVGroup = theVGroup
-# file.write('g %s\n' % theVGroup)
+# # Write the vertex group
+# if EXPORT_POLYGROUPS:
+# if vertGroupNames:
+# # find what vertext group the face belongs to
+# theVGroup = findVertexGroupName(f,vgroupsMap)
+# if theVGroup != currentVGroup:
+# currentVGroup = theVGroup
+# file.write('g %s\n' % theVGroup)
# CHECK FOR CONTEXT SWITCH
if key == contextMat:
- pass # Context alredy switched, dont do anything
+ pass # Context already switched, dont do anything
else:
if key[0] == None and key[1] == None:
# Write a null material, since we know the context has changed.
@@ -725,21 +679,21 @@ def write(filename, objects, scene,
if f_smooth: # Smoothed, use vertex normals
for vi, v in enumerate(f_v):
file.write( ' %d/%d/%d' % \
- (v["index"] + totverts,
+ (v.index + totverts,
totuvco + uv_face_mapping[f_index][vi],
- globalNormals[ veckey3d(v["vertex"].normal) ]) ) # vert, uv, normal
+ globalNormals[ veckey3d(v.normal) ]) ) # vert, uv, normal
else: # No smoothing, face normals
no = globalNormals[ veckey3d(f.normal) ]
for vi, v in enumerate(f_v):
file.write( ' %d/%d/%d' % \
- (v["index"] + totverts,
+ (v.index + totverts,
totuvco + uv_face_mapping[f_index][vi],
no) ) # vert, uv, normal
else: # No Normals
for vi, v in enumerate(f_v):
file.write( ' %d/%d' % (\
- v["index"] + totverts,\
+ v.index + totverts,\
totuvco + uv_face_mapping[f_index][vi])) # vert, uv
face_vert_index += len(f_v)
@@ -749,25 +703,25 @@ def write(filename, objects, scene,
if f_smooth: # Smoothed, use vertex normals
for v in f_v:
file.write( ' %d//%d' %
- (v["index"] + totverts, globalNormals[ veckey3d(v["vertex"].normal) ]) )
+ (v.index + totverts, globalNormals[ veckey3d(v.normal) ]) )
else: # No smoothing, face normals
no = globalNormals[ veckey3d(f.normal) ]
for v in f_v:
- file.write( ' %d//%d' % (v["index"] + totverts, no) )
+ file.write( ' %d//%d' % (v.index + totverts, no) )
else: # No Normals
for v in f_v:
- file.write( ' %d' % (v["index"] + totverts) )
+ file.write( ' %d' % (v.index + totverts) )
file.write('\n')
# Write edges.
if EXPORT_EDGES:
for ed in edges:
- if ed.loose:
- file.write('f %d %d\n' % (ed.verts[0] + totverts, ed.verts[1] + totverts))
+ if ed.is_loose:
+ file.write('f %d %d\n' % (ed.vertices[0] + totverts, ed.vertices[1] + totverts))
# Make the indicies global rather then per mesh
- totverts += len(me.verts)
+ totverts += len(me_verts)
if faceuv:
totuvco += uv_unique_count
@@ -782,53 +736,53 @@ def write(filename, objects, scene,
# Now we have all our materials, save them
if EXPORT_MTL:
- write_mtl(scene, mtlfilename, EXPORT_COPY_IMAGES, mtl_dict)
-# if EXPORT_COPY_IMAGES:
-# dest_dir = os.path.basename(filename)
-# # dest_dir = filename
-# # # Remove chars until we are just the path.
-# # while dest_dir and dest_dir[-1] not in '\\/':
-# # dest_dir = dest_dir[:-1]
-# if dest_dir:
-# copy_images(dest_dir, mtl_dict)
-# else:
-# print('\tError: "%s" could not be used as a base for an image path.' % filename)
+ write_mtl(scene, mtlfilepath, EXPORT_COPY_IMAGES, mtl_dict)
+# if EXPORT_COPY_IMAGES:
+# dest_dir = os.path.basename(filepath)
+# # dest_dir = filepath
+# # # Remove chars until we are just the path.
+# # while dest_dir and dest_dir[-1] not in '\\/':
+# # dest_dir = dest_dir[:-1]
+# if dest_dir:
+# copy_images(dest_dir, mtl_dict)
+# else:
+# print('\tError: "%s" could not be used as a base for an image path.' % filepath)
print("OBJ Export time: %.2f" % (time.clock() - time1))
-# print "OBJ Export time: %.2f" % (sys.time() - time1)
-
-def do_export(filename, context,
- EXPORT_APPLY_MODIFIERS = True, # not used
- EXPORT_ROTX90 = True, # wrong
- EXPORT_TRI = False, # ok
- EXPORT_EDGES = False,
- EXPORT_NORMALS = False, # not yet
- EXPORT_NORMALS_HQ = False, # not yet
- EXPORT_UV = True, # ok
- EXPORT_MTL = True,
- EXPORT_SEL_ONLY = True, # ok
- EXPORT_ALL_SCENES = False, # XXX not working atm
- EXPORT_ANIMATION = False,
- EXPORT_COPY_IMAGES = False,
- EXPORT_BLEN_OBS = True,
- EXPORT_GROUP_BY_OB = False,
- EXPORT_GROUP_BY_MAT = False,
- EXPORT_KEEP_VERT_ORDER = False,
- EXPORT_POLYGROUPS = False,
- EXPORT_CURVE_AS_NURBS = True):
+
+def write(filepath, context,
+ EXPORT_TRI, # ok
+ EXPORT_EDGES,
+ EXPORT_NORMALS, # not yet
+ EXPORT_NORMALS_HQ, # not yet
+ EXPORT_UV, # ok
+ EXPORT_MTL,
+ EXPORT_COPY_IMAGES,
+ EXPORT_APPLY_MODIFIERS, # ok
+ EXPORT_ROTX90, # wrong
+ EXPORT_BLEN_OBS,
+ EXPORT_GROUP_BY_OB,
+ EXPORT_GROUP_BY_MAT,
+ EXPORT_KEEP_VERT_ORDER,
+ EXPORT_POLYGROUPS,
+ EXPORT_CURVE_AS_NURBS,
+ EXPORT_SEL_ONLY, # ok
+ EXPORT_ALL_SCENES, # XXX not working atm
+ EXPORT_ANIMATION): # Not used
- base_name, ext = splitExt(filename)
+ base_name, ext = os.path.splitext(filepath)
context_name = [base_name, '', '', ext] # Base name, scene name, frame number, extension
orig_scene = context.scene
# Exit edit mode before exporting, so current object states are exported properly.
- bpy.ops.object.mode_set(mode='OBJECT')
+ if context.object:
+ bpy.ops.object.mode_set(mode='OBJECT')
-# if EXPORT_ALL_SCENES:
-# export_scenes = bpy.data.scenes
-# else:
-# export_scenes = [orig_scene]
+# if EXPORT_ALL_SCENES:
+# export_scenes = bpy.data.scenes
+# else:
+# export_scenes = [orig_scene]
# XXX only exporting one scene atm since changing
# current scene is not possible.
@@ -837,49 +791,58 @@ def do_export(filename, context,
export_scenes = [orig_scene]
# Export all scenes.
- for scn in export_scenes:
- # scn.makeCurrent() # If already current, this is not slow.
- # context = scn.getRenderingContext()
- orig_frame = scn.frame_current
+ for scene in export_scenes:
+ # scene.makeCurrent() # If already current, this is not slow.
+ # context = scene.getRenderingContext()
+ orig_frame = scene.frame_current
if EXPORT_ALL_SCENES: # Add scene name into the context_name
- context_name[1] = '_%s' % bpy.utils.clean_name(scn.name) # WARNING, its possible that this could cause a collision. we could fix if were feeling parranoied.
+ context_name[1] = '_%s' % bpy.path.clean_name(scene.name) # WARNING, its possible that this could cause a collision. we could fix if were feeling parranoied.
# Export an animation?
if EXPORT_ANIMATION:
- scene_frames = range(scn.frame_start, context.frame_end + 1) # Up to and including the end frame.
+ scene_frames = range(scene.frame_start, context.frame_end + 1) # Up to and including the end frame.
else:
scene_frames = [orig_frame] # Dont export an animation.
# Loop through all frames in the scene and export.
for frame in scene_frames:
- if EXPORT_ANIMATION: # Add frame to the filename.
+ if EXPORT_ANIMATION: # Add frame to the filepath.
context_name[2] = '_%.6d' % frame
- scn.frame_current = frame
+ scene.frame_current = frame
if EXPORT_SEL_ONLY:
- export_objects = context.selected_objects
+ objects = context.selected_objects
else:
- export_objects = scn.objects
+ objects = scene.objects
full_path= ''.join(context_name)
# erm... bit of a problem here, this can overwrite files when exporting frames. not too bad.
# EXPORT THE FILE.
- write(full_path, export_objects, scn,
- EXPORT_TRI, EXPORT_EDGES, EXPORT_NORMALS,
- EXPORT_NORMALS_HQ, EXPORT_UV, EXPORT_MTL,
- EXPORT_COPY_IMAGES, EXPORT_APPLY_MODIFIERS,
- EXPORT_ROTX90, EXPORT_BLEN_OBS,
- EXPORT_GROUP_BY_OB, EXPORT_GROUP_BY_MAT, EXPORT_KEEP_VERT_ORDER,
- EXPORT_POLYGROUPS, EXPORT_CURVE_AS_NURBS)
-
-
- scn.frame_current = orig_frame
+ write_file(full_path, objects, scene,
+ EXPORT_TRI,
+ EXPORT_EDGES,
+ EXPORT_NORMALS,
+ EXPORT_NORMALS_HQ,
+ EXPORT_UV,
+ EXPORT_MTL,
+ EXPORT_COPY_IMAGES,
+ EXPORT_APPLY_MODIFIERS,
+ EXPORT_ROTX90,
+ EXPORT_BLEN_OBS,
+ EXPORT_GROUP_BY_OB,
+ EXPORT_GROUP_BY_MAT,
+ EXPORT_KEEP_VERT_ORDER,
+ EXPORT_POLYGROUPS,
+ EXPORT_CURVE_AS_NURBS)
+
+
+ scene.frame_current = orig_frame
# Restore old active scene.
-# orig_scene.makeCurrent()
-# Window.WaitCursor(0)
+# orig_scene.makeCurrent()
+# Window.WaitCursor(0)
'''
@@ -900,28 +863,28 @@ class ExportOBJ(bpy.types.Operator):
# List of operator properties, the attributes will be assigned
# to the class instance from the operator settings before calling.
- path = StringProperty(name="File Path", description="File path used for exporting the OBJ file", maxlen= 1024, default= "")
+ filepath = StringProperty(name="File Path", description="Filepath used for exporting the OBJ file", maxlen= 1024, default= "")
check_existing = BoolProperty(name="Check Existing", description="Check and warn on overwriting existing files", default=True, options={'HIDDEN'})
# context group
- use_selection = BoolProperty(name="Selection Only", description="", default= False)
+ use_selection = BoolProperty(name="Selection Only", description="Export selected objects only", default= False)
use_all_scenes = BoolProperty(name="All Scenes", description="", default= False)
- use_animation = BoolProperty(name="All Animation", description="", default= False)
+ use_animation = BoolProperty(name="Animation", description="", default= False)
# object group
- use_modifiers = BoolProperty(name="Apply Modifiers", description="", default= True)
+ use_modifiers = BoolProperty(name="Apply Modifiers", description="Apply modifiers (preview resolution)", default= True)
use_rotate90 = BoolProperty(name="Rotate X90", description="", default= True)
# extra data group
- use_edges = BoolProperty(name="Edges", description="", default= True)
- use_normals = BoolProperty(name="Normals", description="", default= False)
- use_hq_normals = BoolProperty(name="High Quality Normals", description="", default= True)
+ use_edges = BoolProperty(name="Edges", description="", default=True)
+ use_normals = BoolProperty(name="Normals", description="", default=False)
+ use_hq_normals = BoolProperty(name="High Quality Normals", description="", default=True)
use_uvs = BoolProperty(name="UVs", description="", default= True)
- use_materials = BoolProperty(name="Materials", description="", default= True)
- copy_images = BoolProperty(name="Copy Images", description="", default= False)
- use_triangles = BoolProperty(name="Triangulate", description="", default= False)
- use_vertex_groups = BoolProperty(name="Polygroups", description="", default= False)
- use_nurbs = BoolProperty(name="Nurbs", description="", default= False)
+ use_materials = BoolProperty(name="Materials", description="", default=True)
+ copy_images = BoolProperty(name="Copy Images", description="", default=False)
+ use_triangles = BoolProperty(name="Triangulate", description="", default=False)
+ use_vertex_groups = BoolProperty(name="Polygroups", description="", default=False)
+ use_nurbs = BoolProperty(name="Nurbs", description="", default=False)
# grouping group
use_blen_objects = BoolProperty(name="Objects as OBJ Objects", description="", default= True)
@@ -932,48 +895,48 @@ class ExportOBJ(bpy.types.Operator):
def execute(self, context):
- path = self.properties.path
- if not path.lower().endswith(".obj"):
- path += ".obj"
-
- do_export(path, context,
- EXPORT_TRI=self.properties.use_triangles,
- EXPORT_EDGES=self.properties.use_edges,
- EXPORT_NORMALS=self.properties.use_normals,
- EXPORT_NORMALS_HQ=self.properties.use_hq_normals,
- EXPORT_UV=self.properties.use_uvs,
- EXPORT_MTL=self.properties.use_materials,
- EXPORT_COPY_IMAGES=self.properties.copy_images,
- EXPORT_APPLY_MODIFIERS=self.properties.use_modifiers,
- EXPORT_ROTX90=self.properties.use_rotate90,
- EXPORT_BLEN_OBS=self.properties.use_blen_objects,
- EXPORT_GROUP_BY_OB=self.properties.group_by_object,
- EXPORT_GROUP_BY_MAT=self.properties.group_by_material,
- EXPORT_KEEP_VERT_ORDER=self.properties.keep_vertex_order,
- EXPORT_POLYGROUPS=self.properties.use_vertex_groups,
- EXPORT_CURVE_AS_NURBS=self.properties.use_nurbs,
- EXPORT_SEL_ONLY=self.properties.use_selection,
- EXPORT_ALL_SCENES=self.properties.use_all_scenes)
+ filepath = self.properties.filepath
+ filepath = bpy.path.ensure_ext(filepath, ".obj")
+
+ write(filepath, context,
+ EXPORT_TRI=self.properties.use_triangles,
+ EXPORT_EDGES=self.properties.use_edges,
+ EXPORT_NORMALS=self.properties.use_normals,
+ EXPORT_NORMALS_HQ=self.properties.use_hq_normals,
+ EXPORT_UV=self.properties.use_uvs,
+ EXPORT_MTL=self.properties.use_materials,
+ EXPORT_COPY_IMAGES=self.properties.copy_images,
+ EXPORT_APPLY_MODIFIERS=self.properties.use_modifiers,
+ EXPORT_ROTX90=self.properties.use_rotate90,
+ EXPORT_BLEN_OBS=self.properties.use_blen_objects,
+ EXPORT_GROUP_BY_OB=self.properties.group_by_object,
+ EXPORT_GROUP_BY_MAT=self.properties.group_by_material,
+ EXPORT_KEEP_VERT_ORDER=self.properties.keep_vertex_order,
+ EXPORT_POLYGROUPS=self.properties.use_vertex_groups,
+ EXPORT_CURVE_AS_NURBS=self.properties.use_nurbs,
+ EXPORT_SEL_ONLY=self.properties.use_selection,
+ EXPORT_ALL_SCENES=self.properties.use_all_scenes,
+ EXPORT_ANIMATION=self.properties.use_animation)
return {'FINISHED'}
def invoke(self, context, event):
- wm = context.manager
- wm.add_fileselect(self)
+ import os
+ if not self.properties.is_property_set("filepath"):
+ self.properties.filepath = os.path.splitext(bpy.data.filepath)[0] + ".obj"
+
+ context.manager.add_fileselect(self)
return {'RUNNING_MODAL'}
def menu_func(self, context):
- default_path = bpy.data.filename.replace(".blend", ".obj")
- self.layout.operator(ExportOBJ.bl_idname, text="Wavefront (.obj)").path = default_path
+ self.layout.operator(ExportOBJ.bl_idname, text="Wavefront (.obj)")
def register():
- bpy.types.register(ExportOBJ)
bpy.types.INFO_MT_file_export.append(menu_func)
def unregister():
- bpy.types.unregister(ExportOBJ)
bpy.types.INFO_MT_file_export.remove(menu_func)
@@ -986,4 +949,3 @@ def unregister():
if __name__ == "__main__":
register()
-
diff --git a/release/scripts/io/export_ply.py b/release/scripts/io/export_ply.py
index 23a3eb8b9ee..946be68ec41 100644
--- a/release/scripts/io/export_ply.py
+++ b/release/scripts/io/export_ply.py
@@ -99,11 +99,12 @@ def write(filename, scene, ob, \
Window.WaitCursor(1)
"""
- bpy.ops.object.mode_set(mode='OBJECT')
+ if scene.objects.active:
+ bpy.ops.object.mode_set(mode='OBJECT')
#mesh = BPyMesh.getMeshFromObject(ob, None, EXPORT_APPLY_MODIFIERS, False, scn) # XXX
if EXPORT_APPLY_MODIFIERS:
- mesh = ob.create_mesh(True, 'PREVIEW')
+ mesh = ob.create_mesh(scene, True, 'PREVIEW')
else:
mesh = ob.data
@@ -111,7 +112,7 @@ def write(filename, scene, ob, \
raise ("Error, could not get mesh data from active object")
return
- # mesh.transform(ob.matrixWorld) # XXX
+ # mesh.transform(ob.matrix_world) # XXX
faceUV = (len(mesh.uv_textures) > 0)
vertexUV = (len(mesh.sticky) > 0)
@@ -128,7 +129,7 @@ def write(filename, scene, ob, \
vertexColors = False
if faceUV:
- active_uv_layer = mesh.active_uv_texture
+ active_uv_layer = mesh.uv_textures.active
if not active_uv_layer:
EXPORT_UV = False
faceUV = None
@@ -136,7 +137,7 @@ def write(filename, scene, ob, \
active_uv_layer = active_uv_layer.data
if vertexColors:
- active_col_layer = mesh.active_vertex_color
+ active_col_layer = mesh.vertex_colors.active
if not active_col_layer:
EXPORT_COLORS = False
vertexColors = None
@@ -146,7 +147,7 @@ def write(filename, scene, ob, \
# incase
color = uvcoord = uvcoord_key = normal = normal_key = None
- mesh_verts = mesh.verts # save a lookup
+ mesh_verts = mesh.vertices # save a lookup
ply_verts = [] # list of dictionaries
# vdict = {} # (index, normal, uv) -> new index
vdict = [{} for i in range(len(mesh_verts))]
@@ -155,7 +156,7 @@ def write(filename, scene, ob, \
for i, f in enumerate(mesh.faces):
- smooth = f.smooth
+ smooth = f.use_smooth
if not smooth:
normal = tuple(f.normal)
normal_key = rvec3d(normal)
@@ -167,7 +168,7 @@ def write(filename, scene, ob, \
col = active_col_layer[i]
col = col.color1, col.color2, col.color3, col.color4
- f_verts = f.verts
+ f_verts = f.vertices
pf = ply_faces[i]
for j, vidx in enumerate(f_verts):
@@ -203,7 +204,7 @@ def write(filename, scene, ob, \
file.write('ply\n')
file.write('format ascii 1.0\n')
- file.write('comment Created by Blender %s - www.blender.org, source file: %s\n' % (bpy.app.version_string, bpy.data.filename.split('/')[-1].split('\\')[-1]))
+ file.write('comment Created by Blender %s - www.blender.org, source file: %s\n' % (bpy.app.version_string, bpy.data.filepath.split('/')[-1].split('\\')[-1]))
file.write('element vertex %d\n' % len(ply_verts))
@@ -267,23 +268,22 @@ class ExportPLY(bpy.types.Operator):
# to the class instance from the operator settings before calling.
- path = StringProperty(name="File Path", description="File path used for exporting the PLY file", maxlen=1024, default="")
+ filepath = StringProperty(name="File Path", description="Filepath used for exporting the PLY file", maxlen=1024, default="")
check_existing = BoolProperty(name="Check Existing", description="Check and warn on overwriting existing files", default=True, options={'HIDDEN'})
use_modifiers = BoolProperty(name="Apply Modifiers", description="Apply Modifiers to the exported mesh", default=True)
use_normals = BoolProperty(name="Normals", description="Export Normals for smooth and hard shaded faces", default=True)
use_uvs = BoolProperty(name="UVs", description="Exort the active UV layer", default=True)
use_colors = BoolProperty(name="Vertex Colors", description="Exort the active vertex color layer", default=True)
- def poll(self, context):
+ @classmethod
+ def poll(cls, context):
return context.active_object != None
def execute(self, context):
- # print("Selected: " + context.active_object.name)
+ filepath = self.properties.filepath
+ filepath = bpy.path.ensure_ext(filepath, ".ply")
- if not self.properties.path:
- raise Exception("filename not set")
-
- write(self.properties.path, context.scene, context.active_object,\
+ write(filepath, context.scene, context.active_object,\
EXPORT_APPLY_MODIFIERS=self.properties.use_modifiers,
EXPORT_NORMALS=self.properties.use_normals,
EXPORT_UV=self.properties.use_uvs,
@@ -293,8 +293,11 @@ class ExportPLY(bpy.types.Operator):
return {'FINISHED'}
def invoke(self, context, event):
- wm = context.manager
- wm.add_fileselect(self)
+ import os
+ if not self.properties.is_property_set("filepath"):
+ self.properties.filepath = os.path.splitext(bpy.data.filepath)[0] + ".ply"
+
+ context.manager.add_fileselect(self)
return {'RUNNING_MODAL'}
def draw(self, context):
@@ -310,17 +313,14 @@ class ExportPLY(bpy.types.Operator):
def menu_func(self, context):
- default_path = bpy.data.filename.replace(".blend", ".ply")
- self.layout.operator(ExportPLY.bl_idname, text="Stanford (.ply)").path = default_path
+ self.layout.operator(ExportPLY.bl_idname, text="Stanford (.ply)")
def register():
- bpy.types.register(ExportPLY)
bpy.types.INFO_MT_file_export.append(menu_func)
def unregister():
- bpy.types.unregister(ExportPLY)
bpy.types.INFO_MT_file_export.remove(menu_func)
if __name__ == "__main__":
diff --git a/release/scripts/io/export_x3d.py b/release/scripts/io/export_x3d.py
index dccc5808bc5..12fe63f5296 100644
--- a/release/scripts/io/export_x3d.py
+++ b/release/scripts/io/export_x3d.py
@@ -69,7 +69,7 @@ import math
import os
import bpy
-import Mathutils
+import mathutils
from export_3ds import create_derived_objects, free_derived_objects
@@ -81,7 +81,7 @@ from export_3ds import create_derived_objects, free_derived_objects
#
DEG2RAD=0.017453292519943295
-MATWORLD= Mathutils.RotationMatrix(-90, 4, 'X')
+MATWORLD= mathutils.Matrix.Rotation(-90, 4, 'X')
####################################
# Global Variables
@@ -237,7 +237,7 @@ class x3d_class:
lens = min(lens, math.pi)
# get the camera location, subtract 90 degress from X to orient like X3D does
- # mat = ob.matrixWorld - mat is now passed!
+ # mat = ob.matrix_world - mat is now passed!
loc = self.rotatePointForVRML(mat.translation_part())
rot = mat.to_euler()
@@ -258,12 +258,9 @@ class x3d_class:
def writeFog(self, world):
if world:
- mtype = world.mist.falloff
- # mtype = world.getMistype()
- mparam = world.mist
- # mparam = world.getMist()
+ mtype = world.mist_settings.falloff
+ mparam = world.mist_settings
grd = world.horizon_color
- # grd = world.getHor()
grd0, grd1, grd2 = grd[0], grd[1], grd[2]
else:
return
@@ -300,7 +297,7 @@ class x3d_class:
# note -dz seems to equal om[3][1]
# note dy seems to equal om[3][2]
- #location=(ob.matrixWorld*MATWORLD).translation_part() # now passed
+ #location=(ob.matrix_world*MATWORLD).translation_part() # now passed
location=(mtx*MATWORLD).translation_part()
radius = lamp.distance*math.cos(beamWidth)
@@ -346,7 +343,7 @@ class x3d_class:
ambi = 0
ambientIntensity = 0
- # location=(ob.matrixWorld*MATWORLD).translation_part() # now passed
+ # location=(ob.matrix_world*MATWORLD).translation_part() # now passed
location= (mtx*MATWORLD).translation_part()
self.file.write("<PointLight DEF=\"%s\" " % safeName)
@@ -364,7 +361,7 @@ class x3d_class:
return
else:
dx,dy,dz = self.computeDirection(mtx)
- # location=(ob.matrixWorld*MATWORLD).translation_part()
+ # location=(ob.matrix_world*MATWORLD).translation_part()
location=(mtx*MATWORLD).translation_part()
self.writeIndented("<%s\n" % obname,1)
self.writeIndented("direction=\"%s %s %s\"\n" % (round(dx,3),round(dy,3),round(dz,3)))
@@ -402,17 +399,17 @@ class x3d_class:
if len(mesh.faces) == 0: return
mode = []
# mode = 0
- if mesh.active_uv_texture:
+ if mesh.uv_textures.active:
# if mesh.faceUV:
- for face in mesh.active_uv_texture.data:
+ for face in mesh.uv_textures.active.data:
# for face in mesh.faces:
- if face.halo and 'HALO' not in mode:
+ if face.use_halo and 'HALO' not in mode:
mode += ['HALO']
- if face.billboard and 'BILLBOARD' not in mode:
+ if face.use_billboard and 'BILLBOARD' not in mode:
mode += ['BILLBOARD']
- if face.object_color and 'OBJECT_COLOR' not in mode:
+ if face.use_object_color and 'OBJECT_COLOR' not in mode:
mode += ['OBJECT_COLOR']
- if face.collision and 'COLLISION' not in mode:
+ if face.use_collision and 'COLLISION' not in mode:
mode += ['COLLISION']
# mode |= face.mode
@@ -445,7 +442,7 @@ class x3d_class:
else:
bTwoSided=0
- # mtx = ob.matrixWorld * MATWORLD # mtx is now passed
+ # mtx = ob.matrix_world * MATWORLD # mtx is now passed
mtx = mtx * MATWORLD
loc= mtx.translation_part()
@@ -461,16 +458,16 @@ class x3d_class:
self.writeIndented("<Shape>\n",1)
maters=mesh.materials
hasImageTexture=0
- issmooth=0
+ is_smooth = False
- if len(maters) > 0 or mesh.active_uv_texture:
+ if len(maters) > 0 or mesh.uv_textures.active:
# if len(maters) > 0 or mesh.faceUV:
self.writeIndented("<Appearance>\n", 1)
# right now this script can only handle a single material per mesh.
if len(maters) >= 1:
mat=maters[0]
# matFlags = mat.getMode()
- if not mat.face_texture:
+ if not mat.use_face_texture:
# if not matFlags & Blender.Material.Modes['TEXFACE']:
self.writeMaterial(mat, self.cleanStr(mat.name,''), world)
# self.writeMaterial(mat, self.cleanStr(maters[0].name,''), world)
@@ -480,9 +477,9 @@ class x3d_class:
#-- textures
face = None
- if mesh.active_uv_texture:
+ if mesh.uv_textures.active:
# if mesh.faceUV:
- for face in mesh.active_uv_texture.data:
+ for face in mesh.uv_textures.active.data:
# for face in mesh.faces:
if face.image:
# if (hasImageTexture == 0) and (face.image):
@@ -516,16 +513,16 @@ class x3d_class:
self.file.write("solid=\"true\" ")
for face in mesh.faces:
- if face.smooth:
- issmooth=1
- break
- if issmooth==1:
- creaseAngle=(mesh.autosmooth_angle)*(math.pi/180.0)
+ if face.use_smooth:
+ is_smooth = True
+ break
+ if is_smooth == True:
+ creaseAngle=(mesh.auto_smooth_angle)*(math.pi/180.0)
# creaseAngle=(mesh.degr)*(math.pi/180.0)
self.file.write("creaseAngle=\"%s\" " % (round(creaseAngle,self.cp)))
#--- output textureCoordinates if UV texture used
- if mesh.active_uv_texture:
+ if mesh.uv_textures.active:
# if mesh.faceUV:
if self.matonly == 1 and self.share == 1:
self.writeFaceColors(mesh)
@@ -540,7 +537,7 @@ class x3d_class:
self.writeCoordinates(ob, mesh, meshName, EXPORT_TRI)
#--- output textureCoordinates if UV texture used
- if mesh.active_uv_texture:
+ if mesh.uv_textures.active:
# if mesh.faceUV:
if hasImageTexture == 1:
self.writeTextureCoordinates(mesh)
@@ -581,7 +578,7 @@ class x3d_class:
if self.writingcoords == 0:
self.file.write('coordIndex="')
for face in mesh.faces:
- fv = face.verts
+ fv = face.vertices
# fv = face.v
if len(fv)==3:
@@ -601,10 +598,10 @@ class x3d_class:
self.file.write("\">\n")
else:
#-- vertices
- # mesh.transform(ob.matrixWorld)
+ # mesh.transform(ob.matrix_world)
self.writeIndented("<Coordinate DEF=\"%s%s\" \n" % ("coord_",meshName), 1)
self.file.write("\t\t\t\tpoint=\"")
- for v in mesh.verts:
+ for v in mesh.vertices:
self.file.write("%.6f %.6f %.6f, " % tuple(v.co))
self.file.write("\" />")
self.writeIndented("\n", -1)
@@ -614,11 +611,11 @@ class x3d_class:
texIndexList=[]
j=0
- for face in mesh.active_uv_texture.data:
+ for face in mesh.uv_textures.active.data:
# for face in mesh.faces:
# workaround, since tface.uv iteration is wrong atm
uvs = face.uv
- # uvs = [face.uv1, face.uv2, face.uv3, face.uv4] if face.verts[3] else [face.uv1, face.uv2, face.uv3]
+ # uvs = [face.uv1, face.uv2, face.uv3, face.uv4] if face.vertices[3] else [face.uv1, face.uv2, face.uv3]
for uv in uvs:
# for uv in face.uv:
@@ -646,10 +643,10 @@ class x3d_class:
def writeFaceColors(self, mesh):
if self.writingcolor == 0:
self.file.write("colorPerVertex=\"false\" ")
- elif mesh.active_vertex_color:
+ elif mesh.vertex_colors.active:
# else:
self.writeIndented("<Color color=\"", 1)
- for face in mesh.active_vertex_color.data:
+ for face in mesh.vertex_colors.active.data:
c = face.color1
if self.verbose > 2:
print("Debug: face.col r=%d g=%d b=%d" % (c[0], c[1], c[2]))
@@ -699,7 +696,7 @@ class x3d_class:
# specB = (mat.specCol[2]+0.001)/(1.25/(mat.spec+0.001))
transp = 1-mat.alpha
# matFlags = mat.getMode()
- if mat.shadeless:
+ if mat.use_shadeless:
# if matFlags & Blender.Material.Modes['SHADELESS']:
ambient = 1
shine = 1
@@ -717,7 +714,7 @@ class x3d_class:
def writeImageTexture(self, image):
name = image.name
- filename = image.filename.split('/')[-1].split('\\')[-1]
+ filename = image.filepath.split('/')[-1].split('\\')[-1]
if name in self.texNames:
self.writeIndented("<ImageTexture USE=\"%s\" />\n" % self.cleanStr(name))
self.texNames[name] += 1
@@ -731,7 +728,7 @@ class x3d_class:
def writeBackground(self, world, alltextures):
if world: worldname = world.name
else: return
- blending = (world.blend_sky, world.paper_sky, world.real_sky)
+ blending = (world.use_sky_blend, world.use_sky_paper, world.use_sky_real)
# blending = world.getSkytype()
grd = world.horizon_color
# grd = world.getHor()
@@ -794,28 +791,28 @@ class x3d_class:
pic = tex.image
# using .expandpath just in case, os.path may not expect //
- basename = os.path.basename(bpy.utils.expandpath(pic.filename))
+ basename = os.path.basename(bpy.path.abspath(pic.filepath))
pic = alltextures[i].image
# pic = alltextures[i].getImage()
if (namemat == "back") and (pic != None):
self.file.write("\n\tbackUrl=\"%s\" " % basename)
- # self.file.write("\n\tbackUrl=\"%s\" " % pic.filename.split('/')[-1].split('\\')[-1])
+ # self.file.write("\n\tbackUrl=\"%s\" " % pic.filepath.split('/')[-1].split('\\')[-1])
elif (namemat == "bottom") and (pic != None):
self.writeIndented("bottomUrl=\"%s\" " % basename)
- # self.writeIndented("bottomUrl=\"%s\" " % pic.filename.split('/')[-1].split('\\')[-1])
+ # self.writeIndented("bottomUrl=\"%s\" " % pic.filepath.split('/')[-1].split('\\')[-1])
elif (namemat == "front") and (pic != None):
self.writeIndented("frontUrl=\"%s\" " % basename)
- # self.writeIndented("frontUrl=\"%s\" " % pic.filename.split('/')[-1].split('\\')[-1])
+ # self.writeIndented("frontUrl=\"%s\" " % pic.filepath.split('/')[-1].split('\\')[-1])
elif (namemat == "left") and (pic != None):
self.writeIndented("leftUrl=\"%s\" " % basename)
- # self.writeIndented("leftUrl=\"%s\" " % pic.filename.split('/')[-1].split('\\')[-1])
+ # self.writeIndented("leftUrl=\"%s\" " % pic.filepath.split('/')[-1].split('\\')[-1])
elif (namemat == "right") and (pic != None):
self.writeIndented("rightUrl=\"%s\" " % basename)
- # self.writeIndented("rightUrl=\"%s\" " % pic.filename.split('/')[-1].split('\\')[-1])
+ # self.writeIndented("rightUrl=\"%s\" " % pic.filepath.split('/')[-1].split('\\')[-1])
elif (namemat == "top") and (pic != None):
self.writeIndented("topUrl=\"%s\" " % basename)
- # self.writeIndented("topUrl=\"%s\" " % pic.filename.split('/')[-1].split('\\')[-1])
+ # self.writeIndented("topUrl=\"%s\" " % pic.filepath.split('/')[-1].split('\\')[-1])
self.writeIndented("/>\n\n")
##########################################################
@@ -852,10 +849,10 @@ class x3d_class:
# --------------------------
- for ob_main in [o for o in scene.objects if o.is_visible()]:
+ for ob_main in [o for o in scene.objects if o.is_visible(scene)]:
# for ob_main in scene.objects.context:
- free, derived = create_derived_objects(ob_main)
+ free, derived = create_derived_objects(scene, ob_main)
if derived == None: continue
@@ -871,7 +868,7 @@ class x3d_class:
# elif objType in ("Mesh", "Curve", "Surf", "Text") :
if EXPORT_APPLY_MODIFIERS or objType != 'MESH':
# if EXPORT_APPLY_MODIFIERS or objType != 'Mesh':
- me = ob.create_mesh(EXPORT_APPLY_MODIFIERS, 'PREVIEW')
+ me = ob.create_mesh(scene, EXPORT_APPLY_MODIFIERS, 'PREVIEW')
# me= BPyMesh.getMeshFromObject(ob, containerMesh, EXPORT_APPLY_MODIFIERS, False, scene)
else:
me = ob.data
@@ -912,7 +909,7 @@ class x3d_class:
# if EXPORT_APPLY_MODIFIERS:
# if containerMesh:
- # containerMesh.verts = None
+ # containerMesh.vertices = None
self.cleanup()
@@ -961,16 +958,11 @@ class x3d_class:
faceMap={}
nFaceIndx=0
- if mesh.active_uv_texture:
+ if mesh.uv_textures.active:
# if mesh.faceUV:
- for face in mesh.active_uv_texture.data:
- # for face in mesh.faces:
- sidename='';
- if face.twoside:
- # if face.mode & Mesh.FaceModes.TWOSIDE:
- sidename='two'
- else:
- sidename='one'
+ for face in mesh.uv_textures.active.data:
+ # for face in mesh.faces
+ sidename = "two" if face.use_twoside else "one"
if sidename in sided:
sided[sidename]+=1
@@ -1003,8 +995,8 @@ class x3d_class:
if face.mode & Mesh.FaceModes.TWOSIDE:
print("Debug: face.mode twosided")
- print("Debug: face.transp=0x%x (enum)" % face.transp)
- if face.transp == Mesh.FaceTranspModes.SOLID:
+ print("Debug: face.transp=0x%x (enum)" % face.blend_type)
+ if face.blend_type == Mesh.FaceTranspModes.SOLID:
print("Debug: face.transp.SOLID")
if face.image:
@@ -1030,7 +1022,7 @@ class x3d_class:
# print("Debug: mesh.faceUV=%d" % mesh.faceUV)
print("Debug: mesh.hasVertexColours=%d" % (len(mesh.vertex_colors) > 0))
# print("Debug: mesh.hasVertexColours=%d" % mesh.hasVertexColours())
- print("Debug: mesh.verts=%d" % len(mesh.verts))
+ print("Debug: mesh.vertices=%d" % len(mesh.vertices))
print("Debug: mesh.faces=%d" % len(mesh.faces))
print("Debug: mesh.materials=%d" % len(mesh.materials))
@@ -1140,7 +1132,7 @@ class x3d_class:
# Callbacks, needed before Main
##########################################################
-def x3d_export(filename,
+def write(filename,
context,
EXPORT_APPLY_MODIFIERS=False,
EXPORT_TRI=False,
@@ -1156,8 +1148,9 @@ def x3d_export(filename,
scene = context.scene
world = scene.world
-
- bpy.ops.object.mode_set(mode='OBJECT')
+
+ if scene.objects.active:
+ bpy.ops.object.mode_set(mode='OBJECT')
# XXX these are global textures while .Get() returned only scene's?
alltextures = bpy.data.textures
@@ -1174,50 +1167,6 @@ def x3d_export(filename,
)
-def x3d_export_ui(filename):
- if not filename.endswith(extension):
- filename += extension
- #if _safeOverwrite and sys.exists(filename):
- # result = Draw.PupMenu("File Already Exists, Overwrite?%t|Yes%x1|No%x0")
- #if(result != 1):
- # return
-
- # Get user options
- EXPORT_APPLY_MODIFIERS = Draw.Create(1)
- EXPORT_TRI = Draw.Create(0)
- EXPORT_GZIP = Draw.Create( filename.lower().endswith('.x3dz') )
-
- # Get USER Options
- pup_block = [\
- ('Apply Modifiers', EXPORT_APPLY_MODIFIERS, 'Use transformed mesh data from each object.'),\
- ('Triangulate', EXPORT_TRI, 'Triangulate quads.'),\
- ('Compress', EXPORT_GZIP, 'GZip the resulting file, requires a full python install'),\
- ]
-
- if not Draw.PupBlock('Export...', pup_block):
- return
-
- Blender.Window.EditMode(0)
- Blender.Window.WaitCursor(1)
-
- x3d_export(filename,\
- EXPORT_APPLY_MODIFIERS = EXPORT_APPLY_MODIFIERS.val,\
- EXPORT_TRI = EXPORT_TRI.val,\
- EXPORT_GZIP = EXPORT_GZIP.val\
- )
-
- Blender.Window.WaitCursor(0)
-
-
-
-#########################################################
-# main routine
-#########################################################
-
-
-# if __name__ == '__main__':
-# Blender.Window.FileSelector(x3d_export_ui,"Export X3D", Blender.Get('filename').replace('.blend', '.x3d'))
-
from bpy.props import *
class ExportX3D(bpy.types.Operator):
@@ -1227,7 +1176,7 @@ class ExportX3D(bpy.types.Operator):
# List of operator properties, the attributes will be assigned
# to the class instance from the operator settings before calling.
- path = StringProperty(name="File Path", description="File path used for exporting the X3D file", maxlen= 1024, default= "")
+ filepath = StringProperty(name="File Path", description="Filepath used for exporting the X3D 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)
@@ -1235,26 +1184,35 @@ class ExportX3D(bpy.types.Operator):
compress = BoolProperty(name="Compress", description="GZip the resulting file, requires a full python install", default=False)
def execute(self, context):
- x3d_export(self.properties.path, context, self.properties.apply_modifiers, self.properties.triangulate, self.properties.compress)
+ filepath = self.properties.filepath
+ filepath = bpy.path.ensure_ext(filepath, ".x3d")
+
+ write(filepath,
+ context,
+ self.properties.apply_modifiers,
+ self.properties.triangulate,
+ self.properties.compress,
+ )
+
return {'FINISHED'}
def invoke(self, context, event):
- wm = context.manager
- wm.add_fileselect(self)
+ import os
+ if not self.properties.is_property_set("filepath"):
+ self.properties.filepath = os.path.splitext(bpy.data.filepath)[0] + ".x3d"
+
+ context.manager.add_fileselect(self)
return {'RUNNING_MODAL'}
def menu_func(self, context):
- default_path = bpy.data.filename.replace(".blend", ".x3d")
- self.layout.operator(ExportX3D.bl_idname, text="X3D Extensible 3D (.x3d)").path = default_path
+ self.layout.operator(ExportX3D.bl_idname, text="X3D Extensible 3D (.x3d)")
def register():
- bpy.types.register(ExportX3D)
bpy.types.INFO_MT_file_export.append(menu_func)
def unregister():
- bpy.types.unregister(ExportX3D)
bpy.types.INFO_MT_file_export.remove(menu_func)
# NOTES
@@ -1262,4 +1220,3 @@ def unregister():
if __name__ == "__main__":
register()
-
diff --git a/release/scripts/io/import_anim_bvh.py b/release/scripts/io/import_anim_bvh.py
index e6142a2db8a..04cae915a49 100644
--- a/release/scripts/io/import_anim_bvh.py
+++ b/release/scripts/io/import_anim_bvh.py
@@ -22,8 +22,8 @@ import math
from math import radians
import bpy
-import Mathutils
-from Mathutils import Vector, Euler, Matrix, RotationMatrix, TranslationMatrix
+import mathutils
+from mathutils import Vector, Euler, Matrix
class bvh_node_class(object):
@@ -78,12 +78,12 @@ MATRIX_IDENTITY_4x4 = Matrix([1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0,
def eulerRotate(x, y, z, rot_order):
# Clamp all values between 0 and 360, values outside this raise an error.
- mats = [RotationMatrix(x, 3, 'X'), RotationMatrix(y, 3, 'Y'), RotationMatrix(z, 3, 'Z')]
+ mats = [Matrix.Rotation(x, 3, 'X'), Matrix.Rotation(y, 3, 'Y'), Matrix.Rotation(z, 3, 'Z')]
return (MATRIX_IDENTITY_3x3 * mats[rot_order[0]] * (mats[rot_order[1]] * (mats[rot_order[2]]))).to_euler()
# Should work but doesnt!
'''
- eul = Euler(x,y,z)
+ eul = Euler((x, y, z))
eul.order = "XYZ"[rot_order[0]] + "XYZ"[rot_order[1]] + "XYZ"[rot_order[2]]
return tuple(eul.to_matrix().to_euler())
'''
@@ -136,7 +136,7 @@ def read_bvh(context, file_path, ROT_MODE='XYZ', GLOBAL_SCALE=1.0):
#print '%snode: %s, parent: %s' % (len(bvh_nodes_serial) * ' ', name, bvh_nodes_serial[-1])
lineIdx += 2 # Incriment to the next line (Offset)
- rest_head_local = Vector(float(file_lines[lineIdx][1]), float(file_lines[lineIdx][2]), float(file_lines[lineIdx][3])) * GLOBAL_SCALE
+ rest_head_local = Vector((float(file_lines[lineIdx][1]), float(file_lines[lineIdx][2]), float(file_lines[lineIdx][3]))) * GLOBAL_SCALE
lineIdx += 1 # Incriment to the next line (Channels)
# newChannel[Xposition, Yposition, Zposition, Xrotation, Yrotation, Zrotation]
@@ -188,7 +188,7 @@ def read_bvh(context, file_path, ROT_MODE='XYZ', GLOBAL_SCALE=1.0):
# Account for an end node
if file_lines[lineIdx][0].lower() == 'end' and file_lines[lineIdx][1].lower() == 'site': # There is somtimes a name after 'End Site' but we will ignore it.
lineIdx += 2 # Incriment to the next line (Offset)
- rest_tail = Vector(float(file_lines[lineIdx][1]), float(file_lines[lineIdx][2]), float(file_lines[lineIdx][3])) * GLOBAL_SCALE
+ rest_tail = Vector((float(file_lines[lineIdx][1]), float(file_lines[lineIdx][2]), float(file_lines[lineIdx][3]))) * GLOBAL_SCALE
bvh_nodes_serial[-1].rest_tail_world = bvh_nodes_serial[-1].rest_head_world + rest_tail
bvh_nodes_serial[-1].rest_tail_local = bvh_nodes_serial[-1].rest_head_local + rest_tail
@@ -267,8 +267,8 @@ def read_bvh(context, file_path, ROT_MODE='XYZ', GLOBAL_SCALE=1.0):
# raise 'error, bvh node has no end and no children. bad file'
# Removed temp for now
- rest_tail_world = Vector(0.0, 0.0, 0.0)
- rest_tail_local = Vector(0.0, 0.0, 0.0)
+ rest_tail_world = Vector((0.0, 0.0, 0.0))
+ rest_tail_local = Vector((0.0, 0.0, 0.0))
for bvh_node_child in bvh_node.children:
rest_tail_world += bvh_node_child.rest_head_world
rest_tail_local += bvh_node_child.rest_head_local
@@ -328,7 +328,7 @@ def bvh_node_dict2objects(context, bvh_nodes, IMPORT_START_FRAME=1, IMPORT_LOOP=
lx, ly, lz, rx, ry, rz = bvh_node.anim_data[frame_current]
rest_head_local = bvh_node.rest_head_local
- bvh_node.temp.loc = rest_head_local + Vector(lx, ly, lz)
+ bvh_node.temp.loc = rest_head_local + Vector((lx, ly, lz))
bvh_node.temp.rot = rx, ry, rz
@@ -347,7 +347,7 @@ def bvh_node_dict2armature(context, bvh_nodes, ROT_MODE='XYZ', IMPORT_START_FRAM
scn = context.scene
#XXX scn.objects.selected = []
for ob in scn.objects:
- ob.selected = False
+ ob.select = False
scn.set_frame(IMPORT_START_FRAME)
@@ -356,7 +356,7 @@ def bvh_node_dict2armature(context, bvh_nodes, ROT_MODE='XYZ', IMPORT_START_FRAM
scn.objects.link(arm_ob)
- arm_ob.selected = True
+ arm_ob.select = True
scn.objects.active = arm_ob
print(scn.objects.active)
@@ -426,7 +426,7 @@ def bvh_node_dict2armature(context, bvh_nodes, ROT_MODE='XYZ', IMPORT_START_FRAM
bvh_node.parent and\
bvh_node.parent.temp.name not in ZERO_AREA_BONES and\
bvh_node.parent.rest_tail_local == bvh_node.rest_head_local:
- bvh_node.temp.connected = True
+ bvh_node.temp.use_connect = True
# Replace the editbone with the editbone name,
# to avoid memory errors accessing the editbone outside editmode
@@ -458,13 +458,11 @@ def bvh_node_dict2armature(context, bvh_nodes, ROT_MODE='XYZ', IMPORT_START_FRAM
pose_bone = pose_bones[bone_name]
pose_bone.rotation_mode = eul_order_lookup[tuple(bvh_node.rot_order)]
- elif ROT_MODE == 'XYZ':
- print(2)
+ elif ROT_MODE != 'QUATERNION':
for pose_bone in pose_bones:
- pose_bone.rotation_mode = 'XYZ'
+ pose_bone.rotation_mode = ROT_MODE
else:
# Quats default
- print(3)
pass
context.scene.update()
@@ -520,18 +518,18 @@ def bvh_node_dict2armature(context, bvh_nodes, ROT_MODE='XYZ', IMPORT_START_FRAM
lx, ly, lz, rx, ry, rz = bvh_node.anim_data[frame_current + 1]
if bvh_node.has_rot:
- bone_rotation_matrix = Euler(rx, ry, rz).to_matrix().resize4x4()
+ bone_rotation_matrix = Euler((rx, ry, rz)).to_matrix().resize4x4()
bone_rotation_matrix = bone_rest_matrix_inv * bone_rotation_matrix * bone_rest_matrix
if ROT_MODE == 'QUATERNION':
pose_bone.rotation_quaternion = bone_rotation_matrix.to_quat()
else:
- euler = bone_rotation_matrix.to_euler('XYZ', prev_euler[i]) # pose_bone.rotation_mode # TODO, XYZ default for now
+ euler = bone_rotation_matrix.to_euler(pose_bone.rotation_mode, prev_euler[i])
pose_bone.rotation_euler = euler
prev_euler[i] = euler
if bvh_node.has_loc:
- pose_bone.location = (bone_rest_matrix_inv * TranslationMatrix(Vector(lx, ly, lz) - bvh_node.rest_head_local)).translation_part()
+ pose_bone.location = (bone_rest_matrix_inv * Matrix.Translation(Vector((lx, ly, lz)) - bvh_node.rest_head_local)).translation_part()
if bvh_node.has_loc:
pose_bone.keyframe_insert("location")
@@ -563,23 +561,23 @@ class BvhImporter(bpy.types.Operator):
bl_idname = "import_anim.bvh"
bl_label = "Import BVH"
- path = StringProperty(name="File Path", description="File path used for importing the OBJ file", maxlen=1024, default="")
+ filepath = StringProperty(name="File Path", description="Filepath used for importing the OBJ file", maxlen=1024, default="")
scale = FloatProperty(name="Scale", description="Scale the BVH by this value", min=0.0001, max=1000000.0, soft_min=0.001, soft_max=100.0, default=0.1)
frame_start = IntProperty(name="Start Frame", description="Starting frame for the animation", default=1)
loop = BoolProperty(name="Loop", description="Loop the animation playback", default=False)
rotate_mode = EnumProperty(items=(
('QUATERNION', "Quaternion", "Convert rotations to quaternions"),
- # ('NATIVE', "Euler (Native)", "Use the rotation order defined in the BVH file"),
+ ('NATIVE', "Euler (Native)", "Use the rotation order defined in the BVH file"),
('XYZ', "Euler (XYZ)", "Convert rotations to euler XYZ"),
- # ('XZY', "Euler (XZY)", "Convert rotations to euler XZY"),
- # ('YXZ', "Euler (YXZ)", "Convert rotations to euler YXZ"),
- # ('YZX', "Euler (YZX)", "Convert rotations to euler YZX"),
- # ('ZXY', "Euler (ZXY)", "Convert rotations to euler ZXY"),
- # ('ZYX', "Euler (ZYX)", "Convert rotations to euler ZYX")),
+ ('XZY', "Euler (XZY)", "Convert rotations to euler XZY"),
+ ('YXZ', "Euler (YXZ)", "Convert rotations to euler YXZ"),
+ ('YZX', "Euler (YZX)", "Convert rotations to euler YZX"),
+ ('ZXY', "Euler (ZXY)", "Convert rotations to euler ZXY"),
+ ('ZYX', "Euler (ZYX)", "Convert rotations to euler ZYX"),
),
name="Rotation",
description="Rotation conversion.",
- default='QUATERNION')
+ default='NATIVE')
def execute(self, context):
# print("Selected: " + context.active_object.name)
@@ -587,7 +585,7 @@ class BvhImporter(bpy.types.Operator):
t1 = time.time()
print('\tparsing bvh...', end="")
- bvh_nodes = read_bvh(context, self.properties.path,
+ bvh_nodes = read_bvh(context, self.properties.filepath,
ROT_MODE=self.properties.rotate_mode,
GLOBAL_SCALE=self.properties.scale)
@@ -614,12 +612,10 @@ def menu_func(self, context):
def register():
- bpy.types.register(BvhImporter)
bpy.types.INFO_MT_file_import.append(menu_func)
def unregister():
- bpy.types.unregister(BvhImporter)
bpy.types.INFO_MT_file_import.remove(menu_func)
if __name__ == "__main__":
diff --git a/release/scripts/io/import_scene_3ds.py b/release/scripts/io/import_scene_3ds.py
index 19bb734028b..d34b5ad0723 100644
--- a/release/scripts/io/import_scene_3ds.py
+++ b/release/scripts/io/import_scene_3ds.py
@@ -141,10 +141,10 @@ import os
import time
import struct
-from import_scene_obj import unpack_face_list, load_image
+from import_scene_obj import load_image
import bpy
-import Mathutils
+import mathutils
BOUNDS_3DS = []
@@ -266,12 +266,10 @@ def read_string(file):
s += struct.unpack('<c', file.read(1))[0]
#print 'string: ',s
+ #remove the null character from the string
s = str(s[:-1], 'ASCII')
# print("read string", s)
-
- #remove the null character from the string
return s
-# return s[:-1]
######################################################
# IMPORT
@@ -300,7 +298,6 @@ def add_texture_to_material(image, texture, material, mapto):
if image:
texture.image = image
-# if image: texture.setImage(image) # double check its an image.
material.add_texture(texture, "UV", mapto)
@@ -310,12 +307,12 @@ def process_next_chunk(file, previous_chunk, importedObjects, IMAGE_SEARCH):
contextObName = None
contextLamp = [None, None] # object, Data
contextMaterial = None
- contextMatrix_rot = None # Blender.Mathutils.Matrix(); contextMatrix.identity()
- #contextMatrix_tx = None # Blender.Mathutils.Matrix(); contextMatrix.identity()
- contextMesh_vertls = None
+ contextMatrix_rot = None # Blender.mathutils.Matrix(); contextMatrix.identity()
+ #contextMatrix_tx = None # Blender.mathutils.Matrix(); contextMatrix.identity()
+ contextMesh_vertls = None # flat array: (verts * 3)
contextMesh_facels = None
contextMeshMaterials = {} # matname:[face_idxs]
- contextMeshUV = None
+ contextMeshUV = None # flat array (verts * 2)
TEXTURE_DICT = {}
MATDICT = {}
@@ -333,115 +330,71 @@ def process_next_chunk(file, previous_chunk, importedObjects, IMAGE_SEARCH):
# print STRUCT_SIZE_4x3MAT, ' STRUCT_SIZE_4x3MAT'
def putContextMesh(myContextMesh_vertls, myContextMesh_facels, myContextMeshMaterials):
-
- materialFaces = set() # faces that have a material. Can optimize?
-
- # Now make copies with assigned materils.
-
- def makeMeshMaterialCopy(matName, faces):
- '''
- Make a new mesh with only face the faces that use this material.
- faces can be any iterable object - containing ints.
- '''
-
- faceVertUsers = [False] * len(myContextMesh_vertls)
- ok = 0
- for fIdx in faces:
- for vindex in myContextMesh_facels[fIdx]:
- faceVertUsers[vindex] = True
- if matName != None: # if matName is none then this is a set(), meaning we are using the untextured faces and do not need to store textured faces.
- materialFaces.add(fIdx)
- ok = 1
-
- if not ok:
- return
-
- myVertMapping = {}
- vertMappingIndex = 0
-
- vertsToUse = [i for i in range(len(myContextMesh_vertls)) if faceVertUsers[i]]
- myVertMapping = dict( [ (ii, i) for i, ii in enumerate(vertsToUse) ] )
-
- tempName= '%s_%s' % (contextObName, matName) # matName may be None.
- bmesh = bpy.data.meshes.new(tempName)
-
- if matName == None:
- img = None
+
+ bmesh = bpy.data.meshes.new(contextObName)
+ if myContextMesh_vertls:
+
+ bmesh.vertices.add(len(myContextMesh_vertls)//3)
+ bmesh.faces.add(len(myContextMesh_facels))
+ bmesh.vertices.foreach_set("co", myContextMesh_vertls)
+
+ eekadoodle_faces = []
+ for v1, v2, v3 in myContextMesh_facels:
+ eekadoodle_faces.extend([v3, v1, v2, 0] if v3 == 0 else [v1, v2, v3, 0])
+ bmesh.faces.foreach_set("vertices_raw", eekadoodle_faces)
+
+ if bmesh.faces and contextMeshUV:
+ bmesh.uv_textures.new()
+ uv_faces = bmesh.uv_textures.active.data[:]
else:
- bmat = MATDICT[matName][1]
- bmesh.add_material(bmat)
-# bmesh.materials = [bmat]
- try: img = TEXTURE_DICT[bmat.name]
- except: img = None
-
-# bmesh_verts = bmesh.verts
- if len(vertsToUse):
- bmesh.add_geometry(len(vertsToUse), 0, len(faces))
-
- # XXX why add extra vertex?
-# bmesh_verts.extend( [Vector()] )
- bmesh.verts.foreach_set("co", [x for tup in [myContextMesh_vertls[i] for i in vertsToUse] for x in tup])
-# bmesh_verts.extend( [myContextMesh_vertls[i] for i in vertsToUse] )
-
- # +1 because of DUMMYVERT
- bmesh.faces.foreach_set("verts_raw", unpack_face_list([[myVertMapping[vindex] for vindex in myContextMesh_facels[fIdx]] for fIdx in faces]))
-# face_mapping = bmesh.faces.extend( [ [ bmesh_verts[ myVertMapping[vindex]+1] for vindex in myContextMesh_facels[fIdx]] for fIdx in faces ], indexList=True )
-
- if bmesh.faces and (contextMeshUV or img):
- bmesh.add_uv_texture()
- for ii, i in enumerate(faces):
-
- # Mapped index- faces may have not been added- if so, then map to the correct index
- # BUGGY API - face_mapping is not always the right length
-# map_index = face_mapping[ii]
-
- if 1:
-# if map_index != None:
- targetFace = bmesh.faces[ii]
-# targetFace = bmesh.faces[map_index]
-
- uf = bmesh.active_uv_texture.data[ii]
-
- if contextMeshUV:
- # v.index-1 because of the DUMMYVERT
- uvs = [contextMeshUV[vindex] for vindex in myContextMesh_facels[i]]
-
- if len(myContextMesh_facels[i]) == 3:
- uf.uv1, uf.uv2, uf.uv3, uf.uv4 = uvs + [(0.0, 0.0)]
- else:
- uf.uv1, uf.uv2, uf.uv3, uf.uv4 = uvs
-# targetFace.uv = [contextMeshUV[vindex] for vindex in myContextMesh_facels[i]]
- if img:
- uf.image = img
-
- # to get this image to show up in 'Textured' shading mode
- uf.tex = True
-
- # bmesh.transform(contextMatrix)
- ob = bpy.data.objects.new(tempName, bmesh)
- SCN.objects.link(ob)
-# ob = SCN_OBJECTS.new(bmesh, tempName)
- '''
- if contextMatrix_tx:
- ob.setMatrix(contextMatrix_tx)
- '''
-
- if contextMatrix_rot:
- # ob.matrix = [x for row in contextMatrix_rot for x in row]
- ob.matrix = contextMatrix_rot
-# ob.setMatrix(contextMatrix_rot)
-
- importedObjects.append(ob)
- bmesh.update()
-# bmesh.calcNormals()
-
- for matName, faces in myContextMeshMaterials.items():
- makeMeshMaterialCopy(matName, faces)
-
- if len(materialFaces) != len(myContextMesh_facels):
- # Invert material faces.
- makeMeshMaterialCopy(None, set(range(len( myContextMesh_facels ))) - materialFaces)
- #raise 'Some UnMaterialed faces', len(contextMesh.faces)
+ uv_faces = None
+
+ for mat_idx, (matName, faces) in enumerate(myContextMeshMaterials.items()):
+ if matName is None:
+ bmat = None
+ else:
+ bmat = MATDICT[matName][1]
+ img = TEXTURE_DICT.get(bmat.name)
+
+ bmesh.materials.link(bmat) # can be None
+
+ if uv_faces and img:
+ for fidx in faces:
+ bmesh.faces[fidx].material_index = mat_idx
+ uf = uv_faces[fidx]
+ uf.image = img
+ uf.use_image = True
+ else:
+ for fidx in faces:
+ bmesh.faces[fidx].material_index = mat_idx
+
+ if uv_faces:
+ for fidx, uf in enumerate(uv_faces):
+ face = myContextMesh_facels[fidx]
+ v1, v2, v3 = face
+
+ # eekadoodle
+ if v3 == 0:
+ v1, v2, v3 = v3, v1, v2
+
+ uf.uv1 = contextMeshUV[v1 * 2:(v1 * 2) + 2]
+ uf.uv2 = contextMeshUV[v2 * 2:(v2 * 2) + 2]
+ uf.uv3 = contextMeshUV[v3 * 2:(v3 * 2) + 2]
+ # always a tri
+
+ ob = bpy.data.objects.new(tempName, bmesh)
+ SCN.objects.link(ob)
+
+ '''
+ if contextMatrix_tx:
+ ob.setMatrix(contextMatrix_tx)
+ '''
+
+ if contextMatrix_rot:
+ ob.matrix_world = contextMatrix_rot
+
+ importedObjects.append(ob)
+ bmesh.update()
#a spare chunk
new_chunk = chunk()
@@ -460,9 +413,7 @@ def process_next_chunk(file, previous_chunk, importedObjects, IMAGE_SEARCH):
return [float(col)/255 for col in struct.unpack('<3B', temp_data)] # data [0,1,2] == rgb
def read_texture(new_chunk, temp_chunk, name, mapto):
- new_texture = bpy.data.textures.new(name)
- new_texture.type = 'IMAGE'
- new_texture = new_texture.recast_type()
+ new_texture = bpy.data.textures.new(name, type='IMAGE')
img = None
while (new_chunk.bytes_read < new_chunk.length):
@@ -669,14 +620,10 @@ def process_next_chunk(file, previous_chunk, importedObjects, IMAGE_SEARCH):
new_chunk.bytes_read += 2
# print 'number of verts: ', num_verts
- def getvert():
- temp_data = struct.unpack('<3f', file.read(STRUCT_SIZE_3FLOAT))
- new_chunk.bytes_read += STRUCT_SIZE_3FLOAT #12: 3 floats x 4 bytes each
- return temp_data
-
- #contextMesh.verts.extend( [Vector(),] ) # DUMMYVERT! - remove when blenders internals are fixed.
- contextMesh_vertls = [getvert() for i in range(num_verts)]
-
+ contextMesh_vertls = struct.unpack('<%df' % (num_verts * 3), file.read(STRUCT_SIZE_3FLOAT * num_verts))
+ new_chunk.bytes_read += STRUCT_SIZE_3FLOAT * num_verts
+ # dummyvert is not used atm!
+
#print 'object verts: bytes read: ', new_chunk.bytes_read
elif (new_chunk.ID == OBJECT_FACES):
@@ -686,15 +633,11 @@ def process_next_chunk(file, previous_chunk, importedObjects, IMAGE_SEARCH):
new_chunk.bytes_read += 2
#print 'number of faces: ', num_faces
- def getface():
- # print '\ngetting a face'
- temp_data = file.read(STRUCT_SIZE_4UNSIGNED_SHORT)
- new_chunk.bytes_read += STRUCT_SIZE_4UNSIGNED_SHORT #4 short ints x 2 bytes each
- v1,v2,v3,dummy = struct.unpack('<4H', temp_data)
- return v1, v2, v3
-
- contextMesh_facels = [ getface() for i in range(num_faces) ]
-
+ # print '\ngetting a face'
+ temp_data = file.read(STRUCT_SIZE_4UNSIGNED_SHORT * num_faces)
+ new_chunk.bytes_read += STRUCT_SIZE_4UNSIGNED_SHORT * num_faces #4 short ints x 2 bytes each
+ contextMesh_facels = struct.unpack('<%dH' % (num_faces * 4), temp_data)
+ contextMesh_facels = [contextMesh_facels[i - 3:i] for i in range(3, (num_faces * 4) + 3, 4)]
elif (new_chunk.ID == OBJECT_MATERIAL):
# print 'elif (new_chunk.ID == OBJECT_MATERIAL):'
@@ -705,12 +648,11 @@ def process_next_chunk(file, previous_chunk, importedObjects, IMAGE_SEARCH):
num_faces_using_mat = struct.unpack('<H', temp_data)[0]
new_chunk.bytes_read += STRUCT_SIZE_UNSIGNED_SHORT
- def getmat():
- temp_data = file.read(STRUCT_SIZE_UNSIGNED_SHORT)
- new_chunk.bytes_read += STRUCT_SIZE_UNSIGNED_SHORT
- return struct.unpack('<H', temp_data)[0]
+
+ temp_data = file.read(STRUCT_SIZE_UNSIGNED_SHORT * num_faces_using_mat)
+ new_chunk.bytes_read += STRUCT_SIZE_UNSIGNED_SHORT * num_faces_using_mat
- contextMeshMaterials[material_name]= [ getmat() for i in range(num_faces_using_mat) ]
+ contextMeshMaterials[material_name]= struct.unpack("<%dH" % (num_faces_using_mat), temp_data)
#look up the material in all the materials
@@ -719,12 +661,9 @@ def process_next_chunk(file, previous_chunk, importedObjects, IMAGE_SEARCH):
num_uv = struct.unpack('<H', temp_data)[0]
new_chunk.bytes_read += 2
- def getuv():
- temp_data = file.read(STRUCT_SIZE_2FLOAT)
- new_chunk.bytes_read += STRUCT_SIZE_2FLOAT #2 float x 4 bytes each
- return Mathutils.Vector( struct.unpack('<2f', temp_data) )
-
- contextMeshUV = [ getuv() for i in range(num_uv) ]
+ temp_data = file.read(STRUCT_SIZE_2FLOAT * num_uv)
+ new_chunk.bytes_read += STRUCT_SIZE_2FLOAT * num_uv
+ contextMeshUV = struct.unpack('<%df' % (num_uv * 2), temp_data)
elif (new_chunk.ID == OBJECT_TRANS_MATRIX):
# How do we know the matrix size? 54 == 4x4 48 == 4x3
@@ -732,7 +671,7 @@ def process_next_chunk(file, previous_chunk, importedObjects, IMAGE_SEARCH):
data = list( struct.unpack('<ffffffffffff', temp_data) )
new_chunk.bytes_read += STRUCT_SIZE_4x3MAT
- contextMatrix_rot = Mathutils.Matrix(\
+ contextMatrix_rot = mathutils.Matrix(\
data[:3] + [0],\
data[3:6] + [0],\
data[6:9] + [0],\
@@ -740,7 +679,7 @@ def process_next_chunk(file, previous_chunk, importedObjects, IMAGE_SEARCH):
'''
- contextMatrix_rot = Blender.Mathutils.Matrix(\
+ contextMatrix_rot = Blender.mathutils.Matrix(\
data[:3] + [0],\
data[3:6] + [0],\
data[6:9] + [0],\
@@ -748,14 +687,14 @@ def process_next_chunk(file, previous_chunk, importedObjects, IMAGE_SEARCH):
'''
'''
- contextMatrix_rot = Blender.Mathutils.Matrix(\
+ contextMatrix_rot = Blender.mathutils.Matrix(\
data[:3] ,\
data[3:6],\
data[6:9])
'''
'''
- contextMatrix_rot = Blender.Mathutils.Matrix()
+ contextMatrix_rot = Blender.mathutils.Matrix()
m = 0
for j in xrange(4):
for i in xrange(3):
@@ -773,7 +712,7 @@ def process_next_chunk(file, previous_chunk, importedObjects, IMAGE_SEARCH):
#print contextMatrix_rot
contextMatrix_rot.invert()
#print contextMatrix_rot
- #contextMatrix_tx = Blender.Mathutils.TranslationMatrix(0.5 * Blender.Mathutils.Vector(data[9:]))
+ #contextMatrix_tx = mathutils.Matrix.Translation(0.5 * Blender.mathutils.Vector(data[9:]))
#contextMatrix_tx.invert()
#tx.invert()
@@ -808,7 +747,7 @@ def process_next_chunk(file, previous_chunk, importedObjects, IMAGE_SEARCH):
# FINISHED LOOP
# There will be a number of objects still not added
- if contextMesh_facels != None:
+ if CreateBlenderObject:
putContextMesh(contextMesh_vertls, contextMesh_facels, contextMeshMaterials)
def load_3ds(filename, context, IMPORT_CONSTRAIN_BOUNDS=10.0, IMAGE_SEARCH=True, APPLY_MATRIX=False):
@@ -885,14 +824,12 @@ def load_3ds(filename, context, IMPORT_CONSTRAIN_BOUNDS=10.0, IMAGE_SEARCH=True,
# REMOVE DUMMYVERT, - remove this in the next release when blenders internal are fixed.
-
-# for ob in importedObjects:
-# if ob.type == 'MESH':
-# # if ob.type=='Mesh':
-# me = ob.getData(mesh=1)
-# me.verts.delete([me.verts[0],])
-# if not APPLY_MATRIX:
-# me.transform(ob.matrixWorld.copy().invert())
+ for ob in importedObjects:
+ if ob.type == 'MESH':
+ me = ob.data
+# me.vertices.delete([me.vertices[0],]) # XXX, todo
+ if not APPLY_MATRIX:
+ me.transform(ob.matrix_world.copy().invert())
# Done DUMMYVERT
"""
@@ -946,11 +883,11 @@ def load_3ds(filename, context, IMPORT_CONSTRAIN_BOUNDS=10.0, IMAGE_SEARCH=True,
SCALE/=10
# SCALE Matrix
- SCALE_MAT = Mathutils.Matrix([SCALE,0,0,0],[0,SCALE,0,0],[0,0,SCALE,0],[0,0,0,1])
-# SCALE_MAT = Blender.Mathutils.Matrix([SCALE,0,0,0],[0,SCALE,0,0],[0,0,SCALE,0],[0,0,0,1])
+ SCALE_MAT = mathutils.Matrix([SCALE,0,0,0],[0,SCALE,0,0],[0,0,SCALE,0],[0,0,0,1])
+# SCALE_MAT = Blender.mathutils.Matrix([SCALE,0,0,0],[0,SCALE,0,0],[0,0,SCALE,0],[0,0,0,1])
for ob in importedObjects:
- ob.setMatrix(ob.matrixWorld * SCALE_MAT)
+ ob.matrix_world = ob.matrix_world * SCALE_MAT
# Done constraining to bounds.
@@ -1011,17 +948,19 @@ class IMPORT_OT_autodesk_3ds(bpy.types.Operator):
# 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 3DS file", maxlen= 1024, default= "")
- path = StringProperty(name="File Path", description="File path used for importing the 3DS file", maxlen= 1024, default= "")
- filename = StringProperty(name="File Name", description="Name of the file.")
- directory = StringProperty(name="Directory", description="Directory of the file.")
-
-# size_constraint = FloatProperty(name="Size Constraint", description="Scale the model by 10 until it reacehs the size constraint. Zero Disables.", min=0.0, max=1000.0, soft_min=0.0, soft_max=1000.0, default=10.0),
-# search_images = BoolProperty(name="Image Search", description="Search subdirectories for any assosiated images (Warning, may be slow)", default=True),
-# apply_matrix = BoolProperty(name="Transform Fix", description="Workaround for object transformations importing incorrectly", default=False),
+ constrain_size = FloatProperty(name="Size Constraint", description="Scale the model by 10 until it reacehs the size constraint. Zero Disables.", min=0.0, max=1000.0, soft_min=0.0, soft_max=1000.0, default=10.0)
+ search_images = BoolProperty(name="Image Search", description="Search subdirectories for any assosiated images (Warning, may be slow)", default=True)
+ apply_transform = BoolProperty(name="Apply Transform", description="Workaround for object transformations importing incorrectly", default=False)
def execute(self, context):
- load_3ds(self.properties.path, context, 0.0, False, False)
+ load_3ds(self.properties.filepath,
+ context,
+ IMPORT_CONSTRAIN_BOUNDS=self.properties.constrain_size,
+ IMAGE_SEARCH=self.properties.search_images,
+ APPLY_MATRIX=self.properties.apply_transform)
+
return {'FINISHED'}
def invoke(self, context, event):
@@ -1034,11 +973,9 @@ def menu_func(self, context):
self.layout.operator(IMPORT_OT_autodesk_3ds.bl_idname, text="3D Studio (.3ds)")
def register():
- bpy.types.register(IMPORT_OT_autodesk_3ds)
bpy.types.INFO_MT_file_import.append(menu_func)
def unregister():
- bpy.types.unregister(IMPORT_OT_autodesk_3ds)
bpy.types.INFO_MT_file_import.remove(menu_func)
# NOTES:
diff --git a/release/scripts/io/import_scene_obj.py b/release/scripts/io/import_scene_obj.py
index 9a147b06b07..88caaf7eeb5 100644
--- a/release/scripts/io/import_scene_obj.py
+++ b/release/scripts/io/import_scene_obj.py
@@ -30,62 +30,11 @@ Run this script from "File->Import" menu and then load the desired OBJ file.
Note, This loads mesh objects and materials only, nurbs and curves are not supported.
"""
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# Script copyright (C) Campbell J Barton 2007
-#
-# 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 *****
-# --------------------------------------------------------------------------
-
import os
import time
import bpy
-import Mathutils
-import Geometry
-
-# from Blender import Mesh, Draw, Window, Texture, Material, sys
-# # import BPyMesh
-# import BPyImage
-# import BPyMessages
-
-# try: import os
-# except: os= False
-
-# Generic path functions
-def stripFile(path):
- '''Return directory, where the file is'''
- lastSlash= max(path.rfind('\\'), path.rfind('/'))
- if lastSlash != -1:
- path= path[:lastSlash]
- return '%s%s' % (path, os.sep)
-# return '%s%s' % (path, sys.sep)
-
-def stripPath(path):
- '''Strips the slashes from the back of a string'''
- return path.split('/')[-1].split('\\')[-1]
-
-def stripExt(name): # name is a string
- '''Strips the prefix off the name before writing'''
- index= name.rfind('.')
- if index != -1:
- return name[ : index ]
- else:
- return name
-# end path funcs
+import mathutils
+from geometry import PolyFill
def unpack_list(list_of_tuples):
l = []
@@ -95,23 +44,21 @@ def unpack_list(list_of_tuples):
# same as above except that it adds 0 for triangle faces
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)))
+ # allocate the entire list
+ flat_ls = [0] * (len(list_of_tuples) * 4)
+ i = 0
- # 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)
+ for t in list_of_tuples:
+ if len(t) == 3:
+ if t[2] == 0:
+ t = t[1], t[2], t[0]
+ else: # assuem quad
+ if t[3] == 0 or t[2] == 0:
+ t = t[2], t[3], t[0], t[1]
- l.extend(face)
-
- return l
+ flat_ls[i:i + len(t)] = t
+ i += 4
+ return flat_ls
def BPyMesh_ngon(from_data, indices, PREF_FIX_LOOPS= True):
'''
@@ -127,7 +74,7 @@ def BPyMesh_ngon(from_data, indices, PREF_FIX_LOOPS= True):
if not set: # Need sets for this, otherwise do a normal fill.
PREF_FIX_LOOPS= False
- Vector= Mathutils.Vector
+ Vector= mathutils.Vector
if not indices:
return []
@@ -152,13 +99,13 @@ def BPyMesh_ngon(from_data, indices, PREF_FIX_LOOPS= True):
if type(from_data) in (tuple, list):
verts= [Vector(from_data[i]) for ii, i in enumerate(indices)]
else:
- verts= [from_data.verts[i].co for ii, i in enumerate(indices)]
+ verts= [from_data.vertices[i].co for ii, i in enumerate(indices)]
for i in range(len(verts)-1, 0, -1): # same as reversed(xrange(1, len(verts))):
if verts[i][1]==verts[i-1][0]:
verts.pop(i-1)
- fill= Geometry.PolyFill([verts])
+ fill= PolyFill([verts])
else:
'''
@@ -169,7 +116,7 @@ def BPyMesh_ngon(from_data, indices, PREF_FIX_LOOPS= True):
if type(from_data) in (tuple, list):
verts= [vert_treplet(Vector(from_data[i]), ii) for ii, i in enumerate(indices)]
else:
- verts= [vert_treplet(from_data.verts[i].co, ii) for ii, i in enumerate(indices)]
+ verts= [vert_treplet(from_data.vertices[i].co, ii) for ii, i in enumerate(indices)]
edges= [(i, i-1) for i in range(len(verts))]
if edges:
@@ -266,7 +213,7 @@ def BPyMesh_ngon(from_data, indices, PREF_FIX_LOOPS= True):
vert_map[i+ii]= vert[2]
ii+=len(verts)
- fill= Geometry.PolyFill([ [v[0] for v in loop] for loop in loop_list ])
+ fill= PolyFill([ [v[0] for v in loop] for loop in loop_list ])
#draw_loops(loop_list)
#raise 'done loop'
# map to original indicies
@@ -318,24 +265,28 @@ def load_image(imagepath, dirname):
if os.path.exists(imagepath):
return bpy.data.images.load(imagepath)
- variants = [os.path.join(dirname, imagepath), os.path.join(dirname, os.path.basename(imagepath))]
+ variants = [imagepath, os.path.join(dirname, imagepath), os.path.join(dirname, os.path.basename(imagepath))]
- for path in variants:
- if os.path.exists(path):
- return bpy.data.images.load(path)
- else:
- print(path, "doesn't exist")
+ for filepath in variants:
+ for nfilepath in (filepath, bpy.path.resolve_ncase(filepath)):
+ if os.path.exists(nfilepath):
+ return bpy.data.images.load(nfilepath)
# TODO comprehensiveImageLoad also searched in bpy.config.textureDir
return None
def obj_image_load(imagepath, DIR, IMAGE_SEARCH):
-
if '_' in imagepath:
image= load_image(imagepath.replace('_', ' '), DIR)
- if image: return image
+ if image:
+ return image
- return load_image(imagepath, DIR)
+ image = load_image(imagepath, DIR)
+ if image:
+ return image
+
+ print("failed to load '%s' doesn't exist", imagepath)
+ return None
# def obj_image_load(imagepath, DIR, IMAGE_SEARCH):
# '''
@@ -360,25 +311,22 @@ def create_materials(filepath, material_libs, unique_materials, unique_material_
Create all the used materials in this obj,
assign colors and images to the materials from all referenced material libs
'''
- DIR= stripFile(filepath)
+ DIR= os.path.dirname(filepath)
#==================================================================================#
# This function sets textures defined in .mtl file #
#==================================================================================#
def load_material_image(blender_material, context_material_name, imagepath, type):
- texture= bpy.data.textures.new(type)
- texture.type= 'IMAGE'
- texture = texture.recast_type() # Workaround for limitation in rna api.
-# texture= bpy.data.textures.new(type)
-# texture.setType('Image')
+ texture= bpy.data.textures.new(name=type, type='IMAGE')
# Absolute path - c:\.. etc would work here
- image= obj_image_load(imagepath, DIR, IMAGE_SEARCH)
- has_data = image.has_data if image else False
+ image = obj_image_load(imagepath, DIR, IMAGE_SEARCH)
+ has_data = False
if image:
texture.image = image
+ has_data = image.has_data
# Adds textures for materials (rendering)
if type == 'Kd':
@@ -386,38 +334,32 @@ def create_materials(filepath, material_libs, unique_materials, unique_material_
# Image has alpha
# XXX bitmask won't work?
- blender_material.add_texture(texture, "UV", ("COLOR", "ALPHA"))
+ blender_material.add_texture(texture, 'UV', {'COLOR', 'ALPHA'})
texture.mipmap = True
texture.interpolation = True
texture.use_alpha = True
- blender_material.z_transparency = True
+ blender_material.use_transparency = True
blender_material.alpha = 0.0
-
-# blender_material.setTexture(0, texture, Texture.TexCo.UV, Texture.MapTo.COL | Texture.MapTo.ALPHA)
-# texture.setImageFlags('MipMap', 'InterPol', 'UseAlpha')
-# blender_material.mode |= Material.Modes.ZTRANSP
-# blender_material.alpha = 0.0
else:
- blender_material.add_texture(texture, "UV", "COLOR")
-# blender_material.setTexture(0, texture, Texture.TexCo.UV, Texture.MapTo.COL)
+ blender_material.add_texture(texture, 'UV', 'COLOR')
# adds textures to faces (Textured/Alt-Z mode)
# Only apply the diffuse texture to the face if the image has not been set with the inline usemat func.
unique_material_images[context_material_name]= image, has_data # set the texface image
elif type == 'Ka':
- blender_material.add_texture(texture, "UV", "AMBIENT")
+ blender_material.add_texture(texture, 'UV', 'AMBIENT')
# blender_material.setTexture(1, texture, Texture.TexCo.UV, Texture.MapTo.CMIR) # TODO- Add AMB to BPY API
elif type == 'Ks':
- blender_material.add_texture(texture, "UV", "SPECULARITY")
+ blender_material.add_texture(texture, 'UV', 'SPECULARITY')
# blender_material.setTexture(2, texture, Texture.TexCo.UV, Texture.MapTo.SPEC)
elif type == 'Bump':
- blender_material.add_texture(texture, "UV", "NORMAL")
+ blender_material.add_texture(texture, 'UV', 'NORMAL')
# blender_material.setTexture(3, texture, Texture.TexCo.UV, Texture.MapTo.NOR)
elif type == 'D':
- blender_material.add_texture(texture, "UV", "ALPHA")
+ blender_material.add_texture(texture, 'UV', 'ALPHA')
blender_material.z_transparency = True
blender_material.alpha = 0.0
# blender_material.setTexture(4, texture, Texture.TexCo.UV, Texture.MapTo.ALPHA)
@@ -426,15 +368,14 @@ def create_materials(filepath, material_libs, unique_materials, unique_material_
# Todo, unset deffuse material alpha if it has an alpha channel
elif type == 'refl':
- blender_material.add_texture(texture, "UV", "REFLECTION")
+ blender_material.add_texture(texture, 'UV', 'REFLECTION')
# blender_material.setTexture(5, texture, Texture.TexCo.UV, Texture.MapTo.REF)
# Add an MTL with the same name as the obj if no MTLs are spesified.
- temp_mtl= stripExt(stripPath(filepath))+ '.mtl'
+ temp_mtl = os.path.splitext((os.path.basename(filepath)))[0] + '.mtl'
- if os.path.exists(DIR + temp_mtl) and temp_mtl not in material_libs:
-# if sys.exists(DIR + temp_mtl) and temp_mtl not in material_libs:
+ if os.path.exists(os.path.join(DIR, temp_mtl)) and temp_mtl not in material_libs:
material_libs.append( temp_mtl )
del temp_mtl
@@ -448,11 +389,9 @@ def create_materials(filepath, material_libs, unique_materials, unique_material_
unique_material_images[None]= None, False
for libname in material_libs:
- mtlpath= DIR + libname
+ mtlpath= os.path.join(DIR, libname)
if not os.path.exists(mtlpath):
-# if not sys.exists(mtlpath):
- #print '\tError Missing MTL: "%s"' % mtlpath
- pass
+ print ("\tError Missing MTL: '%s'" % mtlpath)
else:
#print '\t\tloading mtl: "%s"' % mtlpath
context_material= None
@@ -471,22 +410,16 @@ def create_materials(filepath, material_libs, unique_materials, unique_material_
line_lower= line.lower().lstrip()
if line_lower.startswith('ka'):
context_material.mirror_color = (float(line_split[1]), float(line_split[2]), float(line_split[3]))
-# context_material.setMirCol((float(line_split[1]), float(line_split[2]), float(line_split[3])))
elif line_lower.startswith('kd'):
context_material.diffuse_color = (float(line_split[1]), float(line_split[2]), float(line_split[3]))
-# context_material.setRGBCol((float(line_split[1]), float(line_split[2]), float(line_split[3])))
elif line_lower.startswith('ks'):
context_material.specular_color = (float(line_split[1]), float(line_split[2]), float(line_split[3]))
-# context_material.setSpecCol((float(line_split[1]), float(line_split[2]), float(line_split[3])))
elif line_lower.startswith('ns'):
context_material.specular_hardness = int((float(line_split[1])*0.51))
-# context_material.setHardness( int((float(line_split[1])*0.51)) )
elif line_lower.startswith('ni'): # Refraction index
- context_material.raytrace_transparency.ior = max(1, min(float(line_split[1]), 3))
-# context_material.setIOR( max(1, min(float(line_split[1]), 3))) # Between 1 and 3
+ context_material.raytrace_transparency.ior = max(1, min(float(line_split[1]), 3)) # Between 1 and 3
elif line_lower.startswith('d') or line_lower.startswith('tr'):
context_material.alpha = float(line_split[1])
-# context_material.setAlpha(float(line_split[1]))
elif line_lower.startswith('map_ka'):
img_filepath= line_value(line.split())
if img_filepath:
@@ -517,49 +450,32 @@ def create_materials(filepath, material_libs, unique_materials, unique_material_
-def split_mesh(verts_loc, faces, unique_materials, filepath, SPLIT_OB_OR_GROUP, SPLIT_MATERIALS):
+def split_mesh(verts_loc, faces, unique_materials, filepath, SPLIT_OB_OR_GROUP):
'''
- Takes vert_loc and faces, and seperates into multiple sets of
+ Takes vert_loc and faces, and separates into multiple sets of
(verts_loc, faces, unique_materials, dataname)
'''
- filename = stripExt(stripPath(filepath))
+ filename = os.path.splitext((os.path.basename(filepath)))[0]
- if not SPLIT_OB_OR_GROUP and not SPLIT_MATERIALS:
+ if not SPLIT_OB_OR_GROUP:
# use the filename for the object name since we arnt chopping up the mesh.
return [(verts_loc, faces, unique_materials, filename)]
-
def key_to_name(key):
# if the key is a tuple, join it to make a string
- if type(key) == tuple:
- return '%s_%s' % key
- elif not key:
+ if not key:
return filename # assume its a string. make sure this is true if the splitting code is changed
else:
return key
# Return a key that makes the faces unique.
- if SPLIT_OB_OR_GROUP and not SPLIT_MATERIALS:
- def face_key(face):
- return face[4] # object
-
- elif not SPLIT_OB_OR_GROUP and SPLIT_MATERIALS:
- def face_key(face):
- return face[2] # material
-
- else: # Both
- def face_key(face):
- return face[4], face[2] # object,material
-
-
face_split_dict= {}
oldkey= -1 # initialize to a value that will never match the key
for face in faces:
-
- key= face_key(face)
+ key= face[4]
if oldkey != key:
# Check the key has changed.
@@ -584,7 +500,6 @@ def split_mesh(verts_loc, faces, unique_materials, filepath, SPLIT_OB_OR_GROUP,
vert_remap[i]= new_index # set the new remapped index so we only add once and can reference next time.
face_vert_loc_indicies[enum] = new_index # remap to the local index
verts_split.append( verts_loc[i] ) # add the vert to the local verts
-
else:
face_vert_loc_indicies[enum] = vert_remap[i] # remap to the local index
@@ -594,12 +509,11 @@ def split_mesh(verts_loc, faces, unique_materials, filepath, SPLIT_OB_OR_GROUP,
faces_split.append(face)
-
# remove one of the itemas and reorder
return [(value[0], value[1], value[2], key_to_name(key)) for key, value in list(face_split_dict.items())]
-def create_mesh(scn, new_objects, has_ngons, CREATE_FGONS, CREATE_EDGES, verts_loc, verts_tex, faces, unique_materials, unique_material_images, unique_smooth_groups, vertex_groups, dataname):
+def create_mesh(new_objects, has_ngons, CREATE_FGONS, CREATE_EDGES, verts_loc, verts_tex, faces, unique_materials, unique_material_images, unique_smooth_groups, vertex_groups, dataname):
'''
Takes all the data gathered and generates a mesh, adding the new object to new_objects
deals with fgons, sharp edges and assigning materials
@@ -609,7 +523,7 @@ def create_mesh(scn, new_objects, has_ngons, CREATE_FGONS, CREATE_EDGES, verts_l
if unique_smooth_groups:
sharp_edges= {}
- smooth_group_users= dict([ (context_smooth_group, {}) for context_smooth_group in list(unique_smooth_groups.keys()) ])
+ smooth_group_users = {context_smooth_group: {} for context_smooth_group in list(unique_smooth_groups.keys())}
context_smooth_group_old= -1
# Split fgons into tri's
@@ -663,14 +577,14 @@ def create_mesh(scn, new_objects, has_ngons, CREATE_FGONS, CREATE_EDGES, verts_l
if has_ngons and len_face_vert_loc_indicies > 4:
ngon_face_indices= BPyMesh_ngon(verts_loc, face_vert_loc_indicies)
- faces.extend(\
- [(\
- [face_vert_loc_indicies[ngon[0]], face_vert_loc_indicies[ngon[1]], face_vert_loc_indicies[ngon[2]] ],\
- [face_vert_tex_indicies[ngon[0]], face_vert_tex_indicies[ngon[1]], face_vert_tex_indicies[ngon[2]] ],\
- context_material,\
- context_smooth_group,\
- context_object)\
- for ngon in ngon_face_indices]\
+ faces.extend(
+ [(
+ [face_vert_loc_indicies[ngon[0]], face_vert_loc_indicies[ngon[1]], face_vert_loc_indicies[ngon[2]] ],
+ [face_vert_tex_indicies[ngon[0]], face_vert_tex_indicies[ngon[1]], face_vert_tex_indicies[ngon[2]] ],
+ context_material,
+ context_smooth_group,
+ context_object)
+ for ngon in ngon_face_indices]
)
# edges to make fgons
@@ -704,7 +618,7 @@ def create_mesh(scn, new_objects, has_ngons, CREATE_FGONS, CREATE_EDGES, verts_l
# map the material names to an index
- material_mapping= dict([(name, i) for i, name in enumerate(unique_materials)]) # enumerate over unique_materials keys()
+ material_mapping = {name: i for i, name in enumerate(unique_materials)} # enumerate over unique_materials keys()
materials= [None] * len(unique_materials)
@@ -715,30 +629,25 @@ def create_mesh(scn, new_objects, has_ngons, CREATE_FGONS, CREATE_EDGES, verts_l
# make sure the list isnt too big
for material in materials:
- me.add_material(material)
- #me.verts.extend([(0,0,0)]) # dummy vert
+ me.materials.link(material)
- me.add_geometry(len(verts_loc), 0, len(faces))
+ me.vertices.add(len(verts_loc))
+ me.faces.add(len(faces))
# verts_loc is a list of (x, y, z) tuples
- me.verts.foreach_set("co", unpack_list(verts_loc))
-# me.verts.extend(verts_loc)
+ me.vertices.foreach_set("co", unpack_list(verts_loc))
# faces is a list of (vert_indices, texco_indices, ...) tuples
# XXX faces should contain either 3 or 4 verts
# XXX no check for valid face indices
- me.faces.foreach_set("verts_raw", unpack_face_list([f[0] for f in faces]))
-# face_mapping= me.faces.extend([f[0] for f in faces], indexList=True)
+ me.faces.foreach_set("vertices_raw", unpack_face_list([f[0] for f in faces]))
if verts_tex and me.faces:
- me.add_uv_texture()
-# me.faceUV= 1
- # TEXMODE= Mesh.FaceModes['TEX']
+ me.uv_textures.new()
context_material_old= -1 # avoid a dict lookup
mat= 0 # rare case it may be un-initialized.
me_faces= me.faces
-# ALPHA= Mesh.FaceTranspModes.ALPHA
for i, face in enumerate(faces):
if len(face[0]) < 2:
@@ -747,14 +656,8 @@ def create_mesh(scn, new_objects, has_ngons, CREATE_FGONS, CREATE_EDGES, verts_l
if CREATE_EDGES:
edges.append(face[0])
else:
-# face_index_map= face_mapping[i]
-
- # since we use foreach_set to add faces, all of them are added
- if 1:
-# if face_index_map!=None: # None means the face wasnt added
blender_face = me.faces[i]
-# blender_face= me_faces[face_index_map]
face_vert_loc_indicies,\
face_vert_tex_indicies,\
@@ -765,7 +668,7 @@ def create_mesh(scn, new_objects, has_ngons, CREATE_FGONS, CREATE_EDGES, verts_l
if context_smooth_group:
- blender_face.smooth= True
+ blender_face.use_smooth = True
if context_material:
if context_material_old is not context_material:
@@ -781,14 +684,12 @@ def create_mesh(scn, new_objects, has_ngons, CREATE_FGONS, CREATE_EDGES, verts_l
blender_tface= me.uv_textures[0].data[i]
if context_material:
- image, has_data= unique_material_images[context_material]
+ image, has_data = unique_material_images[context_material]
if image: # Can be none if the material dosnt have an image.
- blender_tface.image= image
-# blender_face.image= image
- if has_data:
-# if has_data and image.depth == 32:
- blender_tface.transp = 'ALPHA'
-# blender_face.transp |= ALPHA
+ blender_tface.image = image
+ blender_tface.use_image = True
+ if has_data and image.depth == 32:
+ blender_tface.blend_type = 'ALPHA'
# BUG - Evil eekadoodle problem where faces that have vert index 0 location at 3 or 4 are shuffled.
if len(face_vert_loc_indicies)==4:
@@ -814,10 +715,10 @@ def create_mesh(scn, new_objects, has_ngons, CREATE_FGONS, CREATE_EDGES, verts_l
if CREATE_EDGES:
- me.add_geometry(0, len(edges), 0)
+ me.edges.add(len(edges))
# edges should be a list of (a, b) tuples
- me.edges.foreach_set("verts", unpack_list(edges))
+ me.edges.foreach_set("vertices", unpack_list(edges))
# me_edges.extend( edges )
# del me_edges
@@ -832,8 +733,8 @@ def create_mesh(scn, new_objects, has_ngons, CREATE_FGONS, CREATE_EDGES, verts_l
# if CREATE_FGONS and fgon_edges:
# for fgon_edge in fgon_edges.keys():
# for ed in me.edges:
-# if edges_match(fgon_edge, ed.verts):
-# ed.fgon = True
+# if edges_match(fgon_edge, ed.vertices):
+# ed.is_fgon = True
# if CREATE_FGONS and fgon_edges:
# FGON= Mesh.EdgeFlags.FGON
@@ -846,8 +747,8 @@ def create_mesh(scn, new_objects, has_ngons, CREATE_FGONS, CREATE_EDGES, verts_l
# if unique_smooth_groups and sharp_edges:
# for sharp_edge in sharp_edges.keys():
# for ed in me.edges:
-# if edges_match(sharp_edge, ed.verts):
-# ed.sharp = True
+# if edges_match(sharp_edge, ed.vertices):
+# ed.use_edge_sharp = True
# if unique_smooth_groups and sharp_edges:
# SHARP= Mesh.EdgeFlags.SHARP
@@ -860,21 +761,18 @@ def create_mesh(scn, new_objects, has_ngons, CREATE_FGONS, CREATE_EDGES, verts_l
# me.calcNormals()
ob= bpy.data.objects.new("Mesh", me)
- scn.objects.link(ob)
new_objects.append(ob)
# Create the vertex groups. No need to have the flag passed here since we test for the
# content of the vertex_groups. If the user selects to NOT have vertex groups saved then
# the following test will never run
for group_name, group_indicies in vertex_groups.items():
- group= ob.add_vertex_group(group_name)
-# me.addVertGroup(group_name)
+ group= ob.vertex_groups.new(group_name)
for vertex_index in group_indicies:
- ob.add_vertex_to_group(vertex_index, group, 1.0, 'REPLACE')
-# me.assignVertsToGroup(group_name, group_indicies, 1.00, Mesh.AssignModes.REPLACE)
+ ob.vertex_groups.assign(vertex_index, group, 1.0, 'REPLACE')
-def create_nurbs(scn, context_nurbs, vert_loc, new_objects):
+def create_nurbs(context_nurbs, vert_loc, new_objects):
'''
Add nurbs object to blender, only support one type at the moment
'''
@@ -899,21 +797,14 @@ def create_nurbs(scn, context_nurbs, vert_loc, new_objects):
print('\tWarning, surfaces not supported')
return
- cu = bpy.data.curves.new(name, 'Curve')
- cu.flag |= 1 # 3D curve
+ cu = bpy.data.curves.new(name, 'CURVE')
+ cu.dimensions = '3D'
- nu = None
- for pt in curv_idx:
+ nu = cu.splines.new('NURBS')
+ nu.points.add(len(curv_idx) - 1) # a point is added to start with
+ nu.points.foreach_set("co", [co_axis for vt_idx in curv_idx for co_axis in (vert_loc[vt_idx] + (1.0,))])
- pt = vert_loc[pt]
- pt = (pt[0], pt[1], pt[2], 1.0)
-
- if nu == None:
- nu = cu.appendNurb(pt)
- else:
- nu.append(pt)
-
- nu.orderU = deg[0]+1
+ nu.order_u = deg[0] + 1
# get for endpoint flag from the weighting
if curv_range and len(parm_u) > deg[0]+1:
@@ -932,7 +823,7 @@ def create_nurbs(scn, context_nurbs, vert_loc, new_objects):
do_endpoints = False
if do_endpoints:
- nu.flagU |= 2
+ nu.use_endpoint_u = True
# close
@@ -947,10 +838,11 @@ def create_nurbs(scn, context_nurbs, vert_loc, new_objects):
break
if do_closed:
- nu.flagU |= 1
+ nu.use_cyclic_u = True
'''
+
+ ob= bpy.data.objects.new("Nurb", cu)
- ob = scn.objects.new(cu)
new_objects.append(ob)
@@ -1271,11 +1163,9 @@ def load_obj(filepath,
verts_loc[:] = [(v[0], v[2], -v[1]) for v in verts_loc]
# deselect all
-# if context.selected_objects:
-# bpy.ops.OBJECT_OT_select_all()
+ bpy.ops.object.select_all(action='DESELECT')
scene = context.scene
-# scn = bpy.data.scenes.active
# scn.objects.selected = []
new_objects= [] # put new objects here
@@ -1284,13 +1174,20 @@ def load_obj(filepath,
if SPLIT_OBJECTS or SPLIT_GROUPS: SPLIT_OB_OR_GROUP = True
else: SPLIT_OB_OR_GROUP = False
- for verts_loc_split, faces_split, unique_materials_split, dataname in split_mesh(verts_loc, faces, unique_materials, filepath, SPLIT_OB_OR_GROUP, SPLIT_MATERIALS):
+ for verts_loc_split, faces_split, unique_materials_split, dataname in split_mesh(verts_loc, faces, unique_materials, filepath, SPLIT_OB_OR_GROUP):
# Create meshes from the data, warning 'vertex_groups' wont support splitting
- create_mesh(scene, new_objects, has_ngons, CREATE_FGONS, CREATE_EDGES, verts_loc_split, verts_tex, faces_split, unique_materials_split, unique_material_images, unique_smooth_groups, vertex_groups, dataname)
+ create_mesh(new_objects, has_ngons, CREATE_FGONS, CREATE_EDGES, verts_loc_split, verts_tex, faces_split, unique_materials_split, unique_material_images, unique_smooth_groups, vertex_groups, dataname)
# nurbs support
-# for context_nurbs in nurbs:
-# create_nurbs(scn, context_nurbs, verts_loc, new_objects)
+ for context_nurbs in nurbs:
+ create_nurbs(context_nurbs, verts_loc, new_objects)
+
+ # Create new obj
+ for obj in new_objects:
+ base = scene.objects.link(obj)
+ base.select = True
+
+ scene.update()
axis_min= [ 1000000000]*3
@@ -1333,14 +1230,13 @@ def load_obj_ui(filepath, BATCH_LOAD= False):
if BPyMessages.Error_NoFile(filepath):
return
- global CREATE_SMOOTH_GROUPS, CREATE_FGONS, CREATE_EDGES, SPLIT_OBJECTS, SPLIT_GROUPS, SPLIT_MATERIALS, CLAMP_SIZE, IMAGE_SEARCH, POLYGROUPS, KEEP_VERT_ORDER, ROTATE_X90
+ global CREATE_SMOOTH_GROUPS, CREATE_FGONS, CREATE_EDGES, SPLIT_OBJECTS, SPLIT_GROUPS, CLAMP_SIZE, IMAGE_SEARCH, POLYGROUPS, KEEP_VERT_ORDER, ROTATE_X90
CREATE_SMOOTH_GROUPS= Draw.Create(0)
CREATE_FGONS= Draw.Create(1)
CREATE_EDGES= Draw.Create(1)
SPLIT_OBJECTS= Draw.Create(0)
SPLIT_GROUPS= Draw.Create(0)
- SPLIT_MATERIALS= Draw.Create(0)
CLAMP_SIZE= Draw.Create(10.0)
IMAGE_SEARCH= Draw.Create(1)
POLYGROUPS= Draw.Create(0)
@@ -1359,7 +1255,6 @@ def load_obj_ui(filepath, BATCH_LOAD= False):
'Separate objects from obj...',\
('Object', SPLIT_OBJECTS, 'Import OBJ Objects into Blender Objects'),\
('Group', SPLIT_GROUPS, 'Import OBJ Groups into Blender Objects'),\
- ('Split Materials', SPLIT_MATERIALS, 'Import each material into a seperate mesh'),\
'Options...',\
('Keep Vert Order', KEEP_VERT_ORDER, 'Keep vert and face order, disables some other options.'),\
('Clamp Scale:', CLAMP_SIZE, 0.0, 1000.0, 'Clamp the size to this maximum (Zero to Disable)'),\
@@ -1372,7 +1267,6 @@ def load_obj_ui(filepath, BATCH_LOAD= False):
if KEEP_VERT_ORDER.val:
SPLIT_OBJECTS.val = False
SPLIT_GROUPS.val = False
- SPLIT_MATERIALS.val = False
'''
@@ -1394,25 +1288,25 @@ def load_obj_ui(filepath, BATCH_LOAD= False):
GLOBALS['EVENT'] = e
def do_split(e,v):
- global SPLIT_OBJECTS, SPLIT_GROUPS, SPLIT_MATERIALS, KEEP_VERT_ORDER, POLYGROUPS
- if SPLIT_OBJECTS.val or SPLIT_GROUPS.val or SPLIT_MATERIALS.val:
+ global SPLIT_OBJECTS, SPLIT_GROUPS, KEEP_VERT_ORDER, POLYGROUPS
+ if SPLIT_OBJECTS.val or SPLIT_GROUPS.val:
KEEP_VERT_ORDER.val = 0
POLYGROUPS.val = 0
else:
KEEP_VERT_ORDER.val = 1
def do_vertorder(e,v):
- global SPLIT_OBJECTS, SPLIT_GROUPS, SPLIT_MATERIALS, KEEP_VERT_ORDER
+ global SPLIT_OBJECTS, SPLIT_GROUPS, KEEP_VERT_ORDER
if KEEP_VERT_ORDER.val:
- SPLIT_OBJECTS.val = SPLIT_GROUPS.val = SPLIT_MATERIALS.val = 0
+ SPLIT_OBJECTS.val = SPLIT_GROUPS.val = 0
else:
- if not (SPLIT_OBJECTS.val or SPLIT_GROUPS.val or SPLIT_MATERIALS.val):
+ if not (SPLIT_OBJECTS.val or SPLIT_GROUPS.val):
KEEP_VERT_ORDER.val = 1
def do_polygroups(e,v):
- global SPLIT_OBJECTS, SPLIT_GROUPS, SPLIT_MATERIALS, KEEP_VERT_ORDER, POLYGROUPS
+ global SPLIT_OBJECTS, SPLIT_GROUPS, KEEP_VERT_ORDER, POLYGROUPS
if POLYGROUPS.val:
- SPLIT_OBJECTS.val = SPLIT_GROUPS.val = SPLIT_MATERIALS.val = 0
+ SPLIT_OBJECTS.val = SPLIT_GROUPS.val = 0
def do_help(e,v):
url = __url__[0]
@@ -1432,7 +1326,7 @@ def load_obj_ui(filepath, BATCH_LOAD= False):
ui_x -= 165
ui_y -= 90
- global CREATE_SMOOTH_GROUPS, CREATE_FGONS, CREATE_EDGES, SPLIT_OBJECTS, SPLIT_GROUPS, SPLIT_MATERIALS, CLAMP_SIZE, IMAGE_SEARCH, POLYGROUPS, KEEP_VERT_ORDER, ROTATE_X90
+ global CREATE_SMOOTH_GROUPS, CREATE_FGONS, CREATE_EDGES, SPLIT_OBJECTS, SPLIT_GROUPS, CLAMP_SIZE, IMAGE_SEARCH, POLYGROUPS, KEEP_VERT_ORDER, ROTATE_X90
Draw.Label('Import...', ui_x+9, ui_y+159, 220, 21)
Draw.BeginAlign()
@@ -1445,7 +1339,6 @@ def load_obj_ui(filepath, BATCH_LOAD= False):
Draw.BeginAlign()
SPLIT_OBJECTS = Draw.Toggle('Object', EVENT_REDRAW, ui_x+9, ui_y+89, 55, 21, SPLIT_OBJECTS.val, 'Import OBJ Objects into Blender Objects', do_split)
SPLIT_GROUPS = Draw.Toggle('Group', EVENT_REDRAW, ui_x+64, ui_y+89, 55, 21, SPLIT_GROUPS.val, 'Import OBJ Groups into Blender Objects', do_split)
- SPLIT_MATERIALS = Draw.Toggle('Split Materials', EVENT_REDRAW, ui_x+119, ui_y+89, 60, 21, SPLIT_MATERIALS.val, 'Import each material into a seperate mesh', do_split)
Draw.EndAlign()
# Only used for user feedback
@@ -1495,7 +1388,7 @@ def load_obj_ui(filepath, BATCH_LOAD= False):
return
for f in files:
- scn= bpy.data.scenes.new( stripExt(f) )
+ scn= bpy.data.scenes.new(os.path.splitext(f)[0])
scn.makeCurrent()
load_obj(sys.join(filepath, f),\
@@ -1505,7 +1398,6 @@ def load_obj_ui(filepath, BATCH_LOAD= False):
CREATE_EDGES.val,\
SPLIT_OBJECTS.val,\
SPLIT_GROUPS.val,\
- SPLIT_MATERIALS.val,\
ROTATE_X90.val,\
IMAGE_SEARCH.val,\
POLYGROUPS.val
@@ -1519,7 +1411,6 @@ def load_obj_ui(filepath, BATCH_LOAD= False):
CREATE_EDGES.val,\
SPLIT_OBJECTS.val,\
SPLIT_GROUPS.val,\
- SPLIT_MATERIALS.val,\
ROTATE_X90.val,\
IMAGE_SEARCH.val,\
POLYGROUPS.val
@@ -1576,14 +1467,13 @@ class IMPORT_OT_obj(bpy.types.Operator):
# to the class instance from the operator settings before calling.
- path = StringProperty(name="File Path", description="File path used for importing the OBJ file", maxlen= 1024, default= "")
+ filepath = StringProperty(name="File Path", description="Filepath used for importing the OBJ file", maxlen= 1024, default= "")
CREATE_SMOOTH_GROUPS = BoolProperty(name="Smooth Groups", description="Surround smooth groups by sharp edges", default= True)
CREATE_FGONS = BoolProperty(name="NGons as FGons", description="Import faces with more then 4 verts as fgons", default= True)
CREATE_EDGES = BoolProperty(name="Lines as Edges", description="Import lines and faces with 2 verts as edge", default= True)
SPLIT_OBJECTS = BoolProperty(name="Object", description="Import OBJ Objects into Blender Objects", default= True)
SPLIT_GROUPS = BoolProperty(name="Group", description="Import OBJ Groups into Blender Objects", default= True)
- SPLIT_MATERIALS = BoolProperty(name="Split Materials", description="Import each material into a seperate mesh", default= False)
# old comment: only used for user feedback
# disabled this option because in old code a handler for it disabled SPLIT* params, it's not passed to load_obj
# KEEP_VERT_ORDER = BoolProperty(name="Keep Vert Order", description="Keep vert and face order, disables split options, enable for morph targets", default= True)
@@ -1596,7 +1486,7 @@ class IMPORT_OT_obj(bpy.types.Operator):
def execute(self, context):
# print("Selected: " + context.active_object.name)
- load_obj(self.properties.path,
+ load_obj(self.properties.filepath,
context,
self.properties.CLAMP_SIZE,
self.properties.CREATE_FGONS,
@@ -1604,7 +1494,6 @@ class IMPORT_OT_obj(bpy.types.Operator):
self.properties.CREATE_EDGES,
self.properties.SPLIT_OBJECTS,
self.properties.SPLIT_GROUPS,
- self.properties.SPLIT_MATERIALS,
self.properties.ROTATE_X90,
self.properties.IMAGE_SEARCH,
self.properties.POLYGROUPS)
@@ -1612,8 +1501,7 @@ class IMPORT_OT_obj(bpy.types.Operator):
return {'FINISHED'}
def invoke(self, context, event):
- wm = context.manager
- wm.add_fileselect(self)
+ context.manager.add_fileselect(self)
return {'RUNNING_MODAL'}
@@ -1622,11 +1510,9 @@ def menu_func(self, context):
def register():
- bpy.types.register(IMPORT_OT_obj)
bpy.types.INFO_MT_file_import.append(menu_func)
def unregister():
- bpy.types.unregister(IMPORT_OT_obj)
bpy.types.INFO_MT_file_import.remove(menu_func)
@@ -1634,13 +1520,11 @@ def unregister():
# check later: line 489
# can convert now: edge flags, edges: lines 508-528
# ngon (uses python module BPyMesh): 384-414
-# nurbs: 947-
# NEXT clamp size: get bound box with RNA
# get back to l 140 (here)
# search image in bpy.config.textureDir - load_image
# replaced BPyImage.comprehensiveImageLoad with a simplified version that only checks additional directory specified, but doesn't search dirs recursively (obj_image_load)
# bitmask won't work? - 132
-# uses operator bpy.ops.OBJECT_OT_select_all() to deselect all (not necessary?)
# uses bpy.sys.time()
if __name__ == "__main__":
diff --git a/release/scripts/io/import_shape_mdd.py b/release/scripts/io/import_shape_mdd.py
index 884fa92ddd0..c7b199918a2 100644
--- a/release/scripts/io/import_shape_mdd.py
+++ b/release/scripts/io/import_shape_mdd.py
@@ -12,7 +12,7 @@
#
# 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.
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ***** END GPL LICENCE BLOCK *****
@@ -66,7 +66,7 @@ def mdd_import(filepath, ob, scene, PREF_START_FRAME=0, PREF_JUMP=1):
ob.active_shape_key_index = len(ob.data.shape_keys.keys)-1
index = len(ob.data.shape_keys.keys)-1
- ob.shape_key_lock = True
+ ob.show_shape_key = True
verts = ob.data.shape_keys.keys[len(ob.data.shape_keys.keys)-1].data
@@ -74,7 +74,7 @@ def mdd_import(filepath, ob, scene, PREF_START_FRAME=0, PREF_JUMP=1):
for v in verts: # 12 is the size of 3 floats
v.co[:] = unpack('>3f', file.read(12))
#me.update()
- ob.shape_key_lock = False
+ ob.show_shape_key = False
# insert keyframes
@@ -104,7 +104,7 @@ from bpy.props import *
class importMDD(bpy.types.Operator):
'''Import MDD vertex keyframe file to shape keys'''
- bl_idname = "import.mdd"
+ bl_idname = "import_shape.mdd"
bl_label = "Import MDD"
# get first scene to get min and max properties for frames, fps
@@ -116,19 +116,20 @@ class importMDD(bpy.types.Operator):
# List of operator properties, the attributes will be assigned
# to the class instance from the operator settings before calling.
- path = StringProperty(name="File Path", description="File path used for importing the MDD file", maxlen=1024)
+ filepath = StringProperty(name="File Path", description="Filepath used for importing the MDD file", maxlen=1024)
#fps = IntProperty(name="Frames Per Second", description="Number of frames/second", min=minfps, max=maxfps, default=25)
frame_start = IntProperty(name="Start Frame", description="Start frame for inserting animation", min=minframe, max=maxframe, default=0)
- def poll(self, context):
+ @classmethod
+ def poll(cls, context):
ob = context.active_object
return (ob and ob.type == 'MESH')
def execute(self, context):
- if not self.properties.path:
+ if not self.properties.filepath:
raise Exception("filename not set")
- mdd_import(self.properties.path, bpy.context.active_object, context.scene, self.properties.frame_start, 1)
+ mdd_import(self.properties.filepath, bpy.context.active_object, context.scene, self.properties.frame_start, 1)
return {'FINISHED'}
@@ -143,12 +144,10 @@ def menu_func(self, context):
def register():
- bpy.types.register(importMDD)
bpy.types.INFO_MT_file_import.append(menu_func)
def unregister():
- bpy.types.unregister(importMDD)
bpy.types.INFO_MT_file_import.remove(menu_func)
if __name__ == "__main__":
diff --git a/release/scripts/io/netrender/__init__.py b/release/scripts/io/netrender/__init__.py
index e06d061f173..5a705e95aa8 100644
--- a/release/scripts/io/netrender/__init__.py
+++ b/release/scripts/io/netrender/__init__.py
@@ -18,15 +18,31 @@
# This directory is a Python package.
-from netrender import model
-from netrender import operators
-from netrender import client
-from netrender import slave
-from netrender import master
-from netrender import master_html
-from netrender import utils
-from netrender import balancing
-from netrender import ui
+# To support reload properly, try to access a package var, if it's there, reload everything
+try:
+ init_data
+
+ reload(model)
+ reload(operators)
+ reload(client)
+ reload(slave)
+ reload(master)
+ reload(master_html)
+ reload(utils)
+ reload(balancing)
+ reload(ui)
+ reload(repath)
+except:
+ from netrender import model
+ from netrender import operators
+ from netrender import client
+ from netrender import slave
+ from netrender import master
+ from netrender import master_html
+ from netrender import utils
+ from netrender import balancing
+ from netrender import ui
+ from netrender import repath
jobs = []
slaves = []
@@ -37,11 +53,10 @@ init_data = True
init_address = True
def register():
- pass # TODO
+ ui.addProperties()
+
def unregister():
import bpy
- bpy.types.unregister(ui.NetRenderJob)
- bpy.types.unregister(ui.NetRenderSettings)
- bpy.types.unregister(ui.NetRenderSlave)
+ bpy.types.Scene.RemoveProperty("network_render")
diff --git a/release/scripts/io/netrender/client.py b/release/scripts/io/netrender/client.py
index 3acc0e1c2e1..6f0f6460ae1 100644
--- a/release/scripts/io/netrender/client.py
+++ b/release/scripts/io/netrender/client.py
@@ -41,7 +41,7 @@ def addFluidFiles(job, path):
job.addFile(path + fluid_file, current_frame, current_frame)
def addPointCache(job, ob, point_cache, default_path):
- if not point_cache.disk_cache:
+ if not point_cache.use_disk_cache:
return
@@ -49,7 +49,7 @@ def addPointCache(job, ob, point_cache, default_path):
if name == "":
name = "".join(["%02X" % ord(c) for c in ob.name])
- cache_path = bpy.utils.expandpath(point_cache.filepath) if point_cache.external else default_path
+ cache_path = bpy.path.abspath(point_cache.filepath) if point_cache.use_external else default_path
index = "%02i" % point_cache.index
@@ -101,7 +101,7 @@ def clientSendJob(conn, scene, anim = False):
else:
job.addFrame(scene.frame_current)
- filename = bpy.data.filename
+ filename = bpy.data.filepath
job.addFile(filename)
job_name = netsettings.job_name
@@ -113,7 +113,7 @@ def clientSendJob(conn, scene, anim = False):
# LIBRARIES
###########################
for lib in bpy.data.libraries:
- file_path = bpy.utils.expandpath(lib.filename)
+ file_path = bpy.path.abspath(lib.filepath)
if os.path.exists(file_path):
job.addFile(file_path)
@@ -122,9 +122,13 @@ def clientSendJob(conn, scene, anim = False):
###########################
for image in bpy.data.images:
if image.source == "FILE" and not image.packed_file:
- file_path = bpy.utils.expandpath(image.filename)
+ file_path = bpy.path.abspath(image.filepath)
if os.path.exists(file_path):
job.addFile(file_path)
+
+ tex_path = os.path.splitext(file_path)[0] + ".tex"
+ if os.path.exists(tex_path):
+ job.addFile(tex_path)
###########################
# FLUID + POINT CACHE
@@ -135,15 +139,18 @@ def clientSendJob(conn, scene, anim = False):
for object in bpy.data.objects:
for modifier in object.modifiers:
if modifier.type == 'FLUID_SIMULATION' and modifier.settings.type == "DOMAIN":
- addFluidFiles(job, bpy.utils.expandpath(modifier.settings.path))
+ addFluidFiles(job, bpy.path.abspath(modifier.settings.path))
elif modifier.type == "CLOTH":
addPointCache(job, object, modifier.point_cache, default_path)
elif modifier.type == "SOFT_BODY":
addPointCache(job, object, modifier.point_cache, default_path)
elif modifier.type == "SMOKE" and modifier.smoke_type == "TYPE_DOMAIN":
addPointCache(job, object, modifier.domain_settings.point_cache_low, default_path)
- if modifier.domain_settings.highres:
+ if modifier.domain_settings.use_high_resolution:
addPointCache(job, object, modifier.domain_settings.point_cache_high, default_path)
+ elif modifier.type == "MULTIRES" and modifier.is_external:
+ file_path = bpy.path.abspath(modifier.filepath)
+ job.addFile(file_path)
# particles modifier are stupid and don't contain data
# we have to go through the object property
@@ -164,6 +171,7 @@ def clientSendJob(conn, scene, anim = False):
# try to send path first
conn.request("POST", "/job", repr(job.serialize()))
response = conn.getresponse()
+ response.read()
job_id = response.getheader("job-id")
@@ -174,6 +182,7 @@ def clientSendJob(conn, scene, anim = False):
conn.request("PUT", fileURL(job_id, rfile.index), f)
f.close()
response = conn.getresponse()
+ response.read()
# server will reply with ACCEPTED until all files are found
@@ -182,7 +191,6 @@ def clientSendJob(conn, scene, anim = False):
def requestResult(conn, job_id, frame):
conn.request("GET", renderURL(job_id, frame))
-@rnaType
class NetworkRenderEngine(bpy.types.RenderEngine):
bl_idname = 'NET_RENDER'
bl_label = "Network Render"
@@ -202,7 +210,7 @@ class NetworkRenderEngine(bpy.types.RenderEngine):
address = "" if netsettings.server_address == "[default]" else netsettings.server_address
- master.runMaster((address, netsettings.server_port), netsettings.master_broadcast, netsettings.master_clear, netsettings.path, self.update_stats, self.test_break)
+ master.runMaster((address, netsettings.server_port), netsettings.master_broadcast, netsettings.use_master_clear, netsettings.path, self.update_stats, self.test_break)
def render_slave(self, scene):
@@ -230,6 +238,7 @@ class NetworkRenderEngine(bpy.types.RenderEngine):
requestResult(conn, job_id, scene.frame_current)
response = conn.getresponse()
+ response.read()
if response.status == http.client.NO_CONTENT:
new_job = True
@@ -238,16 +247,19 @@ class NetworkRenderEngine(bpy.types.RenderEngine):
requestResult(conn, job_id, scene.frame_current)
response = conn.getresponse()
+ response.read()
while response.status == http.client.ACCEPTED and not self.test_break():
time.sleep(1)
requestResult(conn, job_id, scene.frame_current)
response = conn.getresponse()
+ response.read()
# cancel new jobs (animate on network) on break
if self.test_break() and new_job:
conn.request("POST", cancelURL(job_id))
response = conn.getresponse()
+ response.read()
print( response.status, response.reason )
netsettings.job_id = 0
@@ -259,7 +271,7 @@ class NetworkRenderEngine(bpy.types.RenderEngine):
x= int(r.resolution_x*r.resolution_percentage*0.01)
y= int(r.resolution_y*r.resolution_percentage*0.01)
- f = open(netsettings.path + "output.exr", "wb")
+ f = open(os.path.join(netsettings.path, "output.exr"), "wb")
buf = response.read(1024)
while buf:
@@ -269,7 +281,7 @@ class NetworkRenderEngine(bpy.types.RenderEngine):
f.close()
result = self.begin_result(0, 0, x, y)
- result.load_from_file(netsettings.path + "output.exr")
+ result.load_from_file(os.path.join(netsettings.path, "output.exr"))
self.end_result(result)
conn.close()
@@ -284,3 +296,6 @@ def compatible(module):
#compatible("properties_render")
compatible("properties_world")
compatible("properties_material")
+compatible("properties_data_mesh")
+compatible("properties_data_camera")
+compatible("properties_texture")
diff --git a/release/scripts/io/netrender/master.py b/release/scripts/io/netrender/master.py
index 019f33047d8..6deb925420b 100644
--- a/release/scripts/io/netrender/master.py
+++ b/release/scripts/io/netrender/master.py
@@ -19,6 +19,7 @@
import sys, os
import http, http.client, http.server, urllib, socket, socketserver, threading
import subprocess, shutil, time, hashlib
+import pickle
import select # for select.error
from netrender.utils import *
@@ -27,12 +28,16 @@ import netrender.balancing
import netrender.master_html
class MRenderFile(netrender.model.RenderFile):
- def __init__(self, filepath, index, start, end):
- super().__init__(filepath, index, start, end)
+ def __init__(self, filepath, index, start, end, signature):
+ super().__init__(filepath, index, start, end, signature)
self.found = False
def test(self):
self.found = os.path.exists(self.filepath)
+ if self.found:
+ found_signature = hashFile(self.filepath)
+ self.found = self.signature == found_signature
+
return self.found
@@ -74,7 +79,7 @@ class MRenderJob(netrender.model.RenderJob):
# special server properties
self.last_update = 0
self.save_path = ""
- self.files = [MRenderFile(rfile.filepath, rfile.index, rfile.start, rfile.end) for rfile in job_info.files]
+ self.files = [MRenderFile(rfile.filepath, rfile.index, rfile.start, rfile.end, rfile.signature) for rfile in job_info.files]
self.resolution = None
@@ -84,7 +89,7 @@ class MRenderJob(netrender.model.RenderJob):
def save(self):
if self.save_path:
- f = open(self.save_path + "job.txt", "w")
+ f = open(os.path.join(self.save_path, "job.txt"), "w")
f.write(repr(self.serialize()))
f.close()
@@ -129,8 +134,8 @@ class MRenderJob(netrender.model.RenderJob):
self.status = JOB_QUEUED
def addLog(self, frames):
- log_name = "_".join(("%04d" % f for f in frames)) + ".log"
- log_path = self.save_path + log_name
+ log_name = "_".join(("%06d" % f for f in frames)) + ".log"
+ log_path = os.path.join(self.save_path, log_name)
for number in frames:
frame = self[number]
@@ -190,6 +195,11 @@ pause_pattern = re.compile("/pause_([a-zA-Z0-9]+)")
edit_pattern = re.compile("/edit_([a-zA-Z0-9]+)")
class RenderHandler(http.server.BaseHTTPRequestHandler):
+ def log_message(self, format, *args):
+ # override because the original calls self.address_string(), which
+ # is extremely slow due to some timeout..
+ sys.stderr.write("[%s] %s\n" % (self.log_date_time_string(), format%args))
+
def send_head(self, code = http.client.OK, headers = {}, content = "application/octet-stream"):
self.send_response(code)
self.send_header("Content-type", content)
@@ -250,7 +260,7 @@ class RenderHandler(http.server.BaseHTTPRequestHandler):
elif frame.status == DONE:
self.server.stats("", "Sending result to client")
- filename = job.save_path + "%04d" % frame_number + ".exr"
+ filename = os.path.join(job.save_path, "%06d.exr" % frame_number)
f = open(filename, 'rb')
self.send_head(content = "image/x-exr")
@@ -284,7 +294,7 @@ class RenderHandler(http.server.BaseHTTPRequestHandler):
if frame.status in (QUEUED, DISPATCHED):
self.send_head(http.client.ACCEPTED)
elif frame.status == DONE:
- filename = job.save_path + "%04d" % frame_number + ".exr"
+ filename = os.path.join(job.save_path, "%06d.exr" % frame_number)
thumbname = thumbnail(filename)
@@ -706,12 +716,12 @@ class RenderHandler(http.server.BaseHTTPRequestHandler):
if file_index > 0:
file_path = prefixPath(job.save_path, render_file.filepath, main_path)
else:
- file_path = job.save_path + main_name
+ file_path = os.path.join(job.save_path, main_name)
buf = self.rfile.read(length)
# add same temp file + renames as slave
-
+
f = open(file_path, "wb")
f.write(buf)
f.close()
@@ -762,7 +772,7 @@ class RenderHandler(http.server.BaseHTTPRequestHandler):
if job_result == DONE:
length = int(self.headers['content-length'])
buf = self.rfile.read(length)
- f = open(job.save_path + "%04d" % job_frame + ".exr", 'wb')
+ f = open(os.path.join(job.save_path, "%06d.exr" % job_frame), 'wb')
f.write(buf)
f.close()
@@ -812,13 +822,12 @@ class RenderHandler(http.server.BaseHTTPRequestHandler):
if job.type == netrender.model.JOB_BLENDER:
length = int(self.headers['content-length'])
buf = self.rfile.read(length)
- f = open(job.save_path + "%04d" % job_frame + ".jpg", 'wb')
+ f = open(os.path.join(job.save_path, "%06d.jpg" % job_frame), 'wb')
f.write(buf)
f.close()
del buf
- self.send_head()
else: # frame not found
self.send_head(http.client.NO_CONTENT)
else: # job not found
@@ -861,16 +870,20 @@ class RenderHandler(http.server.BaseHTTPRequestHandler):
self.send_head(http.client.NO_CONTENT)
class RenderMasterServer(socketserver.ThreadingMixIn, http.server.HTTPServer):
- def __init__(self, address, handler_class, path):
+ def __init__(self, address, handler_class, path, subdir=True):
super().__init__(address, handler_class)
self.jobs = []
self.jobs_map = {}
self.slaves = []
self.slaves_map = {}
self.job_id = 0
- self.path = path + "master_" + str(os.getpid()) + os.sep
- self.slave_timeout = 30 # 30 mins: need a parameter for that
+ if subdir:
+ self.path = os.path.join(path, "master_" + str(os.getpid()))
+ else:
+ self.path = path
+
+ self.slave_timeout = 5 # 5 mins: need a parameter for that
self.balancer = netrender.balancing.Balancer()
self.balancer.addRule(netrender.balancing.RatingUsageByCategory(self.getJobs))
@@ -883,6 +896,22 @@ class RenderMasterServer(socketserver.ThreadingMixIn, http.server.HTTPServer):
if not os.path.exists(self.path):
os.mkdir(self.path)
+ def restore(self, jobs, slaves, balancer = None):
+ self.jobs = jobs
+ self.jobs_map = {}
+
+ for job in self.jobs:
+ self.jobs_map[job.id] = job
+ self.job_id = max(self.job_id, int(job.id))
+
+ self.slaves = slaves
+ for slave in self.slaves:
+ self.slaves_map[slave.id] = slave
+
+ if balancer:
+ self.balancer = balancer
+
+
def nextJobID(self):
self.job_id += 1
return str(self.job_id)
@@ -977,7 +1006,7 @@ class RenderMasterServer(socketserver.ThreadingMixIn, http.server.HTTPServer):
self.jobs_map[job.id] = job
# create job directory
- job.save_path = self.path + "job_" + job.id + os.sep
+ job.save_path = os.path.join(self.path, "job_" + job.id)
if not os.path.exists(job.save_path):
os.mkdir(job.save_path)
@@ -1001,8 +1030,29 @@ class RenderMasterServer(socketserver.ThreadingMixIn, http.server.HTTPServer):
def clearMaster(path):
shutil.rmtree(path)
+def createMaster(address, clear, path):
+ filepath = os.path.join(path, "blender_master.data")
+
+ if not clear and os.path.exists(filepath):
+ print("loading saved master:", filepath)
+ with open(filepath, 'rb') as f:
+ path, jobs, slaves = pickle.load(f)
+
+ httpd = RenderMasterServer(address, RenderHandler, path, subdir=False)
+ httpd.restore(jobs, slaves)
+
+ return httpd
+
+ return RenderMasterServer(address, RenderHandler, path)
+
+def saveMaster(path, httpd):
+ filepath = os.path.join(path, "blender_master.data")
+
+ with open(filepath, 'wb') as f:
+ pickle.dump((httpd.path, httpd.jobs, httpd.slaves), f, pickle.HIGHEST_PROTOCOL)
+
def runMaster(address, broadcast, clear, path, update_stats, test_break):
- httpd = RenderMasterServer(address, RenderHandler, path)
+ httpd = createMaster(address, clear, path)
httpd.timeout = 1
httpd.stats = update_stats
@@ -1010,7 +1060,7 @@ def runMaster(address, broadcast, clear, path, update_stats, test_break):
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
- start_time = time.time()
+ start_time = time.time() - 2
while not test_break():
try:
@@ -1018,7 +1068,7 @@ def runMaster(address, broadcast, clear, path, update_stats, test_break):
except select.error:
pass
- if time.time() - start_time >= 10: # need constant here
+ if time.time() - start_time >= 2: # need constant here
httpd.timeoutSlaves()
httpd.updateUsage()
@@ -1031,3 +1081,6 @@ def runMaster(address, broadcast, clear, path, update_stats, test_break):
httpd.server_close()
if clear:
clearMaster(httpd.path)
+ else:
+ saveMaster(path, httpd)
+
diff --git a/release/scripts/io/netrender/master_html.py b/release/scripts/io/netrender/master_html.py
index e5feac86e12..74155f6bd66 100644
--- a/release/scripts/io/netrender/master_html.py
+++ b/release/scripts/io/netrender/master_html.py
@@ -27,8 +27,10 @@ def get(handler):
def output(text):
handler.wfile.write(bytes(text, encoding='utf8'))
- def head(title):
+ def head(title, refresh = False):
output("<html><head>")
+ if refresh:
+ output("<meta http-equiv='refresh' content=5>")
output("<script src='/html/netrender.js' type='text/javascript'></script>")
# output("<script src='/html/json2.js' type='text/javascript'></script>")
output("<title>")
@@ -103,54 +105,7 @@ def get(handler):
f.close()
elif handler.path == "/html" or handler.path == "/":
handler.send_head(content = "text/html")
- head("NetRender")
-
- output("<h2>Master</h2>")
-
- output("""<button title="remove all jobs" onclick="clear_jobs();">CLEAR JOB LIST</button>""")
-
- startTable(caption = "Rules", class_style = "rules")
-
- headerTable("type", "enabled", "description", "limit")
-
- for rule in handler.server.balancer.rules:
- rowTable(
- "rating",
- checkbox("", rule.enabled, "balance_enable('%i', '%s')" % (id(rule), str(not rule.enabled))),
- rule,
- rule.str_limit() +
- """<button title="edit limit" onclick="balance_edit('%i', '%s');">edit</button>""" % (id(rule), str(rule.limit)) if hasattr(rule, "limit") else "&nbsp;"
- )
-
- for rule in handler.server.balancer.priorities:
- rowTable(
- "priority",
- checkbox("", rule.enabled, "balance_enable('%i', '%s')" % (id(rule), str(not rule.enabled))),
- rule,
- rule.str_limit() +
- """<button title="edit limit" onclick="balance_edit('%i', '%s');">edit</button>""" % (id(rule), str(rule.limit)) if hasattr(rule, "limit") else "&nbsp;"
- )
-
- for rule in handler.server.balancer.exceptions:
- rowTable(
- "exception",
- checkbox("", rule.enabled, "balance_enable('%i', '%s')" % (id(rule), str(not rule.enabled))),
- rule,
- rule.str_limit() +
- """<button title="edit limit" onclick="balance_edit('%i', '%s');">edit</button>""" % (id(rule), str(rule.limit)) if hasattr(rule, "limit") else "&nbsp;"
- )
-
- endTable()
-
- output("<h2>Slaves</h2>")
-
- startTable()
- headerTable("name", "address", "last seen", "stats", "job")
-
- for slave in handler.server.slaves:
- rowTable(slave.name, slave.address[0], time.ctime(slave.last_seen), slave.stats, link(slave.job.name, "/html/job" + slave.job.id) if slave.job else "None")
-
- endTable()
+ head("NetRender", refresh = True)
output("<h2>Jobs</h2>")
@@ -203,6 +158,53 @@ def get(handler):
)
endTable()
+
+ output("<h2>Slaves</h2>")
+
+ startTable()
+ headerTable("name", "address", "last seen", "stats", "job")
+
+ for slave in handler.server.slaves:
+ rowTable(slave.name, slave.address[0], time.ctime(slave.last_seen), slave.stats, link(slave.job.name, "/html/job" + slave.job.id) if slave.job else "None")
+
+ endTable()
+
+ output("<h2>Configuration</h2>")
+
+ output("""<button title="remove all jobs" onclick="clear_jobs();">CLEAR JOB LIST</button>""")
+
+ startTable(caption = "Rules", class_style = "rules")
+
+ headerTable("type", "enabled", "description", "limit")
+
+ for rule in handler.server.balancer.rules:
+ rowTable(
+ "rating",
+ checkbox("", rule.enabled, "balance_enable('%i', '%s')" % (id(rule), str(not rule.enabled))),
+ rule,
+ rule.str_limit() +
+ """<button title="edit limit" onclick="balance_edit('%i', '%s');">edit</button>""" % (id(rule), str(rule.limit)) if hasattr(rule, "limit") else "&nbsp;"
+ )
+
+ for rule in handler.server.balancer.priorities:
+ rowTable(
+ "priority",
+ checkbox("", rule.enabled, "balance_enable('%i', '%s')" % (id(rule), str(not rule.enabled))),
+ rule,
+ rule.str_limit() +
+ """<button title="edit limit" onclick="balance_edit('%i', '%s');">edit</button>""" % (id(rule), str(rule.limit)) if hasattr(rule, "limit") else "&nbsp;"
+ )
+
+ for rule in handler.server.balancer.exceptions:
+ rowTable(
+ "exception",
+ checkbox("", rule.enabled, "balance_enable('%i', '%s')" % (id(rule), str(not rule.enabled))),
+ rule,
+ rule.str_limit() +
+ """<button title="edit limit" onclick="balance_edit('%i', '%s');">edit</button>""" % (id(rule), str(rule.limit)) if hasattr(rule, "limit") else "&nbsp;"
+ )
+
+ endTable()
output("</body></html>")
@@ -234,13 +236,17 @@ def get(handler):
tot_cache = 0
tot_fluid = 0
+ rowTable(job.files[0].filepath)
+ rowTable("Other Files", class_style = "toggle", extra = "onclick='toggleDisplay(&quot;.other&quot;, &quot;none&quot;, &quot;table-row&quot;)'")
+
for file in job.files:
if file.filepath.endswith(".bphys"):
tot_cache += 1
elif file.filepath.endswith(".bobj.gz") or file.filepath.endswith(".bvel.gz"):
tot_fluid += 1
else:
- rowTable(file.filepath)
+ if file != job.files[0]:
+ rowTable(file.filepath, class_style = "other")
if tot_cache > 0:
rowTable("%i physic cache files" % tot_cache, class_style = "toggle", extra = "onclick='toggleDisplay(&quot;.cache&quot;, &quot;none&quot;, &quot;table-row&quot;)'")
@@ -256,9 +262,9 @@ def get(handler):
endTable()
- output("<h2>Blacklist</h2>")
-
if job.blacklist:
+ output("<h2>Blacklist</h2>")
+
startTable()
headerTable("name", "address")
@@ -267,8 +273,6 @@ def get(handler):
rowTable(slave.name, slave.address[0])
endTable()
- else:
- output("<i>Empty</i>")
output("<h2>Frames</h2>")
diff --git a/release/scripts/io/netrender/model.py b/release/scripts/io/netrender/model.py
index 8b0f50ba848..e7656f498b4 100644
--- a/release/scripts/io/netrender/model.py
+++ b/release/scripts/io/netrender/model.py
@@ -103,8 +103,10 @@ JOB_TYPES = {
}
class RenderFile:
- def __init__(self, filepath = "", index = 0, start = -1, end = -1):
+ def __init__(self, filepath = "", index = 0, start = -1, end = -1, signature=0):
self.filepath = filepath
+ self.original_path = filepath
+ self.signature = signature
self.index = index
self.start = start
self.end = end
@@ -112,9 +114,11 @@ class RenderFile:
def serialize(self):
return {
"filepath": self.filepath,
+ "original_path": self.original_path,
"index": self.index,
"start": self.start,
- "end": self.end
+ "end": self.end,
+ "signature": self.signature
}
@staticmethod
@@ -122,7 +126,8 @@ class RenderFile:
if not data:
return None
- rfile = RenderFile(data["filepath"], data["index"], data["start"], data["end"])
+ rfile = RenderFile(data["filepath"], data["index"], data["start"], data["end"], data["signature"])
+ rfile.original_path = data["original_path"]
return rfile
@@ -153,7 +158,8 @@ class RenderJob:
self.blacklist = job_info.blacklist
def addFile(self, file_path, start=-1, end=-1):
- self.files.append(RenderFile(file_path, len(self.files), start, end))
+ signature = hashFile(file_path)
+ self.files.append(RenderFile(file_path, len(self.files), start, end, signature))
def addFrame(self, frame_number, command = ""):
frame = RenderFrame(frame_number, command)
diff --git a/release/scripts/io/netrender/netrender.css b/release/scripts/io/netrender/netrender.css
index cc8a93bb9a7..0c54690e002 100644
--- a/release/scripts/io/netrender/netrender.css
+++ b/release/scripts/io/netrender/netrender.css
@@ -68,6 +68,10 @@ button {
display: none;
}
+.other {
+ display: none;
+}
+
.rules {
width: 60em;
text-align: left;
diff --git a/release/scripts/io/netrender/operators.py b/release/scripts/io/netrender/operators.py
index 4c027436560..252b1146b67 100644
--- a/release/scripts/io/netrender/operators.py
+++ b/release/scripts/io/netrender/operators.py
@@ -26,20 +26,20 @@ from netrender.utils import *
import netrender.client as client
import netrender.model
-@rnaType
class RENDER_OT_netslave_bake(bpy.types.Operator):
'''NEED DESCRIPTION'''
bl_idname = "render.netslavebake"
bl_label = "Bake all in file"
- def poll(self, context):
+ @classmethod
+ def poll(cls, context):
return True
def execute(self, context):
scene = context.scene
netsettings = scene.network_render
- filename = bpy.data.filename
+ filename = bpy.data.filepath
path, name = os.path.split(filename)
root, ext = os.path.splitext(name)
default_path = path + os.sep + "blendcache_" + root + os.sep # need an API call for that
@@ -52,45 +52,45 @@ class RENDER_OT_netslave_bake(bpy.types.Operator):
modifier.settings.path = relative_path
bpy.ops.fluid.bake({"active_object": object, "scene": scene})
elif modifier.type == "CLOTH":
- modifier.point_cache.step = 1
- modifier.point_cache.disk_cache = True
- modifier.point_cache.external = False
+ modifier.point_cache.frame_step = 1
+ modifier.point_cache.use_disk_cache = True
+ modifier.point_cache.use_external = False
elif modifier.type == "SOFT_BODY":
- modifier.point_cache.step = 1
- modifier.point_cache.disk_cache = True
- modifier.point_cache.external = False
+ modifier.point_cache.frame_step = 1
+ modifier.point_cache.use_disk_cache = True
+ modifier.point_cache.use_external = False
elif modifier.type == "SMOKE" and modifier.smoke_type == "TYPE_DOMAIN":
- modifier.domain_settings.point_cache_low.step = 1
- modifier.domain_settings.point_cache_low.disk_cache = True
- modifier.domain_settings.point_cache_low.external = False
- modifier.domain_settings.point_cache_high.step = 1
- modifier.domain_settings.point_cache_high.disk_cache = True
- modifier.domain_settings.point_cache_high.external = False
+ modifier.domain_settings.point_cache_low.use_step = 1
+ modifier.domain_settings.point_cache_low.use_disk_cache = True
+ modifier.domain_settings.point_cache_low.use_external = False
+ modifier.domain_settings.point_cache_high.use_step = 1
+ modifier.domain_settings.point_cache_high.use_disk_cache = True
+ modifier.domain_settings.point_cache_high.use_external = False
# particles modifier are stupid and don't contain data
# we have to go through the object property
for psys in object.particle_systems:
- psys.point_cache.step = 1
- psys.point_cache.disk_cache = True
- psys.point_cache.external = False
+ psys.point_cache.use_step = 1
+ psys.point_cache.use_disk_cache = True
+ psys.point_cache.use_external = False
psys.point_cache.filepath = relative_path
bpy.ops.ptcache.bake_all()
- #bpy.ops.wm.save_mainfile(path = path + os.sep + root + "_baked.blend")
+ #bpy.ops.wm.save_mainfile(filepath = path + os.sep + root + "_baked.blend")
return {'FINISHED'}
def invoke(self, context, event):
return self.execute(context)
-@rnaType
class RENDER_OT_netclientanim(bpy.types.Operator):
'''Start rendering an animation on network'''
bl_idname = "render.netclientanim"
bl_label = "Animation on network"
- def poll(self, context):
+ @classmethod
+ def poll(cls, context):
return True
def execute(self, context):
@@ -111,13 +111,13 @@ class RENDER_OT_netclientanim(bpy.types.Operator):
def invoke(self, context, event):
return self.execute(context)
-@rnaType
class RENDER_OT_netclientrun(bpy.types.Operator):
'''Start network rendering service'''
bl_idname = "render.netclientstart"
bl_label = "Start Service"
- def poll(self, context):
+ @classmethod
+ def poll(cls, context):
return True
def execute(self, context):
@@ -128,13 +128,13 @@ class RENDER_OT_netclientrun(bpy.types.Operator):
def invoke(self, context, event):
return self.execute(context)
-@rnaType
class RENDER_OT_netclientsend(bpy.types.Operator):
'''Send Render Job to the Network'''
bl_idname = "render.netclientsend"
bl_label = "Send job"
- def poll(self, context):
+ @classmethod
+ def poll(cls, context):
return True
def execute(self, context):
@@ -158,13 +158,43 @@ class RENDER_OT_netclientsend(bpy.types.Operator):
def invoke(self, context, event):
return self.execute(context)
-@rnaType
+class RENDER_OT_netclientsendframe(bpy.types.Operator):
+ '''Send Render Job with current frame to the Network'''
+ bl_idname = "render.netclientsendframe"
+ bl_label = "Send current frame job"
+
+ @classmethod
+ def poll(cls, context):
+ return True
+
+ def execute(self, context):
+ scene = context.scene
+ netsettings = scene.network_render
+
+ try:
+ conn = clientConnection(netsettings.server_address, netsettings.server_port, self.report)
+
+ if conn:
+ # Sending file
+ scene.network_render.job_id = client.clientSendJob(conn, scene, False)
+ conn.close()
+ self.report('INFO', "Job sent to master")
+ except Exception as err:
+ self.report('ERROR', str(err))
+
+
+ return {'FINISHED'}
+
+ def invoke(self, context, event):
+ return self.execute(context)
+
class RENDER_OT_netclientstatus(bpy.types.Operator):
'''Refresh the status of the current jobs'''
bl_idname = "render.netclientstatus"
bl_label = "Client Status"
- def poll(self, context):
+ @classmethod
+ def poll(cls, context):
return True
def execute(self, context):
@@ -175,6 +205,7 @@ class RENDER_OT_netclientstatus(bpy.types.Operator):
conn.request("GET", "/status")
response = conn.getresponse()
+ response.read()
print( response.status, response.reason )
jobs = (netrender.model.RenderJob.materialize(j) for j in eval(str(response.read(), encoding='utf8')))
@@ -198,13 +229,13 @@ class RENDER_OT_netclientstatus(bpy.types.Operator):
def invoke(self, context, event):
return self.execute(context)
-@rnaType
class RENDER_OT_netclientblacklistslave(bpy.types.Operator):
'''Operator documentation text, will be used for the operator tooltip and python docs.'''
bl_idname = "render.netclientblacklistslave"
bl_label = "Client Blacklist Slave"
- def poll(self, context):
+ @classmethod
+ def poll(cls, context):
return True
def execute(self, context):
@@ -228,13 +259,13 @@ class RENDER_OT_netclientblacklistslave(bpy.types.Operator):
def invoke(self, context, event):
return self.execute(context)
-@rnaType
class RENDER_OT_netclientwhitelistslave(bpy.types.Operator):
'''Operator documentation text, will be used for the operator tooltip and python docs.'''
bl_idname = "render.netclientwhitelistslave"
bl_label = "Client Whitelist Slave"
- def poll(self, context):
+ @classmethod
+ def poll(cls, context):
return True
def execute(self, context):
@@ -259,13 +290,13 @@ class RENDER_OT_netclientwhitelistslave(bpy.types.Operator):
return self.execute(context)
-@rnaType
class RENDER_OT_netclientslaves(bpy.types.Operator):
'''Refresh status about available Render slaves'''
bl_idname = "render.netclientslaves"
bl_label = "Client Slaves"
- def poll(self, context):
+ @classmethod
+ def poll(cls, context):
return True
def execute(self, context):
@@ -276,6 +307,7 @@ class RENDER_OT_netclientslaves(bpy.types.Operator):
conn.request("GET", "/slaves")
response = conn.getresponse()
+ response.read()
print( response.status, response.reason )
slaves = (netrender.model.RenderSlave.materialize(s) for s in eval(str(response.read(), encoding='utf8')))
@@ -304,13 +336,13 @@ class RENDER_OT_netclientslaves(bpy.types.Operator):
def invoke(self, context, event):
return self.execute(context)
-@rnaType
class RENDER_OT_netclientcancel(bpy.types.Operator):
'''Cancel the selected network rendering job.'''
bl_idname = "render.netclientcancel"
bl_label = "Client Cancel"
- def poll(self, context):
+ @classmethod
+ def poll(cls, context):
netsettings = context.scene.network_render
return netsettings.active_job_index >= 0 and len(netsettings.jobs) > 0
@@ -324,6 +356,7 @@ class RENDER_OT_netclientcancel(bpy.types.Operator):
conn.request("POST", cancelURL(job.id))
response = conn.getresponse()
+ response.read()
print( response.status, response.reason )
netsettings.jobs.remove(netsettings.active_job_index)
@@ -333,13 +366,13 @@ class RENDER_OT_netclientcancel(bpy.types.Operator):
def invoke(self, context, event):
return self.execute(context)
-@rnaType
class RENDER_OT_netclientcancelall(bpy.types.Operator):
'''Cancel all running network rendering jobs.'''
bl_idname = "render.netclientcancelall"
bl_label = "Client Cancel All"
- def poll(self, context):
+ @classmethod
+ def poll(cls, context):
return True
def execute(self, context):
@@ -350,6 +383,7 @@ class RENDER_OT_netclientcancelall(bpy.types.Operator):
conn.request("POST", "/clear")
response = conn.getresponse()
+ response.read()
print( response.status, response.reason )
while(len(netsettings.jobs) > 0):
@@ -360,13 +394,13 @@ class RENDER_OT_netclientcancelall(bpy.types.Operator):
def invoke(self, context, event):
return self.execute(context)
-@rnaType
class netclientdownload(bpy.types.Operator):
'''Download render results from the network'''
bl_idname = "render.netclientdownload"
bl_label = "Client Download"
- def poll(self, context):
+ @classmethod
+ def poll(cls, context):
netsettings = context.scene.network_render
return netsettings.active_job_index >= 0 and len(netsettings.jobs) > 0
@@ -382,6 +416,7 @@ class netclientdownload(bpy.types.Operator):
for frame in job.frames:
client.requestResult(conn, job.id, frame.number)
response = conn.getresponse()
+ response.read()
if response.status != http.client.OK:
print("missing", frame.number)
@@ -389,7 +424,7 @@ class netclientdownload(bpy.types.Operator):
print("got back", frame.number)
- f = open(netsettings.path + "%06d" % frame.number + ".exr", "wb")
+ f = open(os.path.join(netsettings.path, "%06d.exr" % frame.number), "wb")
buf = response.read(1024)
while buf:
@@ -405,13 +440,13 @@ class netclientdownload(bpy.types.Operator):
def invoke(self, context, event):
return self.execute(context)
-@rnaType
class netclientscan(bpy.types.Operator):
'''Listen on network for master server broadcasting its address and port.'''
bl_idname = "render.netclientscan"
bl_label = "Client Scan"
- def poll(self, context):
+ @classmethod
+ def poll(cls, context):
return True
def execute(self, context):
@@ -428,13 +463,13 @@ class netclientscan(bpy.types.Operator):
def invoke(self, context, event):
return self.execute(context)
-@rnaType
class netclientweb(bpy.types.Operator):
'''Open new window with information about running rendering jobs'''
bl_idname = "render.netclientweb"
bl_label = "Open Master Monitor"
- def poll(self, context):
+ @classmethod
+ def poll(cls, context):
netsettings = context.scene.network_render
return netsettings.server_address != "[default]"
diff --git a/release/scripts/io/netrender/repath.py b/release/scripts/io/netrender/repath.py
new file mode 100644
index 00000000000..3ac9636b628
--- /dev/null
+++ b/release/scripts/io/netrender/repath.py
@@ -0,0 +1,150 @@
+# ##### 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 sys, os
+import subprocess
+
+import bpy
+
+from netrender.utils import *
+import netrender.model
+
+BLENDER_PATH = sys.argv[0]
+
+def reset(job):
+ main_file = job.files[0]
+
+ job_full_path = main_file.filepath
+
+ if os.path.exists(job_full_path + ".bak"):
+ os.remove(job_full_path) # repathed file
+ os.renames(job_full_path + ".bak", job_full_path)
+
+def update(job):
+ paths = []
+
+ main_file = job.files[0]
+
+ job_full_path = main_file.filepath
+
+
+ path, ext = os.path.splitext(job_full_path)
+
+ new_path = path + ".remap" + ext
+
+ # Disable for now. Partial repath should work anyway
+ #all = main_file.filepath != main_file.original_path
+ all = False
+
+ for rfile in job.files[1:]:
+ if all or rfile.original_path != rfile.filepath:
+ paths.append(rfile.original_path)
+ paths.append(rfile.filepath)
+
+ # Only update if needed
+ if paths:
+ process = subprocess.Popen([BLENDER_PATH, "-b", "-noaudio", job_full_path, "-P", __file__, "--", new_path] + paths, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+ process.wait()
+
+ os.renames(job_full_path, job_full_path + ".bak")
+ os.renames(new_path, job_full_path)
+
+def process(paths):
+ def processPointCache(point_cache):
+ point_cache.use_external = False
+
+ def processFluid(fluid):
+ new_path = path_map.get(fluid.filepath, None)
+ if new_path:
+ fluid.path = new_path
+
+ path_map = {}
+ for i in range(0, len(paths), 2):
+ # special case for point cache
+ if paths[i].endswith(".bphys"):
+ pass # Don't need them in the map, they all use the default external path
+ # NOTE: This is probably not correct all the time, need to be fixed.
+ # special case for fluids
+ elif paths[i].endswith(".bobj.gz"):
+ path_map[os.path.split(paths[i])[0]] = os.path.split(paths[i+1])[0]
+ else:
+ path_map[os.path.split(paths[i])[1]] = paths[i+1]
+
+ # TODO original paths aren't really the orignal path (they are the normalized path
+ # so we repath using the filenames only.
+
+ ###########################
+ # LIBRARIES
+ ###########################
+ for lib in bpy.data.libraries:
+ file_path = bpy.path.abspath(lib.filepath)
+ new_path = path_map.get(os.path.split(file_path)[1], None)
+ if new_path:
+ lib.filepath = new_path
+
+ ###########################
+ # IMAGES
+ ###########################
+ for image in bpy.data.images:
+ if image.source == "FILE" and not image.packed_file:
+ file_path = bpy.path.abspath(image.filepath)
+ new_path = path_map.get(os.path.split(file_path)[1], None)
+ if new_path:
+ image.filepath = new_path
+
+
+ ###########################
+ # FLUID + POINT CACHE
+ ###########################
+ for object in bpy.data.objects:
+ for modifier in object.modifiers:
+ if modifier.type == 'FLUID_SIMULATION' and modifier.settings.type == "DOMAIN":
+ processFluid(settings)
+ elif modifier.type == "CLOTH":
+ processPointCache(modifier.point_cache)
+ elif modifier.type == "SOFT_BODY":
+ processPointCache(modifier.point_cache)
+ elif modifier.type == "SMOKE" and modifier.smoke_type == "TYPE_DOMAIN":
+ processPointCache(modifier.domain_settings.point_cache_low)
+ if modifier.domain_settings.use_high_resolution:
+ processPointCache(modifier.domain_settings.point_cache_high)
+ elif modifier.type == "MULTIRES" and modifier.is_external:
+ file_path = bpy.path.abspath(modifier.filepath)
+ new_path = path_map.get(file_path, None)
+ if new_path:
+ modifier.filepath = new_path
+
+ # particles modifier are stupid and don't contain data
+ # we have to go through the object property
+ for psys in object.particle_systems:
+ processPointCache(psys.point_cache)
+
+
+if __name__ == "__main__":
+ try:
+ i = sys.argv.index("--")
+ except:
+ i = 0
+
+ if i:
+ new_path = sys.argv[i+1]
+ args = sys.argv[i+2:]
+
+ process(args)
+
+ bpy.ops.wm.save_as_mainfile(filepath=new_path, check_existing=False)
diff --git a/release/scripts/io/netrender/slave.py b/release/scripts/io/netrender/slave.py
index d24490385fb..b383481824b 100644
--- a/release/scripts/io/netrender/slave.py
+++ b/release/scripts/io/netrender/slave.py
@@ -22,6 +22,7 @@ import subprocess, time
from netrender.utils import *
import netrender.model
+import netrender.repath
BLENDER_PATH = sys.argv[0]
@@ -58,18 +59,30 @@ def slave_Info():
def testCancel(conn, job_id, frame_number):
conn.request("HEAD", "/status", headers={"job-id":job_id, "job-frame": str(frame_number)})
- # cancelled if job isn't found anymore
- if conn.getresponse().status == http.client.NO_CONTENT:
+ # canceled if job isn't found anymore
+ if responseStatus(conn) == http.client.NO_CONTENT:
return True
else:
return False
-def testFile(conn, job_id, slave_id, file_index, JOB_PREFIX, file_path, main_path = None):
- job_full_path = prefixPath(JOB_PREFIX, file_path, main_path)
-
- if not os.path.exists(job_full_path):
- temp_path = JOB_PREFIX + "slave.temp.blend"
- conn.request("GET", fileURL(job_id, file_index), headers={"slave-id":slave_id})
+def testFile(conn, job_id, slave_id, rfile, JOB_PREFIX, main_path = None):
+ job_full_path = prefixPath(JOB_PREFIX, rfile.filepath, main_path)
+
+ found = os.path.exists(job_full_path)
+
+ if found:
+ found_signature = hashFile(job_full_path)
+ found = found_signature == rfile.signature
+
+ if not found:
+ print("Found file %s at %s but signature mismatch!" % (rfile.filepath, job_full_path))
+ job_full_path = prefixPath(JOB_PREFIX, rfile.filepath, main_path, force = True)
+
+ if not found:
+ # Force prefix path if not found
+ job_full_path = prefixPath(JOB_PREFIX, rfile.filepath, main_path, force = True)
+ temp_path = os.path.join(JOB_PREFIX, "slave.temp")
+ conn.request("GET", fileURL(job_id, rfile.index), headers={"slave-id":slave_id})
response = conn.getresponse()
if response.status != http.client.OK:
@@ -85,6 +98,8 @@ def testFile(conn, job_id, slave_id, file_index, JOB_PREFIX, file_path, main_pat
f.close()
os.renames(temp_path, job_full_path)
+
+ rfile.filepath = job_full_path
return job_full_path
@@ -98,13 +113,16 @@ def render_slave(engine, netsettings, threads):
if conn:
conn.request("POST", "/slave", repr(slave_Info().serialize()))
response = conn.getresponse()
+ response.read()
slave_id = response.getheader("slave-id")
- NODE_PREFIX = netsettings.path + "slave_" + slave_id + os.sep
+ NODE_PREFIX = os.path.join(netsettings.path, "slave_" + slave_id)
if not os.path.exists(NODE_PREFIX):
os.mkdir(NODE_PREFIX)
+ engine.update_stats("", "Network render connected to master, waiting for jobs")
+
while not engine.test_break():
conn.request("GET", "/job", headers={"slave-id":slave_id})
response = conn.getresponse()
@@ -113,8 +131,9 @@ def render_slave(engine, netsettings, threads):
timeout = 1 # reset timeout on new job
job = netrender.model.RenderJob.materialize(eval(str(response.read(), encoding='utf8')))
+ engine.update_stats("", "Network render processing job from master")
- JOB_PREFIX = NODE_PREFIX + "job_" + job.id + os.sep
+ JOB_PREFIX = os.path.join(NODE_PREFIX, "job_" + job.id)
if not os.path.exists(JOB_PREFIX):
os.mkdir(JOB_PREFIX)
@@ -123,19 +142,23 @@ def render_slave(engine, netsettings, threads):
job_path = job.files[0].filepath # path of main file
main_path, main_file = os.path.split(job_path)
- job_full_path = testFile(conn, job.id, slave_id, 0, JOB_PREFIX, job_path)
+ job_full_path = testFile(conn, job.id, slave_id, job.files[0], JOB_PREFIX)
print("Fullpath", job_full_path)
print("File:", main_file, "and %i other files" % (len(job.files) - 1,))
- engine.update_stats("", "Render File "+ main_file+ " for job "+ job.id)
for rfile in job.files[1:]:
+ testFile(conn, job.id, slave_id, rfile, JOB_PREFIX, main_path)
print("\t", rfile.filepath)
- testFile(conn, job.id, slave_id, rfile.index, JOB_PREFIX, rfile.filepath, main_path)
+
+ netrender.repath.update(job)
+
+ engine.update_stats("", "Render File "+ main_file+ " for job "+ job.id)
# announce log to master
logfile = netrender.model.LogFile(job.id, slave_id, [frame.number for frame in job.frames])
conn.request("POST", "/log", bytes(repr(logfile.serialize()), encoding='utf8'))
response = conn.getresponse()
+ response.read()
first_frame = job.frames[0].number
@@ -151,7 +174,7 @@ def render_slave(engine, netsettings, threads):
frame_args += ["-f", str(frame.number)]
val = SetErrorMode()
- process = subprocess.Popen([BLENDER_PATH, "-b", "-noaudio", job_full_path, "-t", str(threads), "-o", JOB_PREFIX + "######", "-E", "BLENDER_RENDER", "-F", "MULTILAYER"] + frame_args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+ process = subprocess.Popen([BLENDER_PATH, "-b", "-noaudio", job_full_path, "-t", str(threads), "-o", os.path.join(JOB_PREFIX, "######"), "-E", "BLENDER_RENDER", "-F", "MULTILAYER"] + frame_args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
RestoreErrorMode(val)
elif job.type == netrender.model.JOB_PROCESS:
command = job.frames[0].command
@@ -175,6 +198,11 @@ def render_slave(engine, netsettings, threads):
# (only need to update on one frame, they are linked
conn.request("PUT", logURL(job.id, first_frame), stdout, headers=headers)
response = conn.getresponse()
+ response.read()
+
+ # Also output on console
+ if netsettings.use_slave_output_log:
+ print(str(stdout, encoding='utf8'), end="")
stdout = bytes()
@@ -182,15 +210,32 @@ def render_slave(engine, netsettings, threads):
if testCancel(conn, job.id, first_frame):
cancelled = True
+ if job.type == netrender.model.JOB_BLENDER:
+ netrender.repath.reset(job)
+
# read leftovers if needed
stdout += process.stdout.read()
if cancelled:
# kill process if needed
if process.poll() == None:
- process.terminate()
+ try:
+ process.terminate()
+ except OSError:
+ pass
continue # to next frame
+ # flush the rest of the logs
+ if stdout:
+ # Also output on console
+ if netsettings.use_slave_thumb:
+ print(str(stdout, encoding='utf8'), end="")
+
+ # (only need to update on one frame, they are linked
+ conn.request("PUT", logURL(job.id, first_frame), stdout, headers=headers)
+ if responseStatus(conn) == http.client.NO_CONTENT:
+ continue
+
total_t = time.time() - start_t
avg_t = total_t / len(job.frames)
@@ -199,13 +244,6 @@ def render_slave(engine, netsettings, threads):
print("status", status)
- # flush the rest of the logs
- if stdout:
- # (only need to update on one frame, they are linked
- conn.request("PUT", logURL(job.id, first_frame), stdout, headers=headers)
- if conn.getresponse().status == http.client.NO_CONTENT:
- continue
-
headers = {"job-id":job.id, "slave-id":slave_id, "job-time":str(avg_t)}
@@ -216,26 +254,27 @@ def render_slave(engine, netsettings, threads):
if job.type == netrender.model.JOB_BLENDER:
# send image back to server
- filename = JOB_PREFIX + "%06d" % frame.number + ".exr"
+ filename = os.path.join(JOB_PREFIX, "%06d.exr" % frame.number)
# thumbnail first
- if netsettings.slave_thumb:
+ if netsettings.use_slave_thumb:
thumbname = thumbnail(filename)
f = open(thumbname, 'rb')
conn.request("PUT", "/thumb", f, headers=headers)
f.close()
- conn.getresponse()
+ responseStatus(conn)
+
f = open(filename, 'rb')
conn.request("PUT", "/render", f, headers=headers)
f.close()
- if conn.getresponse().status == http.client.NO_CONTENT:
+ if responseStatus(conn) == http.client.NO_CONTENT:
continue
elif job.type == netrender.model.JOB_PROCESS:
conn.request("PUT", "/render", headers=headers)
- if conn.getresponse().status == http.client.NO_CONTENT:
+ if responseStatus(conn) == http.client.NO_CONTENT:
continue
else:
headers["job-result"] = str(ERROR)
@@ -243,8 +282,10 @@ def render_slave(engine, netsettings, threads):
headers["job-frame"] = str(frame.number)
# send error result back to server
conn.request("PUT", "/render", headers=headers)
- if conn.getresponse().status == http.client.NO_CONTENT:
+ if responseStatus(conn) == http.client.NO_CONTENT:
continue
+
+ engine.update_stats("", "Network render connected to master, waiting for jobs")
else:
if timeout < MAX_TIMEOUT:
timeout += INCREMENT_TIMEOUT
@@ -256,7 +297,7 @@ def render_slave(engine, netsettings, threads):
conn.close()
- if netsettings.slave_clear:
+ if netsettings.use_slave_clear:
clearSlave(NODE_PREFIX)
if __name__ == "__main__":
diff --git a/release/scripts/io/netrender/ui.py b/release/scripts/io/netrender/ui.py
index f8b29fdd326..c2d943f63f8 100644
--- a/release/scripts/io/netrender/ui.py
+++ b/release/scripts/io/netrender/ui.py
@@ -36,9 +36,14 @@ DISPATCHED = 1
DONE = 2
ERROR = 3
+def base_poll(cls, context):
+ rd = context.scene.render
+ return (rd.use_game_engine==False) and (rd.engine in cls.COMPAT_ENGINES)
+
+
def init_file():
- if netrender.init_file != bpy.data.filename:
- netrender.init_file = bpy.data.filename
+ if netrender.init_file != bpy.data.filepath:
+ netrender.init_file = bpy.data.filepath
netrender.init_data = True
netrender.init_address = True
@@ -76,22 +81,26 @@ def verify_address(netsettings):
else:
netsettings.server_address = "[default]"
-class RenderButtonsPanel(bpy.types.Panel):
+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
-
- def poll(self, context):
+
+ @classmethod
+ def poll(cls, context):
rd = context.scene.render
- return (rd.use_game_engine==False) and (rd.engine in self.COMPAT_ENGINES)
+ return (rd.use_game_engine==False) and (rd.engine in cls.COMPAT_ENGINES)
# Setting panel, use in the scene for now.
-@rnaType
-class RENDER_PT_network_settings(RenderButtonsPanel):
+class RENDER_PT_network_settings(bpy.types.Panel, RenderButtonsPanel):
bl_label = "Network Settings"
COMPAT_ENGINES = {'NET_RENDER'}
+ @classmethod
+ def poll(cls, context):
+ return super(RENDER_PT_network_settings, cls).poll(context)
+
def draw(self, context):
layout = self.layout
@@ -122,15 +131,14 @@ class RENDER_PT_network_settings(RenderButtonsPanel):
layout.operator("render.netclientweb", icon='QUESTION')
-@rnaType
-class RENDER_PT_network_slave_settings(RenderButtonsPanel):
+class RENDER_PT_network_slave_settings(bpy.types.Panel, RenderButtonsPanel):
bl_label = "Slave Settings"
COMPAT_ENGINES = {'NET_RENDER'}
- def poll(self, context):
+ @classmethod
+ def poll(cls, context):
scene = context.scene
- return (super().poll(context)
- and scene.network_render.mode == "RENDER_SLAVE")
+ return super(RENDER_PT_network_slave_settings, cls).poll(context) and scene.network_render.mode == "RENDER_SLAVE"
def draw(self, context):
layout = self.layout
@@ -139,22 +147,23 @@ class RENDER_PT_network_slave_settings(RenderButtonsPanel):
rd = scene.render
netsettings = scene.network_render
- layout.prop(netsettings, "slave_clear")
- layout.prop(netsettings, "slave_thumb")
+ layout.prop(netsettings, "use_slave_clear")
+ layout.prop(netsettings, "use_slave_thumb")
+ layout.prop(netsettings, "use_slave_output_log")
layout.label(text="Threads:")
layout.prop(rd, "threads_mode", expand=True)
sub = layout.column()
sub.enabled = rd.threads_mode == 'FIXED'
sub.prop(rd, "threads")
-@rnaType
-class RENDER_PT_network_master_settings(RenderButtonsPanel):
+
+class RENDER_PT_network_master_settings(bpy.types.Panel, RenderButtonsPanel):
bl_label = "Master Settings"
COMPAT_ENGINES = {'NET_RENDER'}
- def poll(self, context):
+ @classmethod
+ def poll(cls, context):
scene = context.scene
- return (super().poll(context)
- and scene.network_render.mode == "RENDER_MASTER")
+ return super(RENDER_PT_network_master_settings, cls).poll(context) and scene.network_render.mode == "RENDER_MASTER"
def draw(self, context):
layout = self.layout
@@ -162,18 +171,17 @@ class RENDER_PT_network_master_settings(RenderButtonsPanel):
scene = context.scene
netsettings = scene.network_render
- layout.prop(netsettings, "master_broadcast")
- layout.prop(netsettings, "master_clear")
+ layout.prop(netsettings, "use_master_broadcast")
+ layout.prop(netsettings, "use_master_clear")
-@rnaType
-class RENDER_PT_network_job(RenderButtonsPanel):
+class RENDER_PT_network_job(bpy.types.Panel, RenderButtonsPanel):
bl_label = "Job Settings"
COMPAT_ENGINES = {'NET_RENDER'}
- def poll(self, context):
+ @classmethod
+ def poll(cls, context):
scene = context.scene
- return (super().poll(context)
- and scene.network_render.mode == "RENDER_CLIENT")
+ return super(RENDER_PT_network_job, cls).poll(context) and scene.network_render.mode == "RENDER_CLIENT"
def draw(self, context):
layout = self.layout
@@ -186,6 +194,7 @@ class RENDER_PT_network_job(RenderButtonsPanel):
if netsettings.server_address != "[default]":
layout.operator("render.netclientanim", icon='RENDER_ANIMATION')
layout.operator("render.netclientsend", icon='FILE_BLEND')
+ layout.operator("render.netclientsendframe", icon='RENDER_STILL')
if netsettings.job_id:
row = layout.row()
row.operator("render.render", text="Get Image", icon='RENDER_STILL')
@@ -205,18 +214,18 @@ class RENDER_PT_network_job(RenderButtonsPanel):
row.prop(netsettings, "priority")
row.prop(netsettings, "chunks")
-@rnaType
-class RENDER_PT_network_slaves(RenderButtonsPanel):
+class RENDER_PT_network_slaves(bpy.types.Panel, RenderButtonsPanel):
bl_label = "Slaves Status"
COMPAT_ENGINES = {'NET_RENDER'}
- def poll(self, context):
+ @classmethod
+ def poll(cls, context):
scene = context.scene
netsettings = scene.network_render
+ if netsettings.mode != "RENDER_CLIENT":
+ return False
verify_address(netsettings)
- return (super().poll(context)
- and netsettings.mode == "RENDER_CLIENT"
- and netsettings.server_address != "[default]")
+ return super(RENDER_PT_network_slaves, cls).poll(context) and netsettings.server_address != "[default]"
def draw(self, context):
layout = self.layout
@@ -243,18 +252,18 @@ class RENDER_PT_network_slaves(RenderButtonsPanel):
layout.label(text="Seen: " + time.ctime(slave.last_seen))
layout.label(text="Stats: " + slave.stats)
-@rnaType
-class RENDER_PT_network_slaves_blacklist(RenderButtonsPanel):
+class RENDER_PT_network_slaves_blacklist(bpy.types.Panel, RenderButtonsPanel):
bl_label = "Slaves Blacklist"
COMPAT_ENGINES = {'NET_RENDER'}
- def poll(self, context):
+ @classmethod
+ def poll(cls, context):
scene = context.scene
netsettings = scene.network_render
+ if netsettings.mode != "RENDER_CLIENT":
+ return False
verify_address(netsettings)
- return (super().poll(context)
- and netsettings.mode == "RENDER_CLIENT"
- and netsettings.server_address != "[default]")
+ return super(RENDER_PT_network_slaves_blacklist, cls).poll(context) and netsettings.server_address != "[default]"
def draw(self, context):
layout = self.layout
@@ -280,18 +289,18 @@ class RENDER_PT_network_slaves_blacklist(RenderButtonsPanel):
layout.label(text="Seen: " + time.ctime(slave.last_seen))
layout.label(text="Stats: " + slave.stats)
-@rnaType
-class RENDER_PT_network_jobs(RenderButtonsPanel):
+class RENDER_PT_network_jobs(bpy.types.Panel, RenderButtonsPanel):
bl_label = "Jobs"
COMPAT_ENGINES = {'NET_RENDER'}
- def poll(self, context):
+ @classmethod
+ def poll(cls, context):
scene = context.scene
netsettings = scene.network_render
+ if netsettings.mode != "RENDER_CLIENT":
+ return False
verify_address(netsettings)
- return (super().poll(context)
- and netsettings.mode == "RENDER_CLIENT"
- and netsettings.server_address != "[default]")
+ return super(RENDER_PT_network_jobs, cls).poll(context) and netsettings.server_address != "[default]"
def draw(self, context):
layout = self.layout
@@ -320,145 +329,148 @@ class RENDER_PT_network_jobs(RenderButtonsPanel):
layout.label(text="Done: %04i" % job.results[DONE])
layout.label(text="Error: %04i" % job.results[ERROR])
-@rnaType
class NetRenderSettings(bpy.types.IDPropertyGroup):
pass
-@rnaType
class NetRenderSlave(bpy.types.IDPropertyGroup):
pass
-@rnaType
class NetRenderJob(bpy.types.IDPropertyGroup):
pass
-bpy.types.Scene.PointerProperty(attr="network_render", type=NetRenderSettings, name="Network Render", description="Network Render Settings")
-
-NetRenderSettings.StringProperty( attr="server_address",
- name="Server address",
- description="IP or name of the master render server",
- maxlen = 128,
- default = "[default]")
-
-NetRenderSettings.IntProperty( attr="server_port",
- name="Server port",
- description="port of the master render server",
- default = 8000,
- min=1,
- max=65535)
-
-NetRenderSettings.BoolProperty( attr="master_broadcast",
- name="Broadcast",
- description="broadcast master server address on local network",
- default = True)
-
-NetRenderSettings.BoolProperty( attr="slave_clear",
- name="Clear on exit",
- description="delete downloaded files on exit",
- default = True)
-
-NetRenderSettings.BoolProperty( attr="slave_thumb",
- name="Generate thumbnails",
- description="Generate thumbnails on slaves instead of master",
- default = False)
-
-NetRenderSettings.BoolProperty( attr="master_clear",
- name="Clear on exit",
- description="delete saved files on exit",
- default = False)
-
-default_path = os.environ.get("TEMP")
-
-if not default_path:
- if os.name == 'nt':
- default_path = "c:/tmp/"
- else:
- default_path = "/tmp/"
-elif not default_path.endswith(os.sep):
- default_path += os.sep
-
-NetRenderSettings.StringProperty( attr="path",
- name="Path",
- description="Path for temporary files",
- maxlen = 128,
- default = default_path,
- subtype='FILE_PATH')
-
-NetRenderSettings.StringProperty( attr="job_name",
- name="Job name",
- description="Name of the job",
- maxlen = 128,
- default = "[default]")
-
-NetRenderSettings.StringProperty( attr="job_category",
- name="Job category",
- description="Category of the job",
- maxlen = 128,
- default = "")
-
-NetRenderSettings.IntProperty( attr="chunks",
- name="Chunks",
- description="Number of frame to dispatch to each slave in one chunk",
- default = 5,
- min=1,
- max=65535)
-
-NetRenderSettings.IntProperty( attr="priority",
- name="Priority",
- description="Priority of the job",
- default = 1,
- min=1,
- max=10)
-
-NetRenderSettings.StringProperty( attr="job_id",
- name="Network job id",
- description="id of the last sent render job",
- maxlen = 64,
- default = "")
-
-NetRenderSettings.IntProperty( attr="active_slave_index",
- name="Index of the active slave",
- description="",
- default = -1,
- min= -1,
- max=65535)
-
-NetRenderSettings.IntProperty( attr="active_blacklisted_slave_index",
- name="Index of the active slave",
- description="",
- default = -1,
- min= -1,
- max=65535)
-
-NetRenderSettings.IntProperty( attr="active_job_index",
- name="Index of the active job",
- description="",
- default = -1,
- min= -1,
- max=65535)
-
-NetRenderSettings.EnumProperty(attr="mode",
- items=(
- ("RENDER_CLIENT", "Client", "Act as render client"),
- ("RENDER_MASTER", "Master", "Act as render master"),
- ("RENDER_SLAVE", "Slave", "Act as render slave"),
- ),
- name="Network mode",
- description="Mode of operation of this instance",
- default="RENDER_CLIENT")
-
-NetRenderSettings.CollectionProperty(attr="slaves", type=NetRenderSlave, name="Slaves", description="")
-NetRenderSettings.CollectionProperty(attr="slaves_blacklist", type=NetRenderSlave, name="Slaves Blacklist", description="")
-NetRenderSettings.CollectionProperty(attr="jobs", type=NetRenderJob, name="Job List", description="")
-
-NetRenderSlave.StringProperty( attr="name",
- name="Name of the slave",
- description="",
- maxlen = 64,
- default = "")
-
-NetRenderJob.StringProperty( attr="name",
- name="Name of the job",
- description="",
- maxlen = 128,
- default = "")
+def addProperties():
+ bpy.types.Scene.PointerProperty(attr="network_render", type=NetRenderSettings, name="Network Render", description="Network Render Settings")
+
+ NetRenderSettings.StringProperty( attr="server_address",
+ name="Server address",
+ description="IP or name of the master render server",
+ maxlen = 128,
+ default = "[default]")
+
+ NetRenderSettings.IntProperty( attr="server_port",
+ name="Server port",
+ description="port of the master render server",
+ default = 8000,
+ min=1,
+ max=65535)
+
+ NetRenderSettings.BoolProperty( attr="use_master_broadcast",
+ name="Broadcast",
+ description="broadcast master server address on local network",
+ default = True)
+
+ NetRenderSettings.BoolProperty( attr="use_slave_clear",
+ name="Clear on exit",
+ description="delete downloaded files on exit",
+ default = True)
+
+ NetRenderSettings.BoolProperty( attr="use_slave_thumb",
+ name="Generate thumbnails",
+ description="Generate thumbnails on slaves instead of master",
+ default = False)
+
+ NetRenderSettings.BoolProperty( attr="use_slave_output_log",
+ name="Output render log on console",
+ description="Output render text log to console as well as sending it to the master",
+ default = True)
+
+ NetRenderSettings.BoolProperty( attr="use_master_clear",
+ name="Clear on exit",
+ description="delete saved files on exit",
+ default = False)
+
+ default_path = os.environ.get("TEMP")
+
+ if not default_path:
+ if os.name == 'nt':
+ default_path = "c:/tmp/"
+ else:
+ default_path = "/tmp/"
+ elif not default_path.endswith(os.sep):
+ default_path += os.sep
+
+ NetRenderSettings.StringProperty( attr="path",
+ name="Path",
+ description="Path for temporary files",
+ maxlen = 128,
+ default = default_path,
+ subtype='FILE_PATH')
+
+ NetRenderSettings.StringProperty( attr="job_name",
+ name="Job name",
+ description="Name of the job",
+ maxlen = 128,
+ default = "[default]")
+
+ NetRenderSettings.StringProperty( attr="job_category",
+ name="Job category",
+ description="Category of the job",
+ maxlen = 128,
+ default = "")
+
+ NetRenderSettings.IntProperty( attr="chunks",
+ name="Chunks",
+ description="Number of frame to dispatch to each slave in one chunk",
+ default = 5,
+ min=1,
+ max=65535)
+
+ NetRenderSettings.IntProperty( attr="priority",
+ name="Priority",
+ description="Priority of the job",
+ default = 1,
+ min=1,
+ max=10)
+
+ NetRenderSettings.StringProperty( attr="job_id",
+ name="Network job id",
+ description="id of the last sent render job",
+ maxlen = 64,
+ default = "")
+
+ NetRenderSettings.IntProperty( attr="active_slave_index",
+ name="Index of the active slave",
+ description="",
+ default = -1,
+ min= -1,
+ max=65535)
+
+ NetRenderSettings.IntProperty( attr="active_blacklisted_slave_index",
+ name="Index of the active slave",
+ description="",
+ default = -1,
+ min= -1,
+ max=65535)
+
+ NetRenderSettings.IntProperty( attr="active_job_index",
+ name="Index of the active job",
+ description="",
+ default = -1,
+ min= -1,
+ max=65535)
+
+ NetRenderSettings.EnumProperty(attr="mode",
+ items=(
+ ("RENDER_CLIENT", "Client", "Act as render client"),
+ ("RENDER_MASTER", "Master", "Act as render master"),
+ ("RENDER_SLAVE", "Slave", "Act as render slave"),
+ ),
+ name="Network mode",
+ description="Mode of operation of this instance",
+ default="RENDER_CLIENT")
+
+ NetRenderSettings.CollectionProperty(attr="slaves", type=NetRenderSlave, name="Slaves", description="")
+ NetRenderSettings.CollectionProperty(attr="slaves_blacklist", type=NetRenderSlave, name="Slaves Blacklist", description="")
+ NetRenderSettings.CollectionProperty(attr="jobs", type=NetRenderJob, name="Job List", description="")
+
+ NetRenderSlave.StringProperty( attr="name",
+ name="Name of the slave",
+ description="",
+ maxlen = 64,
+ default = "")
+
+ NetRenderJob.StringProperty( attr="name",
+ name="Name of the job",
+ description="",
+ maxlen = 128,
+ default = "")
diff --git a/release/scripts/io/netrender/utils.py b/release/scripts/io/netrender/utils.py
index 37787732f09..81617ac0d30 100644
--- a/release/scripts/io/netrender/utils.py
+++ b/release/scripts/io/netrender/utils.py
@@ -19,7 +19,7 @@
import sys, os
import re
import http, http.client, http.server, urllib, socket
-import subprocess, shutil, time, hashlib
+import subprocess, shutil, time, hashlib, zlib
import netrender.model
@@ -28,7 +28,7 @@ try:
except:
bpy = None
-VERSION = bytes("0.8", encoding='utf8')
+VERSION = bytes("0.9", encoding='utf8')
# Jobs status
JOB_WAITING = 0 # before all data has been entered
@@ -57,9 +57,10 @@ FRAME_STATUS_TEXT = {
ERROR: "Error"
}
-def rnaType(rna_type):
- if bpy: bpy.types.register(rna_type)
- return rna_type
+def responseStatus(conn):
+ response = conn.getresponse()
+ response.read()
+ return response.status
def reporting(report, message, errorType = None):
if errorType:
@@ -154,22 +155,37 @@ def renderURL(job_id, frame_number):
def cancelURL(job_id):
return "/cancel_%s" % (job_id)
-def prefixPath(prefix_directory, file_path, prefix_path):
+def hashFile(path):
+ f = open(path, "rb")
+ value = hashData(f.read())
+ f.close()
+ return value
+
+def hashData(data):
+ m = hashlib.md5()
+ m.update(data)
+ return m.hexdigest()
+
+
+def prefixPath(prefix_directory, file_path, prefix_path, force = False):
if os.path.isabs(file_path):
# if an absolute path, make sure path exists, if it doesn't, use relative local path
full_path = file_path
- if not os.path.exists(full_path):
- p, n = os.path.split(full_path)
+ if force or not os.path.exists(full_path):
+ p, n = os.path.split(os.path.normpath(full_path))
if prefix_path and p.startswith(prefix_path):
- directory = prefix_directory + p[len(prefix_path):]
- full_path = directory + os.sep + n
- if not os.path.exists(directory):
- os.mkdir(directory)
+ if len(prefix_path) < len(p):
+ directory = os.path.join(prefix_directory, p[len(prefix_path)+1:]) # +1 to remove separator
+ if not os.path.exists(directory):
+ os.mkdir(directory)
+ else:
+ directory = prefix_directory
+ full_path = os.path.join(directory, n)
else:
- full_path = prefix_directory + n
+ full_path = os.path.join(prefix_directory, n)
else:
- full_path = prefix_directory + file_path
+ full_path = (prefix_directory, file_path)
return full_path
@@ -200,7 +216,7 @@ def thumbnail(filename):
scene = bpy.data.scenes[0] # FIXME, this is dodgy!
scene.render.file_format = "JPEG"
scene.render.file_quality = 90
- bpy.ops.image.open(path = filename)
+ bpy.ops.image.open(filepath=filename)
img = bpy.data.images[imagename]
img.save_render(thumbname, scene=scene)