From 900f66ff11993909faf229ab10bfdebc7ca84b76 Mon Sep 17 00:00:00 2001 From: Banbury Date: Sat, 28 Sep 2013 16:44:00 +0200 Subject: [PATCH 1/5] Fixes for Quads and Smoothing. --- ldraw_import.py | 60 ++++++++++++++++++++++++++++++++++++------------- 1 file changed, 44 insertions(+), 16 deletions(-) diff --git a/ldraw_import.py b/ldraw_import.py index dc7c6b0..185616c 100644 --- a/ldraw_import.py +++ b/ldraw_import.py @@ -70,12 +70,7 @@ def __init__(self, filename, mat, colour = None): if (colour is None): self.material = None else: - if colour in mat_list: - self.ob.data.materials.append(mat_list[colour]) - else: - mat_list[colour] = bpy.data.materials.new('Mat_'+colour+"_") - mat_list[colour].diffuse_color = colors[colour] - self.ob.data.materials.append(mat_list[colour]) + self.ob.data.materials.append(getMaterial(colour)) # Link object to scene bpy.context.scene.objects.link(self.ob) @@ -83,16 +78,16 @@ def __init__(self, filename, mat, colour = None): self.parse(filename) self.me.from_pydata(self.points, [], self.faces) - + + objects.append(self.ob) self.ob.select = True - - objects.append(self.ob) + for i in self.subparts: self.submodels.append(ldraw_file( i[0], i[1], i[2] )) - + def parse_line(self, line): verts = [] -# color = int(line[1]) + color = int(line[1]) num_points = int (( len(line) - 2 ) / 3) #matrix = mathutils.Matrix(mat) for i in range(num_points): @@ -101,6 +96,30 @@ def parse_line(self, line): verts.append(len(self.points)-1) self.faces.append(verts) + def parse_quad(self, line): + color = int(line[1]) + verts = [] + num_points = 4 + v = [] + + v.append(self.mat * mathutils.Vector((float(line[0 * 3 + 2]), float(line[0 * 3 + 3]), float(line[0 * 3 + 4])))) + v.append(self.mat * mathutils.Vector((float(line[1 * 3 + 2]), float(line[1 * 3 + 3]), float(line[1 * 3 + 4])))) + v.append(self.mat * mathutils.Vector((float(line[2 * 3 + 2]), float(line[2 * 3 + 3]), float(line[2 * 3 + 4])))) + v.append(self.mat * mathutils.Vector((float(line[3 * 3 + 2]), float(line[3 * 3 + 3]), float(line[3 * 3 + 4])))) + + nA = (v[1] - v[0]).cross(v[2] - v[0]) + nB = (v[2] - v[1]).cross(v[3] - v[1]) + + for i in range(num_points): + verts.append(len(self.points) + i) + + if (nA.dot(nB) < 0): + self.points.extend([v[0].to_tuple(), v[1].to_tuple(), v[3].to_tuple(), v[2].to_tuple()]) + else: + self.points.extend([v[0].to_tuple(), v[1].to_tuple(), v[2].to_tuple(), v[3].to_tuple()]) + + self.faces.append(verts) + def parse(self, filename): while True: # file_found = True @@ -145,7 +164,7 @@ def parse(self, filename): # Quadrilateral (quad) if tmpdate[0] == "4": - self.parse_line(tmpdate) + self.parse_quad(tmpdate) if len(self.subfiles) > 0: subfile = self.subfiles.pop() filename = subfile[0] @@ -154,6 +173,12 @@ def parse(self, filename): else: break +def getMaterial(colour): + if not (colour in mat_list): + mat_list[colour] = bpy.data.materials.new('Mat_'+colour+"_") + mat_list[colour].diffuse_color = colors[colour] + return mat_list[colour] + # Find the needed parts and add it to the list, so second scan is not necessary # Every last LDraw Brick Library folder added for the ability to import every single brick. @@ -241,14 +266,17 @@ def create_model(self, context): bpy.context.scene.objects.active = cur_obj bpy.ops.object.editmode_toggle() bpy.ops.mesh.select_all(action='SELECT') - bpy.ops.mesh.remove_doubles() + bpy.ops.mesh.remove_doubles(threshold=0.01) bpy.ops.mesh.normals_make_consistent() bpy.ops.object.mode_set(mode='OBJECT') + bpy.ops.object.shade_smooth() bpy.ops.object.mode_set() + m = cur_obj.modifiers.new("edge_split", type='EDGE_SPLIT') + m.split_angle = 0.78539 - except: + except Exception as ex: + print(ex) print("Oops. Something messed up.") - pass print ("Import complete!") @@ -273,7 +301,7 @@ class IMPORT_OT_ldraw(bpy.types.Operator, ImportHelper): cleanupModel = bpy.props.BoolProperty(name="Disable Model Cleanup", description="Does not remove double vertices or make normals consistent.", default=False) - highresBricks = bpy.props.BoolProperty(name="Do Not Use High-res bricks", description="Do not use high-res bricks to import your model.", default=False) + highresBricks = bpy.props.BoolProperty(name="Do Not Use High-res bricks", description="Do not use high-res bricks to import your model.", default=True) #ldraw_path = StringProperty( #name="LDraw Path", From 0e10d1a2562168d1011ab3d5659d20ff4115811d Mon Sep 17 00:00:00 2001 From: Banbury Date: Sat, 28 Sep 2013 19:38:13 +0200 Subject: [PATCH 2/5] Fix for materials for multi-colored bricks and color value 16. --- ldraw_import.py | 66 +++++++++++++++++++++++++++++++++---------------- 1 file changed, 45 insertions(+), 21 deletions(-) diff --git a/ldraw_import.py b/ldraw_import.py index 185616c..ce4a330 100644 --- a/ldraw_import.py +++ b/ldraw_import.py @@ -31,6 +31,7 @@ "category": "Import-Export"} import os, sys, math, mathutils +import traceback import bpy from bpy_extras.io_utils import ImportHelper @@ -52,9 +53,9 @@ class ldraw_file(object): def __init__(self, filename, mat, colour = None): - self.subfiles = [] self.points = [] self.faces = [] + self.material_index = [] self.subparts = [] self.submodels = [] self.part_count = 0 @@ -78,6 +79,15 @@ def __init__(self, filename, mat, colour = None): self.parse(filename) self.me.from_pydata(self.points, [], self.faces) + + for i, f in enumerate(self.me.polygons): + n = self.material_index[i] + mat = getMaterial(n) + + if self.me.materials.get(mat.name) == None: + self.me.materials.append(mat) + + f.material_index = self.me.materials.find(mat.name) objects.append(self.ob) self.ob.select = True @@ -87,7 +97,11 @@ def __init__(self, filename, mat, colour = None): def parse_line(self, line): verts = [] - color = int(line[1]) + color = line[1] + + if color == '16': + color = self.colour + num_points = int (( len(line) - 2 ) / 3) #matrix = mathutils.Matrix(mat) for i in range(num_points): @@ -95,13 +109,17 @@ def parse_line(self, line): to_tuple()) verts.append(len(self.points)-1) self.faces.append(verts) + self.material_index.append(color) def parse_quad(self, line): - color = int(line[1]) + color = line[1] verts = [] num_points = 4 v = [] + if color == '16': + color = self.colour + v.append(self.mat * mathutils.Vector((float(line[0 * 3 + 2]), float(line[0 * 3 + 3]), float(line[0 * 3 + 4])))) v.append(self.mat * mathutils.Vector((float(line[1 * 3 + 2]), float(line[1 * 3 + 3]), float(line[1 * 3 + 4])))) v.append(self.mat * mathutils.Vector((float(line[2 * 3 + 2]), float(line[2 * 3 + 3]), float(line[2 * 3 + 4])))) @@ -119,21 +137,23 @@ def parse_quad(self, line): self.points.extend([v[0].to_tuple(), v[1].to_tuple(), v[2].to_tuple(), v[3].to_tuple()]) self.faces.append(verts) + self.material_index.append(color) def parse(self, filename): + subfiles = [] + while True: # file_found = True try: f_in = open(filename) except: try: - finds = locate(filename) - isPart = finds[1] - f_in = open(finds[0]) + fname, isPart = locate(filename) + f_in = open(fname) except: - print("File not found: ",filename) -# file_found = False - self.part_count = self.part_count + 1 + print("File not found: ", filename) + + self.part_count += 1 if self.part_count > 1 and isPart: self.subparts.append([filename, self.mat, self.colour]) else: @@ -156,7 +176,11 @@ def parse(self, filename): x, y, z, a, b, c, d, e, f, g, h, i = map(float, tmpdate[2:14]) # mat_new = self.mat * mathutils.Matrix( [[a, d, g, 0], [b, e, h, 0], [c, f, i, 0], [x, y, z, 1]] ) mat_new = self.mat * mathutils.Matrix(((a, b, c, x), (d, e, f, y), (g, h, i, z), (0, 0, 0, 1))) - self.subfiles.append([new_file, mat_new, tmpdate[1]]) + + color = tmpdate[1] + if color == '16': + color = self.colour + subfiles.append([new_file, mat_new, color]) # Triangle (tri) if tmpdate[0] == "3": @@ -165,8 +189,9 @@ def parse(self, filename): # Quadrilateral (quad) if tmpdate[0] == "4": self.parse_quad(tmpdate) - if len(self.subfiles) > 0: - subfile = self.subfiles.pop() + + if len(subfiles) > 0: + subfile = subfiles.pop() filename = subfile[0] self.mat = subfile[1] self.colour = subfile[2] @@ -174,10 +199,12 @@ def parse(self, filename): break def getMaterial(colour): - if not (colour in mat_list): - mat_list[colour] = bpy.data.materials.new('Mat_'+colour+"_") - mat_list[colour].diffuse_color = colors[colour] - return mat_list[colour] + if colour in colors: + if not (colour in mat_list): + mat_list[colour] = bpy.data.materials.new('Mat_'+colour+"_") + mat_list[colour].diffuse_color = colors[colour] + return mat_list[colour] + return mat_list['0'] # Find the needed parts and add it to the list, so second scan is not necessary @@ -185,7 +212,6 @@ def getMaterial(colour): def locate(pattern): '''Locate all files matching supplied filename pattern in and below supplied root directory.''' - finds = [] fname = pattern.replace('\\', os.path.sep) isPart = False if str.lower(os.path.split(fname)[0]) == 's' : @@ -231,9 +257,7 @@ def locate(pattern): print("Could not find file %s" % fname) return - finds.append(fname) - finds.append(isPart) - return finds + return (fname, isPart) # Create the actual model def create_model(self, context): @@ -275,7 +299,7 @@ def create_model(self, context): m.split_angle = 0.78539 except Exception as ex: - print(ex) + print (traceback.format_exc()) print("Oops. Something messed up.") print ("Import complete!") From 7b3fa09ee387786f102e74ad4f40875c06e226f5 Mon Sep 17 00:00:00 2001 From: Banbury Date: Sat, 28 Sep 2013 23:55:02 +0200 Subject: [PATCH 3/5] Added support for transparent colors. --- ldraw_import.py | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/ldraw_import.py b/ldraw_import.py index ce4a330..6ba3e05 100644 --- a/ldraw_import.py +++ b/ldraw_import.py @@ -32,6 +32,7 @@ import os, sys, math, mathutils import traceback +from struct import unpack import bpy from bpy_extras.io_utils import ImportHelper @@ -201,8 +202,15 @@ def parse(self, filename): def getMaterial(colour): if colour in colors: if not (colour in mat_list): + print(colors[colour]) mat_list[colour] = bpy.data.materials.new('Mat_'+colour+"_") - mat_list[colour].diffuse_color = colors[colour] + mat_list[colour].diffuse_color = colors[colour]['color'] + + alpha = colors[colour]['alpha'] + if alpha < 1.0: + mat_list[colour].use_transparency = True + mat_list[colour].alpha = alpha + return mat_list[colour] return mat_list['0'] @@ -279,9 +287,11 @@ def create_model(self, context): if len(line) > 3 : if line[2:4].lower() == '!c': line_split = line.split() - print(line, 'color ', line_split[4], 'code ', line_split[6][1:]) - colors[line_split[4]] = [float(int(line_split[6][1:3], 16)) / 255.0, float (int( line_split[6][3:5], 16)) / 255.0, float - (int(line_split[6][5:7], 16)) / 255.0] + #print(line, 'color ', line_split[4], 'code ', line_split[6][1:]) + name = line_split[4] + colors[name] = {'color': hex_to_rgb(line_split[6][1:]), 'alpha': 1.0} + if len(line_split) > 10 and line_split[9] == 'ALPHA': + colors[name]['alpha'] = int(line_split[10]) / 255.0 model = ldraw_file(file_name, mat) # Removes doubles and recalculate normals in each brick. Model is super high-poly without it. @@ -308,6 +318,10 @@ def get_path(self, context): print(self) print(context) +def hex_to_rgb(rgb_str): + int_tuple = unpack('BBB', bytes.fromhex(rgb_str)) + return tuple([val/255 for val in int_tuple]) + #----------------- Operator ------------------------------------------- class IMPORT_OT_ldraw(bpy.types.Operator, ImportHelper): '''LDraw Importer Operator''' From 0257dad2c16e2cd63874bbb80d699c5cc19612f9 Mon Sep 17 00:00:00 2001 From: Banbury Date: Sun, 29 Sep 2013 12:42:57 +0200 Subject: [PATCH 4/5] Several bugfixes and optimizations. --- ldraw_import.py | 79 ++++++++++++++++++++++++++----------------------- 1 file changed, 42 insertions(+), 37 deletions(-) diff --git a/ldraw_import.py b/ldraw_import.py index 6ba3e05..d3abfac 100644 --- a/ldraw_import.py +++ b/ldraw_import.py @@ -63,35 +63,31 @@ def __init__(self, filename, mat, colour = None): self.mat = mat self.colour = colour - self.me = bpy.data.meshes.new('LDrawMesh') - self.ob = bpy.data.objects.new('LDrawObj', self.me) - self.ob.name = os.path.basename(filename) - - self.ob.location = (0,0,0) - - if (colour is None): - self.material = None - else: - self.ob.data.materials.append(getMaterial(colour)) - - # Link object to scene - bpy.context.scene.objects.link(self.ob) - self.parse(filename) - self.me.from_pydata(self.points, [], self.faces) + if len(self.points) > 0 and len(self.faces) > 0: + me = bpy.data.meshes.new('LDrawMesh') + me.from_pydata(self.points, [], self.faces) + me.validate() + me.update() - for i, f in enumerate(self.me.polygons): - n = self.material_index[i] - mat = getMaterial(n) - - if self.me.materials.get(mat.name) == None: - self.me.materials.append(mat) + for i, f in enumerate(me.polygons): + n = self.material_index[i] + mat = getMaterial(n) + + if me.materials.get(mat.name) == None: + me.materials.append(mat) + + f.material_index = me.materials.find(mat.name) + + self.ob = bpy.data.objects.new('LDrawObj', me) + self.ob.name = os.path.basename(filename) - f.material_index = self.me.materials.find(mat.name) + self.ob.location = (0,0,0) - objects.append(self.ob) - self.ob.select = True + objects.append(self.ob) + # Link object to scene + bpy.context.scene.objects.link(self.ob) for i in self.subparts: self.submodels.append(ldraw_file( i[0], i[1], i[2] )) @@ -154,12 +150,14 @@ def parse(self, filename): except: print("File not found: ", filename) + if f_in != None: + lines = f_in.readlines() + f_in.close() + self.part_count += 1 if self.part_count > 1 and isPart: self.subparts.append([filename, self.mat, self.colour]) else: - lines = f_in.readlines() - f_in.close() for retval in lines: tmpdate = retval.strip() if tmpdate != '': @@ -202,7 +200,6 @@ def parse(self, filename): def getMaterial(colour): if colour in colors: if not (colour in mat_list): - print(colors[colour]) mat_list[colour] = bpy.data.materials.new('Mat_'+colour+"_") mat_list[colour].diffuse_color = colors[colour]['color'] @@ -210,7 +207,7 @@ def getMaterial(colour): if alpha < 1.0: mat_list[colour].use_transparency = True mat_list[colour].alpha = alpha - + return mat_list[colour] return mat_list['0'] @@ -269,6 +266,7 @@ def locate(pattern): # Create the actual model def create_model(self, context): + global objects file_name = self.filepath print(file_name) try: @@ -297,16 +295,23 @@ def create_model(self, context): # Removes doubles and recalculate normals in each brick. Model is super high-poly without it. if not CleanUp: for cur_obj in objects: + cur_obj.select = True bpy.context.scene.objects.active = cur_obj - bpy.ops.object.editmode_toggle() - bpy.ops.mesh.select_all(action='SELECT') - bpy.ops.mesh.remove_doubles(threshold=0.01) - bpy.ops.mesh.normals_make_consistent() - bpy.ops.object.mode_set(mode='OBJECT') - bpy.ops.object.shade_smooth() - bpy.ops.object.mode_set() - m = cur_obj.modifiers.new("edge_split", type='EDGE_SPLIT') - m.split_angle = 0.78539 + if bpy.ops.object.mode_set.poll(): + bpy.ops.object.mode_set(mode='EDIT') + bpy.ops.mesh.select_all(action='SELECT') + bpy.ops.mesh.remove_doubles(threshold=0.01) + bpy.ops.mesh.normals_make_consistent() + if bpy.ops.object.mode_set.poll(): + bpy.ops.object.mode_set(mode='OBJECT') + bpy.ops.object.shade_smooth() + bpy.ops.object.mode_set() + m = cur_obj.modifiers.new("edge_split", type='EDGE_SPLIT') + m.split_angle = 0.78539 + cur_obj.select = False + + context.scene.update() + objects = [] except Exception as ex: print (traceback.format_exc()) From 0ea94223296d3b5ff1464e04e7bac0e1149fd628 Mon Sep 17 00:00:00 2001 From: Banbury Date: Sun, 29 Sep 2013 14:24:37 +0200 Subject: [PATCH 5/5] Fix for crash when importing a second time during the same session. The cause were global variables which weren't properly initialized. --- ldraw_import.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/ldraw_import.py b/ldraw_import.py index d3abfac..ee43533 100644 --- a/ldraw_import.py +++ b/ldraw_import.py @@ -40,7 +40,6 @@ # Global variables -file_list = {} mat_list = {} colors = {} scale = 1.0 @@ -267,6 +266,9 @@ def locate(pattern): # Create the actual model def create_model(self, context): global objects + global colors + global mat_list + file_name = self.filepath print(file_name) try: @@ -281,6 +283,8 @@ def create_model(self, context): ldconfig_lines = ldconfig.readlines() ldconfig.close() + colors = {} + mat_list = {} for line in ldconfig_lines: if len(line) > 3 : if line[2:4].lower() == '!c':