diff options
Diffstat (limited to 'release/scripts/io')
20 files changed, 923 insertions, 2046 deletions
diff --git a/release/scripts/io/engine_render_pov.py b/release/scripts/io/engine_render_pov.py deleted file mode 100644 index 9cda4375ecc..00000000000 --- a/release/scripts/io/engine_render_pov.py +++ /dev/null @@ -1,1001 +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_world - - # compute resolution - Qsize = float(render.resolution_x) / float(render.resolution_y) - - file.write('camera {\n') - file.write('\tlocation <0, 0, 0>\n') - file.write('\tlook_at <0, 0, -1>\n') - file.write('\tright <%s, 0, 0>\n' % - Qsize) - file.write('\tup <0, 1, 0>\n') - file.write('\tangle %f \n' % (360.0 * 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_world - - color = tuple([c * lamp.energy for c in lamp.color]) # Colour is modified by energy - - file.write('light_source {\n') - file.write('\t< 0,0,0 >\n') - file.write('\tcolor rgb<%.3g, %.3g, %.3g>\n' % color) - - if lamp.type == 'POINT': # Point Lamp - pass - elif lamp.type == 'SPOT': # Spot - file.write('\tspotlight\n') - - # Falloff is the main radius from the centre line - file.write('\tfalloff %.2f\n' % (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_world) - - file.write('}\n') - - def exportMeshs(scene, sel): - - ob_num = 0 - - for ob in sel: - ob_num += 1 - - if ob.type in ('LAMP', 'CAMERA', 'EMPTY', 'META', 'ARMATURE'): - continue - - me = ob.data - me_materials = me.materials - - me = ob.create_mesh(scene, 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_world - 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.use_mist: - file.write('fog {\n') - file.write('\tdistance %.6f\n' % mist.depth) - file.write('\tcolor rgbt<%.3g, %.3g, %.3g, %.3g>\n' % (tuple(world.horizon_color) + (1 - mist.intensity,))) - #file.write('\tfog_offset %.6f\n' % mist.start) - #file.write('\tfog_alt 5\n') - #file.write('\tturbulence 0.2\n') - #file.write('\tturb_depth 0.3\n') - file.write('\tfog_type 1\n') - file.write('}\n') - - def exportGlobalSettings(scene): - - file.write('global_settings {\n') - - if scene.pov_radio_enable: - file.write('\tradiosity {\n') - file.write("\t\tadc_bailout %.4g\n" % scene.pov_radio_adc_bailout) - file.write("\t\talways_sample %d\n" % scene.pov_radio_always_sample) - file.write("\t\tbrightness %.4g\n" % scene.pov_radio_brightness) - file.write("\t\tcount %d\n" % scene.pov_radio_count) - file.write("\t\terror_bound %.4g\n" % scene.pov_radio_error_bound) - file.write("\t\tgray_threshold %.4g\n" % scene.pov_radio_gray_threshold) - file.write("\t\tlow_error_factor %.4g\n" % scene.pov_radio_low_error_factor) - file.write("\t\tmedia %d\n" % scene.pov_radio_media) - file.write("\t\tminimum_reuse %.4g\n" % scene.pov_radio_minimum_reuse) - file.write("\t\tnearest_count %d\n" % scene.pov_radio_nearest_count) - file.write("\t\tnormal %d\n" % scene.pov_radio_normal) - file.write("\t\trecursion_limit %d\n" % scene.pov_radio_recursion_limit) - file.write('\t}\n') - - if world: - file.write("\tambient_light rgb<%.3g, %.3g, %.3g>\n" % tuple(world.ambient_color)) - - file.write('}\n') - - - # Convert all materials to strings we can access directly per vertex. - writeMaterial(None) # default material - - for material in bpy.data.materials: - writeMaterial(material) - - exportCamera() - #exportMaterials() - sel = scene.objects - exportLamps([l for l in sel if l.type == 'LAMP']) - exportMeta([l for l in sel if l.type == 'META']) - exportMeshs(scene, sel) - exportWorld(scene.world) - exportGlobalSettings(scene) - - file.close() - - -def write_pov_ini(filename_ini, filename_pov, filename_image): - scene = bpy.data.scenes[0] - render = scene.render - - x = int(render.resolution_x * render.resolution_percentage * 0.01) - y = int(render.resolution_y * render.resolution_percentage * 0.01) - - file = open(filename_ini, 'w') - - file.write('Input_File_Name="%s"\n' % filename_pov) - file.write('Output_File_Name="%s"\n' % filename_image) - - file.write('Width=%d\n' % x) - file.write('Height=%d\n' % y) - - # Needed for border render. - ''' - file.write('Start_Column=%d\n' % part.x) - file.write('End_Column=%d\n' % (part.x+part.w)) - - file.write('Start_Row=%d\n' % (part.y)) - file.write('End_Row=%d\n' % (part.y+part.h)) - ''' - - file.write('Display=0\n') - file.write('Pause_When_Done=0\n') - file.write('Output_File_Type=T\n') # TGA, best progressive loading - file.write('Output_Alpha=1\n') - - if render.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 - try: - self._process = subprocess.Popen([pov_binary, self._temp_file_ini]) # stdout=subprocess.PIPE, stderr=subprocess.PIPE - except OSError: - # TODO, report api - print("POVRAY: could not execute '%s', possibly povray isn't installed" % pov_binary) - import traceback - traceback.print_exc() - print ("***-DONE-***") - return False - - else: - # This works too but means we have to wait until its done - os.system('%s %s' % (pov_binary, self._temp_file_ini)) - - print ("***-DONE-***") - return True - - def _cleanup(self): - for f in (self._temp_file_in, self._temp_file_ini, self._temp_file_out): - try: - os.remove(f) - except: - pass - - self.update_stats("", "") - - def render(self, scene): - - self.update_stats("", "POVRAY: Exporting data from Blender") - self._export(scene) - self.update_stats("", "POVRAY: Parsing File") - - if not self._render(): - self.update_stats("", "POVRAY: Not found") - return - - r = scene.render - - # compute resolution - x = int(r.resolution_x * r.resolution_percentage * 0.01) - y = int(r.resolution_y * r.resolution_percentage * 0.01) - - # Wait for the file to be created - while not os.path.exists(self._temp_file_out): - if self.test_break(): - try: - self._process.terminate() - except: - pass - break - - if self._process.poll() != None: - self.update_stats("", "POVRAY: Failed") - break - - time.sleep(self.DELAY) - - if os.path.exists(self._temp_file_out): - - self.update_stats("", "POVRAY: Rendering") - - prev_size = -1 - - def update_image(): - result = self.begin_result(0, 0, x, y) - lay = result.layers[0] - # possible the image wont load early on. - try: - lay.load_from_file(self._temp_file_out) - except: - pass - self.end_result(result) - - # Update while povray renders - while True: - - # test if povray exists - if self._process.poll() is not None: - update_image() - break - - # user exit - if self.test_break(): - try: - self._process.terminate() - except: - pass - - break - - # Would be nice to redirect the output - # stdout_value, stderr_value = self._process.communicate() # locks - - - # check if the file updated - new_size = os.path.getsize(self._temp_file_out) - - if new_size != prev_size: - update_image() - prev_size = new_size - - time.sleep(self.DELAY) - - self._cleanup() - - -# Use some of the existing buttons. -import properties_render -properties_render.RENDER_PT_render.COMPAT_ENGINES.add('POVRAY_RENDER') -properties_render.RENDER_PT_dimensions.COMPAT_ENGINES.add('POVRAY_RENDER') -properties_render.RENDER_PT_antialiasing.COMPAT_ENGINES.add('POVRAY_RENDER') -properties_render.RENDER_PT_output.COMPAT_ENGINES.add('POVRAY_RENDER') -del properties_render - -# Use only a subset of the world panels -import properties_world -properties_world.WORLD_PT_preview.COMPAT_ENGINES.add('POVRAY_RENDER') -properties_world.WORLD_PT_context_world.COMPAT_ENGINES.add('POVRAY_RENDER') -properties_world.WORLD_PT_world.COMPAT_ENGINES.add('POVRAY_RENDER') -properties_world.WORLD_PT_mist.COMPAT_ENGINES.add('POVRAY_RENDER') -del properties_world - -# Example of wrapping every class 'as is' -import properties_material -for member in dir(properties_material): - subclass = getattr(properties_material, member) - try: - subclass.COMPAT_ENGINES.add('POVRAY_RENDER') - except: - pass -del properties_material -import properties_data_mesh -for member in dir(properties_data_mesh): - subclass = getattr(properties_data_mesh, member) - try: - subclass.COMPAT_ENGINES.add('POVRAY_RENDER') - except: - pass -del properties_data_mesh -import properties_texture -for member in dir(properties_texture): - subclass = getattr(properties_texture, member) - try: - subclass.COMPAT_ENGINES.add('POVRAY_RENDER') - except: - pass -del properties_texture -import properties_data_camera -for member in dir(properties_data_camera): - subclass = getattr(properties_data_camera, member) - try: - subclass.COMPAT_ENGINES.add('POVRAY_RENDER') - except: - pass -del properties_data_camera - - -class RenderButtonsPanel(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 4fd889c75c6..4a5521bd9e9 100644 --- a/release/scripts/io/export_3ds.py +++ b/release/scripts/io/export_3ds.py @@ -564,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 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 @@ -761,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: @@ -922,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 @@ -941,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) @@ -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,50 +1107,46 @@ 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. - - 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.filepath, 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 = os.path.splitext(bpy.data.filepath)[0] + ".3ds" - self.layout.operator(Export3DS.bl_idname, text="3D Studio (.3ds)").filepath = 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__": diff --git a/release/scripts/io/export_fbx.py b/release/scripts/io/export_fbx.py index 4505b56b41c..60e9e90e11b 100644 --- a/release/scripts/io/export_fbx.py +++ b/release/scripts/io/export_fbx.py @@ -55,7 +55,7 @@ import math # math.pi import shutil # for file copying import bpy -from mathutils import Vector, Euler, Matrix, RotationMatrix +from mathutils import Vector, Euler, Matrix def copy_file(source, dest): # XXX - remove, can use shutil @@ -75,7 +75,7 @@ def copy_images(dest_dir, textures): image_paths = set() for tex in textures: - image_paths.add(bpy.utils.expandpath(tex.filepath)) + image_paths.add(bpy.path.abspath(tex.filepath)) # Now copy images copyCount = 0 @@ -83,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) @@ -107,19 +107,19 @@ def eulerRadToDeg(eul): mtx4_identity = Matrix() # testing -mtx_x90 = 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 = RotationMatrix(-math.pi/2, 4, 'X') # used -#mtx4_y90 = RotationMatrix( 90, 4, 'y') -mtx4_y90n = RotationMatrix(-math.pi/2, 4, 'Y') # used -mtx4_z90 = RotationMatrix( math.pi/2, 4, 'Z') # used -mtx4_z90n = 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] @@ -176,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) @@ -200,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 @@ -221,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)) @@ -243,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 @@ -305,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: @@ -353,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: @@ -391,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, @@ -561,7 +562,7 @@ def write(filename, batch_objects = None, \ elif type =='CAMERA': # elif ob and type =='Camera': y = matrix_rot * Vector((0.0, 1.0, 0.0)) - matrix_rot = RotationMatrix(math.pi/2, 3, y) * matrix_rot + matrix_rot = Matrix.Rotation(math.pi/2, 3, y) * matrix_rot return matrix_rot @@ -663,7 +664,7 @@ def write(filename, batch_objects = None, \ rot = tuple(matrix_rot.to_euler()) elif ob and ob.type =='Camera': y = matrix_rot * Vector((0.0, 1.0, 0.0)) - matrix_rot = RotationMatrix(math.pi/2, 3, y) * matrix_rot + matrix_rot = Matrix.Rotation(math.pi/2, 3, y) * matrix_rot rot = tuple(matrix_rot.to_euler()) else: rot = tuple(matrix_rot.to_euler()) @@ -947,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 @@ -962,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') @@ -975,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) @@ -1086,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: @@ -1194,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' @@ -1254,7 +1250,7 @@ def write(filename, batch_objects = None, \ file.write('\n\t}') def copy_image(image): - fn = bpy.utils.expandpath(image.filepath) + fn = bpy.path.abspath(image.filepath) fn_strip = os.path.basename(fn) if EXP_IMAGE_COPY: @@ -1331,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(''' @@ -1402,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 = [] @@ -1491,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: @@ -1503,7 +1499,7 @@ def write(filename, batch_objects = None, \ file.write('\n\t\tPolygonVertexIndex: ') i=-1 for f in me.faces: - fi = f.verts[:] + fi = f.vertices[:] # last index XORd w. -1 indicates end of face fi[-1] = fi[-1] ^ -1 @@ -1523,8 +1519,8 @@ def write(filename, batch_objects = None, \ # write loose edges as faces. for ed in me.edges: - if ed.loose: - ed_val = ed.verts[:] + if ed.is_loose: + ed_val = ed.vertices[:] ed_val = ed_val[0], ed_val[-1] ^ -1 if i==-1: @@ -1542,14 +1538,14 @@ def write(filename, batch_objects = None, \ 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 @@ -1564,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 @@ -1588,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}') @@ -1606,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] @@ -2076,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) @@ -2763,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)) @@ -2782,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) @@ -2918,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') @@ -2940,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}') @@ -2964,7 +2957,7 @@ 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: @@ -3037,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 @@ -3364,20 +3357,24 @@ 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.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 if self.properties.TX_XROT90: GLOBAL_MATRIX = mtx4_x90n * GLOBAL_MATRIX 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.filepath, + write(filepath, None, # XXX context, self.properties.EXP_OBS_SELECTED, @@ -3397,13 +3394,17 @@ 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'} @@ -3415,7 +3416,7 @@ class ExportFBX(bpy.types.Operator): # 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 @@ -3430,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 = os.path.splitext(bpy.data.filepath)[0] + ".fbx" - self.layout.operator(ExportFBX.bl_idname, text="Autodesk FBX (.fbx)").filepath = 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 d2e53070910..b2eda13fc8f 100644 --- a/release/scripts/io/export_mdd.py +++ b/release/scripts/io/export_mdd.py @@ -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) @@ -94,7 +94,7 @@ def write(filename, sce, ob, PREF_STARTFRAME, PREF_ENDFRAME, PREF_FPS): [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) @@ -114,7 +114,7 @@ def write(filename, sce, ob, PREF_STARTFRAME, PREF_ENDFRAME, PREF_FPS): check_vertcount(me, numverts) me.transform(mat_flip * ob.matrix_world) - 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])) for frame in range(PREF_STARTFRAME, PREF_ENDFRAME + 1):#in order to start at desired frame """ @@ -128,10 +128,10 @@ def write(filename, sce, ob, PREF_STARTFRAME, PREF_ENDFRAME, PREF_FPS): 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() @@ -165,36 +165,43 @@ class ExportMDD(bpy.types.Operator): 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.filepath: - raise Exception("filename not set") - write(self.properties.filepath, 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): - import os - default_path = os.path.splitext(bpy.data.filepath)[0] + ".mdd" - self.layout.operator(ExportMDD.bl_idname, text="Lightwave Point Cache (.mdd)").filepath = 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 626b92c3591..53c4a324ed1 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" @@ -49,16 +42,6 @@ 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:] - def fixName(name): if name == None: return 'None' @@ -73,7 +56,7 @@ def write_mtl(scene, filepath, copy_images, mtl_dict): dest_dir = os.path.dirname(filepath) def copy_image(image): - fn = bpy.utils.expandpath(image.filepath) + fn = bpy.path.abspath(image.filepath) fn_strip = os.path.basename(fn) if copy_images: rel = fn_strip @@ -88,7 +71,7 @@ def write_mtl(scene, filepath, copy_images, mtl_dict): file = open(filepath, "w") # XXX -# file.write('# Blender MTL File: %s\n' % Blender.Get('filepath').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, filepath, 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, filepath, 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,25 +103,25 @@ def write_mtl(scene, filepath, 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.filepath.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: filepath = copy_image(mtex.texture.image) -# filepath = mtex.texture.image.filepath.split('\\')[-1].split('/')[-1] +# filepath = mtex.texture.image.filepath.split('\\')[-1].split('/')[-1] file.write('map_Kd %s\n' % filepath) # Diffuse mapping image break except: @@ -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,20 +171,20 @@ def copy_images(dest_dir): # Now copy images copyCount = 0 -# for bImage in uniqueImages.values(): -# image_path = bpy.utils.expandpath(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 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) +# print('\tCopied %d images' % copyCount) # XXX not converted def test_nurbs_compat(ob): @@ -224,8 +207,8 @@ def write_nurb(file, ob, ob_mat): 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 + if nu.type==0: DEG_ORDER_U = 1 + else: DEG_ORDER_U = nu.orderU-1 # Tested to be correct if nu.type==1: print("\tWarning, bezier curve:", ob.name, "only poly and nurbs curves supported") @@ -282,7 +265,7 @@ def write_nurb(file, ob, ob_mat): return tot_verts -def write(filepath, objects, scene, +def write_file(filepath, objects, scene, EXPORT_TRI=False, EXPORT_EDGES=False, EXPORT_NORMALS=False, @@ -299,7 +282,7 @@ def write(filepath, 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 +308,10 @@ def write(filepath, 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 +326,7 @@ def write(filepath, 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)) @@ -355,8 +338,8 @@ def write(filepath, objects, scene, temp_mesh_name = '~tmp-mesh' time1 = time.clock() -# time1 = sys.time() -# scn = Scene.GetCurrent() +# time1 = sys.time() +# scn = Scene.GetCurrent() file = open(filepath, "w") @@ -370,7 +353,7 @@ def write(filepath, objects, scene, 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 @@ -408,15 +391,15 @@ def write(filepath, objects, scene, 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 +# # 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) +# totverts += write_nurb(file, ob, ob_mat) -# continue -# end nurbs +# continue +# end nurbs if ob.type != 'MESH': continue @@ -428,16 +411,19 @@ def write(filepath, objects, scene, 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.active_uv_texture.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 +432,7 @@ def write(filepath, 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 +454,7 @@ def write(filepath, 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 +465,13 @@ def write(filepath, 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 +496,24 @@ def write(filepath, 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 +534,17 @@ def write(filepath, 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.active_uv_texture.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 +552,16 @@ def write(filepath, 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 +581,66 @@ def write(filepath, 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 +684,21 @@ def write(filepath, 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 +708,25 @@ def write(filepath, 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 @@ -783,52 +742,52 @@ def write(filepath, objects, scene, # Now we have all our materials, save them if EXPORT_MTL: 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) +# 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(filepath, 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(filepath) + 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,17 +796,17 @@ def do_export(filepath, 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. @@ -856,30 +815,39 @@ def do_export(filepath, context, 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) ''' @@ -904,12 +872,12 @@ class ExportOBJ(bpy.types.Operator): 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 @@ -933,47 +901,47 @@ class ExportOBJ(bpy.types.Operator): def execute(self, context): filepath = self.properties.filepath - if not filepath.lower().endswith(".obj"): - filepath += ".obj" - - do_export(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) + 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 = os.path.splitext(bpy.data.filepath)[0] + ".obj" - self.layout.operator(ExportOBJ.bl_idname, text="Wavefront (.obj)").filepath = 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 +954,3 @@ def unregister(): if __name__ == "__main__": register() - diff --git a/release/scripts/io/export_ply.py b/release/scripts/io/export_ply.py index 0b936bdceb2..1a4fd7a6ff9 100644 --- a/release/scripts/io/export_ply.py +++ b/release/scripts/io/export_ply.py @@ -99,7 +99,8 @@ 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: @@ -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): @@ -274,16 +275,15 @@ class ExportPLY(bpy.types.Operator): 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.filepath: - raise Exception("filename not set") - - write(self.properties.filepath, 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,18 +313,14 @@ class ExportPLY(bpy.types.Operator): def menu_func(self, context): - import os - default_path = os.path.splitext(bpy.data.filepath)[0] + ".ply" - self.layout.operator(ExportPLY.bl_idname, text="Stanford (.ply)").filepath = 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 1bad80f6d8e..aafb7c922a1 100644 --- a/release/scripts/io/export_x3d.py +++ b/release/scripts/io/export_x3d.py @@ -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 @@ -406,13 +406,13 @@ class x3d_class: # if mesh.faceUV: for face in mesh.active_uv_texture.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 @@ -461,7 +461,7 @@ 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.faceUV: @@ -470,7 +470,7 @@ class x3d_class: 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) @@ -516,11 +516,11 @@ 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))) @@ -581,7 +581,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: @@ -604,7 +604,7 @@ class x3d_class: # 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) @@ -618,7 +618,7 @@ class x3d_class: # 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: @@ -699,7 +699,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 @@ -731,7 +731,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.blend_sky, world.paper_sky, world.use_sky_real) # blending = world.getSkytype() grd = world.horizon_color # grd = world.getHor() @@ -794,7 +794,7 @@ class x3d_class: pic = tex.image # using .expandpath just in case, os.path may not expect // - basename = os.path.basename(bpy.utils.expandpath(pic.filepath)) + basename = os.path.basename(bpy.path.abspath(pic.filepath)) pic = alltextures[i].image # pic = alltextures[i].getImage() @@ -912,7 +912,7 @@ class x3d_class: # if EXPORT_APPLY_MODIFIERS: # if containerMesh: - # containerMesh.verts = None + # containerMesh.vertices = None self.cleanup() @@ -964,13 +964,8 @@ class x3d_class: if mesh.active_uv_texture: # 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.faces + sidename = "two" if face.use_twoside else "one" if sidename in sided: sided[sidename]+=1 @@ -1003,8 +998,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 +1025,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 +1135,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 +1151,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,47 +1170,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 -######################################################### - - from bpy.props import * class ExportX3D(bpy.types.Operator): @@ -1232,26 +1187,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.filepath, 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 = os.path.splitext(bpy.data.filepath)[0] + ".x3d" - self.layout.operator(ExportX3D.bl_idname, text="X3D Extensible 3D (.x3d)").filepath = 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 diff --git a/release/scripts/io/import_anim_bvh.py b/release/scripts/io/import_anim_bvh.py index d497ac47065..04cae915a49 100644 --- a/release/scripts/io/import_anim_bvh.py +++ b/release/scripts/io/import_anim_bvh.py @@ -23,7 +23,7 @@ from math import radians import bpy import mathutils -from mathutils import Vector, Euler, Matrix, RotationMatrix, TranslationMatrix +from mathutils import Vector, Euler, Matrix class bvh_node_class(object): @@ -78,7 +78,7 @@ 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! @@ -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 @@ -529,7 +529,7 @@ def bvh_node_dict2armature(context, bvh_nodes, ROT_MODE='XYZ', IMPORT_START_FRAM 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") @@ -612,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 7b3004d4f52..6378d93df62 100644 --- a/release/scripts/io/import_scene_3ds.py +++ b/release/scripts/io/import_scene_3ds.py @@ -141,7 +141,7 @@ 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 @@ -312,10 +312,10 @@ def process_next_chunk(file, previous_chunk, importedObjects, IMAGE_SEARCH): contextMaterial = None contextMatrix_rot = None # Blender.mathutils.Matrix(); contextMatrix.identity() #contextMatrix_tx = None # Blender.mathutils.Matrix(); contextMatrix.identity() - contextMesh_vertls = None + 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,113 +333,69 @@ 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 = {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.add_geometry(len(myContextMesh_vertls)//3, 0, 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.add_uv_texture() + uv_faces = bmesh.active_uv_texture.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_world = 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: + bmesh.add_material(None) + else: + bmat = MATDICT[matName][1] + bmesh.add_material(bmat) # can be None + img = TEXTURE_DICT.get(bmat.name) + + 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() @@ -667,14 +623,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): @@ -684,15 +636,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):' @@ -703,12 +651,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 @@ -717,12 +664,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 @@ -771,7 +715,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() @@ -806,7 +750,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): @@ -883,14 +827,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.matrix_world.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 """ @@ -1009,15 +951,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= "") -# 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.filepath, 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): @@ -1030,11 +976,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 afe82410557..655f797750e 100644 --- a/release/scripts/io/import_scene_obj.py +++ b/release/scripts/io/import_scene_obj.py @@ -82,23 +82,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))) - - # rotate indices if the 4th is 0 - if len(face) == 4 and face[3] == 0: - face = [face[3], face[0], face[1], face[2]] + # allocate the entire list + flat_ls = [0] * (len(list_of_tuples) * 4) + i = 0 - if len(face) == 3: - face.append(0) - - l.extend(face) + 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] - return l + flat_ls[i:i + len(t)] = t + i += 4 + return flat_ls def BPyMesh_ngon(from_data, indices, PREF_FIX_LOOPS= True): ''' @@ -139,7 +137,7 @@ 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]: @@ -156,7 +154,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: @@ -305,24 +303,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): # ''' @@ -373,38 +375,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) @@ -413,15 +409,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 = 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 @@ -435,11 +430,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 @@ -504,49 +497,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 = 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. @@ -571,7 +547,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 @@ -581,12 +556,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 @@ -703,18 +677,18 @@ 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.vertices.extend([(0,0,0)]) # dummy vert me.add_geometry(len(verts_loc), 0, 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)) +# me.vertices.extend(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])) + me.faces.foreach_set("vertices_raw", unpack_face_list([f[0] for f in faces])) # face_mapping= me.faces.extend([f[0] for f in faces], indexList=True) if verts_tex and me.faces: @@ -752,7 +726,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: @@ -768,14 +742,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: @@ -804,7 +776,7 @@ def create_mesh(scn, new_objects, has_ngons, CREATE_FGONS, CREATE_EDGES, verts_l me.add_geometry(0, len(edges), 0) # 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 @@ -819,8 +791,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 @@ -833,8 +805,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 @@ -847,7 +819,6 @@ 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 @@ -861,7 +832,7 @@ def create_mesh(scn, new_objects, has_ngons, CREATE_FGONS, CREATE_EDGES, verts_l # me.assignVertsToGroup(group_name, group_indicies, 1.00, Mesh.AssignModes.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 ''' @@ -936,8 +907,9 @@ def create_nurbs(scn, context_nurbs, vert_loc, new_objects): if do_closed: nu.flagU |= 1 ''' + + ob= bpy.data.objects.new("Mesh", me) - ob = scn.objects.new(cu) new_objects.append(ob) @@ -1262,7 +1234,6 @@ def load_obj(filepath, # bpy.ops.OBJECT_OT_select_all() scene = context.scene -# scn = bpy.data.scenes.active # scn.objects.selected = [] new_objects= [] # put new objects here @@ -1271,14 +1242,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) + # Create new obj + for obj in new_objects: + scene.objects.link(obj) + + scene.update() + axis_min= [ 1000000000]*3 axis_max= [-1000000000]*3 @@ -1320,14 +1297,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) @@ -1346,7 +1322,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)'),\ @@ -1359,7 +1334,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 ''' @@ -1381,25 +1355,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] @@ -1419,7 +1393,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() @@ -1432,7 +1406,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 @@ -1492,7 +1465,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 @@ -1506,7 +1478,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 @@ -1570,7 +1541,6 @@ class IMPORT_OT_obj(bpy.types.Operator): 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) @@ -1591,7 +1561,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) @@ -1599,8 +1568,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'} @@ -1609,11 +1577,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) diff --git a/release/scripts/io/import_shape_mdd.py b/release/scripts/io/import_shape_mdd.py index ec0e7696630..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 @@ -120,7 +120,8 @@ class importMDD(bpy.types.Operator): #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') @@ -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 f5f104d6d92..5a705e95aa8 100644 --- a/release/scripts/io/netrender/__init__.py +++ b/release/scripts/io/netrender/__init__.py @@ -18,16 +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 -from netrender import repath +# 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 = [] @@ -38,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 9f6d1a7639e..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 @@ -113,7 +113,7 @@ def clientSendJob(conn, scene, anim = False): # LIBRARIES ########################### for lib in bpy.data.libraries: - file_path = bpy.utils.expandpath(lib.filepath) + file_path = bpy.path.abspath(lib.filepath) if os.path.exists(file_path): job.addFile(file_path) @@ -122,7 +122,7 @@ 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.filepath) + file_path = bpy.path.abspath(image.filepath) if os.path.exists(file_path): job.addFile(file_path) @@ -139,17 +139,17 @@ 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.external: - file_path = bpy.utils.expandpath(modifier.filepath) + 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 @@ -171,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") @@ -181,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 @@ -189,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" @@ -209,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): @@ -237,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 @@ -245,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 @@ -266,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: @@ -276,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() diff --git a/release/scripts/io/netrender/master.py b/release/scripts/io/netrender/master.py index f227f61a536..6deb925420b 100644 --- a/release/scripts/io/netrender/master.py +++ b/release/scripts/io/netrender/master.py @@ -89,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() @@ -134,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] @@ -260,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") @@ -294,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) @@ -716,7 +716,7 @@ 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) @@ -772,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() @@ -822,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 @@ -880,7 +879,7 @@ class RenderMasterServer(socketserver.ThreadingMixIn, http.server.HTTPServer): self.job_id = 0 if subdir: - self.path = path + "master_" + str(os.getpid()) + os.sep + self.path = os.path.join(path, "master_" + str(os.getpid())) else: self.path = path @@ -1007,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) diff --git a/release/scripts/io/netrender/master_html.py b/release/scripts/io/netrender/master_html.py index c3695cd4f0f..74155f6bd66 100644 --- a/release/scripts/io/netrender/master_html.py +++ b/release/scripts/io/netrender/master_html.py @@ -27,9 +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>") - output("<meta http-equiv='refresh' content=5>") + 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>") @@ -104,7 +105,7 @@ def get(handler): f.close() elif handler.path == "/html" or handler.path == "/": handler.send_head(content = "text/html") - head("NetRender") + head("NetRender", refresh = True) output("<h2>Jobs</h2>") diff --git a/release/scripts/io/netrender/operators.py b/release/scripts/io/netrender/operators.py index 858ec800dbc..252b1146b67 100644 --- a/release/scripts/io/netrender/operators.py +++ b/release/scripts/io/netrender/operators.py @@ -26,13 +26,13 @@ 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): @@ -52,27 +52,27 @@ 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() @@ -84,13 +84,13 @@ class RENDER_OT_netslave_bake(bpy.types.Operator): 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,13 @@ 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" - def poll(self, context): + @classmethod + def poll(cls, context): return True def execute(self, context): @@ -188,13 +188,13 @@ class RENDER_OT_netclientsendframe(bpy.types.Operator): def invoke(self, context, event): return self.execute(context) -@rnaType 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): @@ -205,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'))) @@ -228,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): @@ -258,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): @@ -289,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): @@ -306,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'))) @@ -334,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 @@ -354,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) @@ -363,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): @@ -380,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): @@ -390,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 @@ -412,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) @@ -419,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: @@ -435,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): @@ -458,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 index 7f9befd34fb..3ac9636b628 100755..100644 --- a/release/scripts/io/netrender/repath.py +++ b/release/scripts/io/netrender/repath.py @@ -66,10 +66,10 @@ def update(job): def process(paths): def processPointCache(point_cache): - point_cache.external = False + point_cache.use_external = False def processFluid(fluid): - new_path = path_map.get(fluid.path, None) + new_path = path_map.get(fluid.filepath, None) if new_path: fluid.path = new_path @@ -83,14 +83,17 @@ def process(paths): elif paths[i].endswith(".bobj.gz"): path_map[os.path.split(paths[i])[0]] = os.path.split(paths[i+1])[0] else: - path_map[paths[i]] = paths[i+1] + 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.utils.expandpath(lib.filepath) - new_path = path_map.get(file_path, None) + 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 @@ -99,8 +102,8 @@ def process(paths): ########################### for image in bpy.data.images: if image.source == "FILE" and not image.packed_file: - file_path = bpy.utils.expandpath(image.filepath) - new_path = path_map.get(file_path, None) + 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 @@ -118,10 +121,10 @@ def process(paths): 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.highres: + if modifier.domain_settings.use_high_resolution: processPointCache(modifier.domain_settings.point_cache_high) - elif modifier.type == "MULTIRES" and modifier.external: - file_path = bpy.utils.expandpath(modifier.filepath) + 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 @@ -144,4 +147,4 @@ if __name__ == "__main__": process(args) - bpy.ops.wm.save_as_mainfile(path=new_path, check_existing=False) + 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 9fd00152dc1..b383481824b 100644 --- a/release/scripts/io/netrender/slave.py +++ b/release/scripts/io/netrender/slave.py @@ -59,8 +59,8 @@ 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 @@ -79,7 +79,9 @@ def testFile(conn, job_id, slave_id, rfile, JOB_PREFIX, main_path = None): job_full_path = prefixPath(JOB_PREFIX, rfile.filepath, main_path, force = True) if not found: - temp_path = JOB_PREFIX + "slave.temp" + # 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() @@ -111,10 +113,11 @@ 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) @@ -130,7 +133,7 @@ def render_slave(engine, netsettings, threads): 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) @@ -155,6 +158,7 @@ def render_slave(engine, netsettings, threads): 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 @@ -170,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 @@ -194,9 +198,10 @@ 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.slave_thumb: + if netsettings.use_slave_output_log: print(str(stdout, encoding='utf8'), end="") stdout = bytes() @@ -214,18 +219,21 @@ def render_slave(engine, netsettings, threads): 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.slave_thumb: + 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 conn.getresponse().status == http.client.NO_CONTENT: + if responseStatus(conn) == http.client.NO_CONTENT: continue total_t = time.time() - start_t @@ -246,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) @@ -273,7 +282,7 @@ 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") @@ -288,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 c60b10c484a..c2d943f63f8 100644 --- a/release/scripts/io/netrender/ui.py +++ b/release/scripts/io/netrender/ui.py @@ -36,6 +36,11 @@ 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.filepath: netrender.init_file = bpy.data.filepath @@ -81,17 +86,21 @@ class RenderButtonsPanel(): 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(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(bpy.types.Panel, RenderButtonsPanel): layout.operator("render.netclientweb", icon='QUESTION') -@rnaType 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,23 +147,23 @@ class RENDER_PT_network_slave_settings(bpy.types.Panel, RenderButtonsPanel): rd = scene.render netsettings = scene.network_render - layout.prop(netsettings, "slave_clear") - layout.prop(netsettings, "slave_thumb") - layout.prop(netsettings, "slave_outputlog") + 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(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 @@ -163,18 +171,17 @@ class RENDER_PT_network_master_settings(bpy.types.Panel, 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(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 @@ -207,19 +214,18 @@ class RENDER_PT_network_job(bpy.types.Panel, RenderButtonsPanel): row.prop(netsettings, "priority") row.prop(netsettings, "chunks") -@rnaType 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.server_address != "[default]") + return super(RENDER_PT_network_slaves, cls).poll(context) and netsettings.server_address != "[default]" def draw(self, context): layout = self.layout @@ -246,19 +252,18 @@ class RENDER_PT_network_slaves(bpy.types.Panel, RenderButtonsPanel): layout.label(text="Seen: " + time.ctime(slave.last_seen)) layout.label(text="Stats: " + slave.stats) -@rnaType 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.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 @@ -284,19 +289,18 @@ class RENDER_PT_network_slaves_blacklist(bpy.types.Panel, RenderButtonsPanel): layout.label(text="Seen: " + time.ctime(slave.last_seen)) layout.label(text="Stats: " + slave.stats) -@rnaType 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.server_address != "[default]") + return super(RENDER_PT_network_jobs, cls).poll(context) and netsettings.server_address != "[default]" def draw(self, context): layout = self.layout @@ -325,150 +329,148 @@ class RENDER_PT_network_jobs(bpy.types.Panel, 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="slave_outputlog", - 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="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 6288b9747c0..81617ac0d30 100644 --- a/release/scripts/io/netrender/utils.py +++ b/release/scripts/io/netrender/utils.py @@ -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: @@ -171,20 +172,20 @@ def prefixPath(prefix_directory, file_path, prefix_path, force = False): # if an absolute path, make sure path exists, if it doesn't, use relative local path full_path = file_path if force or not os.path.exists(full_path): - p, n = os.path.split(full_path) + p, n = os.path.split(os.path.normpath(full_path)) if prefix_path and p.startswith(prefix_path): if len(prefix_path) < len(p): - directory = prefix_directory + p[len(prefix_path)+1:] + os.sep # +1 to remove separator + 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 = directory + n + 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 |