Skip to content

Commit

Permalink
Merge pull request #78 from Grim-es/feature/76
Browse files Browse the repository at this point in the history
Pressing Save Atlas To re-selects all materials #76
  • Loading branch information
Grim-es authored Jul 23, 2023
2 parents 6572858 + d1c1867 commit 55a235d
Show file tree
Hide file tree
Showing 10 changed files with 161 additions and 119 deletions.
2 changes: 1 addition & 1 deletion __init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
'name': "Shotariya's Material Combiner",
'description': 'Public Release Material Combiner 2',
'author': 'shotariya',
'version': (2, 1, 2, 7),
'version': (2, 1, 2, 8),
'blender': (2, 80, 0),
'location': 'View3D',
# 'warning': '',
Expand Down
2 changes: 1 addition & 1 deletion addon_updater.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ def __init__(self):
self._error_msg = None
self._prefiltered_tag_count = 0

# UI code only, ie not used within this module but still useful
# UI code only, i.e., not used within this module but still useful
# properties to have

# to verify a valid import, in place of placeholder import
Expand Down
45 changes: 30 additions & 15 deletions extend_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,22 @@
class CombineList(bpy.types.PropertyGroup):
ob = PointerProperty(
name='Current Object',
type=bpy.types.Object)
type=bpy.types.Object,
)
ob_id = IntProperty(default=0)
mat = PointerProperty(
name='Current Object Material',
type=bpy.types.Material)
type=bpy.types.Material,
)
layer = IntProperty(
name='Material Layers',
description='Materials with the same number will be merged together.'
'\nUse this to create multiple materials linked to the same atlas file',
min=1,
max=99,
step=1,
default=1)
default=1,
)
used = BoolProperty(default=True)
type = IntProperty(default=0)

Expand Down Expand Up @@ -75,71 +79,82 @@ def register() -> None:
('STRICTCUST', 'Strict Custom', 'Combined image has exact custom width and height'),
],
description='Select atlas size',
default='QUAD')
default='QUAD',
)
bpy.types.Scene.smc_size_width = IntProperty(
name='Max width (px)',
description='Select max width for combined image',
min=8,
max=8192,
step=1,
default=4096)
default=4096,
)
bpy.types.Scene.smc_size_height = IntProperty(
name='Max height (px)',
description='Select max height for combined image',
min=8,
max=8192,
step=1,
default=4096)
default=4096,
)
bpy.types.Scene.smc_crop = BoolProperty(
name='Crop outside images by UV',
description='Crop images by UV if materials UV outside of bounds',
default=True
default=True,
)
bpy.types.Scene.smc_diffuse_size = IntProperty(
name='Size of materials without image',
description='Select the size of materials that only consist of a color',
min=8,
max=256,
step=1,
default=32)
default=32,
)
bpy.types.Scene.smc_gaps = IntProperty(
name='Size of gaps between images',
description='Select size of gaps between images',
min=0,
max=32,
step=200,
default=0,
options={'HIDDEN'})
options={'HIDDEN'},
)
bpy.types.Scene.smc_save_path = StringProperty(
description='Select the directory in which the generated texture atlas will be saved',
default='')
default='',
)

bpy.types.Material.root_mat = PointerProperty(
name='Material Root',
type=bpy.types.Material)
type=bpy.types.Material,
)
bpy.types.Material.smc_diffuse = BoolProperty(
name='Multiply image with diffuse color',
description='Multiply the materials image with its diffuse color.'
'\nINFO: If this color is white the final image will be the same',
default=True)
default=True,
)
bpy.types.Material.smc_size = BoolProperty(
name='Custom image size',
description='Select the max size for this materials image in the texture atlas',
default=False)
default=False,
)
bpy.types.Material.smc_size_width = IntProperty(
name='Max width (px)',
description='Select max width for material image',
min=8,
max=8192,
step=1,
default=2048)
default=2048,
)
bpy.types.Material.smc_size_height = IntProperty(
name='Max height (px)',
description='Select max height for material image',
min=8,
max=8192,
step=1,
default=2048)
default=2048,
)


def unregister() -> None:
Expand Down
84 changes: 45 additions & 39 deletions operators/combiner/combiner_ops.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,15 +88,15 @@ def get_data(data: Sequence[bpy.types.PropertyGroup]) -> SMCObData:


def get_mats_uv(scn: Scene, data: SMCObData) -> MatsUV:
mats_uv = {}
mats_uv = defaultdict(lambda: defaultdict(list))
for ob_n, item in data.items():
ob = scn.objects[ob_n]
mats_uv[ob_n] = defaultdict(list)
for idx, polys in get_polys(ob).items():
mat = ob.data.materials[idx]
if mat in item:
for poly in polys:
mats_uv[ob_n][mat].extend(align_uv(get_uv(ob, poly)))
if mat not in item:
continue
for poly in polys:
mats_uv[ob_n][mat].extend(align_uv(get_uv(ob, poly)))
return mats_uv


