Fixed branch for Blender 3.6 release #104626
@ -157,7 +157,7 @@ def sane_name(name):
|
||||
new_name = new_name_clean + '.%.3d' % i
|
||||
i += 1
|
||||
|
||||
# note, appending the 'str' version.
|
||||
# note, appending the 'str' version
|
||||
name_unique.append(new_name)
|
||||
name_mapping[name] = new_name = new_name.encode("ASCII", "replace")
|
||||
return new_name
|
||||
@ -166,14 +166,13 @@ def sane_name(name):
|
||||
def uv_key(uv):
|
||||
return round(uv[0], 6), round(uv[1], 6)
|
||||
|
||||
# size defines:
|
||||
# size defines
|
||||
SZ_SHORT = 2
|
||||
SZ_INT = 4
|
||||
SZ_FLOAT = 4
|
||||
|
||||
class _3ds_ushort(object):
|
||||
"""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***"""
|
||||
"""Class representing a short (2-byte integer) for a 3ds file."""
|
||||
__slots__ = ("value", )
|
||||
|
||||
def __init__(self, val=0):
|
||||
@ -308,7 +307,7 @@ class _3ds_float_color(object):
|
||||
return 3 * SZ_FLOAT
|
||||
|
||||
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):
|
||||
return '{%f, %f, %f}' % (self.r, self.g, self.b)
|
||||
@ -342,9 +341,7 @@ class _3ds_face(object):
|
||||
def get_size(self):
|
||||
return 4 * SZ_SHORT
|
||||
|
||||
# no need to validate every face vert. the oversized array will
|
||||
# catch this problem
|
||||
|
||||
# no need to validate every face vert, the oversized array will catch this problem
|
||||
def write(self, file):
|
||||
# The last short is used for face flags
|
||||
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 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"
|
||||
|
||||
def __init__(self):
|
||||
self.values = []
|
||||
self.size = SZ_SHORT
|
||||
|
||||
# add an item:
|
||||
# add an item
|
||||
def add(self, item):
|
||||
self.values.append(item)
|
||||
self.size += item.get_size()
|
||||
@ -380,7 +376,7 @@ class _3ds_array(object):
|
||||
value.write(file)
|
||||
|
||||
# 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):
|
||||
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.
|
||||
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,
|
||||
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
|
||||
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))
|
||||
mat_sub.add_subchunk(rgb)
|
||||
|
||||
# store all textures for this mapto in order. This at least is what
|
||||
# the 3DS exporter did so far, afaik most readers will just skip
|
||||
# over 2nd textures.
|
||||
# store all textures for this mapto in order. This at least is what the
|
||||
# 3DS exporter did so far, afaik most readers will just skip over 2nd textures
|
||||
for slot in texslots:
|
||||
if slot.image is not None:
|
||||
add_texslot(slot)
|
||||
@ -685,9 +680,9 @@ def make_material_chunk(material, image):
|
||||
primary_tex = False
|
||||
|
||||
if wrap.base_color_texture:
|
||||
d_pct = 0.7 + sum(wrap.base_color[:]) * 0.1
|
||||
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:
|
||||
material_chunk.add_subchunk(matmap)
|
||||
primary_tex = True
|
||||
@ -729,8 +724,8 @@ def make_material_chunk(material, image):
|
||||
material_chunk.add_subchunk(matmap)
|
||||
|
||||
if wrap.emission_color_texture:
|
||||
e_pct = wrap.emission_strength
|
||||
emission = [wrap.emission_color_texture]
|
||||
e_pct = wrap.emission_strength
|
||||
matmap = make_material_texture_chunk(MAT_SELFIMAP, emission, e_pct)
|
||||
if 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
|
||||
there are multiple uv coordinates per vertex."""
|
||||
|
||||
# initialize a list of UniqueLists, one per vertex:
|
||||
# uv_list = [UniqueList() for i in xrange(len(verts))]
|
||||
# initialize a list of UniqueLists, one per vertex
|
||||
unique_uvs = [{} for i in range(len(verts))]
|
||||
|
||||
# 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]]
|
||||
uvkey = tri.faceuvs[i]
|
||||
|
||||
offset_index__uv_3ds = context_uv_vert.get(uvkey)
|
||||
|
||||
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]
|
||||
|
||||
# At this point, each vertex has a UniqueList containing every uv coordinate that is associated with it
|
||||
# only once.
|
||||
|
||||
# At this point, each vertex has a UniqueList containing every uv coordinate associated with it only once
|
||||
# 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_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
|
||||
uvmap = [None] * len(unique_uvs[i])
|
||||
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)
|
||||
# add the uv coordinate to the uv array:
|
||||
# This for loop does not give uv's ordered by ii, so we create a new map
|
||||
# and add the uv's later
|
||||
# add the uv coordinate to the uv array, this for loop does not give
|
||||
# uv's ordered by ii, so we create a new map and add the uv's later
|
||||
# uv_array.add(uv_3ds)
|
||||
uvmap[ii] = uv_3ds
|
||||
|
||||
# Add the uv's in the correct order
|
||||
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)
|
||||
|
||||
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 i in range(3):
|
||||
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):
|
||||
"""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)
|
||||
|
||||
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)
|
||||
else:
|
||||
# Add the vertices to the vertex array:
|
||||
# Add the vertices to the vertex array
|
||||
vert_array = _3ds_array()
|
||||
for vert in mesh.vertices:
|
||||
vert_array.add(_3ds_point_3d(vert.co))
|
||||
# no UV at all:
|
||||
# no UV at all
|
||||
uv_array = None
|
||||
|
||||
# create the chunk:
|
||||
# create the chunk
|
||||
mesh_chunk = _3ds_chunk(OBJECT_MESH)
|
||||
|
||||
# add vertex chunk:
|
||||
# add vertex chunk
|
||||
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))
|
||||
|
||||
# if available, add uv chunk:
|
||||
# if available, add uv chunk
|
||||
if 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():
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
|
||||
# Initialize the main chunk (primary):
|
||||
# Initialize the main chunk (primary)
|
||||
primary = _3ds_chunk(PRIMARY)
|
||||
|
||||
# Add version chunk:
|
||||
# Add version chunk
|
||||
version_chunk = _3ds_chunk(VERSION)
|
||||
version_chunk.add_variable("version", _3ds_uint(3))
|
||||
primary.add_subchunk(version_chunk)
|
||||
|
||||
# Init main object info chunk:
|
||||
# Init main object info chunk
|
||||
object_info = _3ds_chunk(OBJECTINFO)
|
||||
mesh_version = _3ds_chunk(MESHVERSION)
|
||||
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,
|
||||
# each material is added once):
|
||||
# each material is added once)
|
||||
materialDict = {}
|
||||
mesh_objects = []
|
||||
|
||||
@ -1270,7 +1260,7 @@ def save(operator,
|
||||
ma_ls = data.materials
|
||||
ma_ls_len = len(ma_ls)
|
||||
|
||||
# get material/image tuples.
|
||||
# get material/image tuples
|
||||
if data.uv_layers:
|
||||
if not ma_ls:
|
||||
ma = ma_name = None
|
||||
@ -1291,7 +1281,7 @@ def save(operator,
|
||||
|
||||
else:
|
||||
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))
|
||||
|
||||
# Why 0 Why!
|
||||
@ -1300,14 +1290,14 @@ def save(operator,
|
||||
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():
|
||||
object_info.add_subchunk(make_material_chunk(ma_image[0], ma_image[1]))
|
||||
|
||||
# Collect translation for transformation matrix
|
||||
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 = {}
|
||||
|
||||
for ob, data, matrix in mesh_objects:
|
||||
@ -1318,7 +1308,7 @@ def save(operator,
|
||||
translation[ob.name] = ob.location
|
||||
# name_to_id[ob.name]= len(name_to_id)
|
||||
|
||||
# Create object chunks for all meshes:
|
||||
# Create object chunks for all meshes
|
||||
i = 0
|
||||
for ob, mesh, matrix in mesh_objects:
|
||||
# create a new object chunk
|
||||
@ -1327,12 +1317,11 @@ def save(operator,
|
||||
# set the object 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))
|
||||
|
||||
# ensure the mesh has no over sized arrays
|
||||
# skip ones that do!, otherwise we cant write since the array size wont
|
||||
# fit into USHORT.
|
||||
# Ensure the mesh has no over sized arrays, skip ones that do!
|
||||
# Otherwise we cant write since the array size wont fit into USHORT
|
||||
if object_chunk.validate():
|
||||
object_info.add_subchunk(object_chunk)
|
||||
else:
|
||||
@ -1345,7 +1334,7 @@ def save(operator,
|
||||
|
||||
i += i
|
||||
|
||||
# Create chunks for all empties:
|
||||
# Create chunks for all empties
|
||||
''' # COMMENTED OUT FOR 2.42 RELEASE!! CRASHES 3DS MAX
|
||||
for ob in empty_objects:
|
||||
# Empties only require a kf object node:
|
||||
@ -1408,7 +1397,7 @@ def save(operator,
|
||||
object_chunk.add_subchunk(camera_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)
|
||||
|
||||
''' # COMMENTED OUT FOR 2.42 RELEASE!! CRASHES 3DS MAX
|
||||
@ -1416,27 +1405,27 @@ def save(operator,
|
||||
primary.add_subchunk(kfdata)
|
||||
'''
|
||||
|
||||
# At this point, the chunk hierarchy is completely built.
|
||||
# Check the size:
|
||||
# At this point, the chunk hierarchy is completely built
|
||||
# Check the size
|
||||
primary.get_size()
|
||||
|
||||
# Open the file for writing:
|
||||
# Open the file for writing
|
||||
file = open(filepath, 'wb')
|
||||
|
||||
# Recursively write the chunks to file:
|
||||
# Recursively write the chunks to file
|
||||
primary.write(file)
|
||||
|
||||
# Close the file:
|
||||
# Close the file
|
||||
file.close()
|
||||
|
||||
# Clear name mapping vars, could make locals too
|
||||
del name_unique[:]
|
||||
name_mapping.clear()
|
||||
|
||||
# Debugging only: report the exporting time:
|
||||
# Debugging only: report the exporting time
|
||||
print("3ds export time: %.2f" % (time.time() - duration))
|
||||
|
||||
# Debugging only: dump the chunk hierarchy:
|
||||
# Debugging only: dump the chunk hierarchy
|
||||
# primary.dump()
|
||||
|
||||
return {'FINISHED'}
|
||||
|
Loading…
Reference in New Issue
Block a user