Fixed branch for Blender 3.6 release #104626
@ -157,7 +157,7 @@ def sane_name(name):
|
|||||||
new_name = new_name_clean + '.%.3d' % i
|
new_name = new_name_clean + '.%.3d' % i
|
||||||
i += 1
|
i += 1
|
||||||
|
|
||||||
# note, appending the 'str' version.
|
# note, appending the 'str' version
|
||||||
name_unique.append(new_name)
|
name_unique.append(new_name)
|
||||||
name_mapping[name] = new_name = new_name.encode("ASCII", "replace")
|
name_mapping[name] = new_name = new_name.encode("ASCII", "replace")
|
||||||
return new_name
|
return new_name
|
||||||
@ -166,14 +166,13 @@ def sane_name(name):
|
|||||||
def uv_key(uv):
|
def uv_key(uv):
|
||||||
return round(uv[0], 6), round(uv[1], 6)
|
return round(uv[0], 6), round(uv[1], 6)
|
||||||
|
|
||||||
# size defines:
|
# size defines
|
||||||
SZ_SHORT = 2
|
SZ_SHORT = 2
|
||||||
SZ_INT = 4
|
SZ_INT = 4
|
||||||
SZ_FLOAT = 4
|
SZ_FLOAT = 4
|
||||||
|
|
||||||
class _3ds_ushort(object):
|
class _3ds_ushort(object):
|
||||||
"""Class representing a short (2-byte integer) for a 3ds file.
|
"""Class representing a short (2-byte integer) for a 3ds file."""
|
||||||
*** This looks like an unsigned short H is unsigned from the struct docs - Cam***"""
|
|
||||||
__slots__ = ("value", )
|
__slots__ = ("value", )
|
||||||
|
|
||||||
def __init__(self, val=0):
|
def __init__(self, val=0):
|
||||||
@ -308,7 +307,7 @@ class _3ds_float_color(object):
|
|||||||
return 3 * SZ_FLOAT
|
return 3 * SZ_FLOAT
|
||||||
|
|
||||||
def write(self, file):
|
def write(self, file):
|
||||||
file.write(struct.pack('3f', self.r, self.g, self.b))
|
file.write(struct.pack('<3f', self.r, self.g, self.b))
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return '{%f, %f, %f}' % (self.r, self.g, self.b)
|
return '{%f, %f, %f}' % (self.r, self.g, self.b)
|
||||||
@ -342,9 +341,7 @@ class _3ds_face(object):
|
|||||||
def get_size(self):
|
def get_size(self):
|
||||||
return 4 * SZ_SHORT
|
return 4 * SZ_SHORT
|
||||||
|
|
||||||
# no need to validate every face vert. the oversized array will
|
# no need to validate every face vert, the oversized array will catch this problem
|
||||||
# catch this problem
|
|
||||||
|
|
||||||
def write(self, file):
|
def write(self, file):
|
||||||
# The last short is used for face flags
|
# The last short is used for face flags
|
||||||
file.write(struct.pack('<4H', self.vindex[0], self.vindex[1], self.vindex[2], self.flag))
|
file.write(struct.pack('<4H', self.vindex[0], self.vindex[1], self.vindex[2], self.flag))
|
||||||
@ -355,15 +352,14 @@ class _3ds_face(object):
|
|||||||
|
|
||||||
class _3ds_array(object):
|
class _3ds_array(object):
|
||||||
"""Class representing an array of variables for a 3ds file.
|
"""Class representing an array of variables for a 3ds file.
|
||||||
Consists of a _3ds_ushort to indicate the number of items, followed by the items themselves.
|
Consists of a _3ds_ushort to indicate the number of items, followed by the items themselves."""
|
||||||
"""
|
|
||||||
__slots__ = "values", "size"
|
__slots__ = "values", "size"
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.values = []
|
self.values = []
|
||||||
self.size = SZ_SHORT
|
self.size = SZ_SHORT
|
||||||
|
|
||||||
# add an item:
|
# add an item
|
||||||
def add(self, item):
|
def add(self, item):
|
||||||
self.values.append(item)
|
self.values.append(item)
|
||||||
self.size += item.get_size()
|
self.size += item.get_size()
|
||||||
@ -380,7 +376,7 @@ class _3ds_array(object):
|
|||||||
value.write(file)
|
value.write(file)
|
||||||
|
|
||||||
# To not overwhelm the output in a dump, a _3ds_array only
|
# To not overwhelm the output in a dump, a _3ds_array only
|
||||||
# outputs the number of items, not all of the actual items.
|
# outputs the number of items, not all of the actual items
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return '(%d items)' % len(self.values)
|
return '(%d items)' % len(self.values)
|
||||||
|
|
||||||
@ -583,7 +579,7 @@ def make_material_texture_chunk(chunk_id, texslots, pct):
|
|||||||
0x40 activates alpha source, 0x80 activates tinting, 0x100 ignores alpha, 0x200 activates RGB tint.
|
0x40 activates alpha source, 0x80 activates tinting, 0x100 ignores alpha, 0x200 activates RGB tint.
|
||||||
Bits 0x80, 0x100, and 0x200 are only used with TEXMAP, TEX2MAP, and SPECMAP chunks.
|
Bits 0x80, 0x100, and 0x200 are only used with TEXMAP, TEX2MAP, and SPECMAP chunks.
|
||||||
0x40, when used with a TEXMAP, TEX2MAP, or SPECMAP chunk must be accompanied with a tint bit,
|
0x40, when used with a TEXMAP, TEX2MAP, or SPECMAP chunk must be accompanied with a tint bit,
|
||||||
either 0x100 or 0x200, tintcolor will be processed if colorchunks are present"""
|
either 0x100 or 0x200, tintcolor will be processed if tintflags are present"""
|
||||||
|
|
||||||
mapflags = 0
|
mapflags = 0
|
||||||
if texslot.extension == 'EXTEND':
|
if texslot.extension == 'EXTEND':
|
||||||
@ -632,9 +628,8 @@ def make_material_texture_chunk(chunk_id, texslots, pct):
|
|||||||
rgb.add_variable("mapcolor", _3ds_rgb_color(spec if texslot.socket_dst.identifier == 'Specular' else base))
|
rgb.add_variable("mapcolor", _3ds_rgb_color(spec if texslot.socket_dst.identifier == 'Specular' else base))
|
||||||
mat_sub.add_subchunk(rgb)
|
mat_sub.add_subchunk(rgb)
|
||||||
|
|
||||||
# store all textures for this mapto in order. This at least is what
|
# store all textures for this mapto in order. This at least is what the
|
||||||
# the 3DS exporter did so far, afaik most readers will just skip
|
# 3DS exporter did so far, afaik most readers will just skip over 2nd textures
|
||||||
# over 2nd textures.
|
|
||||||
for slot in texslots:
|
for slot in texslots:
|
||||||
if slot.image is not None:
|
if slot.image is not None:
|
||||||
add_texslot(slot)
|
add_texslot(slot)
|
||||||
@ -685,9 +680,9 @@ def make_material_chunk(material, image):
|
|||||||
primary_tex = False
|
primary_tex = False
|
||||||
|
|
||||||
if wrap.base_color_texture:
|
if wrap.base_color_texture:
|
||||||
d_pct = 0.7 + sum(wrap.base_color[:]) * 0.1
|
|
||||||
color = [wrap.base_color_texture]
|
color = [wrap.base_color_texture]
|
||||||
matmap = make_material_texture_chunk(MAT_DIFFUSEMAP, color, d_pct)
|
c_pct = 0.7 + sum(wrap.base_color[:]) * 0.1
|
||||||
|
matmap = make_material_texture_chunk(MAT_DIFFUSEMAP, color, c_pct)
|
||||||
if matmap:
|
if matmap:
|
||||||
material_chunk.add_subchunk(matmap)
|
material_chunk.add_subchunk(matmap)
|
||||||
primary_tex = True
|
primary_tex = True
|
||||||
@ -729,8 +724,8 @@ def make_material_chunk(material, image):
|
|||||||
material_chunk.add_subchunk(matmap)
|
material_chunk.add_subchunk(matmap)
|
||||||
|
|
||||||
if wrap.emission_color_texture:
|
if wrap.emission_color_texture:
|
||||||
e_pct = wrap.emission_strength
|
|
||||||
emission = [wrap.emission_color_texture]
|
emission = [wrap.emission_color_texture]
|
||||||
|
e_pct = wrap.emission_strength
|
||||||
matmap = make_material_texture_chunk(MAT_SELFIMAP, emission, e_pct)
|
matmap = make_material_texture_chunk(MAT_SELFIMAP, emission, e_pct)
|
||||||
if matmap:
|
if matmap:
|
||||||
material_chunk.add_subchunk(matmap)
|
material_chunk.add_subchunk(matmap)
|
||||||
@ -849,8 +844,7 @@ def remove_face_uv(verts, tri_list):
|
|||||||
need to be converted to vertex uv coordinates. That means that vertices need to be duplicated when
|
need to be converted to vertex uv coordinates. That means that vertices need to be duplicated when
|
||||||
there are multiple uv coordinates per vertex."""
|
there are multiple uv coordinates per vertex."""
|
||||||
|
|
||||||
# initialize a list of UniqueLists, one per vertex:
|
# initialize a list of UniqueLists, one per vertex
|
||||||
# uv_list = [UniqueList() for i in xrange(len(verts))]
|
|
||||||
unique_uvs = [{} for i in range(len(verts))]
|
unique_uvs = [{} for i in range(len(verts))]
|
||||||
|
|
||||||
# for each face uv coordinate, add it to the UniqueList of the vertex
|
# for each face uv coordinate, add it to the UniqueList of the vertex
|
||||||
@ -861,7 +855,6 @@ def remove_face_uv(verts, tri_list):
|
|||||||
|
|
||||||
context_uv_vert = unique_uvs[tri.vertex_index[i]]
|
context_uv_vert = unique_uvs[tri.vertex_index[i]]
|
||||||
uvkey = tri.faceuvs[i]
|
uvkey = tri.faceuvs[i]
|
||||||
|
|
||||||
offset_index__uv_3ds = context_uv_vert.get(uvkey)
|
offset_index__uv_3ds = context_uv_vert.get(uvkey)
|
||||||
|
|
||||||
if not offset_index__uv_3ds:
|
if not offset_index__uv_3ds:
|
||||||
@ -869,11 +862,9 @@ def remove_face_uv(verts, tri_list):
|
|||||||
|
|
||||||
tri.offset[i] = offset_index__uv_3ds[0]
|
tri.offset[i] = offset_index__uv_3ds[0]
|
||||||
|
|
||||||
# At this point, each vertex has a UniqueList containing every uv coordinate that is associated with it
|
# At this point, each vertex has a UniqueList containing every uv coordinate associated with it only once
|
||||||
# only once.
|
|
||||||
|
|
||||||
# Now we need to duplicate every vertex as many times as it has uv coordinates and make sure the
|
# Now we need to duplicate every vertex as many times as it has uv coordinates and make sure the
|
||||||
# faces refer to the new face indices:
|
# faces refer to the new face indices
|
||||||
vert_index = 0
|
vert_index = 0
|
||||||
vert_array = _3ds_array()
|
vert_array = _3ds_array()
|
||||||
uv_array = _3ds_array()
|
uv_array = _3ds_array()
|
||||||
@ -884,22 +875,21 @@ def remove_face_uv(verts, tri_list):
|
|||||||
pt = _3ds_point_3d(vert.co) # reuse, should be ok
|
pt = _3ds_point_3d(vert.co) # reuse, should be ok
|
||||||
uvmap = [None] * len(unique_uvs[i])
|
uvmap = [None] * len(unique_uvs[i])
|
||||||
for ii, uv_3ds in unique_uvs[i].values():
|
for ii, uv_3ds in unique_uvs[i].values():
|
||||||
# add a vertex duplicate to the vertex_array for every uv associated with this vertex:
|
# add a vertex duplicate to the vertex_array for every uv associated with this vertex
|
||||||
vert_array.add(pt)
|
vert_array.add(pt)
|
||||||
# add the uv coordinate to the uv array:
|
# add the uv coordinate to the uv array, this for loop does not give
|
||||||
# This for loop does not give uv's ordered by ii, so we create a new map
|
# uv's ordered by ii, so we create a new map and add the uv's later
|
||||||
# and add the uv's later
|
|
||||||
# uv_array.add(uv_3ds)
|
# uv_array.add(uv_3ds)
|
||||||
uvmap[ii] = uv_3ds
|
uvmap[ii] = uv_3ds
|
||||||
|
|
||||||
# Add the uv's in the correct order
|
# Add the uv's in the correct order
|
||||||
for uv_3ds in uvmap:
|
for uv_3ds in uvmap:
|
||||||
# add the uv coordinate to the uv array:
|
# add the uv coordinate to the uv array
|
||||||
uv_array.add(uv_3ds)
|
uv_array.add(uv_3ds)
|
||||||
|
|
||||||
vert_index += len(unique_uvs[i])
|
vert_index += len(unique_uvs[i])
|
||||||
|
|
||||||
# Make sure the triangle vertex indices now refer to the new vertex list:
|
# Make sure the triangle vertex indices now refer to the new vertex list
|
||||||
for tri in tri_list:
|
for tri in tri_list:
|
||||||
for i in range(3):
|
for i in range(3):
|
||||||
tri.offset[i] += index_list[tri.vertex_index[i]]
|
tri.offset[i] += index_list[tri.vertex_index[i]]
|
||||||
@ -1003,30 +993,30 @@ def make_uv_chunk(uv_array):
|
|||||||
def make_mesh_chunk(ob, mesh, matrix, materialDict, translation):
|
def make_mesh_chunk(ob, mesh, matrix, materialDict, translation):
|
||||||
"""Make a chunk out of a Blender mesh."""
|
"""Make a chunk out of a Blender mesh."""
|
||||||
|
|
||||||
# Extract the triangles from the mesh:
|
# Extract the triangles from the mesh
|
||||||
tri_list = extract_triangles(mesh)
|
tri_list = extract_triangles(mesh)
|
||||||
|
|
||||||
if mesh.uv_layers:
|
if mesh.uv_layers:
|
||||||
# Remove the face UVs and convert it to vertex UV:
|
# Remove the face UVs and convert it to vertex UV
|
||||||
vert_array, uv_array, tri_list = remove_face_uv(mesh.vertices, tri_list)
|
vert_array, uv_array, tri_list = remove_face_uv(mesh.vertices, tri_list)
|
||||||
else:
|
else:
|
||||||
# Add the vertices to the vertex array:
|
# Add the vertices to the vertex array
|
||||||
vert_array = _3ds_array()
|
vert_array = _3ds_array()
|
||||||
for vert in mesh.vertices:
|
for vert in mesh.vertices:
|
||||||
vert_array.add(_3ds_point_3d(vert.co))
|
vert_array.add(_3ds_point_3d(vert.co))
|
||||||
# no UV at all:
|
# no UV at all
|
||||||
uv_array = None
|
uv_array = None
|
||||||
|
|
||||||
# create the chunk:
|
# create the chunk
|
||||||
mesh_chunk = _3ds_chunk(OBJECT_MESH)
|
mesh_chunk = _3ds_chunk(OBJECT_MESH)
|
||||||
|
|
||||||
# add vertex chunk:
|
# add vertex chunk
|
||||||
mesh_chunk.add_subchunk(make_vert_chunk(vert_array))
|
mesh_chunk.add_subchunk(make_vert_chunk(vert_array))
|
||||||
|
|
||||||
# add faces chunk:
|
# add faces chunk
|
||||||
mesh_chunk.add_subchunk(make_faces_chunk(tri_list, mesh, materialDict))
|
mesh_chunk.add_subchunk(make_faces_chunk(tri_list, mesh, materialDict))
|
||||||
|
|
||||||
# if available, add uv chunk:
|
# if available, add uv chunk
|
||||||
if uv_array:
|
if uv_array:
|
||||||
mesh_chunk.add_subchunk(make_uv_chunk(uv_array))
|
mesh_chunk.add_subchunk(make_uv_chunk(uv_array))
|
||||||
|
|
||||||
@ -1200,15 +1190,15 @@ def save(operator,
|
|||||||
if bpy.ops.object.mode_set.poll():
|
if bpy.ops.object.mode_set.poll():
|
||||||
bpy.ops.object.mode_set(mode='OBJECT')
|
bpy.ops.object.mode_set(mode='OBJECT')
|
||||||
|
|
||||||
# Initialize the main chunk (primary):
|
# Initialize the main chunk (primary)
|
||||||
primary = _3ds_chunk(PRIMARY)
|
primary = _3ds_chunk(PRIMARY)
|
||||||
|
|
||||||
# Add version chunk:
|
# Add version chunk
|
||||||
version_chunk = _3ds_chunk(VERSION)
|
version_chunk = _3ds_chunk(VERSION)
|
||||||
version_chunk.add_variable("version", _3ds_uint(3))
|
version_chunk.add_variable("version", _3ds_uint(3))
|
||||||
primary.add_subchunk(version_chunk)
|
primary.add_subchunk(version_chunk)
|
||||||
|
|
||||||
# Init main object info chunk:
|
# Init main object info chunk
|
||||||
object_info = _3ds_chunk(OBJECTINFO)
|
object_info = _3ds_chunk(OBJECTINFO)
|
||||||
mesh_version = _3ds_chunk(MESHVERSION)
|
mesh_version = _3ds_chunk(MESHVERSION)
|
||||||
mesh_version.add_variable("mesh", _3ds_uint(3))
|
mesh_version.add_variable("mesh", _3ds_uint(3))
|
||||||
@ -1233,7 +1223,7 @@ def save(operator,
|
|||||||
'''
|
'''
|
||||||
|
|
||||||
# Make a list of all materials used in the selected meshes (use a dictionary,
|
# Make a list of all materials used in the selected meshes (use a dictionary,
|
||||||
# each material is added once):
|
# each material is added once)
|
||||||
materialDict = {}
|
materialDict = {}
|
||||||
mesh_objects = []
|
mesh_objects = []
|
||||||
|
|
||||||
@ -1270,7 +1260,7 @@ def save(operator,
|
|||||||
ma_ls = data.materials
|
ma_ls = data.materials
|
||||||
ma_ls_len = len(ma_ls)
|
ma_ls_len = len(ma_ls)
|
||||||
|
|
||||||
# get material/image tuples.
|
# get material/image tuples
|
||||||
if data.uv_layers:
|
if data.uv_layers:
|
||||||
if not ma_ls:
|
if not ma_ls:
|
||||||
ma = ma_name = None
|
ma = ma_name = None
|
||||||
@ -1291,7 +1281,7 @@ def save(operator,
|
|||||||
|
|
||||||
else:
|
else:
|
||||||
for ma in ma_ls:
|
for ma in ma_ls:
|
||||||
if ma: # material may be None so check its not.
|
if ma: # material may be None so check its not
|
||||||
materialDict.setdefault((ma.name, None), (ma, None))
|
materialDict.setdefault((ma.name, None), (ma, None))
|
||||||
|
|
||||||
# Why 0 Why!
|
# Why 0 Why!
|
||||||
@ -1300,14 +1290,14 @@ def save(operator,
|
|||||||
f.material_index = 0
|
f.material_index = 0
|
||||||
|
|
||||||
|
|
||||||
# Make material chunks for all materials used in the meshes:
|
# Make material chunks for all materials used in the meshes
|
||||||
for ma_image in materialDict.values():
|
for ma_image in materialDict.values():
|
||||||
object_info.add_subchunk(make_material_chunk(ma_image[0], ma_image[1]))
|
object_info.add_subchunk(make_material_chunk(ma_image[0], ma_image[1]))
|
||||||
|
|
||||||
# Collect translation for transformation matrix
|
# Collect translation for transformation matrix
|
||||||
translation = {}
|
translation = {}
|
||||||
|
|
||||||
# Give all objects a unique ID and build a dictionary from object name to object id:
|
# Give all objects a unique ID and build a dictionary from object name to object id
|
||||||
# name_to_id = {}
|
# name_to_id = {}
|
||||||
|
|
||||||
for ob, data, matrix in mesh_objects:
|
for ob, data, matrix in mesh_objects:
|
||||||
@ -1318,7 +1308,7 @@ def save(operator,
|
|||||||
translation[ob.name] = ob.location
|
translation[ob.name] = ob.location
|
||||||
# name_to_id[ob.name]= len(name_to_id)
|
# name_to_id[ob.name]= len(name_to_id)
|
||||||
|
|
||||||
# Create object chunks for all meshes:
|
# Create object chunks for all meshes
|
||||||
i = 0
|
i = 0
|
||||||
for ob, mesh, matrix in mesh_objects:
|
for ob, mesh, matrix in mesh_objects:
|
||||||
# create a new object chunk
|
# create a new object chunk
|
||||||
@ -1327,12 +1317,11 @@ def save(operator,
|
|||||||
# set the object name
|
# set the object name
|
||||||
object_chunk.add_variable("name", _3ds_string(sane_name(ob.name)))
|
object_chunk.add_variable("name", _3ds_string(sane_name(ob.name)))
|
||||||
|
|
||||||
# make a mesh chunk out of the mesh:
|
# make a mesh chunk out of the mesh
|
||||||
object_chunk.add_subchunk(make_mesh_chunk(ob, mesh, matrix, materialDict, translation))
|
object_chunk.add_subchunk(make_mesh_chunk(ob, mesh, matrix, materialDict, translation))
|
||||||
|
|
||||||
# ensure the mesh has no over sized arrays
|
# Ensure the mesh has no over sized arrays, skip ones that do!
|
||||||
# skip ones that do!, otherwise we cant write since the array size wont
|
# Otherwise we cant write since the array size wont fit into USHORT
|
||||||
# fit into USHORT.
|
|
||||||
if object_chunk.validate():
|
if object_chunk.validate():
|
||||||
object_info.add_subchunk(object_chunk)
|
object_info.add_subchunk(object_chunk)
|
||||||
else:
|
else:
|
||||||
@ -1345,7 +1334,7 @@ def save(operator,
|
|||||||
|
|
||||||
i += i
|
i += i
|
||||||
|
|
||||||
# Create chunks for all empties:
|
# Create chunks for all empties
|
||||||
''' # COMMENTED OUT FOR 2.42 RELEASE!! CRASHES 3DS MAX
|
''' # COMMENTED OUT FOR 2.42 RELEASE!! CRASHES 3DS MAX
|
||||||
for ob in empty_objects:
|
for ob in empty_objects:
|
||||||
# Empties only require a kf object node:
|
# Empties only require a kf object node:
|
||||||
@ -1408,7 +1397,7 @@ def save(operator,
|
|||||||
object_chunk.add_subchunk(camera_chunk)
|
object_chunk.add_subchunk(camera_chunk)
|
||||||
object_info.add_subchunk(object_chunk)
|
object_info.add_subchunk(object_chunk)
|
||||||
|
|
||||||
# Add main object info chunk to primary chunk:
|
# Add main object info chunk to primary chunk
|
||||||
primary.add_subchunk(object_info)
|
primary.add_subchunk(object_info)
|
||||||
|
|
||||||
''' # COMMENTED OUT FOR 2.42 RELEASE!! CRASHES 3DS MAX
|
''' # COMMENTED OUT FOR 2.42 RELEASE!! CRASHES 3DS MAX
|
||||||
@ -1416,27 +1405,27 @@ def save(operator,
|
|||||||
primary.add_subchunk(kfdata)
|
primary.add_subchunk(kfdata)
|
||||||
'''
|
'''
|
||||||
|
|
||||||
# At this point, the chunk hierarchy is completely built.
|
# At this point, the chunk hierarchy is completely built
|
||||||
# Check the size:
|
# Check the size
|
||||||
primary.get_size()
|
primary.get_size()
|
||||||
|
|
||||||
# Open the file for writing:
|
# Open the file for writing
|
||||||
file = open(filepath, 'wb')
|
file = open(filepath, 'wb')
|
||||||
|
|
||||||
# Recursively write the chunks to file:
|
# Recursively write the chunks to file
|
||||||
primary.write(file)
|
primary.write(file)
|
||||||
|
|
||||||
# Close the file:
|
# Close the file
|
||||||
file.close()
|
file.close()
|
||||||
|
|
||||||
# Clear name mapping vars, could make locals too
|
# Clear name mapping vars, could make locals too
|
||||||
del name_unique[:]
|
del name_unique[:]
|
||||||
name_mapping.clear()
|
name_mapping.clear()
|
||||||
|
|
||||||
# Debugging only: report the exporting time:
|
# Debugging only: report the exporting time
|
||||||
print("3ds export time: %.2f" % (time.time() - duration))
|
print("3ds export time: %.2f" % (time.time() - duration))
|
||||||
|
|
||||||
# Debugging only: dump the chunk hierarchy:
|
# Debugging only: dump the chunk hierarchy
|
||||||
# primary.dump()
|
# primary.dump()
|
||||||
|
|
||||||
return {'FINISHED'}
|
return {'FINISHED'}
|
||||||
|
Loading…
Reference in New Issue
Block a user