Advertisement
Doyousketch2

import_obj.py

Feb 14th, 2017
76
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 52.74 KB | None | 0 0
  1. # ##### BEGIN GPL LICENSE BLOCK #####
  2. #
  3. #  This program is free software; you can redistribute it and/or
  4. #  modify it under the terms of the GNU General Public License
  5. #  as published by the Free Software Foundation; either version 2
  6. #  of the License, or (at your option) any later version.
  7. #
  8. #  This program is distributed in the hope that it will be useful,
  9. #  but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  11. #  GNU General Public License for more details.
  12. #
  13. #  You should have received a copy of the GNU General Public License
  14. #  along with this program; if not, write to the Free Software Foundation,
  15. #  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  16. #
  17. # ##### END GPL LICENSE BLOCK #####
  18.  
  19. # <pep8 compliant>
  20.  
  21. # Script copyright (C) Campbell Barton
  22. # Contributors: Campbell Barton, Jiri Hnidek, Paolo Ciccone
  23.  
  24. """
  25. This script imports a Wavefront OBJ files to Blender.
  26.  
  27. Usage:
  28. Run this script from "File->Import" menu and then load the desired OBJ file.
  29. Note, This loads mesh objects and materials only, nurbs and curves are not supported.
  30.  
  31. http://wiki.blender.org/index.php/Scripts/Manual/Import/wavefront_obj
  32. """
  33.  
  34. import array
  35. import os
  36. import time
  37. import bpy
  38. import mathutils
  39. from bpy_extras.io_utils import unpack_list
  40. from bpy_extras.image_utils import load_image
  41.  
  42. from progress_report import ProgressReport, ProgressReportSubstep
  43.  
  44.  
  45. def line_value(line_split):
  46.     """
  47.    Returns 1 string representing the value for this line
  48.    None will be returned if theres only 1 word
  49.    """
  50.     length = len(line_split)
  51.     if length == 1:
  52.         return None
  53.  
  54.     elif length == 2:
  55.         return line_split[1]
  56.  
  57.     elif length > 2:
  58.         return b' '.join(line_split[1:])
  59.  
  60.  
  61. def obj_image_load(context_imagepath_map, line, DIR, recursive, relpath):
  62.     """
  63.    Mainly uses comprehensiveImageLoad
  64.    But we try all space-separated items from current line when file is not found with last one
  65.    (users keep generating/using image files with spaces in a format that does not support them, sigh...)
  66.    Also tries to replace '_' with ' ' for Max's exporter replaces spaces with underscores.
  67.    """
  68.     filepath_parts = line.split(b' ')
  69.     image = None
  70.     for i in range(-1, -len(filepath_parts), -1):
  71.         imagepath = os.fsdecode(b" ".join(filepath_parts[i:]))
  72.         image = context_imagepath_map.get(imagepath, ...)
  73.         if image is ...:
  74.             image = load_image(imagepath, DIR, recursive=recursive, relpath=relpath)
  75.             if image is None and "_" in imagepath:
  76.                 image = load_image(imagepath.replace("_", " "), DIR, recursive=recursive, relpath=relpath)
  77.             if image is not None:
  78.                 context_imagepath_map[imagepath] = image
  79.                 break;
  80.  
  81.     if image is None:
  82.         imagepath = os.fsdecode(filepath_parts[-1])
  83.         image = load_image(imagepath, DIR, recursive=recursive, place_holder=True, relpath=relpath)
  84.         context_imagepath_map[imagepath] = image
  85.  
  86.     return image
  87.  
  88.  
  89. def create_materials(filepath, relpath,
  90.                      material_libs, unique_materials, unique_material_images,
  91.                      use_image_search, float_func):
  92.     """
  93.    Create all the used materials in this obj,
  94.    assign colors and images to the materials from all referenced material libs
  95.    """
  96.     DIR = os.path.dirname(filepath)
  97.     context_material_vars = set()
  98.  
  99.     # Don't load the same image multiple times
  100.     context_imagepath_map = {}
  101.  
  102.     def load_material_image(blender_material, context_material_name, img_data, line, type):
  103.         """
  104.        Set textures defined in .mtl file.
  105.        """
  106.         map_options = {}
  107.  
  108.         curr_token = []
  109.         for token in img_data[:-1]:
  110.             if token.startswith(b'-'):
  111.                 if curr_token:
  112.                     map_options[curr_token[0]] = curr_token[1:]
  113.                 curr_token[:] = []
  114.             curr_token.append(token)
  115.  
  116.         texture = bpy.data.textures.new(name=type, type='IMAGE')
  117.  
  118.         # Absolute path - c:\.. etc would work here
  119.         image = obj_image_load(context_imagepath_map, line, DIR, use_image_search, relpath)
  120.  
  121.         if image is not None:
  122.             texture.image = image
  123.  
  124.         # Adds textures for materials (rendering)
  125.         if type == 'Kd':
  126.             mtex = blender_material.texture_slots.add()
  127.             mtex.texture = texture
  128.             mtex.texture_coords = 'UV'
  129.             mtex.use_map_color_diffuse = True
  130.  
  131.             # adds textures to faces (Textured/Alt-Z mode)
  132.             # Only apply the diffuse texture to the face if the image has not been set with the inline usemat func.
  133.             unique_material_images[context_material_name] = image  # set the texface image
  134.  
  135.         elif type == 'Ka':
  136.             mtex = blender_material.texture_slots.add()
  137.             mtex.use_map_color_diffuse = False
  138.  
  139.             mtex.texture = texture
  140.             mtex.texture_coords = 'UV'
  141.             mtex.use_map_ambient = True
  142.  
  143.         elif type == 'Ks':
  144.             mtex = blender_material.texture_slots.add()
  145.             mtex.use_map_color_diffuse = False
  146.  
  147.             mtex.texture = texture
  148.             mtex.texture_coords = 'UV'
  149.             mtex.use_map_color_spec = True
  150.  
  151.         elif type == 'Ke':
  152.             mtex = blender_material.texture_slots.add()
  153.             mtex.use_map_color_diffuse = False
  154.  
  155.             mtex.texture = texture
  156.             mtex.texture_coords = 'UV'
  157.             mtex.use_map_emit = True
  158.  
  159.         elif type == 'Bump':
  160.             mtex = blender_material.texture_slots.add()
  161.             mtex.use_map_color_diffuse = False
  162.  
  163.             mtex.texture = texture
  164.             mtex.texture_coords = 'UV'
  165.             mtex.use_map_normal = True
  166.  
  167.             bump_mult = map_options.get(b'-bm')
  168.             if bump_mult:
  169.                 mtex.normal_factor = bump_mult[0]
  170.  
  171.         elif type == 'D':
  172.             mtex = blender_material.texture_slots.add()
  173.             mtex.use_map_color_diffuse = False
  174.  
  175.             mtex.texture = texture
  176.             mtex.texture_coords = 'UV'
  177.             mtex.use_map_alpha = True
  178.             blender_material.use_transparency = True
  179.             blender_material.transparency_method = 'Z_TRANSPARENCY'
  180.             if "alpha" not in context_material_vars:
  181.                 blender_material.alpha = 0.0
  182.             # Todo, unset deffuse material alpha if it has an alpha channel
  183.  
  184.         elif type == 'disp':
  185.             mtex = blender_material.texture_slots.add()
  186.             mtex.use_map_color_diffuse = False
  187.  
  188.             mtex.texture = texture
  189.             mtex.texture_coords = 'UV'
  190.             mtex.use_map_displacement = True
  191.  
  192.         elif type == 'refl':
  193.             mtex = blender_material.texture_slots.add()
  194.             mtex.use_map_color_diffuse = False
  195.  
  196.             mtex.texture = texture
  197.             mtex.texture_coords = 'REFLECTION'
  198.             mtex.use_map_color_diffuse = True
  199.  
  200.             map_type = map_options.get(b'-type')
  201.             if map_type and map_type != [b'sphere']:
  202.                 print("WARNING, unsupported reflection type '%s', defaulting to 'sphere'"
  203.                       "" % ' '.join(i.decode() for i in map_type))
  204.             mtex.mapping = 'SPHERE'
  205.         else:
  206.             raise Exception("invalid type %r" % type)
  207.  
  208.         map_offset = map_options.get(b'-o')
  209.         map_scale = map_options.get(b'-s')
  210.         if map_offset:
  211.             mtex.offset.x = float(map_offset[0])
  212.             if len(map_offset) >= 2:
  213.                 mtex.offset.y = float(map_offset[1])
  214.             if len(map_offset) >= 3:
  215.                 mtex.offset.z = float(map_offset[2])
  216.         if map_scale:
  217.             mtex.scale.x = float(map_scale[0])
  218.             if len(map_scale) >= 2:
  219.                 mtex.scale.y = float(map_scale[1])
  220.             if len(map_scale) >= 3:
  221.                 mtex.scale.z = float(map_scale[2])
  222.  
  223.     # Add an MTL with the same name as the obj if no MTLs are spesified.
  224.     temp_mtl = os.path.splitext((os.path.basename(filepath)))[0] + ".mtl"
  225.  
  226.     if os.path.exists(os.path.join(DIR, temp_mtl)):
  227.         material_libs.add(temp_mtl)
  228.     del temp_mtl
  229.  
  230.     # Create new materials
  231.     for name in unique_materials:  # .keys()
  232.         if name is not None:
  233.             unique_materials[name] = bpy.data.materials.new(name.decode('utf-8', "replace"))
  234.             unique_material_images[name] = None  # assign None to all material images to start with, add to later.
  235.  
  236.     # XXX Why was this needed? Cannot find any good reason, and adds stupid empty matslot in case we do not separate
  237.     #     mesh (see T44947).
  238.     #~ unique_materials[None] = None
  239.     #~ unique_material_images[None] = None
  240.  
  241.     for libname in sorted(material_libs):
  242.         # print(libname)
  243.         mtlpath = os.path.join(DIR, libname)
  244.         if not os.path.exists(mtlpath):
  245.             print("\tMaterial not found MTL: %r" % mtlpath)
  246.         else:
  247.             do_ambient = True
  248.             do_highlight = False
  249.             do_reflection = False
  250.             do_transparency = False
  251.             do_glass = False
  252.             do_fresnel = False
  253.             do_raytrace = False
  254.             emit_colors = [0.0, 0.0, 0.0]
  255.  
  256.             # print('\t\tloading mtl: %e' % mtlpath)
  257.             context_material = None
  258.             mtl = open(mtlpath, 'rb')
  259.             for line in mtl:  # .readlines():
  260.                 line = line.strip()
  261.                 if not line or line.startswith(b'#'):
  262.                     continue
  263.  
  264.                 line_split = line.split()
  265.                 line_id = line_split[0].lower()
  266.  
  267.                 if line_id == b'newmtl':
  268.                     # Finalize previous mat, if any.
  269.                     if context_material:
  270.                         emit_value = sum(emit_colors) / 3.0
  271.                         if emit_value > 1e-6:
  272.                             # We have to adapt it to diffuse color too...
  273.                             emit_value /= sum(context_material.diffuse_color) / 3.0
  274.                         context_material.emit = emit_value
  275.  
  276.                         if not do_ambient:
  277.                             context_material.ambient = 0.0
  278.  
  279.                         if do_highlight:
  280.                             # FIXME, how else to use this?
  281.                             context_material.specular_intensity = 1.0
  282.  
  283.                         if do_reflection:
  284.                             context_material.raytrace_mirror.use = True
  285.                             context_material.raytrace_mirror.reflect_factor = 1.0
  286.  
  287.                         if do_transparency:
  288.                             context_material.use_transparency = True
  289.                             context_material.transparency_method = 'RAYTRACE' if do_raytrace else 'Z_TRANSPARENCY'
  290.                             if "alpha" not in context_material_vars:
  291.                                 context_material.alpha = 0.0
  292.  
  293.                         if do_glass:
  294.                             if "ior" not in context_material_vars:
  295.                                 context_material.raytrace_transparency.ior = 1.5
  296.  
  297.                         if do_fresnel:
  298.                             context_material.raytrace_mirror.fresnel = 1.0  # could be any value for 'ON'
  299.  
  300.                         """
  301.                        if do_raytrace:
  302.                            context_material.use_raytrace = True
  303.                        else:
  304.                            context_material.use_raytrace = False
  305.                        """
  306.                         # XXX, this is not following the OBJ spec, but this was
  307.                         # written when raytracing wasnt default, annoying to disable for blender users.
  308.                         context_material.use_raytrace = True
  309.  
  310.                     context_material_name = line_value(line_split)
  311.                     context_material = unique_materials.get(context_material_name)
  312.                     context_material_vars.clear()
  313.  
  314.                     emit_colors[:] = [0.0, 0.0, 0.0]
  315.                     do_ambient = True
  316.                     do_highlight = False
  317.                     do_reflection = False
  318.                     do_transparency = False
  319.                     do_glass = False
  320.                     do_fresnel = False
  321.                     do_raytrace = False
  322.  
  323.  
  324.                 elif context_material:
  325.                     # we need to make a material to assign properties to it.
  326.                     if line_id == b'ka':
  327.                         context_material.mirror_color = (
  328.                             float_func(line_split[1]), float_func(line_split[2]), float_func(line_split[3]))
  329.                         # This is highly approximated, but let's try to stick as close from exporter as possible... :/
  330.                         context_material.ambient = sum(context_material.mirror_color) / 3
  331.                     elif line_id == b'kd':
  332.                         context_material.diffuse_color = (
  333.                             float_func(line_split[1]), float_func(line_split[2]), float_func(line_split[3]))
  334.                         context_material.diffuse_intensity = 1.0
  335.                     elif line_id == b'ks':
  336.                         context_material.specular_color = (
  337.                             float_func(line_split[1]), float_func(line_split[2]), float_func(line_split[3]))
  338.                         context_material.specular_intensity = 1.0
  339.                     elif line_id == b'ke':
  340.                         # We cannot set context_material.emit right now, we need final diffuse color as well for this.
  341.                         emit_colors[:] = [
  342.                             float_func(line_split[1]), float_func(line_split[2]), float_func(line_split[3])]
  343.                     elif line_id == b'ns':
  344.                         context_material.specular_hardness = int((float_func(line_split[1]) * 0.51) + 1)
  345.                     elif line_id == b'ni':  # Refraction index (between 1 and 3).
  346.                         context_material.raytrace_transparency.ior = max(1, min(float_func(line_split[1]), 3))
  347.                         context_material_vars.add("ior")
  348.                     elif line_id == b'd':  # dissolve (transparency)
  349.                         context_material.alpha = float_func(line_split[1])
  350.                         context_material.use_transparency = True
  351.                         context_material.transparency_method = 'Z_TRANSPARENCY'
  352.                         context_material_vars.add("alpha")
  353.                     elif line_id == b'tr':  # translucency
  354.                         context_material.translucency = float_func(line_split[1])
  355.                     elif line_id == b'tf':
  356.                         # rgb, filter color, blender has no support for this.
  357.                         pass
  358.                     elif line_id == b'illum':
  359.                         illum = int(line_split[1])
  360.  
  361.                         # inline comments are from the spec, v4.2
  362.                         if illum == 0:
  363.                             # Color on and Ambient off
  364.                             do_ambient = False
  365.                         elif illum == 1:
  366.                             # Color on and Ambient on
  367.                             pass
  368.                         elif illum == 2:
  369.                             # Highlight on
  370.                             do_highlight = True
  371.                         elif illum == 3:
  372.                             # Reflection on and Ray trace on
  373.                             do_reflection = True
  374.                             do_raytrace = True
  375.                         elif illum == 4:
  376.                             # Transparency: Glass on
  377.                             # Reflection: Ray trace on
  378.                             do_transparency = True
  379.                             do_reflection = True
  380.                             do_glass = True
  381.                             do_raytrace = True
  382.                         elif illum == 5:
  383.                             # Reflection: Fresnel on and Ray trace on
  384.                             do_reflection = True
  385.                             do_fresnel = True
  386.                             do_raytrace = True
  387.                         elif illum == 6:
  388.                             # Transparency: Refraction on
  389.                             # Reflection: Fresnel off and Ray trace on
  390.                             do_transparency = True
  391.                             do_reflection = True
  392.                             do_raytrace = True
  393.                         elif illum == 7:
  394.                             # Transparency: Refraction on
  395.                             # Reflection: Fresnel on and Ray trace on
  396.                             do_transparency = True
  397.                             do_reflection = True
  398.                             do_fresnel = True
  399.                             do_raytrace = True
  400.                         elif illum == 8:
  401.                             # Reflection on and Ray trace off
  402.                             do_reflection = True
  403.                         elif illum == 9:
  404.                             # Transparency: Glass on
  405.                             # Reflection: Ray trace off
  406.                             do_transparency = True
  407.                             do_reflection = True
  408.                             do_glass = True
  409.                         elif illum == 10:
  410.                             # Casts shadows onto invisible surfaces
  411.  
  412.                             # blender can't do this
  413.                             pass
  414.  
  415.                     elif line_id == b'map_ka':
  416.                         img_data = line.split()[1:]
  417.                         if img_data:
  418.                             load_material_image(context_material, context_material_name, img_data, line, 'Ka')
  419.                     elif line_id == b'map_ks':
  420.                         img_data = line.split()[1:]
  421.                         if img_data:
  422.                             load_material_image(context_material, context_material_name, img_data, line, 'Ks')
  423.                     elif line_id == b'map_kd':
  424.                         img_data = line.split()[1:]
  425.                         if img_data:
  426.                             load_material_image(context_material, context_material_name, img_data, line, 'Kd')
  427.                     elif line_id == b'map_ke':
  428.                         img_data = line.split()[1:]
  429.                         if img_data:
  430.                             load_material_image(context_material, context_material_name, img_data, line, 'Ke')
  431.                     elif line_id in {b'map_bump', b'bump'}:  # 'bump' is incorrect but some files use it.
  432.                         img_data = line.split()[1:]
  433.                         if img_data:
  434.                             load_material_image(context_material, context_material_name, img_data, line, 'Bump')
  435.                     elif line_id in {b'map_d', b'map_tr'}:  # Alpha map - Dissolve
  436.                         img_data = line.split()[1:]
  437.                         if img_data:
  438.                             load_material_image(context_material, context_material_name, img_data, line, 'D')
  439.  
  440.                     elif line_id in {b'map_disp', b'disp'}:  # displacementmap
  441.                         img_data = line.split()[1:]
  442.                         if img_data:
  443.                             load_material_image(context_material, context_material_name, img_data, line, 'disp')
  444.  
  445.                     elif line_id in {b'map_refl', b'refl'}:  # reflectionmap
  446.                         img_data = line.split()[1:]
  447.                         if img_data:
  448.                             load_material_image(context_material, context_material_name, img_data, line, 'refl')
  449.                     else:
  450.                         print("\t%r:%r (ignored)" % (filepath, line))
  451.             mtl.close()
  452.  
  453.  
  454. def split_mesh(verts_loc, faces, unique_materials, filepath, SPLIT_OB_OR_GROUP):
  455.     """
  456.    Takes vert_loc and faces, and separates into multiple sets of
  457.    (verts_loc, faces, unique_materials, dataname)
  458.    """
  459.  
  460.     filename = os.path.splitext((os.path.basename(filepath)))[0]
  461.  
  462.     if not SPLIT_OB_OR_GROUP or not faces:
  463.         use_verts_nor = any((False if f[1] is ... else True) for f in faces)
  464.         use_verts_tex = any((False if f[2] is ... else True) for f in faces)
  465.         # use the filename for the object name since we aren't chopping up the mesh.
  466.         return [(verts_loc, faces, unique_materials, filename, use_verts_nor, use_verts_tex)]
  467.  
  468.     def key_to_name(key):
  469.         # if the key is a tuple, join it to make a string
  470.         if not key:
  471.             return filename  # assume its a string. make sure this is true if the splitting code is changed
  472.         else:
  473.             return key.decode('utf-8', 'replace')
  474.  
  475.     # Return a key that makes the faces unique.
  476.     face_split_dict = {}
  477.  
  478.     oldkey = -1  # initialize to a value that will never match the key
  479.  
  480.     for face in faces:
  481.         key = face[5]
  482.  
  483.         if oldkey != key:
  484.             # Check the key has changed.
  485.             (verts_split, faces_split, unique_materials_split, vert_remap,
  486.              use_verts_nor, use_verts_tex) = face_split_dict.setdefault(key, ([], [], {}, {}, [], []))
  487.             oldkey = key
  488.  
  489.         face_vert_loc_indices = face[0]
  490.  
  491.         if not use_verts_nor and face[1] is not ...:
  492.             use_verts_nor.append(True)
  493.  
  494.         if not use_verts_tex and face[2] is not ...:
  495.             use_verts_tex.append(True)
  496.  
  497.         # Remap verts to new vert list and add where needed
  498.         for enum, i in enumerate(face_vert_loc_indices):
  499.             map_index = vert_remap.get(i)
  500.             if map_index is None:
  501.                 map_index = len(verts_split)
  502.                 vert_remap[i] = map_index  # set the new remapped index so we only add once and can reference next time.
  503.                 verts_split.append(verts_loc[i])  # add the vert to the local verts
  504.  
  505.             face_vert_loc_indices[enum] = map_index  # remap to the local index
  506.  
  507.             matname = face[3]
  508.             if matname and matname not in unique_materials_split:
  509.                 unique_materials_split[matname] = unique_materials[matname]
  510.  
  511.         faces_split.append(face)
  512.  
  513.     # remove one of the items and reorder
  514.     return [(verts_split, faces_split, unique_materials_split, key_to_name(key), bool(use_vnor), bool(use_vtex))
  515.             for key, (verts_split, faces_split, unique_materials_split, _, use_vnor, use_vtex)
  516.             in face_split_dict.items()]
  517.  
  518.  
  519. def create_mesh(new_objects,
  520.                 use_edges,
  521.                 verts_loc,
  522.                 verts_nor,
  523.                 verts_tex,
  524.                 faces,
  525.                 unique_materials,
  526.                 unique_material_images,
  527.                 unique_smooth_groups,
  528.                 vertex_groups,
  529.                 dataname,
  530.                 ):
  531.     """
  532.    Takes all the data gathered and generates a mesh, adding the new object to new_objects
  533.    deals with ngons, sharp edges and assigning materials
  534.    """
  535.  
  536.     if unique_smooth_groups:
  537.         sharp_edges = set()
  538.         smooth_group_users = {context_smooth_group: {} for context_smooth_group in unique_smooth_groups.keys()}
  539.         context_smooth_group_old = -1
  540.  
  541.     fgon_edges = set()  # Used for storing fgon keys when we need to tesselate/untesselate them (ngons with hole).
  542.     edges = []
  543.     tot_loops = 0
  544.  
  545.     context_object = None
  546.  
  547.     # reverse loop through face indices
  548.     for f_idx in range(len(faces) - 1, -1, -1):
  549.         (face_vert_loc_indices,
  550.          face_vert_nor_indices,
  551.          face_vert_tex_indices,
  552.          context_material,
  553.          context_smooth_group,
  554.          context_object,
  555.          face_invalid_blenpoly,
  556.          ) = faces[f_idx]
  557.  
  558.         len_face_vert_loc_indices = len(face_vert_loc_indices)
  559.  
  560.         if len_face_vert_loc_indices == 1:
  561.             faces.pop(f_idx)  # cant add single vert faces
  562.  
  563.         # Face with a single item in face_vert_nor_indices is actually a polyline!
  564.         elif len(face_vert_nor_indices) == 1 or len_face_vert_loc_indices == 2:
  565.             if use_edges:
  566.                 edges.extend((face_vert_loc_indices[i], face_vert_loc_indices[i + 1])
  567.                              for i in range(len_face_vert_loc_indices - 1))
  568.             faces.pop(f_idx)
  569.  
  570.         else:
  571.             # Smooth Group
  572.             if unique_smooth_groups and context_smooth_group:
  573.                 # Is a part of of a smooth group and is a face
  574.                 if context_smooth_group_old is not context_smooth_group:
  575.                     edge_dict = smooth_group_users[context_smooth_group]
  576.                     context_smooth_group_old = context_smooth_group
  577.  
  578.                 prev_vidx = face_vert_loc_indices[-1]
  579.                 for vidx in face_vert_loc_indices:
  580.                     edge_key = (prev_vidx, vidx) if (prev_vidx < vidx) else (vidx, prev_vidx)
  581.                     prev_vidx = vidx
  582.                     edge_dict[edge_key] = edge_dict.get(edge_key, 0) + 1
  583.  
  584.             # NGons into triangles
  585.             if face_invalid_blenpoly:
  586.                 # ignore triangles with invalid indices
  587.                 if len(face_vert_loc_indices) > 3:
  588.                     from bpy_extras.mesh_utils import ngon_tessellate
  589.                     ngon_face_indices = ngon_tessellate(verts_loc, face_vert_loc_indices)
  590.                     faces.extend([([face_vert_loc_indices[ngon[0]],
  591.                                     face_vert_loc_indices[ngon[1]],
  592.                                     face_vert_loc_indices[ngon[2]],
  593.                                     ],
  594.                                 [face_vert_nor_indices[ngon[0]],
  595.                                     face_vert_nor_indices[ngon[1]],
  596.                                     face_vert_nor_indices[ngon[2]],
  597.                                     ] if face_vert_nor_indices else [],
  598.                                 [face_vert_tex_indices[ngon[0]],
  599.                                     face_vert_tex_indices[ngon[1]],
  600.                                     face_vert_tex_indices[ngon[2]],
  601.                                     ] if face_vert_tex_indices else [],
  602.                                 context_material,
  603.                                 context_smooth_group,
  604.                                 context_object,
  605.                                 [],
  606.                                 )
  607.                                 for ngon in ngon_face_indices]
  608.                                 )
  609.                     tot_loops += 3 * len(ngon_face_indices)
  610.  
  611.                     # edges to make ngons
  612.                     if len(ngon_face_indices) > 1:
  613.                         edge_users = set()
  614.                         for ngon in ngon_face_indices:
  615.                             prev_vidx = face_vert_loc_indices[ngon[-1]]
  616.                             for ngidx in ngon:
  617.                                 vidx = face_vert_loc_indices[ngidx]
  618.                                 if vidx == prev_vidx:
  619.                                     continue  # broken OBJ... Just skip.
  620.                                 edge_key = (prev_vidx, vidx) if (prev_vidx < vidx) else (vidx, prev_vidx)
  621.                                 prev_vidx = vidx
  622.                                 if edge_key in edge_users:
  623.                                     fgon_edges.add(edge_key)
  624.                                 else:
  625.                                     edge_users.add(edge_key)
  626.  
  627.                 faces.pop(f_idx)
  628.             else:
  629.                 tot_loops += len_face_vert_loc_indices
  630.  
  631.     # Build sharp edges
  632.     if unique_smooth_groups:
  633.         for edge_dict in smooth_group_users.values():
  634.             for key, users in edge_dict.items():
  635.                 if users == 1:  # This edge is on the boundry of a group
  636.                     sharp_edges.add(key)
  637.  
  638.     # map the material names to an index
  639.     material_mapping = {name: i for i, name in enumerate(unique_materials)}  # enumerate over unique_materials keys()
  640.  
  641.     materials = [None] * len(unique_materials)
  642.  
  643.     for name, index in material_mapping.items():
  644.         materials[index] = unique_materials[name]
  645.  
  646.     me = bpy.data.meshes.new(dataname)
  647.  
  648.     # make sure the list isnt too big
  649.     for material in materials:
  650.         me.materials.append(material)
  651.  
  652.     me.vertices.add(len(verts_loc))
  653.     me.loops.add(tot_loops)
  654.     me.polygons.add(len(faces))
  655.  
  656.     # verts_loc is a list of (x, y, z) tuples
  657.     me.vertices.foreach_set("co", unpack_list(verts_loc))
  658.  
  659.     loops_vert_idx = []
  660.     faces_loop_start = []
  661.     faces_loop_total = []
  662.     lidx = 0
  663.     for f in faces:
  664.         vidx = f[0]
  665.         nbr_vidx = len(vidx)
  666.         loops_vert_idx.extend(vidx)
  667.         faces_loop_start.append(lidx)
  668.         faces_loop_total.append(nbr_vidx)
  669.         lidx += nbr_vidx
  670.  
  671.     me.loops.foreach_set("vertex_index", loops_vert_idx)
  672.     me.polygons.foreach_set("loop_start", faces_loop_start)
  673.     me.polygons.foreach_set("loop_total", faces_loop_total)
  674.  
  675.     if verts_nor and me.loops:
  676.         # Note: we store 'temp' normals in loops, since validate() may alter final mesh,
  677.         #       we can only set custom lnors *after* calling it.
  678.         me.create_normals_split()
  679.  
  680.     if verts_tex and me.polygons:
  681.         me.uv_textures.new()
  682.  
  683.     context_material_old = -1  # avoid a dict lookup
  684.     mat = 0  # rare case it may be un-initialized.
  685.  
  686.     for i, (face, blen_poly) in enumerate(zip(faces, me.polygons)):
  687.         if len(face[0]) < 3:
  688.             raise Exception("bad face")  # Shall not happen, we got rid of those earlier!
  689.  
  690.         (face_vert_loc_indices,
  691.          face_vert_nor_indices,
  692.          face_vert_tex_indices,
  693.          context_material,
  694.          context_smooth_group,
  695.          context_object,
  696.          face_invalid_blenpoly,
  697.          ) = face
  698.  
  699.         if context_smooth_group:
  700.             blen_poly.use_smooth = True
  701.  
  702.         if context_material:
  703.             if context_material_old is not context_material:
  704.                 mat = material_mapping[context_material]
  705.                 context_material_old = context_material
  706.             blen_poly.material_index = mat
  707.  
  708.         if verts_nor and face_vert_nor_indices:
  709.             for face_noidx, lidx in zip(face_vert_nor_indices, blen_poly.loop_indices):
  710.                 me.loops[lidx].normal[:] = verts_nor[0 if (face_noidx is ...) else face_noidx]
  711.  
  712.         if verts_tex and face_vert_tex_indices:
  713.             if context_material:
  714.                 image = unique_material_images[context_material]
  715.                 if image:  # Can be none if the material dosnt have an image.
  716.                     me.uv_textures[0].data[i].image = image
  717.  
  718.             blen_uvs = me.uv_layers[0]
  719.             for face_uvidx, lidx in zip(face_vert_tex_indices, blen_poly.loop_indices):
  720.                 blen_uvs.data[lidx].uv = verts_tex[0 if (face_uvidx is ...) else face_uvidx]
  721.  
  722.     use_edges = use_edges and bool(edges)
  723.     if use_edges:
  724.         me.edges.add(len(edges))
  725.         # edges should be a list of (a, b) tuples
  726.         me.edges.foreach_set("vertices", unpack_list(edges))
  727.  
  728.     me.validate(clean_customdata=False)  # *Very* important to not remove lnors here!
  729.     me.update(calc_edges=use_edges)
  730.  
  731.     # Un-tessellate as much as possible, in case we had to triangulate some ngons...
  732.     if fgon_edges:
  733.         import bmesh
  734.         bm = bmesh.new()
  735.         bm.from_mesh(me)
  736.         verts = bm.verts[:]
  737.         get = bm.edges.get
  738.         edges = [get((verts[vidx1], verts[vidx2])) for vidx1, vidx2 in fgon_edges]
  739.         try:
  740.             bmesh.ops.dissolve_edges(bm, edges=edges, use_verts=False)
  741.         except:
  742.             # Possible dissolve fails for some edges, but don't fail silently in case this is a real bug.
  743.             import traceback
  744.             traceback.print_exc()
  745.  
  746.         bm.to_mesh(me)
  747.         bm.free()
  748.  
  749.     # XXX If validate changes the geometry, this is likely to be broken...
  750.     if unique_smooth_groups and sharp_edges:
  751.         for e in me.edges:
  752.             if e.key in sharp_edges:
  753.                 e.use_edge_sharp = True
  754.         me.show_edge_sharp = True
  755.  
  756.     if verts_nor:
  757.         clnors = array.array('f', [0.0] * (len(me.loops) * 3))
  758.         me.loops.foreach_get("normal", clnors)
  759.  
  760.         if not unique_smooth_groups:
  761.             me.polygons.foreach_set("use_smooth", [True] * len(me.polygons))
  762.  
  763.         me.normals_split_custom_set(tuple(zip(*(iter(clnors),) * 3)))
  764.         me.use_auto_smooth = True
  765.         me.show_edge_sharp = True
  766.  
  767.     ob = bpy.data.objects.new(me.name, me)
  768.     new_objects.append(ob)
  769.  
  770.     # Create the vertex groups. No need to have the flag passed here since we test for the
  771.     # content of the vertex_groups. If the user selects to NOT have vertex groups saved then
  772.     # the following test will never run
  773.     for group_name, group_indices in vertex_groups.items():
  774.         group = ob.vertex_groups.new(group_name.decode('utf-8', "replace"))
  775.         group.add(group_indices, 1.0, 'REPLACE')
  776.  
  777.  
  778. def create_nurbs(context_nurbs, vert_loc, new_objects):
  779.     """
  780.    Add nurbs object to blender, only support one type at the moment
  781.    """
  782.     deg = context_nurbs.get(b'deg', (3,))
  783.     curv_range = context_nurbs.get(b'curv_range')
  784.     curv_idx = context_nurbs.get(b'curv_idx', [])
  785.     parm_u = context_nurbs.get(b'parm_u', [])
  786.     parm_v = context_nurbs.get(b'parm_v', [])
  787.     name = context_nurbs.get(b'name', b'ObjNurb')
  788.     cstype = context_nurbs.get(b'cstype')
  789.  
  790.     if cstype is None:
  791.         print('\tWarning, cstype not found')
  792.         return
  793.     if cstype != b'bspline':
  794.         print('\tWarning, cstype is not supported (only bspline)')
  795.         return
  796.     if not curv_idx:
  797.         print('\tWarning, curv argument empty or not set')
  798.         return
  799.     if len(deg) > 1 or parm_v:
  800.         print('\tWarning, surfaces not supported')
  801.         return
  802.  
  803.     cu = bpy.data.curves.new(name.decode('utf-8', "replace"), 'CURVE')
  804.     cu.dimensions = '3D'
  805.  
  806.     nu = cu.splines.new('NURBS')
  807.     nu.points.add(len(curv_idx) - 1)  # a point is added to start with
  808.     nu.points.foreach_set("co", [co_axis for vt_idx in curv_idx for co_axis in (vert_loc[vt_idx] + (1.0,))])
  809.  
  810.     nu.order_u = deg[0] + 1
  811.  
  812.     # get for endpoint flag from the weighting
  813.     if curv_range and len(parm_u) > deg[0] + 1:
  814.         do_endpoints = True
  815.         for i in range(deg[0] + 1):
  816.  
  817.             if abs(parm_u[i] - curv_range[0]) > 0.0001:
  818.                 do_endpoints = False
  819.                 break
  820.  
  821.             if abs(parm_u[-(i + 1)] - curv_range[1]) > 0.0001:
  822.                 do_endpoints = False
  823.                 break
  824.  
  825.     else:
  826.         do_endpoints = False
  827.  
  828.     if do_endpoints:
  829.         nu.use_endpoint_u = True
  830.  
  831.     # close
  832.     '''
  833.    do_closed = False
  834.    if len(parm_u) > deg[0]+1:
  835.        for i in xrange(deg[0]+1):
  836.            #print curv_idx[i], curv_idx[-(i+1)]
  837.  
  838.            if curv_idx[i]==curv_idx[-(i+1)]:
  839.                do_closed = True
  840.                break
  841.  
  842.    if do_closed:
  843.        nu.use_cyclic_u = True
  844.    '''
  845.  
  846.     ob = bpy.data.objects.new(name.decode('utf-8', "replace"), cu)
  847.  
  848.     new_objects.append(ob)
  849.  
  850.  
  851. def strip_slash(line_split):
  852.     if line_split[-1][-1] == 92:  # '\' char
  853.         if len(line_split[-1]) == 1:
  854.             line_split.pop()  # remove the \ item
  855.         else:
  856.             line_split[-1] = line_split[-1][:-1]  # remove the \ from the end last number
  857.         return True
  858.     return False
  859.  
  860.  
  861. def get_float_func(filepath):
  862.     """
  863.    find the float function for this obj file
  864.    - whether to replace commas or not
  865.    """
  866.     file = open(filepath, 'rb')
  867.     for line in file:  # .readlines():
  868.         line = line.lstrip()
  869.         if line.startswith(b'v'):  # vn vt v
  870.             if b',' in line:
  871.                 file.close()
  872.                 return lambda f: float(f.replace(b',', b'.'))
  873.             elif b'.' in line:
  874.                 file.close()
  875.                 return float
  876.  
  877.     file.close()
  878.     # in case all vert values were ints
  879.     return float
  880.  
  881.  
  882. def load(context,
  883.          filepath,
  884.          *,
  885.          global_clamp_size=0.0,
  886.          use_smooth_groups=True,
  887.          use_edges=True,
  888.          use_split_objects=True,
  889.          use_split_groups=True,
  890.          use_image_search=True,
  891.          use_groups_as_vgroups=False,
  892.          relpath=None,
  893.          global_matrix=None
  894.          ):
  895.     """
  896.    Called by the user interface or another script.
  897.    load_obj(path) - should give acceptable results.
  898.    This function passes the file and sends the data off
  899.        to be split into objects and then converted into mesh objects
  900.    """
  901.  
  902.     def handle_vec(line_start, context_multi_line, line_split, tag, data, vec, vec_len):
  903.         ret_context_multi_line = tag if strip_slash(line_split) else b''
  904.         if line_start == tag:
  905.             vec[:] = [float_func(v) for v in line_split[1:]]
  906.         elif context_multi_line == tag:
  907.             vec += [float_func(v) for v in line_split]
  908.         if not ret_context_multi_line:
  909.             data.append(tuple(vec[:vec_len]))
  910.         return ret_context_multi_line
  911.  
  912.     def create_face(context_material, context_smooth_group, context_object):
  913.         face_vert_loc_indices = []
  914.         face_vert_nor_indices = []
  915.         face_vert_tex_indices = []
  916.         return (
  917.             face_vert_loc_indices,
  918.             face_vert_nor_indices,
  919.             face_vert_tex_indices,
  920.             context_material,
  921.             context_smooth_group,
  922.             context_object,
  923.             [],  # If non-empty, that face is a Blender-invalid ngon (holes...), need a mutable object for that...
  924.         )
  925.  
  926.     with ProgressReport(context.window_manager) as progress:
  927.         progress.enter_substeps(1, "Importing OBJ %r..." % filepath)
  928.  
  929.         if global_matrix is None:
  930.             global_matrix = mathutils.Matrix()
  931.  
  932.         if use_split_objects or use_split_groups:
  933.             use_groups_as_vgroups = False
  934.  
  935.         time_main = time.time()
  936.  
  937.         verts_loc = []
  938.         verts_nor = []
  939.         verts_tex = []
  940.         faces = []  # tuples of the faces
  941.         material_libs = set()  # filenames to material libs this OBJ uses
  942.         vertex_groups = {}  # when use_groups_as_vgroups is true
  943.  
  944.         # Get the string to float conversion func for this file- is 'float' for almost all files.
  945.         float_func = get_float_func(filepath)
  946.  
  947.         # Context variables
  948.         context_material = None
  949.         context_smooth_group = None
  950.         context_object = None
  951.         context_vgroup = None
  952.  
  953.         # Nurbs
  954.         context_nurbs = {}
  955.         nurbs = []
  956.         context_parm = b''  # used by nurbs too but could be used elsewhere
  957.  
  958.         # Until we can use sets
  959.         unique_materials = {}
  960.         unique_material_images = {}
  961.         unique_smooth_groups = {}
  962.         # unique_obects= {} - no use for this variable since the objects are stored in the face.
  963.  
  964.         # when there are faces that end with \
  965.         # it means they are multiline-
  966.         # since we use xreadline we cant skip to the next line
  967.         # so we need to know whether
  968.         context_multi_line = b''
  969.  
  970.         # Per-face handling data.
  971.         face_vert_loc_indices = None
  972.         face_vert_nor_indices = None
  973.         face_vert_tex_indices = None
  974.         face_vert_nor_valid = face_vert_tex_valid = False
  975.         face_items_usage = set()
  976.         face_invalid_blenpoly = None
  977.         prev_vidx = None
  978.         face = None
  979.         vec = []
  980.  
  981.         progress.enter_substeps(3, "Parsing OBJ file...")
  982.         with open(filepath, 'rb') as f:
  983.             for line in f:  # .readlines():
  984.                 line_split = line.split()
  985.  
  986.                 if not line_split:
  987.                     continue
  988.  
  989.                 line_start = line_split[0]  # we compare with this a _lot_
  990.  
  991.                 if line_start == b'v' or context_multi_line == b'v':
  992.                     context_multi_line = handle_vec(line_start, context_multi_line, line_split, b'v', verts_loc, vec, 3)
  993.  
  994.                 elif line_start == b'vn' or context_multi_line == b'vn':
  995.                     context_multi_line = handle_vec(line_start, context_multi_line, line_split, b'vn', verts_nor, vec, 3)
  996.  
  997.                 elif line_start == b'vt' or context_multi_line == b'vt':
  998.                     context_multi_line = handle_vec(line_start, context_multi_line, line_split, b'vt', verts_tex, vec, 2)
  999.  
  1000.                 # Handle faces lines (as faces) and the second+ lines of fa multiline face here
  1001.                 # use 'f' not 'f ' because some objs (very rare have 'fo ' for faces)
  1002.                 elif line_start == b'f' or context_multi_line == b'f':
  1003.                     if not context_multi_line:
  1004.                         line_split = line_split[1:]
  1005.                         # Instantiate a face
  1006.                         face = create_face(context_material, context_smooth_group, context_object)
  1007.                         (face_vert_loc_indices, face_vert_nor_indices, face_vert_tex_indices,
  1008.                          _1, _2, _3, face_invalid_blenpoly) = face
  1009.                         faces.append(face)
  1010.                         face_items_usage.clear()
  1011.                     # Else, use face_vert_loc_indices and face_vert_tex_indices previously defined and used the obj_face
  1012.  
  1013.                     context_multi_line = b'f' if strip_slash(line_split) else b''
  1014.  
  1015.                     for v in line_split:
  1016.                         obj_vert = v.split(b'/')
  1017.                         idx = int(obj_vert[0]) - 1
  1018.                         vert_loc_index = (idx + len(verts_loc) + 1) if (idx < 0) else idx
  1019.                         # Add the vertex to the current group
  1020.                         # *warning*, this wont work for files that have groups defined around verts
  1021.                         if use_groups_as_vgroups and context_vgroup:
  1022.                             vertex_groups[context_vgroup].append(vert_loc_index)
  1023.                         # This a first round to quick-detect ngons that *may* use a same edge more than once.
  1024.                         # Potential candidate will be re-checked once we have done parsing the whole face.
  1025.                         if not face_invalid_blenpoly:
  1026.                             # If we use more than once a same vertex, invalid ngon is suspected.
  1027.                             if vert_loc_index in face_items_usage:
  1028.                                 face_invalid_blenpoly.append(True)
  1029.                             else:
  1030.                                 face_items_usage.add(vert_loc_index)
  1031.                         face_vert_loc_indices.append(vert_loc_index)
  1032.  
  1033.                         # formatting for faces with normals and textures is
  1034.                         # loc_index/tex_index/nor_index
  1035.                         if len(obj_vert) > 1 and obj_vert[1] and obj_vert[1] != b'0':
  1036.                             idx = int(obj_vert[1]) - 1
  1037.                             face_vert_tex_indices.append((idx + len(verts_tex) + 1) if (idx < 0) else idx)
  1038.                             face_vert_tex_valid = True
  1039.                         else:
  1040.                             face_vert_tex_indices.append(...)
  1041.  
  1042.                         if len(obj_vert) > 2 and obj_vert[2] and obj_vert[2] != b'0':
  1043.                             idx = int(obj_vert[2]) - 1
  1044.                             face_vert_nor_indices.append((idx + len(verts_nor) + 1) if (idx < 0) else idx)
  1045.                             face_vert_nor_valid = True
  1046.                         else:
  1047.                             face_vert_nor_indices.append(...)
  1048.  
  1049.                     if not context_multi_line:
  1050.                         # Clear nor/tex indices in case we had none defined for this face.
  1051.                         if not face_vert_nor_valid:
  1052.                             face_vert_nor_indices.clear()
  1053.                         if not face_vert_tex_valid:
  1054.                             face_vert_tex_indices.clear()
  1055.                         face_vert_nor_valid = face_vert_tex_valid = False
  1056.  
  1057.                         # Means we have finished a face, we have to do final check if ngon is suspected to be blender-invalid...
  1058.                         if face_invalid_blenpoly:
  1059.                             face_invalid_blenpoly.clear()
  1060.                             face_items_usage.clear()
  1061.                             prev_vidx = face_vert_loc_indices[-1]
  1062.                             for vidx in face_vert_loc_indices:
  1063.                                 edge_key = (prev_vidx, vidx) if (prev_vidx < vidx) else (vidx, prev_vidx)
  1064.                                 if edge_key in face_items_usage:
  1065.                                     face_invalid_blenpoly.append(True)
  1066.                                     break
  1067.                                 face_items_usage.add(edge_key)
  1068.                                 prev_vidx = vidx
  1069.  
  1070.                 elif use_edges and (line_start == b'l' or context_multi_line == b'l'):
  1071.                     # very similar to the face load function above with some parts removed
  1072.                     if not context_multi_line:
  1073.                         line_split = line_split[1:]
  1074.                         # Instantiate a face
  1075.                         face = create_face(context_material, context_smooth_group, context_object)
  1076.                         face_vert_loc_indices = face[0]
  1077.                         # XXX A bit hackish, we use special 'value' of face_vert_nor_indices (a single True item) to tag this
  1078.                         #     as a polyline, and not a regular face...
  1079.                         face[1][:] = [True]
  1080.                         faces.append(face)
  1081.                     # Else, use face_vert_loc_indices previously defined and used the obj_face
  1082.  
  1083.                     context_multi_line = b'l' if strip_slash(line_split) else b''
  1084.  
  1085.                     for v in line_split:
  1086.                         obj_vert = v.split(b'/')
  1087.                         idx = int(obj_vert[0]) - 1
  1088.                         face_vert_loc_indices.append((idx + len(verts_loc) + 1) if (idx < 0) else idx)
  1089.  
  1090.                 elif line_start == b's':
  1091.                     if use_smooth_groups:
  1092.                         context_smooth_group = line_value(line_split)
  1093.                         if context_smooth_group == b'off':
  1094.                             context_smooth_group = None
  1095.                         elif context_smooth_group:  # is not None
  1096.                             unique_smooth_groups[context_smooth_group] = None
  1097.  
  1098.                 elif line_start == b'o':
  1099.                     if use_split_objects:
  1100.                         context_object = line_value(line_split)
  1101.                         # unique_obects[context_object]= None
  1102.  
  1103.                 elif line_start == b'g':
  1104.                     if use_split_groups:
  1105.                         context_object = line_value(line.split())
  1106.                         # print 'context_object', context_object
  1107.                         # unique_obects[context_object]= None
  1108.                     elif use_groups_as_vgroups:
  1109.                         context_vgroup = line_value(line.split())
  1110.                         if context_vgroup and context_vgroup != b'(null)':
  1111.                             vertex_groups.setdefault(context_vgroup, [])
  1112.                         else:
  1113.                             context_vgroup = None  # dont assign a vgroup
  1114.  
  1115.                 elif line_start == b'usemtl':
  1116.                     context_material = line_value(line.split())
  1117.                     unique_materials[context_material] = None
  1118.                 elif line_start == b'mtllib':  # usemap or usemat
  1119.                     # can have multiple mtllib filenames per line, mtllib can appear more than once,
  1120.                     # so make sure only occurrence of material exists
  1121.                     material_libs |= {os.fsdecode(f) for f in line.split()[1:]}
  1122.  
  1123.                     # Nurbs support
  1124.                 elif line_start == b'cstype':
  1125.                     context_nurbs[b'cstype'] = line_value(line.split())  # 'rat bspline' / 'bspline'
  1126.                 elif line_start == b'curv' or context_multi_line == b'curv':
  1127.                     curv_idx = context_nurbs[b'curv_idx'] = context_nurbs.get(b'curv_idx', [])  # in case were multiline
  1128.  
  1129.                     if not context_multi_line:
  1130.                         context_nurbs[b'curv_range'] = float_func(line_split[1]), float_func(line_split[2])
  1131.                         line_split[0:3] = []  # remove first 3 items
  1132.  
  1133.                     if strip_slash(line_split):
  1134.                         context_multi_line = b'curv'
  1135.                     else:
  1136.                         context_multi_line = b''
  1137.  
  1138.                     for i in line_split:
  1139.                         vert_loc_index = int(i) - 1
  1140.  
  1141.                         if vert_loc_index < 0:
  1142.                             vert_loc_index = len(verts_loc) + vert_loc_index + 1
  1143.  
  1144.                         curv_idx.append(vert_loc_index)
  1145.  
  1146.                 elif line_start == b'parm' or context_multi_line == b'parm':
  1147.                     if context_multi_line:
  1148.                         context_multi_line = b''
  1149.                     else:
  1150.                         context_parm = line_split[1]
  1151.                         line_split[0:2] = []  # remove first 2
  1152.  
  1153.                     if strip_slash(line_split):
  1154.                         context_multi_line = b'parm'
  1155.                     else:
  1156.                         context_multi_line = b''
  1157.  
  1158.                     if context_parm.lower() == b'u':
  1159.                         context_nurbs.setdefault(b'parm_u', []).extend([float_func(f) for f in line_split])
  1160.                     elif context_parm.lower() == b'v':  # surfaces not supported yet
  1161.                         context_nurbs.setdefault(b'parm_v', []).extend([float_func(f) for f in line_split])
  1162.                     # else: # may want to support other parm's ?
  1163.  
  1164.                 elif line_start == b'deg':
  1165.                     context_nurbs[b'deg'] = [int(i) for i in line.split()[1:]]
  1166.                 elif line_start == b'end':
  1167.                     # Add the nurbs curve
  1168.                     if context_object:
  1169.                         context_nurbs[b'name'] = context_object
  1170.                     nurbs.append(context_nurbs)
  1171.                     context_nurbs = {}
  1172.                     context_parm = b''
  1173.  
  1174.                 ''' # How to use usemap? depricated?
  1175.                elif line_start == b'usema': # usemap or usemat
  1176.                    context_image= line_value(line_split)
  1177.                '''
  1178.  
  1179.         progress.step("Done, loading materials and images...")
  1180.  
  1181.         create_materials(filepath, relpath, material_libs, unique_materials,
  1182.                          unique_material_images, use_image_search, float_func)
  1183.  
  1184.         progress.step("Done, building geometries (verts:%i faces:%i materials: %i smoothgroups:%i) ..." %
  1185.                       (len(verts_loc), len(faces), len(unique_materials), len(unique_smooth_groups)))
  1186.  
  1187.         # deselect all
  1188.         if bpy.ops.object.select_all.poll():
  1189.             bpy.ops.object.select_all(action='DESELECT')
  1190.  
  1191.         scene = context.scene
  1192.         new_objects = []  # put new objects here
  1193.  
  1194.         # Split the mesh by objects/materials, may
  1195.         SPLIT_OB_OR_GROUP = bool(use_split_objects or use_split_groups)
  1196.  
  1197.         for data in split_mesh(verts_loc, faces, unique_materials, filepath, SPLIT_OB_OR_GROUP):
  1198.             verts_loc_split, faces_split, unique_materials_split, dataname, use_vnor, use_vtex = data
  1199.             # Create meshes from the data, warning 'vertex_groups' wont support splitting
  1200.             #~ print(dataname, use_vnor, use_vtex)
  1201.             create_mesh(new_objects,
  1202.                         use_edges,
  1203.                         verts_loc_split,
  1204.                         verts_nor if use_vnor else [],
  1205.                         verts_tex if use_vtex else [],
  1206.                         faces_split,
  1207.                         unique_materials_split,
  1208.                         unique_material_images,
  1209.                         unique_smooth_groups,
  1210.                         vertex_groups,
  1211.                         dataname,
  1212.                         )
  1213.  
  1214.         # nurbs support
  1215.         for context_nurbs in nurbs:
  1216.             create_nurbs(context_nurbs, verts_loc, new_objects)
  1217.  
  1218.         # Create new obj
  1219.         for obj in new_objects:
  1220.             base = scene.objects.link(obj)
  1221.             base.select = True
  1222.  
  1223.             # we could apply this anywhere before scaling.
  1224.             obj.matrix_world = global_matrix
  1225.  
  1226.         scene.update()
  1227.  
  1228.         axis_min = [1000000000] * 3
  1229.         axis_max = [-1000000000] * 3
  1230.  
  1231.         if global_clamp_size:
  1232.             # Get all object bounds
  1233.             for ob in new_objects:
  1234.                 for v in ob.bound_box:
  1235.                     for axis, value in enumerate(v):
  1236.                         if axis_min[axis] > value:
  1237.                             axis_min[axis] = value
  1238.                         if axis_max[axis] < value:
  1239.                             axis_max[axis] = value
  1240.  
  1241.             # Scale objects
  1242.             max_axis = max(axis_max[0] - axis_min[0], axis_max[1] - axis_min[1], axis_max[2] - axis_min[2])
  1243.             scale = 1
  1244.  
  1245.             while global_clamp_size < max_axis * scale:
  1246.                 scale = scale / 10.0
  1247.  
  1248.             for obj in new_objects:
  1249.                 obj.scale = scale, scale, scale
  1250.  
  1251.         for obj in new_objects:
  1252.             obj.scale = 0.01, 0.01, 0.01
  1253.             obj.rotation_euler = 0, 0, 0
  1254.  
  1255.         progress.leave_substeps("Done.")
  1256.         progress.leave_substeps("Finished importing: %r" % filepath)
  1257.  
  1258.     return {'FINISHED'}
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement