diff options
author | Campbell Barton <ideasman42@gmail.com> | 2011-06-03 05:43:04 +0400 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2011-06-03 05:43:04 +0400 |
commit | 441323973644509b857b865a8ed509eb3bf90633 (patch) | |
tree | 40e51ced6e19d2a259f2ac451bac9951fac2acde /io_scene_x3d/export_x3d.py | |
parent | e07e8ed44b7c6c76a69ec4e908b9a43a86e1ec3f (diff) |
- ensure unique names (before it was possible 2+ cleaned names would collide)
- use XML escaping rather then cleaning to for strings
Diffstat (limited to 'io_scene_x3d/export_x3d.py')
-rw-r--r-- | io_scene_x3d/export_x3d.py | 196 |
1 files changed, 93 insertions, 103 deletions
diff --git a/io_scene_x3d/export_x3d.py b/io_scene_x3d/export_x3d.py index 3ff2ea98..71df0e3d 100644 --- a/io_scene_x3d/export_x3d.py +++ b/io_scene_x3d/export_x3d.py @@ -73,25 +73,12 @@ def clamp_color(col): return tuple([max(min(c, 1.0), 0.0) for c in col]) -def matrix_direction_neg_z(mtx): - return (mathutils.Vector((0.0, 0.0, -1.0)) * mtx.to_3x3()).normalized()[:] +def matrix_direction_neg_z(matrix): + return (mathutils.Vector((0.0, 0.0, -1.0)) * matrix.to_3x3()).normalized()[:] -def clean_str(name, prefix='rsvd_'): - """cleanStr(name,prefix) - try to create a valid VRML DEF name from object name""" - - newName = name - - if newName in x3d_names_reserved: - newName = '%s%s' % (prefix, newName) - - if newName[0].isdigit(): - newName = '%s%s' % ('_', newName) - - for bad in [' ', '"', '#', "'", ', ', '.', '[', '\\', ']', '{', '}']: - newName = newName.replace(bad, '_') - return newName - +def prefix_quoted_str(value, prefix): + return value[0] + prefix + value[1:] ########################################################## # Functions for writing output file @@ -109,8 +96,18 @@ def export(file, ): # ------------------------------------------------------------------------- - # global setup + # Global Setup # ------------------------------------------------------------------------- + from bpy_extras.io_utils import unique_name + from xml.sax.saxutils import quoteattr + + uuid_cache_object = {} # object + uuid_cache_view = {} # object, different namespace + uuid_cache_mesh = {} # mesh + uuid_cache_material = {} # material + uuid_cache_image = {} # image + uuid_cache_world = {} # world + fw = file.write dirname = os.path.dirname(file.name) gpu_shader_cache = {} @@ -120,13 +117,14 @@ def export(file, gpu_shader_dummy_mat = bpy.data.materials.new('X3D_DYMMY_MAT') gpu_shader_cache[None] = gpu.export_shader(scene, gpu_shader_dummy_mat) -########################################################## -# Writing nodes routines -########################################################## + # ------------------------------------------------------------------------- + # File Writing Functions + # ------------------------------------------------------------------------- def writeHeader(ident): - filepath = fw.__self__.name - bfile = repr(os.path.basename(filepath).replace('<', '<').replace('>', '>'))[1:-1] # use outfile name + filepath_quoted = quoteattr(os.path.basename(file.name)) + blender_ver_quoted = quoteattr('Blender %s' % bpy.app.version_string) + fw('%s<?xml version="1.0" encoding="UTF-8"?>\n' % ident) if use_h3d: fw('%s<X3D profile="H3DAPI" version="1.4">\n' % ident) @@ -137,8 +135,8 @@ def export(file, ident += '\t' fw('%s<head>\n' % ident) ident += '\t' - fw('%s<meta name="filename" content="%s" />\n' % (ident, bfile)) - fw('%s<meta name="generator" content="Blender %s" />\n' % (ident, bpy.app.version_string)) + fw('%s<meta name="filename" content=%s />\n' % (ident, filepath_quoted)) + fw('%s<meta name="generator" content=%s />\n' % (ident, blender_ver_quoted)) # this info was never updated, so blender version should be enough # fw('%s<meta name="translator" content="X3D exporter v1.55 (2006/01/17)" />\n' % ident) ident = ident[:-1] @@ -154,13 +152,14 @@ def export(file, fw('%s</X3D>' % ident) return ident - def writeViewpoint(ident, obj, mat, scene): - loc, quat, scale = mat.decompose() + def writeViewpoint(ident, obj, matrix, scene): + view_id = unique_name(obj, 'CA_' + obj.name, uuid_cache_view, clean_func=quoteattr) + + loc, quat, scale = matrix.decompose() ident_step = ident + (' ' * (-len(ident) + \ fw('%s<Viewpoint ' % ident))) - fw('DEF="%s"\n' % clean_str(obj.name)) - fw(ident_step + 'description="%s"\n' % obj.name) + fw('DEF=%s\n' % view_id) fw(ident_step + 'centerOfRotation="0 0 0"\n') fw(ident_step + 'position="%3.2f %3.2f %3.2f"\n' % loc[:]) fw(ident_step + 'orientation="%3.2f %3.2f %3.2f %3.2f"\n' % (quat.axis[:] + (quat.angle, ))) @@ -193,8 +192,10 @@ def export(file, fw(ident_step + 'avatarSize="0.25, 1.75, 0.75"\n') fw(ident_step + '/>\n') - def writeSpotLight(ident, obj, mtx, lamp, world): - safeName = clean_str(obj.name) + def writeSpotLight(ident, obj, matrix, lamp, world): + # note, lamp_id is not re-used + lamp_id = unique_name(obj, 'LA_' + obj.name, uuid_cache_object, clean_func=quoteattr) + if world: ambi = world.ambient_color amb_intensity = ((ambi[0] + ambi[1] + ambi[2]) / 3.0) / 2.5 @@ -208,15 +209,15 @@ def export(file, # beamWidth=((lamp.spotSize*math.pi)/180.0)*.37 cutOffAngle = beamWidth * 1.3 - orientation = matrix_direction_neg_z(mtx) + orientation = matrix_direction_neg_z(matrix) - location = mtx.to_translation()[:] + location = matrix.to_translation()[:] radius = lamp.distance * math.cos(beamWidth) # radius = lamp.dist*math.cos(beamWidth) ident_step = ident + (' ' * (-len(ident) + \ fw('%s<SpotLight ' % ident))) - fw('DEF="%s"\n' % safeName) + fw('DEF=%s\n' % lamp_id) fw(ident_step + 'radius="%.4g"\n' % radius) fw(ident_step + 'ambientIntensity="%.4g"\n' % amb_intensity) fw(ident_step + 'intensity="%.4g"\n' % intensity) @@ -227,8 +228,10 @@ def export(file, fw(ident_step + 'location="%.4g %.4g %.4g"\n' % location) fw(ident_step + '/>\n') - def writeDirectionalLight(ident, obj, mtx, lamp, world): - safeName = clean_str(obj.name) + def writeDirectionalLight(ident, obj, matrix, lamp, world): + # note, lamp_id is not re-used + lamp_id = unique_name(obj, 'LA_' + obj.name, uuid_cache_object, clean_func=quoteattr) + if world: ambi = world.ambient_color # ambi = world.amb @@ -239,20 +242,21 @@ def export(file, intensity = min(lamp.energy / 1.75, 1.0) - orientation = matrix_direction_neg_z(mtx) + orientation = matrix_direction_neg_z(matrix) ident_step = ident + (' ' * (-len(ident) + \ fw('%s<DirectionalLight ' % ident))) - fw('DEF="%s"\n' % safeName) + fw('DEF=%s\n' % lamp_id) fw(ident_step + 'ambientIntensity="%.4g"\n' % amb_intensity) fw(ident_step + 'color="%.4g %.4g %.4g"\n' % clamp_color(lamp.color)) fw(ident_step + 'intensity="%.4g"\n' % intensity) fw(ident_step + 'direction="%.4g %.4g %.4g"\n' % orientation) fw(ident_step + '/>\n') - def writePointLight(ident, obj, mtx, lamp, world): + def writePointLight(ident, obj, matrix, lamp, world): + # note, lamp_id is not re-used + lamp_id = unique_name(obj, 'LA_' + obj.name, uuid_cache_object, clean_func=quoteattr) - safeName = clean_str(obj.name) if world: ambi = world.ambient_color # ambi = world.amb @@ -262,11 +266,11 @@ def export(file, amb_intensity = 0.0 intensity = min(lamp.energy / 1.75, 1.0) - location = mtx.to_translation()[:] + location = matrix.to_translation()[:] ident_step = ident + (' ' * (-len(ident) + \ fw('%s<PointLight ' % ident))) - fw('DEF="%s"\n' % safeName) + fw('DEF=%s\n' % lamp_id) fw(ident_step + 'ambientIntensity="%.4g"\n' % amb_intensity) fw(ident_step + 'color="%.4g %.4g %.4g"\n' % clamp_color(lamp.color)) @@ -275,30 +279,12 @@ def export(file, fw(ident_step + 'location="%.4g %.4g %.4g"\n' % location) fw(ident_step + '/>\n') - def secureName(name): - name = name + str(secureName.nodeID) - secureName.nodeID += 1 - if len(name) <= 3: - newname = '_' + str(secureName.nodeID) - return "%s" % (newname) - else: - for bad in ('"', '#', "'", ', ', '.', '[', '\\', ']', '{', '}'): - name = name.replace(bad, '_') - if name in x3d_names_reserved: - newname = name[0:3] + '_' + str(secureName.nodeID) - return "%s" % (newname) - elif name[0].isdigit(): - newname = '_' + name + str(secureName.nodeID) - return "%s" % (newname) - else: - newname = name - return "%s" % (newname) - secureName.nodeID = 0 - - def writeIndexedFaceSet(ident, obj, mesh, mtx, world): - - shape_name_x3d = clean_str(obj.name) - mesh_name_x3d = clean_str(mesh.name) + def writeIndexedFaceSet(ident, obj, mesh, matrix, world): + obj_id = unique_name(obj, 'OB_' + obj.name, uuid_cache_object, clean_func=quoteattr) + mesh_id = unique_name(mesh, 'ME_' + mesh.name, uuid_cache_mesh, clean_func=quoteattr) + mesh_id_group = prefix_quoted_str(mesh_id, 'group_') + mesh_id_coords = prefix_quoted_str(mesh_id, 'coords_') + mesh_id_normals = prefix_quoted_str(mesh_id, 'normals_') if not mesh.faces: return @@ -336,11 +322,11 @@ def export(file, del texface_use_collision # del texface_use_object_color - loc, quat, sca = mtx.decompose() + loc, quat, sca = matrix.decompose() ident_step = ident + (' ' * (-len(ident) + \ fw('%s<Transform ' % ident))) - fw('DEF="%s"\n' % shape_name_x3d) + fw('DEF=%s\n' % obj_id) fw(ident_step + 'translation="%.6g %.6g %.6g"\n' % loc[:]) fw(ident_step + 'scale="%.6g %.6g %.6g"\n' % sca[:]) fw(ident_step + 'rotation="%.6g %.6g %.6g %.6g"\n' % (quat.axis[:] + (quat.angle, ))) @@ -348,11 +334,11 @@ def export(file, ident += '\t' if mesh.tag: - fw('%s<Group USE="G_%s" />\n' % (ident, mesh_name_x3d)) + fw('%s<Group USE=%s />\n' % (ident, mesh_id_group)) else: mesh.tag = True - fw('%s<Group DEF="G_%s">\n' % (ident, mesh_name_x3d)) + fw('%s<Group DEF=%s>\n' % (ident, mesh_id_group)) ident += '\t' is_uv = bool(mesh.uv_textures.active) @@ -480,11 +466,11 @@ def export(file, if use_h3d: mat_tmp = material if material else gpu_shader_dummy_mat - writeMaterialH3D(ident, mat_tmp, clean_str(mat_tmp.name, ''), world, + writeMaterialH3D(ident, mat_tmp, world, obj, gpu_shader) del mat_tmp else: - writeMaterial(ident, material, clean_str(material.name, ''), world) + writeMaterial(ident, material, world) ident = ident[:-1] fw('%s</Appearance>\n' % ident) @@ -687,13 +673,13 @@ def export(file, # --- Write IndexedFaceSet Elements if True: if is_coords_written: - fw('%s<Coordinate USE="%s%s" />\n' % (ident, 'coord_', mesh_name_x3d)) + fw('%s<Coordinate USE=%s />\n' % (ident, mesh_id_coords)) if use_normals: - fw('%s<Normal USE="%s%s" />\n' % (ident, 'normals_', mesh_name_x3d)) + fw('%s<Normal USE=%s />\n' % (ident, mesh_id_normals)) else: ident_step = ident + (' ' * (-len(ident) + \ fw('%s<Coordinate ' % ident))) - fw('DEF="%s%s"\n' % ('coord_', mesh_name_x3d)) + fw('DEF=%s\n' % mesh_id_coords) fw(ident_step + 'point="') for v in mesh.vertices: fw('%.6g %.6g %.6g ' % v.co[:]) @@ -705,7 +691,7 @@ def export(file, if use_normals: ident_step = ident + (' ' * (-len(ident) + \ fw('%s<Normal ' % ident))) - fw('DEF="%s%s"\n' % ('normals_', mesh_name_x3d)) + fw('DEF=%s\n' % mesh_id_normals) fw(ident_step + 'vector="') for v in mesh.vertices: fw('%.6g %.6g %.6g ' % v.normal[:]) @@ -753,34 +739,36 @@ def export(file, ident = ident[:-1] fw('%s</Collision>\n' % ident) - def writeMaterial(ident, mat, material_id, world): + def writeMaterial(ident, material, world): + material_id = unique_name(material, 'MA_' + material.name, uuid_cache_material, clean_func=quoteattr) + # look up material name, use it if available - if mat.tag: - fw('%s<Material USE="MA_%s" />\n' % (ident, material_id)) + if material.tag: + fw('%s<Material USE=%s />\n' % (ident, material_id)) else: - mat.tag = True + material.tag = True - emit = mat.emit - ambient = mat.ambient / 3.0 - diffuseColor = mat.diffuse_color[:] + emit = material.emit + ambient = material.ambient / 3.0 + diffuseColor = material.diffuse_color[:] if world: - ambiColor = tuple(((c * mat.ambient) * 2.0) for c in world.ambient_color) + ambiColor = ((material.ambient * 2.0) * world.ambient_color)[:] else: ambiColor = 0.0, 0.0, 0.0 emitColor = tuple(((c * emit) + ambiColor[i]) / 2.0 for i, c in enumerate(diffuseColor)) - shininess = mat.specular_hardness / 512.0 - specColor = tuple((c + 0.001) / (1.25 / (mat.specular_intensity + 0.001)) for c in mat.specular_color) - transp = 1.0 - mat.alpha + shininess = material.specular_hardness / 512.0 + specColor = tuple((c + 0.001) / (1.25 / (material.specular_intensity + 0.001)) for c in material.specular_color) + transp = 1.0 - material.alpha - if mat.use_shadeless: + if material.use_shadeless: ambient = 1.0 shininess = 0.0 specColor = emitColor = diffuseColor ident_step = ident + (' ' * (-len(ident) + \ fw('%s<Material ' % ident))) - fw('DEF="MA_%s"\n' % material_id) + fw('DEF=%s\n' % material_id) fw(ident_step + 'diffuseColor="%.3g %.3g %.3g"\n' % clamp_color(diffuseColor)) fw(ident_step + 'specularColor="%.3g %.3g %.3g"\n' % clamp_color(specColor)) fw(ident_step + 'emissiveColor="%.3g %.3g %.3g"\n' % clamp_color(emitColor)) @@ -789,14 +777,15 @@ def export(file, fw(ident_step + 'transparency="%s"\n' % transp) fw(ident_step + '/>\n') - def writeMaterialH3D(ident, mat, material_id, world, + def writeMaterialH3D(ident, material, world, obj, gpu_shader): + material_id = unique_name(material, 'MA_' + material.name, uuid_cache_material, clean_func=quoteattr) fw('%s<Material />\n' % ident) - if mat.tag: - fw('%s<ComposedShader USE="MA_%s" />\n' % (ident, material_id)) + if material.tag: + fw('%s<ComposedShader USE=%s />\n' % (ident, material_id)) else: - mat.tag = True + material.tag = True #~ CD_MCOL 6 #~ CD_MTFACE 5 @@ -875,7 +864,7 @@ def export(file, ''' import gpu - fw('%s<ComposedShader DEF="MA_%s" language="GLSL" >\n' % (ident, material_id)) + fw('%s<ComposedShader DEF=%s language="GLSL" >\n' % (ident, material_id)) ident += '\t' shader_url_frag = 'shaders/glsl_%s.frag' % material_id @@ -943,7 +932,7 @@ def export(file, # value = ' '.join(['%.6g' % (f / 256) for f in uniform['texpixels']]) fw('%s<field name="%s" type="SFInt32" accessType="inputOutput" value="%s" />\n' % (ident, uniform['varname'], value)) - print("ass", len(uniform['texpixels'])) + print('test', len(uniform['texpixels'])) else: assert(0) @@ -962,16 +951,16 @@ def export(file, fw('%s</ComposedShader>\n' % ident) def writeImageTexture(ident, image): - name = image.name + image_id = unique_name(image, 'IM_' + image.name, uuid_cache_image, clean_func=quoteattr) if image.tag: - fw('%s<ImageTexture USE="%s" />\n' % (ident, clean_str(name))) + fw('%s<ImageTexture USE=%s />\n' % (ident, image_id)) else: image.tag = True ident_step = ident + (' ' * (-len(ident) + \ fw('%s<ImageTexture ' % ident))) - fw('DEF="%s"\n' % clean_str(name)) + fw('DEF=%s\n' % image_id) filepath = image.filepath filepath_full = bpy.path.abspath(filepath) @@ -990,11 +979,12 @@ def export(file, def writeBackground(ident, world): - if world: - worldname = world.name - else: + if world is None: return + # note, not re-used + world_id = unique_name(world, 'WO_' + world.name, uuid_cache_world, clean_func=quoteattr) + blending = world.use_sky_blend, world.use_sky_paper, world.use_sky_real grd_triple = clamp_color(world.horizon_color) @@ -1003,7 +993,7 @@ def export(file, ident_step = ident + (' ' * (-len(ident) + \ fw('%s<Background ' % ident))) - fw('DEF="%s"\n' % secureName(worldname)) + fw('DEF=%s\n' % world_id) # No Skytype - just Hor color if blending == (False, False, False): fw(ident_step + 'groundColor="%.3g %.3g %.3g"\n' % grd_triple) @@ -1158,7 +1148,7 @@ def save(operator, context, filepath="", global_matrix=None, ): - py.path.ensure_ext(filepath, '.x3dz' if use_compress else '.x3d') + bpy.path.ensure_ext(filepath, '.x3dz' if use_compress else '.x3d') if bpy.ops.object.mode_set.poll(): bpy.ops.object.mode_set(mode='OBJECT') |