Expand All @@ -119,7 +119,7 @@ def _delete_material(ob: bpy.types.Object, mat_name: str) -> None:


def get_duplicates(mats_uv: MatsUV) -> None:
mat_list = set(chain.from_iterable(mats_uv.values()))
mat_list = list(chain.from_iterable(mats_uv.values()))
sorted_mat_list = sort_materials(mat_list)
for mats in sorted_mat_list:
root_mat = mats[0]
Expand All @@ -128,28 +128,28 @@ def get_duplicates(mats_uv: MatsUV) -> None:


def get_structure(scn: Scene, data: SMCObData, mats_uv: MatsUV) -> Structure:
structure = {}
structure = defaultdict(lambda: {
'gfx': {
'img_or_color': None,
'size': (),
'uv_size': ()
},
'dup': [],
'ob': [],
'uv': []
})

for ob_n, item in data.items():
ob = scn.objects[ob_n]
for mat in item:
if mat.name in ob.data.materials:
root_mat = mat.root_mat or mat
if root_mat not in structure:
structure[root_mat] = {
'gfx': {
'img_or_color': None,
'size': (),
'uv_size': ()
},
'dup': [],
'ob': [],
'uv': []
}
if mat.root_mat and mat.name not in structure[root_mat]['dup']:
structure[root_mat]['dup'].append(mat.name)
if ob.name not in structure[root_mat]['ob']:
structure[root_mat]['ob'].append(ob.name)
structure[root_mat]['uv'].extend(mats_uv[ob_n][mat])
if mat.name not in ob.data.materials:
continue
root_mat = mat.root_mat or mat
if mat.root_mat and mat.name not in structure[root_mat]['dup']:
structure[root_mat]['dup'].append(mat.name)
if ob.name not in structure[root_mat]['ob']:
structure[root_mat]['ob'].append(ob.name)
structure[root_mat]['uv'].extend(mats_uv[ob_n][mat])
return structure


Expand Down Expand Up @@ -283,11 +283,13 @@ def _set_image_or_color(item: StructureItem, mat: bpy.types.Material) -> None:


def _paste_gfx(scn: Scene, item: StructureItem, mat: bpy.types.Material, img: ImageType, half_gaps: int) -> None:
if item['gfx']['fit']:
img.paste(
_get_gfx(scn, mat, item, item['gfx']['img_or_color']),
(int(item['gfx']['fit']['x'] + half_gaps), int(item['gfx']['fit']['y'] + half_gaps))
)
if not item['gfx']['fit']:
return

img.paste(
_get_gfx(scn, mat, item, item['gfx']['img_or_color']),
(int(item['gfx']['fit']['x'] + half_gaps), int(item['gfx']['fit']['y'] + half_gaps))
)


def _get_gfx(scn: Scene, mat: bpy.types.Material, item: StructureItem,
Expand Down Expand Up @@ -403,10 +405,12 @@ def _get_unique_id(scn: Scene) -> str:
def _add_its_from_existing_materials(scn: Scene, existed_ids: Set[int]) -> None:
atlas_material_pattern = re.compile(r'{0}(\d+)_\d+'.format(atlas_material_prefix))
for item in scn.smc_ob_data:
if item.type == globs.CL_MATERIAL:
match = atlas_material_pattern.fullmatch(item.mat.name)
if match:
existed_ids.add(int(match.group(1)))
if item.type != globs.CL_MATERIAL:
continue

match = atlas_material_pattern.fullmatch(item.mat.name)
if match:
existed_ids.add(int(match.group(1)))


def _generate_random_unique_id(existed_ids: Set[int]) -> str:
Expand Down Expand Up @@ -487,11 +491,13 @@ def _assign_mats(item: SMCObDataItem, comb_mats: CombMats, ob_materials: ObMats)

def _assign_mats_to_polys(item: SMCObDataItem, comb_mats: CombMats, ob: bpy.types.Object, ob_materials: ObMats) -> None:
for idx, polys in get_polys(ob).items():
if ob_materials[idx] in item:
mat_name = comb_mats[item[ob_materials[idx]]].name
mat_idx = ob_materials.find(mat_name)
for poly in polys:
poly.material_index = mat_idx
if ob_materials[idx] not in item:
continue

mat_name = comb_mats[item[ob_materials[idx]]].name
mat_idx = ob_materials.find(mat_name)
for poly in polys:
poly.material_index = mat_idx


def clear_mats(scn: Scene, mats_uv: MatsUV) -> None:
Expand Down
2 changes: 1 addition & 1 deletion operators/get-pip.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ def cert_parse_args(self, args):

# We want to support people passing things like 'pip<8' to get-pip.py which
# will let them install a specific version. However, because of the dreaded
# DoubleRequirement error if any of the args look like they might be a
# DoubleRequirement error, if any of the args look like they might be a
# specific for one of our packages, then we'll turn off the implicit
# installation of them.
for arg in args:
Expand Down
Loading

0 comments on commit 55a235d

Please sign in to comment.