Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6d564c26bc | |||
| d02e72dd80 | |||
|
|
1d23946c1d | ||
| cde365759a | |||
| 78c1b78488 | |||
| c68d02dc50 | |||
|
|
bd885f1b99 |
Binary file not shown.
BIN
Blender/L1960_Tools/_Release/L1960_Tools_1_8_3.zip
Normal file
BIN
Blender/L1960_Tools/_Release/L1960_Tools_1_8_3.zip
Normal file
Binary file not shown.
BIN
Blender/L1960_Tools/_Release/L1960_Tools_1_8_4.zip
Normal file
BIN
Blender/L1960_Tools/_Release/L1960_Tools_1_8_4.zip
Normal file
Binary file not shown.
@@ -0,0 +1,333 @@
|
||||
import bpy
|
||||
import math
|
||||
import csv
|
||||
import os
|
||||
import json
|
||||
from mathutils import Vector
|
||||
|
||||
### GENRATE MLOD ###
|
||||
|
||||
plugin_dir = bpy.utils.user_resource('SCRIPTS')
|
||||
plugin_path = "addons\L1960Tools"
|
||||
L1960_path = os.path.join(plugin_dir, plugin_path)
|
||||
|
||||
colorpalettes = [
|
||||
json.dumps(["ColorPalette_01.png", "BF1BC94A0DE4398F"]),
|
||||
json.dumps(["ColorPalette_02.png", "A95B2794A0EE8340"])
|
||||
]
|
||||
|
||||
enum_palettes = []
|
||||
for palettes in colorpalettes:
|
||||
file = json.loads(palettes)[0]
|
||||
enum_palettes.append((palettes, file[:-4], "Select " + file[:-4] + " for MLOD"))
|
||||
|
||||
class EnumColorPalettes(bpy.types.PropertyGroup):
|
||||
mlod_enum_selection: bpy.props.EnumProperty(name="Color Palettes for MLOD", items = enum_palettes, description = "Choose a palette", default = 0)
|
||||
|
||||
class MESH_OT_set_up_mlod(bpy.types.Operator):
|
||||
"""Set´s up a material to be used for MLOD´s"""
|
||||
|
||||
bl_idname = "mesh.set_up_mlod"
|
||||
bl_label = "Set´s up a material to be used for MLOD´s"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def execute(self, context):
|
||||
|
||||
#Load Color Palettes
|
||||
self.import_palettes_textures()
|
||||
|
||||
#Selected Mesh
|
||||
obj = bpy.context.active_object
|
||||
|
||||
if obj not in bpy.context.selected_objects or obj.type != "MESH":
|
||||
self.report({'WARNING'}, 'Select a Mesh to continue')
|
||||
return {"CANCELLED"}
|
||||
|
||||
arr_layers = obj.data.uv_layers
|
||||
if not arr_layers.get("MLOD") or len(arr_layers) > 1:
|
||||
for uv_layer in reversed(arr_layers):
|
||||
arr_layers.remove(uv_layer)
|
||||
arr_layers.new(name = 'MLOD')
|
||||
|
||||
if not len(obj.data.materials) == 0:
|
||||
obj.data.materials.clear()
|
||||
|
||||
palette_enum_selection = json.loads(context.scene.color_palettes.mlod_enum_selection)
|
||||
mlod_material_name = "MLOD_" + palette_enum_selection[0][:-4] + "_" + palette_enum_selection[1]
|
||||
|
||||
if not bpy.data.materials.get(mlod_material_name):
|
||||
material = bpy.data.materials.new(name=mlod_material_name)
|
||||
material.use_nodes = True
|
||||
bsdf_node = material.node_tree.nodes["Principled BSDF"]
|
||||
texImage = material.node_tree.nodes.new('ShaderNodeTexImage')
|
||||
texImage.image = bpy.data.images.get(palette_enum_selection[0])
|
||||
|
||||
material.node_tree.links.new(bsdf_node.inputs['Base Color'], texImage.outputs['Color'])
|
||||
|
||||
obj.data.materials.append(bpy.data.materials.get(mlod_material_name))
|
||||
|
||||
self.report({'INFO'}, 'Mesh configured like MLOD')
|
||||
return {"FINISHED"}
|
||||
|
||||
def import_palettes_textures(self):
|
||||
for image_name in colorpalettes:
|
||||
image_name = json.loads(image_name)[0]
|
||||
texture_name = image_name.split(".")[0]
|
||||
if texture_name not in bpy.data.textures:
|
||||
texture = bpy.data.textures.new(name=texture_name, type='IMAGE')
|
||||
else:
|
||||
texture = bpy.data.textures.get(texture_name)
|
||||
if image_name not in bpy.data.images:
|
||||
image = bpy.data.images.load(os.path.join(L1960_path, image_name))
|
||||
else:
|
||||
image = bpy.data.images.get(image_name)
|
||||
texture.image = image
|
||||
|
||||
# texture_filepath = os.path.join(L1960_path, colorpalettes[1])
|
||||
|
||||
### Palette MLOD ###
|
||||
# class MESH_OT_bake_basic_mlod(bpy.types.Operator):
|
||||
# """Set´s up a basic MLOD via Bake"""
|
||||
|
||||
# bl_idname = "mesh.bake_basic_mlod"
|
||||
# bl_label = "Set´s up a basic MLOD via Bake"
|
||||
# bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
# def execute(self, context):
|
||||
# obj = context.active_object
|
||||
|
||||
# #Palette selection
|
||||
# palette_enum_selection = json.loads(context.scene.color_palettes.mlod_enum_selection)
|
||||
|
||||
# if obj not in bpy.context.selected_objects or obj.type != "MESH":
|
||||
# self.report({'WARNING'}, 'Select a Mesh to continue')
|
||||
# return {"CANCELLED"}
|
||||
|
||||
# faces_with_color = self.get_faces_with_color(obj)
|
||||
|
||||
# grouped_colors = self.groupe_colors(faces_with_color, threshold=50)
|
||||
|
||||
# matched_colors = self.find_matching_color(grouped_colors, palette_enum_selection[0][:-4])
|
||||
|
||||
# self.adjust_UV(obj, matched_colors)
|
||||
|
||||
# #Entfernen des referenz Bake Image
|
||||
# #bpy.data.images.remove(bpy.data.images["MLOD_Temp"])
|
||||
|
||||
# # Entfernen aller Meterials
|
||||
# if not len(obj.data.materials) == 0:
|
||||
# obj.data.materials.clear()
|
||||
|
||||
# # Create new Material with selected Palette
|
||||
# mlod_material_name = "MLOD_" + palette_enum_selection[0][:-4] + palette_enum_selection[1]
|
||||
|
||||
# texture_filepath = os.path.join(L1960_path, palette_enum_selection[0])
|
||||
# image = bpy.data.images.load(texture_filepath)
|
||||
|
||||
# if not bpy.data.materials.get(mlod_material_name):
|
||||
# material = bpy.data.materials.new(name=mlod_material_name)
|
||||
# material.use_nodes = True
|
||||
# bsdf_node = material.node_tree.nodes["Principled BSDF"]
|
||||
# texImage = material.node_tree.nodes.new('ShaderNodeTexImage')
|
||||
# texImage.image = image
|
||||
# material.node_tree.links.new(bsdf_node.inputs['Base Color'], texImage.outputs['Color'])
|
||||
# obj.data.materials.append(bpy.data.materials.get(mlod_material_name))
|
||||
|
||||
# self.report({'INFO'}, f'MLOD sucessfully created with {palette_enum_selection[0][:-4]}.')
|
||||
# return {"FINISHED"}
|
||||
|
||||
# def get_faces_with_color(self, obj):
|
||||
|
||||
# #Bake Image
|
||||
# image = self.bake_diffuse(obj)
|
||||
|
||||
# mesh = obj.data
|
||||
# uv_layer = mesh.uv_layers.active.data # direct UV access
|
||||
|
||||
# colors = []
|
||||
|
||||
# for poly in mesh.polygons: # same as "face" in BMesh
|
||||
# # Durchschnittliche UV-Koordinaten berechnen
|
||||
# uv = Vector((0.0, 0.0))
|
||||
# for loop_index in poly.loop_indices:
|
||||
# uv += uv_layer[loop_index].uv
|
||||
# uv /= len(poly.loop_indices)
|
||||
|
||||
# # UV → Pixel-Koordinaten (Bildgröße)
|
||||
# x = int(uv.x * (image.size[0] - 1))
|
||||
# y = int(uv.y * (image.size[1] - 1))
|
||||
|
||||
# # RGBA Pixel holen
|
||||
# index = (y * image.size[0] + x) * 4
|
||||
# pixel = image.pixels[index:index+4]
|
||||
|
||||
# # In 0–255 Werte umwandeln
|
||||
# rgb_255 = [round(c * 255) for c in pixel][:3]
|
||||
|
||||
# colors.append({
|
||||
# "face": poly.index,
|
||||
# "rgb": rgb_255
|
||||
# })
|
||||
|
||||
# # print(colors[-1]) # -> [{'face': <BMFace(0x000002B417086A30), index=0, totverts=4>, 'rgb': [0, 0, 0]}]
|
||||
|
||||
# return colors
|
||||
|
||||
# def groupe_colors(self, color_list, threshold = 10):
|
||||
# groups = []
|
||||
|
||||
# for color in color_list:
|
||||
# found_group = False
|
||||
# for group in groups:
|
||||
# # Compute average color of the group
|
||||
# avg_color = [sum(c["rgb"][i] for c in group)/len(group) for i in range(3)]
|
||||
# if self.color_distance(color["rgb"], avg_color) <= threshold:
|
||||
# group.append(color)
|
||||
# found_group = True
|
||||
# break
|
||||
# if not found_group:
|
||||
# groups.append([color])
|
||||
|
||||
# # Compute the average color for each group
|
||||
# grouped_colors = [{
|
||||
# "face": [c["face"] for c in group],
|
||||
# "rgb": [round(sum(c["rgb"][i] for c in group) / len(group)) for i in range(3)]
|
||||
# }
|
||||
# for group in groups
|
||||
# ]
|
||||
|
||||
# return grouped_colors
|
||||
|
||||
# def color_distance(self, c1, c2):
|
||||
# return math.sqrt(
|
||||
# (c1[0]-c2[0])**2 +
|
||||
# (c1[1]-c2[1])**2 +
|
||||
# (c1[2]-c2[2])**2
|
||||
# )
|
||||
|
||||
# def read_color_csv(self, palette):
|
||||
# colors = []
|
||||
# try:
|
||||
# with open(f"{palette}.csv", newline="") as datei:
|
||||
# reader = csv.DictReader(datei)
|
||||
# for row in reader:
|
||||
# colors.append({
|
||||
# "rgb": [int(row["r"]), int(row["g"]), int(row["b"])],
|
||||
# "norm_x": float(row["norm_x"]),
|
||||
# "norm_y": float(row["norm_y"])
|
||||
# })
|
||||
# return colors
|
||||
# except:
|
||||
# return []
|
||||
|
||||
# def find_matching_color(self, colors, palette):
|
||||
# match = []
|
||||
# for color in colors:
|
||||
# best = None
|
||||
# min_dist = float("inf")
|
||||
|
||||
# for target in self.read_color_csv(palette):
|
||||
# dist = self.color_distance(target["rgb"], color["rgb"])
|
||||
# if dist < min_dist:
|
||||
# min_dist = dist
|
||||
# best = {
|
||||
# "face": color["face"],
|
||||
# "rgb": color["rgb"],
|
||||
# "norm_x": target["norm_x"],
|
||||
# "norm_y": target["norm_y"]
|
||||
# }
|
||||
# match.append(best)
|
||||
# return match
|
||||
|
||||
# def adjust_UV(self, obj, new_face_coords):
|
||||
# scale = 0.001 # Skalierung
|
||||
|
||||
# mesh = obj.data
|
||||
|
||||
# arr_layers = obj.data.uv_layers
|
||||
# if not arr_layers.get("MLOD") or len(arr_layers) > 1:
|
||||
# for uv_layer in reversed(arr_layers):
|
||||
# arr_layers.remove(uv_layer)
|
||||
# arr_layers.new(name = 'MLOD')
|
||||
# uv_layer = arr_layers.get("MLOD")
|
||||
# mesh.uv_layers.active = uv_layer
|
||||
|
||||
# for poly in mesh.polygons:
|
||||
# for coords in new_face_coords:
|
||||
# if poly.index in coords["face"]:
|
||||
|
||||
# # Mittelpunkt der UVs dieses Polygons berechnen
|
||||
# uvs = [uv_layer.data[i].uv.copy() for i in poly.loop_indices]
|
||||
# center = sum(uvs, Vector((0.0, 0.0))) / len(uvs)
|
||||
|
||||
# # Skalieren + Verschieben
|
||||
# for i in poly.loop_indices:
|
||||
# uv = uv_layer.data[i].uv
|
||||
# uv -= center
|
||||
# uv *= scale
|
||||
# uv += Vector((float(coords["norm_x"]), float(coords["norm_y"])))
|
||||
|
||||
# # Mesh updaten
|
||||
# mesh.update()
|
||||
|
||||
# def bake_diffuse(self, selected_obj, res = 1024):
|
||||
|
||||
# source_obj = None
|
||||
# for obj in bpy.data.objects:
|
||||
# if obj.type == 'MESH' and obj.name.endswith("_LOD0"):
|
||||
# print(obj.name)
|
||||
# source_obj = obj.copy()
|
||||
# source_obj.data = obj.data.copy()
|
||||
# bpy.context.collection.objects.link(source_obj)
|
||||
# break
|
||||
|
||||
# if source_obj is None:
|
||||
# source_obj = selected_obj.copy()
|
||||
# source_obj.data = selected_obj.data.copy()
|
||||
# bpy.context.collection.objects.link(source_obj)
|
||||
|
||||
# # Material erstellen
|
||||
# if "MLOD_Temp" in bpy.data.materials:
|
||||
# mat = bpy.data.materials.remove["MLOD_Temp"]
|
||||
# mat = bpy.data.materials.new(name="MLOD_Temp")
|
||||
# source_obj.data.materials.clear()
|
||||
# source_obj.data.materials.append(mat)
|
||||
|
||||
# # WICHTIG: Material als aktives Material setzen
|
||||
# mat.use_nodes = True
|
||||
# source_obj.active_material = mat
|
||||
|
||||
# # Ziel Image Node konfigurieren
|
||||
# nodes = mat.node_tree.nodes
|
||||
# links = mat.node_tree.links
|
||||
# nodes.clear()
|
||||
# tex_node = nodes.new(type="ShaderNodeTexImage")
|
||||
# bsdf = nodes.new(type="ShaderNodeBsdfPrincipled")
|
||||
# output = nodes.new(type="ShaderNodeOutputMaterial")
|
||||
# links.new(bsdf.outputs["BSDF"], output.inputs["Surface"])
|
||||
# links.new(tex_node.outputs["Color"], bsdf.inputs["Base Color"])
|
||||
# nodes.active = tex_node
|
||||
|
||||
# # Erstellen des Images
|
||||
# if "MLOD_Temp" in bpy.data.images:
|
||||
# bpy.data.images.remove(bpy.data.images["MLOD_Temp"])
|
||||
# image = bpy.data.images.new("MLOD_Temp", res, res)
|
||||
# tex_node.image = image
|
||||
|
||||
# # Selected Object = Quelle
|
||||
# bpy.context.view_layer.objects.active = source_obj
|
||||
# # Active Object = Ziel
|
||||
# selected_obj.select_set(True)
|
||||
|
||||
# # Bake
|
||||
# bpy.context.scene.render.engine = 'CYCLES'
|
||||
# bpy.ops.object.bake(type='COMBINED', width=512, height=512, cage_extrusion=0.5, pass_filter={'COLOR'}, margin=16, use_selected_to_active=True)
|
||||
|
||||
# # Temporäre Helfer entfernen
|
||||
# bpy.data.objects.remove(source_obj, do_unlink=True)
|
||||
# if "MLOD_Temp" in bpy.data.materials:
|
||||
# bpy.data.materials.remove(mat)
|
||||
|
||||
# bpy.context.view_layer.objects.active = selected_obj
|
||||
|
||||
# return image
|
||||
1025
Blender/L1960_Tools/_Source/L1960_Tools_1_8_3/ColorPalette_01.csv
Normal file
1025
Blender/L1960_Tools/_Source/L1960_Tools_1_8_3/ColorPalette_01.csv
Normal file
File diff suppressed because it is too large
Load Diff
Binary file not shown.
|
After Width: | Height: | Size: 9.7 KiB |
1025
Blender/L1960_Tools/_Source/L1960_Tools_1_8_3/ColorPalette_02.csv
Normal file
1025
Blender/L1960_Tools/_Source/L1960_Tools_1_8_3/ColorPalette_02.csv
Normal file
File diff suppressed because it is too large
Load Diff
Binary file not shown.
|
After Width: | Height: | Size: 9.1 KiB |
@@ -0,0 +1,94 @@
|
||||
import bpy
|
||||
from math import pi
|
||||
|
||||
L1960_Arr_PlainData = [
|
||||
["Proj_Empty_01", (0, 0, 2), (0, 0, 0)],
|
||||
["Proj_Empty_02", (2, 0, 0), ((pi * 90 / 180), 0, (pi * 90 / 180))],
|
||||
["Proj_Empty_03", (0, 2, 0), ((pi * 90 / 180), 0, (pi * 180 / 180))],
|
||||
["Proj_Empty_04", (0, 0, -2), ((pi * 180 / 180), 0, 0)],
|
||||
["Proj_Empty_05", (-2, 0, 0), ((pi * 90 / 180), 0, (pi * -90 / 180))],
|
||||
["Proj_Empty_06", (0, -2, 0), ((pi * 90 / 180), 0, 0)]
|
||||
]
|
||||
|
||||
class MESH_OT_add_auto_cube_projection(bpy.types.Operator):
|
||||
"""Check Empty´s for projecting, if not existing create new one´s"""
|
||||
|
||||
bl_idname = "mesh.add_auto_cube_projection"
|
||||
bl_label = "Add Plain_Axes to scene"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def execute(self, context):
|
||||
|
||||
scene = context.scene
|
||||
oldSelection = context.selected_objects
|
||||
oldActive = context.active_object
|
||||
|
||||
for EmptyData in L1960_Arr_PlainData:
|
||||
|
||||
EmptyName = EmptyData[0]
|
||||
EmptyLocation = EmptyData[1]
|
||||
EmptyRotation = EmptyData[2]
|
||||
|
||||
if not scene.objects.get(EmptyName):
|
||||
bpy.ops.object.empty_add(type='PLAIN_AXES', align='WORLD', location=EmptyLocation, scale=(1, 1, 1), rotation=EmptyRotation)
|
||||
empty = context.active_object
|
||||
empty.name = EmptyName
|
||||
empty.hide_select = True
|
||||
empty.hide_set(True)
|
||||
|
||||
#Change back to old selection and select old active
|
||||
for obj in oldSelection:
|
||||
obj.select_set(True)
|
||||
context.view_layer.objects.active = oldActive
|
||||
|
||||
self.report({'INFO'}, 'Added/Fixed Emptys for Projection to Scene')
|
||||
return {"FINISHED"}
|
||||
|
||||
class MESH_OT_add_modifier_to_mesh(bpy.types.Operator):
|
||||
"""Add Modifier to selected Mesh´s and prepare UV-Maps"""
|
||||
|
||||
bl_idname = "mesh.add_modifier_to_mesh"
|
||||
bl_label = "Add Modifier to selected Mesh"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def execute(self, context):
|
||||
|
||||
newModifierName = "CubeTexModifier"
|
||||
arr_obj = context.selected_objects
|
||||
if not arr_obj:
|
||||
self.report({'WARNING'}, 'Select a mesh to add the UVProject-Modifier')
|
||||
return {"CANCELLED"}
|
||||
|
||||
empty_objs = [emp_obj for emp_obj in context.scene.objects if emp_obj.name.startswith("Proj_Empty")]
|
||||
if len(empty_objs) < 6:
|
||||
self.report({'WARNING'}, 'Create/Recreate projectors, they need to be set up first!')
|
||||
return {"CANCELLED"};
|
||||
|
||||
for obj in arr_obj:
|
||||
|
||||
if obj.data.uv_layers.get("UVMap"):
|
||||
obj.data.uv_layers['UVMap'].name = 'UVMap0'
|
||||
|
||||
if not obj.data.uv_layers.get("UVMap0"):
|
||||
obj.data.uv_layers.new(name = 'UVMap0')
|
||||
|
||||
if not obj.data.uv_layers.get("UVMap1"):
|
||||
obj.data.uv_layers.new(name = 'UVMap1')
|
||||
|
||||
|
||||
if obj.type == "MESH" and newModifierName not in obj.modifiers:
|
||||
obj.modifiers.new(type='UV_PROJECT', name=newModifierName)
|
||||
mod = obj.modifiers[newModifierName]
|
||||
mod.uv_layer = "UVMap1"
|
||||
mod.projector_count = 6
|
||||
|
||||
i = 0
|
||||
for p in mod.projectors:
|
||||
p.object = bpy.data.objects[L1960_Arr_PlainData[i][0]]
|
||||
i = i+1
|
||||
else:
|
||||
self.report({'INFO'}, 'UVProject-Modifier allready set')
|
||||
return {"FINISHED"}
|
||||
|
||||
self.report({'INFO'}, 'Added UVProject-Modifier to mesh')
|
||||
return {"FINISHED"}
|
||||
187
Blender/L1960_Tools/_Source/L1960_Tools_1_8_3/Dekogon.py
Normal file
187
Blender/L1960_Tools/_Source/L1960_Tools_1_8_3/Dekogon.py
Normal file
@@ -0,0 +1,187 @@
|
||||
import bpy
|
||||
import re
|
||||
import os
|
||||
|
||||
### GROUP OBJECTS TO COLLECTIONS ###
|
||||
|
||||
class MESH_OT_group_objects_in_collections(bpy.types.Operator):
|
||||
"""Groups objects by name into seperate collections, usefull for Unreal Decogon import"""
|
||||
|
||||
bl_idname = "mesh.group_objects_in_collections"
|
||||
bl_label = "Groups objects by name into seperate collections, usefull for Unreal Decogon import"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def execute(self, context):
|
||||
# Erstellen einer leeren Dictionary zur Speicherung der Collections nach Basisnamen
|
||||
collection_dict = {}
|
||||
|
||||
# Durchlaufen aller Objekte in der Szene
|
||||
for obj in context.scene.objects:
|
||||
# Überprüfen, ob das Objekt ein leeres Elternobjekt ist
|
||||
if obj.type == 'EMPTY':
|
||||
# Anwenden der Regex auf den Objektnamen
|
||||
match = re.match(r'^(.*?)_(.*?)_(\d+)([a-zA-Z]+)$', obj.name)
|
||||
if match:
|
||||
prefix = match.group(1)
|
||||
name = match.group(2)
|
||||
number = match.group(3)
|
||||
letter = match.group(4)
|
||||
|
||||
# Extrahieren des Basisnamens für die Collection
|
||||
base_name = f"L1960_{name}"
|
||||
|
||||
# Hinzufügen des Objekts zur entsprechenden Liste in der Dictionary
|
||||
if base_name not in collection_dict:
|
||||
collection_dict[base_name] = {}
|
||||
if number not in collection_dict[base_name]:
|
||||
collection_dict[base_name][number] = {}
|
||||
if letter not in collection_dict[base_name][number]:
|
||||
collection_dict[base_name][number][letter] = {'empty': obj, 'children': []}
|
||||
|
||||
# Durchlaufen der Dictionary und Erstellen der Collections
|
||||
for base_name, number_dict in collection_dict.items():
|
||||
# Erstellen einer neuen Collection für den Basisnamen
|
||||
base_collection = bpy.data.collections.new(base_name)
|
||||
bpy.context.scene.collection.children.link(base_collection)
|
||||
|
||||
# Durchlaufen der sortierten Liste der Objekte und Verschieben in die Collections
|
||||
for number, letter_dict in number_dict.items():
|
||||
# Erstellen einer Collection für die Nummer und Verschieben des leeren Elternobjekts dorthin
|
||||
number_collection = bpy.data.collections.new(f"{base_name}_{number}")
|
||||
base_collection.children.link(number_collection)
|
||||
|
||||
# Durchlaufen der Buchstaben und Erstellen der Buchstaben-Collection unter der Nummer
|
||||
for letter, obj_data in letter_dict.items():
|
||||
empty = obj_data['empty']
|
||||
children = empty.children
|
||||
|
||||
letter_collection = bpy.data.collections.new(f"{base_name}_{number}{letter}")
|
||||
number_collection.children.link(letter_collection)
|
||||
|
||||
# Verschieben des leeren Elternobjekts in die entsprechende Collection
|
||||
letter_collection.objects.link(empty)
|
||||
|
||||
# Verschieben der Kinder des leeren Elternobjekts in die entsprechende Collection
|
||||
for child in children:
|
||||
letter_collection.objects.link(child)
|
||||
|
||||
# Entfernen des leeren Elternobjekts und seiner Kinder aus der Szene
|
||||
bpy.context.collection.objects.unlink(empty)
|
||||
for child in children:
|
||||
bpy.context.collection.objects.unlink(child)
|
||||
|
||||
# -------------------------------------------------------------------------------------------
|
||||
# Regular expression pattern to match any _LOD1, _LOD2, etc., but not _LOD0
|
||||
pattern = re.compile(r"_LOD[1-9]\d*$")
|
||||
|
||||
# Loop through all objects in the scene
|
||||
for obj in bpy.context.scene.objects:
|
||||
# If the object name matches the pattern, hide it
|
||||
if pattern.search(obj.name):
|
||||
obj.hide_set(True) # This hides the object in the viewport
|
||||
else:
|
||||
obj.hide_set(False) # Ensure _LOD0 objects remain visible
|
||||
|
||||
# Update the view layer to reflect changes
|
||||
bpy.context.view_layer.update()
|
||||
|
||||
self.report({'INFO'}, 'All objects sorted')
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
### ASSIGN TEXTURES ###
|
||||
|
||||
class MESH_OT_assign_textures(bpy.types.Operator):
|
||||
"""Assign Textures to Mesh´s, usefull for Unreal Decogon import"""
|
||||
|
||||
bl_idname = "mesh.assign_textures"
|
||||
bl_label = "Assign Textures to Mesh´s, usefull for Unreal Decogon import"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def execute(self, context):
|
||||
|
||||
# Define the path to the folder containing your textures
|
||||
texture_folder_path = context.scene.dekogon_file_path
|
||||
|
||||
texture_prefix = context.scene.dekogon_settings_prefix
|
||||
if texture_prefix != "":
|
||||
if texture_prefix[-1] != "_":
|
||||
texture_prefix = texture_prefix + "_"
|
||||
|
||||
texture_suffix = context.scene.dekogon_settings_suffix
|
||||
if texture_suffix != "":
|
||||
if texture_suffix[0] != "_":
|
||||
texture_suffix = "_" + texture_suffix
|
||||
|
||||
texture_filetype = context.scene.dekogon_settings_filetype
|
||||
|
||||
if not os.path.exists(texture_folder_path):
|
||||
self.report({'ERROR'}, f"The texture folder path '{texture_folder_path}' does not exist.")
|
||||
return {"FINISHED"}
|
||||
else:
|
||||
self.report({'INFO'}, f"Texture folder path: {texture_folder_path}")
|
||||
# List all files in the texture folder for debugging purposes
|
||||
#texture_files = os.listdir(texture_folder_path)
|
||||
#self.report({'INFO'}, "Files in texture folder:")
|
||||
#for f in texture_files:
|
||||
# print(f" - {f}")
|
||||
|
||||
# Iterate over all materials in the Blender file
|
||||
for material in bpy.data.materials:
|
||||
self.report({'INFO'}, f"Processing material: {material.name}")
|
||||
# Ensure the material uses nodes
|
||||
if not material.use_nodes:
|
||||
material.use_nodes = True
|
||||
self.report({'INFO'}, f"Enabled nodes for material: {material.name}")
|
||||
|
||||
# Get the node tree of the material
|
||||
if material.node_tree is None:
|
||||
self.report({'WARNING'}, f"Material {material.name} has no node tree.")
|
||||
continue
|
||||
|
||||
nodes = material.node_tree.nodes
|
||||
|
||||
# Find or create an Image Texture node
|
||||
image_texture_node = None
|
||||
for node in nodes:
|
||||
if node.type == 'TEX_IMAGE':
|
||||
image_texture_node = node
|
||||
break
|
||||
if image_texture_node is None:
|
||||
image_texture_node = nodes.new(type='ShaderNodeTexImage')
|
||||
self.report({'INFO'}, f"Created new Image Texture node for material: {material.name}")
|
||||
else:
|
||||
self.report({'INFO'}, f"Found existing Image Texture node for material: {material.name}")
|
||||
|
||||
# Construct the expected texture filename based on the material name
|
||||
texture_filename = f"{texture_prefix}{material.name}{texture_suffix}.{texture_filetype}"
|
||||
texture_filepath = os.path.join(texture_folder_path, texture_filename)
|
||||
self.report({'INFO'}, f"Looking for texture: {texture_filepath}")
|
||||
|
||||
# Check if the texture file exists
|
||||
if os.path.exists(texture_filepath):
|
||||
try:
|
||||
# Load the image and assign it to the Image Texture node
|
||||
image = bpy.data.images.load(texture_filepath)
|
||||
image_texture_node.image = image
|
||||
self.report({'INFO'}, f"Loaded texture: {texture_filename} for material: {material.name}")
|
||||
|
||||
# Link the Image Texture node to the Base Color of the Principled BSDF shader
|
||||
principled_node = None
|
||||
for node in nodes:
|
||||
if node.type == 'BSDF_PRINCIPLED':
|
||||
principled_node = node
|
||||
break
|
||||
if principled_node is not None:
|
||||
links = material.node_tree.links
|
||||
links.new(image_texture_node.outputs['Color'], principled_node.inputs['Base Color'])
|
||||
self.report({'INFO'}, f"Linked texture to Principled BSDF for material: {material.name}")
|
||||
else:
|
||||
self.report({'WARNING'}, f"No Principled BSDF node found for material: {material.name}")
|
||||
except RuntimeError as e:
|
||||
self.report({'ERROR'}, f"Failed to load image {texture_filename}: {e}")
|
||||
else:
|
||||
self.report({'WARNING'}, "Texture file not found for material {material.name}: {texture_filename}")
|
||||
|
||||
self.report({'INFO'}, 'Texture assignment complete.')
|
||||
return {"FINISHED"}
|
||||
139
Blender/L1960_Tools/_Source/L1960_Tools_1_8_3/Helper.py
Normal file
139
Blender/L1960_Tools/_Source/L1960_Tools_1_8_3/Helper.py
Normal file
@@ -0,0 +1,139 @@
|
||||
import bpy
|
||||
import bmesh
|
||||
|
||||
### FIX MATERIALS ###
|
||||
|
||||
class MESH_OT_fix_material_names(bpy.types.Operator):
|
||||
"""Fixes the material naming, if duplicated are present e.g. Material.001, Material.002 ..."""
|
||||
|
||||
bl_idname = "mesh.fix_material_names"
|
||||
bl_label = "Fixes the material naming, if duplicated are present"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def execute(self, context):
|
||||
#Remove all duplicated materials
|
||||
self.merge_duplicated_materials()
|
||||
|
||||
#Merge material slots for every mesh in the scene
|
||||
for obj in bpy.context.scene.objects:
|
||||
if obj.type == "MESH":
|
||||
self.merge_material_slots(obj)
|
||||
|
||||
|
||||
self.report({'INFO'}, 'All duplicated Materials fixed')
|
||||
return {"FINISHED"}
|
||||
|
||||
def merge_duplicated_materials(self):
|
||||
for material in bpy.data.materials:
|
||||
#Remove MI for Dekogon material names
|
||||
if material.name.split('_')[0] == 'MI':
|
||||
material.name = material.name[3:]
|
||||
#Check for .001 at end and remove
|
||||
if material.name[-3:].isnumeric():
|
||||
opti_matName = material.name[:-4]
|
||||
if bpy.data.materials.get(opti_matName): #check if og_mat exists
|
||||
material.user_remap(bpy.data.materials.get(opti_matName))
|
||||
print("Removed Material: " + material.name)
|
||||
bpy.data.materials.remove(material)
|
||||
else:
|
||||
material.name = opti_matName
|
||||
|
||||
def merge_material_slots(self, obj):
|
||||
duplicated_material_list = []
|
||||
|
||||
#create list with indexes of material slots with the same name and merge them
|
||||
for og_slot in obj.material_slots:
|
||||
for slot in obj.material_slots:
|
||||
if slot.name == og_slot.name:
|
||||
if slot.slot_index == og_slot.slot_index:
|
||||
continue
|
||||
if og_slot.slot_index in duplicated_material_list:
|
||||
continue
|
||||
duplicated_material_list.append(int(slot.slot_index))
|
||||
|
||||
#delete all material slots within list
|
||||
for slot_index in sorted(duplicated_material_list, reverse=True):
|
||||
obj.data.materials.pop(index = slot_index)
|
||||
|
||||
|
||||
### FIX NAMING CONVENTIONS ###
|
||||
|
||||
class MESH_OT_fix_naming_conventions(bpy.types.Operator):
|
||||
"""Changes . to _ to solve naming issues with workbench"""
|
||||
|
||||
bl_idname = "mesh.fix_naming_convention"
|
||||
bl_label = "Changes . to _ to solve naming issues with workbench"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def execute(self, context):
|
||||
for obj in bpy.data.objects:
|
||||
obj.name = obj.name.replace(".","_")
|
||||
|
||||
self.report({'INFO'}, 'Fixed Naming')
|
||||
return {"FINISHED"}
|
||||
|
||||
class MESH_OT_generate_empty_for_mesh(bpy.types.Operator):
|
||||
"""Generates a Empty with the objects name at it´s position"""
|
||||
|
||||
bl_idname = "mesh.generate_empty_for_mesh"
|
||||
bl_label = "Generates a Empty with the objects name at it´s position"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def execute(self, context):
|
||||
scene = bpy.context.scene
|
||||
Selection = bpy.context.selected_objects
|
||||
FilteredSelection = [obj for obj in Selection if obj.type != 'EMPTY']
|
||||
ActiveObj = bpy.context.active_object
|
||||
|
||||
for obj in FilteredSelection:
|
||||
oldEmpty = scene.objects.get("Socket_" + obj.name)
|
||||
if oldEmpty:
|
||||
oldEmpty.location = obj.location
|
||||
oldEmpty.rotation_euler = obj.rotation_euler
|
||||
else:
|
||||
obj.select_set(True)
|
||||
bpy.ops.object.empty_add(type='PLAIN_AXES', align='WORLD', location=obj.location, scale=(1, 1, 1), rotation=obj.rotation_euler)
|
||||
empty = bpy.context.active_object
|
||||
empty.name = "Socket_" + obj.name
|
||||
|
||||
#Change back to selection and select old active
|
||||
bpy.ops.object.select_all(action='DESELECT')
|
||||
|
||||
self.report({'INFO'}, 'Generated Emptys for selectes Meshes in Scene')
|
||||
return {"FINISHED"}
|
||||
|
||||
class MESH_OT_select_face_id(bpy.types.Operator):
|
||||
"""Highlights Face with given ID"""
|
||||
|
||||
bl_idname = "mesh.select_face_id"
|
||||
bl_label = "Highlight/Select Face with given Index"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def execute(self, context):
|
||||
EditObj = bpy.context.active_object
|
||||
|
||||
face_Index = int(context.scene.face_id_field)
|
||||
|
||||
if EditObj != None:
|
||||
bpy.ops.object.mode_set(mode='EDIT')
|
||||
bpy.ops.mesh.select_all(action='DESELECT')
|
||||
bm = bmesh.from_edit_mesh(EditObj.data)
|
||||
bm.faces.ensure_lookup_table()
|
||||
|
||||
for area in bpy.context.screen.areas:
|
||||
if area.type == 'VIEW_3D':
|
||||
for space in area.spaces:
|
||||
if space.type == 'VIEW_3D':
|
||||
space.shading.type = 'WIREFRAME'
|
||||
try:
|
||||
bm.faces[face_Index].select = True
|
||||
bmesh.update_edit_mesh(EditObj.data)
|
||||
|
||||
self.report({'INFO'}, f'Highlighted Face with Index: {face_Index}')
|
||||
return {"FINISHED"}
|
||||
except IndexError:
|
||||
self.report({'INFO'}, f'Index: {face_Index} out of range!')
|
||||
return {"FINISHED"}
|
||||
else:
|
||||
self.report({'INFO'}, 'Please select a Mesh first.')
|
||||
return {"FINISHED"}
|
||||
217
Blender/L1960_Tools/_Source/L1960_Tools_1_8_3/MaterialToMask.py
Normal file
217
Blender/L1960_Tools/_Source/L1960_Tools_1_8_3/MaterialToMask.py
Normal file
@@ -0,0 +1,217 @@
|
||||
import bpy
|
||||
import bmesh
|
||||
|
||||
# Callback for Enum Items
|
||||
def get_uv_layers(self, context):
|
||||
items = []
|
||||
obj = context.object
|
||||
|
||||
if obj and obj.type == 'MESH' and obj.data.uv_layers:
|
||||
for i, uv in enumerate(obj.data.uv_layers):
|
||||
items.append((str(i), uv.name, f"UV Layer {i}"))
|
||||
else:
|
||||
items.append(("NONE", "No UVs", "No UV available within Mesh"))
|
||||
|
||||
return items
|
||||
|
||||
class UVEnumProperties(bpy.types.PropertyGroup):
|
||||
uv_enum: bpy.props.EnumProperty(name="UV Map", description="Select UV-Layer", items=get_uv_layers, default=0)
|
||||
|
||||
class MESH_OT_merge_materials_to_mask(bpy.types.Operator):
|
||||
"""Merges 4 Materials into one Material (Mask)"""
|
||||
|
||||
bl_idname = "mesh.merge_materials_to_mask"
|
||||
bl_label = "Merges 4 Materials into one Material (Mask)"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def execute(self, context):
|
||||
scene = context.scene
|
||||
arr_obj = context.selected_objects
|
||||
activeObj = context.active_object
|
||||
|
||||
ignore_custom = context.scene.settings_multi_ignor
|
||||
island_margin_custom = context.scene.uv_island_margin_slider
|
||||
|
||||
# Scale and offset for UV allignment
|
||||
SCALE = 0.5
|
||||
OFFSETS = [
|
||||
(0.0, 0.5),
|
||||
(0.5, 0.5),
|
||||
(0.0, 0.0),
|
||||
(0.5, 0.0)
|
||||
]
|
||||
IGNORE = ["glass", "glas", "grass", "gras"] + ignore_custom.split(",")
|
||||
|
||||
# No Mesh selected
|
||||
if not arr_obj:
|
||||
self.report({'WARNING'}, 'Select one mesh')
|
||||
return {"CANCELLED"}
|
||||
|
||||
# Only one Mesh selected?
|
||||
if len(arr_obj) > 1:
|
||||
self.report({'WARNING'}, 'Only one Mesh can be selected')
|
||||
return {"CANCELLED"}
|
||||
|
||||
obj = arr_obj[0]
|
||||
selected_uv = context.scene.uv_enum_props.uv_enum
|
||||
|
||||
# UV Maps present?
|
||||
if not obj.data.uv_layers or not selected_uv:
|
||||
self.report({'WARNING'}, 'No UV-Map selected')
|
||||
return {"CANCELLED"}
|
||||
|
||||
obj.data.uv_layers.active_index = int(selected_uv)
|
||||
|
||||
skip = 0
|
||||
idx_multi = None
|
||||
delete = []
|
||||
|
||||
# Loop through all Materials
|
||||
for i, slot in enumerate(obj.material_slots):
|
||||
|
||||
# Skip Materials in static ignore list or user ignore list
|
||||
if any(name in slot.material.name.lower() for name in IGNORE):
|
||||
self.report({'INFO'}, f'Material "{slot.material.name}" skipped.')
|
||||
skip += 1
|
||||
continue
|
||||
|
||||
# Switch to edit mode
|
||||
bpy.ops.object.mode_set(mode='EDIT')
|
||||
|
||||
# Create bmesh to work with
|
||||
bm = bmesh.from_edit_mesh(obj.data)
|
||||
uv_layer = bm.loops.layers.uv.active
|
||||
|
||||
# Deselect all
|
||||
bpy.ops.mesh.select_all(action='DESELECT')
|
||||
|
||||
if slot.material:
|
||||
# Select Mat slot
|
||||
obj.active_material_index = i
|
||||
|
||||
# Select all Faces of Mat
|
||||
bpy.ops.object.material_slot_select()
|
||||
|
||||
# If UV has assigned faces
|
||||
if any(f.select for f in bm.faces):
|
||||
# Repack UV Islands
|
||||
bpy.ops.uv.select_all(action='SELECT')
|
||||
bpy.ops.uv.pack_islands(margin=island_margin_custom)
|
||||
|
||||
# Select Offset
|
||||
group = (i - skip) % len(OFFSETS)
|
||||
offset = OFFSETS[group]
|
||||
|
||||
# Scale and offset UV
|
||||
for f in bm.faces:
|
||||
if f.select:
|
||||
for loop in f.loops:
|
||||
uv = loop[uv_layer].uv
|
||||
uv[0] = offset[0] + uv[0] * SCALE
|
||||
uv[1] = offset[1] + uv[1] * SCALE
|
||||
|
||||
# Apply Changes
|
||||
bmesh.update_edit_mesh(obj.data)
|
||||
|
||||
# Create Texture Attributes with previous material names
|
||||
match group:
|
||||
case 0:
|
||||
mat = bpy.data.materials.get(obj.material_slots[i].name)
|
||||
mat["Black "] = mat.name
|
||||
|
||||
# Change name and use as base to merge
|
||||
mat.name = "Multi_" + mat.name
|
||||
idx_multi = i
|
||||
self.report({'INFO'}, f'Material "{mat.name}" created.')
|
||||
continue
|
||||
case 1:
|
||||
mat = bpy.data.materials.get(obj.material_slots[idx_multi].name)
|
||||
mat["Red "] = slot.material.name
|
||||
case 2:
|
||||
mat = bpy.data.materials.get(obj.material_slots[idx_multi].name)
|
||||
mat["Green "] = slot.material.name
|
||||
case 3:
|
||||
mat = bpy.data.materials.get(obj.material_slots[idx_multi].name)
|
||||
mat["Blue "] = slot.material.name
|
||||
case _:
|
||||
pass
|
||||
|
||||
# Merge Material A -> B
|
||||
self.merge_mat_A_to_B(obj, i, idx_multi)
|
||||
|
||||
# Add Material B to delete list
|
||||
delete.insert(0, i)
|
||||
|
||||
# Switch to object mode
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
|
||||
# Delete not used materials from list
|
||||
for mat in delete:
|
||||
obj.active_material_index = mat
|
||||
bpy.ops.object.material_slot_remove()
|
||||
|
||||
# Put UV first
|
||||
self.put_UV_first(obj, int(selected_uv))
|
||||
|
||||
# Change UV names like in Reforger Tools
|
||||
mesh = obj.data
|
||||
uv_layers = mesh.uv_layers
|
||||
for i, layer in enumerate(uv_layers):
|
||||
layer.name = f"UVMap{i + 1}"
|
||||
|
||||
self.report({'INFO'}, 'Merged Materials to Multitextures.')
|
||||
return {"FINISHED"}
|
||||
|
||||
def merge_mat_A_to_B(self, obj, mat_A, mat_B):
|
||||
# check if Mat Name is index or string and convert
|
||||
if type(mat_A) is str:
|
||||
mat_A = bpy.data.materials.get(mat_A)
|
||||
mat_A = obj.material_slots.find(mat_A)
|
||||
if type(mat_B) is str:
|
||||
mat_B = bpy.data.materials.get(mat_B)
|
||||
mat_B = obj.material_slots.find(mat_B)
|
||||
|
||||
# Change to Edit Mode
|
||||
bpy.ops.object.mode_set(mode='EDIT')
|
||||
bpy.ops.mesh.select_all(action='DESELECT')
|
||||
|
||||
# Select all Faces from Mat B
|
||||
obj.active_material_index = mat_A
|
||||
bpy.ops.object.material_slot_select()
|
||||
|
||||
# Select Mat A and assign Faces from Mat B
|
||||
obj.active_material_index = mat_B
|
||||
bpy.ops.object.material_slot_assign() # Faces from B → A
|
||||
|
||||
# Switch to object mode
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
|
||||
def put_UV_first(self, obj, target_index):
|
||||
mesh = obj.data
|
||||
uv_layers = mesh.uv_layers
|
||||
|
||||
if len(uv_layers) > 1:
|
||||
# Transform UV-Layers to dict
|
||||
uv_data_dict = {i: [loop_uv.uv.copy() for loop_uv in layer.data] for i, layer in enumerate(uv_layers)}
|
||||
|
||||
# Order: target_index -> first
|
||||
indices = list(range(len(uv_layers)))
|
||||
new_order = [target_index] + [i for i in indices if i != target_index]
|
||||
|
||||
print(new_order)
|
||||
|
||||
# Delete all UV-layers
|
||||
while len(uv_layers) > 0:
|
||||
uv_layers.remove(uv_layers[0])
|
||||
|
||||
# write new order of UV´s
|
||||
new_layers = []
|
||||
for old_idx in new_order:
|
||||
new_layer = uv_layers.new(name=f"Temp_{old_idx}") # temp Name
|
||||
old_data = uv_data_dict[old_idx]
|
||||
for j, loop_uv in enumerate(old_data):
|
||||
new_layer.data[j].uv = loop_uv
|
||||
new_layers.append(new_layer)
|
||||
|
||||
# Set active UV
|
||||
uv_layers.active_index = 0
|
||||
42
Blender/L1960_Tools/_Source/L1960_Tools_1_8_3/PrepareLods.py
Normal file
42
Blender/L1960_Tools/_Source/L1960_Tools_1_8_3/PrepareLods.py
Normal file
@@ -0,0 +1,42 @@
|
||||
import bpy
|
||||
|
||||
### PREPARE LODS ###
|
||||
|
||||
class MESH_OT_prepare_lods_decimate(bpy.types.Operator):
|
||||
"""Copy current Mesh and apply decimate Modifier"""
|
||||
|
||||
bl_idname = "mesh.prepare_lods_decimate"
|
||||
bl_label = "Copy current Mesh and apply decimate Modifier"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def execute(self, context):
|
||||
|
||||
#Selected Mesh
|
||||
obj = bpy.context.active_object
|
||||
|
||||
if obj not in bpy.context.selected_objects or obj.type != "MESH":
|
||||
self.report({'WARNING'}, 'Select a Mesh to continue')
|
||||
return {"CANCELLED"}
|
||||
|
||||
if not obj.name[:-1].endswith('LOD'):
|
||||
obj.name = obj.name + '_LOD0'
|
||||
|
||||
LODnumber = context.scene.lod_slider #Get from Slider
|
||||
startLODcount = int(obj.name[-1])
|
||||
endLODcount = startLODcount + LODnumber
|
||||
|
||||
for i in range (startLODcount + 1, endLODcount):
|
||||
new_obj = obj.copy()
|
||||
new_obj.data = obj.data.copy()
|
||||
new_obj.name = obj.name[:-1] + str(i)
|
||||
bpy.context.collection.objects.link(new_obj)
|
||||
|
||||
for t in range (startLODcount, i):
|
||||
newModifierName = 'LOD_Decimate_' + str(t)
|
||||
new_obj.modifiers.new(type='DECIMATE', name=newModifierName)
|
||||
mod = new_obj.modifiers[newModifierName]
|
||||
mod.ratio = 0.49
|
||||
mod.use_collapse_triangulate = True
|
||||
|
||||
self.report({'INFO'}, 'LOD´s created')
|
||||
return {"FINISHED"}
|
||||
@@ -0,0 +1,30 @@
|
||||
from PIL import Image
|
||||
import csv
|
||||
|
||||
palettes = ["ColorPalette_01", "ColorPalette_02"]
|
||||
|
||||
for palette in palettes:
|
||||
# Bild öffnen (Pfad anpassen)
|
||||
bild = Image.open(f"{palette}.png").convert("RGB")
|
||||
|
||||
breite, hoehe = bild.size
|
||||
tiles_x, tiles_y = 32, 32
|
||||
|
||||
# Auf 32x32 verkleinern (nimmt repräsentative Pixel pro Kachel)
|
||||
klein = bild.resize((32, 32), Image.NEAREST)
|
||||
|
||||
# CSV-Datei schreiben
|
||||
with open(f"{palette}.csv", mode="w", newline="") as datei:
|
||||
writer = csv.writer(datei)
|
||||
writer.writerow(["norm_x", "norm_y", "r", "g", "b"])
|
||||
|
||||
for py in range(tiles_y):
|
||||
for px in range(tiles_x):
|
||||
# Farbe an diesem Pixel holen
|
||||
r, g, b = bild.getpixel((int(px), int(py)))
|
||||
|
||||
# Normalisierung [0,1]
|
||||
norm_x = (px / (breite)) + 1/64
|
||||
norm_y = 1.0 - ((py / (hoehe))) - 1/64
|
||||
|
||||
writer.writerow([f"{norm_x:.6f}", f"{norm_y:.6f}", r, g, b])
|
||||
207
Blender/L1960_Tools/_Source/L1960_Tools_1_8_3/__init__.py
Normal file
207
Blender/L1960_Tools/_Source/L1960_Tools_1_8_3/__init__.py
Normal file
@@ -0,0 +1,207 @@
|
||||
bl_info = {
|
||||
"name": "L1960 Tools",
|
||||
"author": "Prodeath21",
|
||||
"version": (1, 8, 3),
|
||||
"blender": (4, 2, 0),
|
||||
"location": "3D Viewport > Sidebar > 1960Life category",
|
||||
"description": "Set´s up the Projection-Modifier automatically and add´s in the Emptys if not allready created.",
|
||||
"category": "Object",
|
||||
}
|
||||
|
||||
# ----------------------------------------------
|
||||
# Import modules
|
||||
# ----------------------------------------------
|
||||
if "bpy" in locals():
|
||||
import imp
|
||||
imp.reload(Dekogon)
|
||||
imp.reload(CubeProjection)
|
||||
imp.reload(Helper)
|
||||
imp.reload(PrepareLods)
|
||||
imp.reload(AutoColorPalette)
|
||||
imp.reload(MaterialToMask)
|
||||
print("L1960 Tools: Reloaded multifiles")
|
||||
else:
|
||||
from . import Dekogon
|
||||
from . import CubeProjection
|
||||
from . import Helper
|
||||
from . import PrepareLods
|
||||
from . import AutoColorPalette
|
||||
from . import MaterialToMask
|
||||
|
||||
import bpy
|
||||
|
||||
from . Dekogon import MESH_OT_group_objects_in_collections, MESH_OT_assign_textures
|
||||
from . CubeProjection import MESH_OT_add_auto_cube_projection, MESH_OT_add_modifier_to_mesh
|
||||
from . Helper import MESH_OT_fix_material_names, MESH_OT_fix_naming_conventions, MESH_OT_generate_empty_for_mesh, MESH_OT_select_face_id
|
||||
from . PrepareLods import MESH_OT_prepare_lods_decimate
|
||||
from . AutoColorPalette import MESH_OT_set_up_mlod, EnumColorPalettes # MESH_OT_bake_basic_mlod,
|
||||
from . MaterialToMask import UVEnumProperties, MESH_OT_merge_materials_to_mask
|
||||
|
||||
class L1960_PT_dekogon(bpy.types.Panel):
|
||||
#where to add the panel
|
||||
bl_space_type = "VIEW_3D"
|
||||
bl_region_type = "UI"
|
||||
|
||||
#add labels
|
||||
bl_label = "1960-Life Import"
|
||||
bl_category = "1960-Life"
|
||||
bl_options = {'DEFAULT_CLOSED'}
|
||||
|
||||
def draw(self, context):
|
||||
box = self.layout.box()
|
||||
# Dekogon-Import
|
||||
box.label(text="Dekogon-Import")
|
||||
row = box.row()
|
||||
row.operator("mesh.group_objects_in_collections", text="Group to Collections")
|
||||
row = box.row()
|
||||
split = row.split(factor=0.5)
|
||||
split.operator("mesh.assign_textures", text="Assign Textures")
|
||||
split.prop(context.scene, "dekogon_file_path", text="")
|
||||
row = box.row()
|
||||
row.prop(context.scene, "section1",
|
||||
text="Settings",
|
||||
icon="TRIA_DOWN" if context.scene.section1 else "TRIA_RIGHT",
|
||||
emboss=False)
|
||||
if context.scene.section1:
|
||||
box.prop(context.scene, "dekogon_settings_prefix", text="Prefix")
|
||||
box.prop(context.scene, "dekogon_settings_suffix", text="Suffix")
|
||||
box.prop(context.scene, "dekogon_settings_filetype", text="File Type")
|
||||
self.layout.separator()
|
||||
|
||||
box = self.layout.box()
|
||||
# Americano-Import
|
||||
box.label(text="Materials-to-Multi")
|
||||
row = box.row()
|
||||
row.operator("mesh.merge_materials_to_mask", text="Merge Materials to Mask")
|
||||
row = box.row()
|
||||
row.prop(context.scene, "section2",
|
||||
text="Settings",
|
||||
icon="TRIA_DOWN" if context.scene.section2 else "TRIA_RIGHT",
|
||||
emboss=False)
|
||||
if context.scene.section2:
|
||||
row = box.row()
|
||||
props = context.scene.uv_enum_props
|
||||
row.prop(props, "uv_enum", text="Use UV")
|
||||
box.prop(context.scene, "settings_multi_ignor", text="Ignore")
|
||||
box.prop(context.scene, "uv_island_margin_slider", text="Island Margin")
|
||||
|
||||
class L1960_PT_tools(bpy.types.Panel):
|
||||
#where to add the panel
|
||||
bl_space_type = "VIEW_3D"
|
||||
bl_region_type = "UI"
|
||||
|
||||
#add labels
|
||||
bl_label = "1960-Life Tools"
|
||||
bl_category = "1960-Life"
|
||||
|
||||
def draw(self, context):
|
||||
"""define the layout of the panel"""
|
||||
box = self.layout.box()
|
||||
# UV-Project helper
|
||||
box.label(text="UV-Projection")
|
||||
row = box.row()
|
||||
row.operator("mesh.add_auto_cube_projection", text="Set up Projectors")
|
||||
row = box.row()
|
||||
row.operator("mesh.add_modifier_to_mesh", text="Add Modifier to Mesh")
|
||||
self.layout.separator()
|
||||
# Helpers
|
||||
box = self.layout.box()
|
||||
box.label(text="Various Helper")
|
||||
row = box.row()
|
||||
row.operator("mesh.fix_material_names", text="Fix Material Name´s")
|
||||
row = box.row()
|
||||
row.operator("mesh.fix_naming_convention", text="Fix Naming Convention")
|
||||
row = box.row()
|
||||
row.operator("mesh.generate_empty_for_mesh", text="Generate Empty")
|
||||
row = box.row()
|
||||
split = row.split(factor=0.7)
|
||||
split.operator("mesh.select_face_id", text="Show Face Index")
|
||||
split.prop(context.scene, "face_id_field", text="")
|
||||
self.layout.separator()
|
||||
# Generate LODs
|
||||
box = self.layout.box()
|
||||
box.label(text="LOD´s")
|
||||
row = box.row()
|
||||
row.operator("mesh.prepare_lods_decimate", text="Create LOD´s")
|
||||
box.prop(context.scene, "lod_slider", text="Amount")
|
||||
box = self.layout.box()
|
||||
box.prop(context.scene.color_palettes, "mlod_enum_selection", expand=True)
|
||||
# row = box.row()
|
||||
# row.operator("mesh.set_up_mlod", text="Set up MLOD")
|
||||
row = box.row()
|
||||
row.operator("mesh.set_up_mlod", text="Generate MLOD (Palette)")
|
||||
self.layout.separator()
|
||||
###############################
|
||||
# Enfusion Blender Tools Linked
|
||||
box = self.layout.box()
|
||||
box.label(text="EBT Linked")
|
||||
row = box.row()
|
||||
row.operator("view3d.ebt_sort", text="Sort Objects")
|
||||
# colliders setup is allowed in both OBJECT and EDIT mode
|
||||
row = box.row()
|
||||
row.operator("view3d.ebt_colliders_setup", text=" Colliders Setup")
|
||||
row = box.row()
|
||||
# Light Setup
|
||||
row.operator("view3d.ebt_setup_light", text=" Light Setup")
|
||||
row = box.row()
|
||||
col = row.column(align=True)
|
||||
# Update Materials
|
||||
col.operator("scene.ebt_update_enf_materials",)
|
||||
row = box.row()
|
||||
col = row.column(align=True)
|
||||
|
||||
#register the panel with blender
|
||||
modules = [ L1960_PT_dekogon,
|
||||
L1960_PT_tools,
|
||||
MESH_OT_add_auto_cube_projection,
|
||||
MESH_OT_add_modifier_to_mesh,
|
||||
MESH_OT_merge_materials_to_mask,
|
||||
MESH_OT_fix_material_names,
|
||||
MESH_OT_group_objects_in_collections,
|
||||
MESH_OT_assign_textures,
|
||||
MESH_OT_fix_naming_conventions,
|
||||
MESH_OT_generate_empty_for_mesh,
|
||||
MESH_OT_prepare_lods_decimate,
|
||||
# MESH_OT_bake_basic_mlod,
|
||||
MESH_OT_set_up_mlod,
|
||||
EnumColorPalettes,
|
||||
MESH_OT_select_face_id,
|
||||
UVEnumProperties
|
||||
]
|
||||
|
||||
def register():
|
||||
for mod in modules:
|
||||
bpy.utils.register_class(mod)
|
||||
|
||||
bpy.types.Scene.lod_slider = bpy.props.IntProperty(name="LOD Number", default=3, min=0, max=10)
|
||||
bpy.types.Scene.color_palettes = bpy.props.PointerProperty(type=EnumColorPalettes)
|
||||
bpy.types.Scene.face_id_field = bpy.props.IntProperty(name="Face ID", default=0, min=0)
|
||||
bpy.types.Scene.section1 = bpy.props.BoolProperty(name="Expand Section", default=False)
|
||||
bpy.types.Scene.section2 = bpy.props.BoolProperty(name="Expand Section", default=False)
|
||||
bpy.types.Scene.dekogon_file_path = bpy.props.StringProperty(name="Textures", description="Path to the texture folder, textures to be applied from", subtype="DIR_PATH", default="")
|
||||
bpy.types.Scene.dekogon_settings_prefix = bpy.props.StringProperty(name="Prefix", default="TX")
|
||||
bpy.types.Scene.dekogon_settings_suffix = bpy.props.StringProperty(name="Suffix", default="ALB")
|
||||
bpy.types.Scene.dekogon_settings_filetype = bpy.props.StringProperty(name="File Type", default="tga")
|
||||
bpy.types.Scene.settings_multi_ignor = bpy.props.StringProperty(name="Ignore", default="", description="Ignore material when string is in name (split by comma)")
|
||||
bpy.types.Scene.uv_enum_props = bpy.props.PointerProperty(type=UVEnumProperties)
|
||||
bpy.types.Scene.uv_island_margin_slider = bpy.props.FloatProperty(name="Island Margin", default=0.02, min=0.01, max=0.1)
|
||||
|
||||
def unregister():
|
||||
for mod in modules:
|
||||
bpy.utils.unregister_class(mod)
|
||||
|
||||
del bpy.types.Scene.lod_slider
|
||||
del bpy.types.Scene.color_palettes
|
||||
del bpy.types.Scene.face_id_field
|
||||
del bpy.types.Scene.section1
|
||||
del bpy.types.Scene.section2
|
||||
del bpy.types.Scene.dekogon_file_path
|
||||
del bpy.types.Scene.dekogon_settings_prefix
|
||||
del bpy.types.Scene.dekogon_settings_suffix
|
||||
del bpy.types.Scene.dekogon_settings_filetype
|
||||
del bpy.types.Scene.settings_multi_ignor
|
||||
del bpy.types.Scene.uv_enum_props
|
||||
del bpy.types.Scene.uv_island_margin_slider
|
||||
|
||||
if __name__== "__main__":
|
||||
register()
|
||||
@@ -0,0 +1,333 @@
|
||||
import bpy
|
||||
import math
|
||||
import csv
|
||||
import os
|
||||
import json
|
||||
from mathutils import Vector
|
||||
|
||||
### GENRATE MLOD ###
|
||||
|
||||
plugin_dir = bpy.utils.user_resource('SCRIPTS')
|
||||
plugin_path = "addons\L1960Tools"
|
||||
L1960_path = os.path.join(plugin_dir, plugin_path)
|
||||
|
||||
colorpalettes = [
|
||||
json.dumps(["ColorPalette_01.png", "BF1BC94A0DE4398F"]),
|
||||
json.dumps(["ColorPalette_02.png", "A95B2794A0EE8340"])
|
||||
]
|
||||
|
||||
enum_palettes = []
|
||||
for palettes in colorpalettes:
|
||||
file = json.loads(palettes)[0]
|
||||
enum_palettes.append((palettes, file[:-4], "Select " + file[:-4] + " for MLOD"))
|
||||
|
||||
class EnumColorPalettes(bpy.types.PropertyGroup):
|
||||
mlod_enum_selection: bpy.props.EnumProperty(name="Color Palettes for MLOD", items = enum_palettes, description = "Choose a palette", default = 0)
|
||||
|
||||
class MESH_OT_set_up_mlod(bpy.types.Operator):
|
||||
"""Set´s up a material to be used for MLOD´s"""
|
||||
|
||||
bl_idname = "mesh.set_up_mlod"
|
||||
bl_label = "Set´s up a material to be used for MLOD´s"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def execute(self, context):
|
||||
|
||||
#Load Color Palettes
|
||||
self.import_palettes_textures()
|
||||
|
||||
#Selected Mesh
|
||||
obj = bpy.context.active_object
|
||||
|
||||
if obj not in bpy.context.selected_objects or obj.type != "MESH":
|
||||
self.report({'WARNING'}, 'Select a Mesh to continue')
|
||||
return {"CANCELLED"}
|
||||
|
||||
arr_layers = obj.data.uv_layers
|
||||
if not arr_layers.get("MLOD") or len(arr_layers) > 1:
|
||||
for uv_layer in reversed(arr_layers):
|
||||
arr_layers.remove(uv_layer)
|
||||
arr_layers.new(name = 'MLOD')
|
||||
|
||||
if not len(obj.data.materials) == 0:
|
||||
obj.data.materials.clear()
|
||||
|
||||
palette_enum_selection = json.loads(context.scene.color_palettes.mlod_enum_selection)
|
||||
mlod_material_name = "MLOD_" + palette_enum_selection[0][:-4] + "_" + palette_enum_selection[1]
|
||||
|
||||
if not bpy.data.materials.get(mlod_material_name):
|
||||
material = bpy.data.materials.new(name=mlod_material_name)
|
||||
material.use_nodes = True
|
||||
bsdf_node = material.node_tree.nodes["Principled BSDF"]
|
||||
texImage = material.node_tree.nodes.new('ShaderNodeTexImage')
|
||||
texImage.image = bpy.data.images.get(palette_enum_selection[0])
|
||||
|
||||
material.node_tree.links.new(bsdf_node.inputs['Base Color'], texImage.outputs['Color'])
|
||||
|
||||
obj.data.materials.append(bpy.data.materials.get(mlod_material_name))
|
||||
|
||||
self.report({'INFO'}, 'Mesh configured like MLOD')
|
||||
return {"FINISHED"}
|
||||
|
||||
def import_palettes_textures(self):
|
||||
for image_name in colorpalettes:
|
||||
image_name = json.loads(image_name)[0]
|
||||
texture_name = image_name.split(".")[0]
|
||||
if texture_name not in bpy.data.textures:
|
||||
texture = bpy.data.textures.new(name=texture_name, type='IMAGE')
|
||||
else:
|
||||
texture = bpy.data.textures.get(texture_name)
|
||||
if image_name not in bpy.data.images:
|
||||
image = bpy.data.images.load(os.path.join(L1960_path, image_name))
|
||||
else:
|
||||
image = bpy.data.images.get(image_name)
|
||||
texture.image = image
|
||||
|
||||
# texture_filepath = os.path.join(L1960_path, colorpalettes[1])
|
||||
|
||||
### Palette MLOD ###
|
||||
# class MESH_OT_bake_basic_mlod(bpy.types.Operator):
|
||||
# """Set´s up a basic MLOD via Bake"""
|
||||
|
||||
# bl_idname = "mesh.bake_basic_mlod"
|
||||
# bl_label = "Set´s up a basic MLOD via Bake"
|
||||
# bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
# def execute(self, context):
|
||||
# obj = context.active_object
|
||||
|
||||
# #Palette selection
|
||||
# palette_enum_selection = json.loads(context.scene.color_palettes.mlod_enum_selection)
|
||||
|
||||
# if obj not in bpy.context.selected_objects or obj.type != "MESH":
|
||||
# self.report({'WARNING'}, 'Select a Mesh to continue')
|
||||
# return {"CANCELLED"}
|
||||
|
||||
# faces_with_color = self.get_faces_with_color(obj)
|
||||
|
||||
# grouped_colors = self.groupe_colors(faces_with_color, threshold=50)
|
||||
|
||||
# matched_colors = self.find_matching_color(grouped_colors, palette_enum_selection[0][:-4])
|
||||
|
||||
# self.adjust_UV(obj, matched_colors)
|
||||
|
||||
# #Entfernen des referenz Bake Image
|
||||
# #bpy.data.images.remove(bpy.data.images["MLOD_Temp"])
|
||||
|
||||
# # Entfernen aller Meterials
|
||||
# if not len(obj.data.materials) == 0:
|
||||
# obj.data.materials.clear()
|
||||
|
||||
# # Create new Material with selected Palette
|
||||
# mlod_material_name = "MLOD_" + palette_enum_selection[0][:-4] + palette_enum_selection[1]
|
||||
|
||||
# texture_filepath = os.path.join(L1960_path, palette_enum_selection[0])
|
||||
# image = bpy.data.images.load(texture_filepath)
|
||||
|
||||
# if not bpy.data.materials.get(mlod_material_name):
|
||||
# material = bpy.data.materials.new(name=mlod_material_name)
|
||||
# material.use_nodes = True
|
||||
# bsdf_node = material.node_tree.nodes["Principled BSDF"]
|
||||
# texImage = material.node_tree.nodes.new('ShaderNodeTexImage')
|
||||
# texImage.image = image
|
||||
# material.node_tree.links.new(bsdf_node.inputs['Base Color'], texImage.outputs['Color'])
|
||||
# obj.data.materials.append(bpy.data.materials.get(mlod_material_name))
|
||||
|
||||
# self.report({'INFO'}, f'MLOD sucessfully created with {palette_enum_selection[0][:-4]}.')
|
||||
# return {"FINISHED"}
|
||||
|
||||
# def get_faces_with_color(self, obj):
|
||||
|
||||
# #Bake Image
|
||||
# image = self.bake_diffuse(obj)
|
||||
|
||||
# mesh = obj.data
|
||||
# uv_layer = mesh.uv_layers.active.data # direct UV access
|
||||
|
||||
# colors = []
|
||||
|
||||
# for poly in mesh.polygons: # same as "face" in BMesh
|
||||
# # Durchschnittliche UV-Koordinaten berechnen
|
||||
# uv = Vector((0.0, 0.0))
|
||||
# for loop_index in poly.loop_indices:
|
||||
# uv += uv_layer[loop_index].uv
|
||||
# uv /= len(poly.loop_indices)
|
||||
|
||||
# # UV → Pixel-Koordinaten (Bildgröße)
|
||||
# x = int(uv.x * (image.size[0] - 1))
|
||||
# y = int(uv.y * (image.size[1] - 1))
|
||||
|
||||
# # RGBA Pixel holen
|
||||
# index = (y * image.size[0] + x) * 4
|
||||
# pixel = image.pixels[index:index+4]
|
||||
|
||||
# # In 0–255 Werte umwandeln
|
||||
# rgb_255 = [round(c * 255) for c in pixel][:3]
|
||||
|
||||
# colors.append({
|
||||
# "face": poly.index,
|
||||
# "rgb": rgb_255
|
||||
# })
|
||||
|
||||
# # print(colors[-1]) # -> [{'face': <BMFace(0x000002B417086A30), index=0, totverts=4>, 'rgb': [0, 0, 0]}]
|
||||
|
||||
# return colors
|
||||
|
||||
# def groupe_colors(self, color_list, threshold = 10):
|
||||
# groups = []
|
||||
|
||||
# for color in color_list:
|
||||
# found_group = False
|
||||
# for group in groups:
|
||||
# # Compute average color of the group
|
||||
# avg_color = [sum(c["rgb"][i] for c in group)/len(group) for i in range(3)]
|
||||
# if self.color_distance(color["rgb"], avg_color) <= threshold:
|
||||
# group.append(color)
|
||||
# found_group = True
|
||||
# break
|
||||
# if not found_group:
|
||||
# groups.append([color])
|
||||
|
||||
# # Compute the average color for each group
|
||||
# grouped_colors = [{
|
||||
# "face": [c["face"] for c in group],
|
||||
# "rgb": [round(sum(c["rgb"][i] for c in group) / len(group)) for i in range(3)]
|
||||
# }
|
||||
# for group in groups
|
||||
# ]
|
||||
|
||||
# return grouped_colors
|
||||
|
||||
# def color_distance(self, c1, c2):
|
||||
# return math.sqrt(
|
||||
# (c1[0]-c2[0])**2 +
|
||||
# (c1[1]-c2[1])**2 +
|
||||
# (c1[2]-c2[2])**2
|
||||
# )
|
||||
|
||||
# def read_color_csv(self, palette):
|
||||
# colors = []
|
||||
# try:
|
||||
# with open(f"{palette}.csv", newline="") as datei:
|
||||
# reader = csv.DictReader(datei)
|
||||
# for row in reader:
|
||||
# colors.append({
|
||||
# "rgb": [int(row["r"]), int(row["g"]), int(row["b"])],
|
||||
# "norm_x": float(row["norm_x"]),
|
||||
# "norm_y": float(row["norm_y"])
|
||||
# })
|
||||
# return colors
|
||||
# except:
|
||||
# return []
|
||||
|
||||
# def find_matching_color(self, colors, palette):
|
||||
# match = []
|
||||
# for color in colors:
|
||||
# best = None
|
||||
# min_dist = float("inf")
|
||||
|
||||
# for target in self.read_color_csv(palette):
|
||||
# dist = self.color_distance(target["rgb"], color["rgb"])
|
||||
# if dist < min_dist:
|
||||
# min_dist = dist
|
||||
# best = {
|
||||
# "face": color["face"],
|
||||
# "rgb": color["rgb"],
|
||||
# "norm_x": target["norm_x"],
|
||||
# "norm_y": target["norm_y"]
|
||||
# }
|
||||
# match.append(best)
|
||||
# return match
|
||||
|
||||
# def adjust_UV(self, obj, new_face_coords):
|
||||
# scale = 0.001 # Skalierung
|
||||
|
||||
# mesh = obj.data
|
||||
|
||||
# arr_layers = obj.data.uv_layers
|
||||
# if not arr_layers.get("MLOD") or len(arr_layers) > 1:
|
||||
# for uv_layer in reversed(arr_layers):
|
||||
# arr_layers.remove(uv_layer)
|
||||
# arr_layers.new(name = 'MLOD')
|
||||
# uv_layer = arr_layers.get("MLOD")
|
||||
# mesh.uv_layers.active = uv_layer
|
||||
|
||||
# for poly in mesh.polygons:
|
||||
# for coords in new_face_coords:
|
||||
# if poly.index in coords["face"]:
|
||||
|
||||
# # Mittelpunkt der UVs dieses Polygons berechnen
|
||||
# uvs = [uv_layer.data[i].uv.copy() for i in poly.loop_indices]
|
||||
# center = sum(uvs, Vector((0.0, 0.0))) / len(uvs)
|
||||
|
||||
# # Skalieren + Verschieben
|
||||
# for i in poly.loop_indices:
|
||||
# uv = uv_layer.data[i].uv
|
||||
# uv -= center
|
||||
# uv *= scale
|
||||
# uv += Vector((float(coords["norm_x"]), float(coords["norm_y"])))
|
||||
|
||||
# # Mesh updaten
|
||||
# mesh.update()
|
||||
|
||||
# def bake_diffuse(self, selected_obj, res = 1024):
|
||||
|
||||
# source_obj = None
|
||||
# for obj in bpy.data.objects:
|
||||
# if obj.type == 'MESH' and obj.name.endswith("_LOD0"):
|
||||
# print(obj.name)
|
||||
# source_obj = obj.copy()
|
||||
# source_obj.data = obj.data.copy()
|
||||
# bpy.context.collection.objects.link(source_obj)
|
||||
# break
|
||||
|
||||
# if source_obj is None:
|
||||
# source_obj = selected_obj.copy()
|
||||
# source_obj.data = selected_obj.data.copy()
|
||||
# bpy.context.collection.objects.link(source_obj)
|
||||
|
||||
# # Material erstellen
|
||||
# if "MLOD_Temp" in bpy.data.materials:
|
||||
# mat = bpy.data.materials.remove["MLOD_Temp"]
|
||||
# mat = bpy.data.materials.new(name="MLOD_Temp")
|
||||
# source_obj.data.materials.clear()
|
||||
# source_obj.data.materials.append(mat)
|
||||
|
||||
# # WICHTIG: Material als aktives Material setzen
|
||||
# mat.use_nodes = True
|
||||
# source_obj.active_material = mat
|
||||
|
||||
# # Ziel Image Node konfigurieren
|
||||
# nodes = mat.node_tree.nodes
|
||||
# links = mat.node_tree.links
|
||||
# nodes.clear()
|
||||
# tex_node = nodes.new(type="ShaderNodeTexImage")
|
||||
# bsdf = nodes.new(type="ShaderNodeBsdfPrincipled")
|
||||
# output = nodes.new(type="ShaderNodeOutputMaterial")
|
||||
# links.new(bsdf.outputs["BSDF"], output.inputs["Surface"])
|
||||
# links.new(tex_node.outputs["Color"], bsdf.inputs["Base Color"])
|
||||
# nodes.active = tex_node
|
||||
|
||||
# # Erstellen des Images
|
||||
# if "MLOD_Temp" in bpy.data.images:
|
||||
# bpy.data.images.remove(bpy.data.images["MLOD_Temp"])
|
||||
# image = bpy.data.images.new("MLOD_Temp", res, res)
|
||||
# tex_node.image = image
|
||||
|
||||
# # Selected Object = Quelle
|
||||
# bpy.context.view_layer.objects.active = source_obj
|
||||
# # Active Object = Ziel
|
||||
# selected_obj.select_set(True)
|
||||
|
||||
# # Bake
|
||||
# bpy.context.scene.render.engine = 'CYCLES'
|
||||
# bpy.ops.object.bake(type='COMBINED', width=512, height=512, cage_extrusion=0.5, pass_filter={'COLOR'}, margin=16, use_selected_to_active=True)
|
||||
|
||||
# # Temporäre Helfer entfernen
|
||||
# bpy.data.objects.remove(source_obj, do_unlink=True)
|
||||
# if "MLOD_Temp" in bpy.data.materials:
|
||||
# bpy.data.materials.remove(mat)
|
||||
|
||||
# bpy.context.view_layer.objects.active = selected_obj
|
||||
|
||||
# return image
|
||||
1025
Blender/L1960_Tools/_Source/L1960_Tools_1_8_4/ColorPalette_01.csv
Normal file
1025
Blender/L1960_Tools/_Source/L1960_Tools_1_8_4/ColorPalette_01.csv
Normal file
File diff suppressed because it is too large
Load Diff
Binary file not shown.
|
After Width: | Height: | Size: 9.7 KiB |
1025
Blender/L1960_Tools/_Source/L1960_Tools_1_8_4/ColorPalette_02.csv
Normal file
1025
Blender/L1960_Tools/_Source/L1960_Tools_1_8_4/ColorPalette_02.csv
Normal file
File diff suppressed because it is too large
Load Diff
Binary file not shown.
|
After Width: | Height: | Size: 9.1 KiB |
@@ -0,0 +1,94 @@
|
||||
import bpy
|
||||
from math import pi
|
||||
|
||||
L1960_Arr_PlainData = [
|
||||
["Proj_Empty_01", (0, 0, 2), (0, 0, 0)],
|
||||
["Proj_Empty_02", (2, 0, 0), ((pi * 90 / 180), 0, (pi * 90 / 180))],
|
||||
["Proj_Empty_03", (0, 2, 0), ((pi * 90 / 180), 0, (pi * 180 / 180))],
|
||||
["Proj_Empty_04", (0, 0, -2), ((pi * 180 / 180), 0, 0)],
|
||||
["Proj_Empty_05", (-2, 0, 0), ((pi * 90 / 180), 0, (pi * -90 / 180))],
|
||||
["Proj_Empty_06", (0, -2, 0), ((pi * 90 / 180), 0, 0)]
|
||||
]
|
||||
|
||||
class MESH_OT_add_auto_cube_projection(bpy.types.Operator):
|
||||
"""Check Empty´s for projecting, if not existing create new one´s"""
|
||||
|
||||
bl_idname = "mesh.add_auto_cube_projection"
|
||||
bl_label = "Add Plain_Axes to scene"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def execute(self, context):
|
||||
|
||||
scene = context.scene
|
||||
oldSelection = context.selected_objects
|
||||
oldActive = context.active_object
|
||||
|
||||
for EmptyData in L1960_Arr_PlainData:
|
||||
|
||||
EmptyName = EmptyData[0]
|
||||
EmptyLocation = EmptyData[1]
|
||||
EmptyRotation = EmptyData[2]
|
||||
|
||||
if not scene.objects.get(EmptyName):
|
||||
bpy.ops.object.empty_add(type='PLAIN_AXES', align='WORLD', location=EmptyLocation, scale=(1, 1, 1), rotation=EmptyRotation)
|
||||
empty = context.active_object
|
||||
empty.name = EmptyName
|
||||
empty.hide_select = True
|
||||
empty.hide_set(True)
|
||||
|
||||
#Change back to old selection and select old active
|
||||
for obj in oldSelection:
|
||||
obj.select_set(True)
|
||||
context.view_layer.objects.active = oldActive
|
||||
|
||||
self.report({'INFO'}, 'Added/Fixed Emptys for Projection to Scene')
|
||||
return {"FINISHED"}
|
||||
|
||||
class MESH_OT_add_modifier_to_mesh(bpy.types.Operator):
|
||||
"""Add Modifier to selected Mesh´s and prepare UV-Maps"""
|
||||
|
||||
bl_idname = "mesh.add_modifier_to_mesh"
|
||||
bl_label = "Add Modifier to selected Mesh"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def execute(self, context):
|
||||
|
||||
newModifierName = "CubeTexModifier"
|
||||
arr_obj = context.selected_objects
|
||||
if not arr_obj:
|
||||
self.report({'WARNING'}, 'Select a mesh to add the UVProject-Modifier')
|
||||
return {"CANCELLED"}
|
||||
|
||||
empty_objs = [emp_obj for emp_obj in context.scene.objects if emp_obj.name.startswith("Proj_Empty")]
|
||||
if len(empty_objs) < 6:
|
||||
self.report({'WARNING'}, 'Create/Recreate projectors, they need to be set up first!')
|
||||
return {"CANCELLED"};
|
||||
|
||||
for obj in arr_obj:
|
||||
|
||||
if obj.data.uv_layers.get("UVMap"):
|
||||
obj.data.uv_layers['UVMap'].name = 'UVMap0'
|
||||
|
||||
if not obj.data.uv_layers.get("UVMap0"):
|
||||
obj.data.uv_layers.new(name = 'UVMap0')
|
||||
|
||||
if not obj.data.uv_layers.get("UVMap1"):
|
||||
obj.data.uv_layers.new(name = 'UVMap1')
|
||||
|
||||
|
||||
if obj.type == "MESH" and newModifierName not in obj.modifiers:
|
||||
obj.modifiers.new(type='UV_PROJECT', name=newModifierName)
|
||||
mod = obj.modifiers[newModifierName]
|
||||
mod.uv_layer = "UVMap1"
|
||||
mod.projector_count = 6
|
||||
|
||||
i = 0
|
||||
for p in mod.projectors:
|
||||
p.object = bpy.data.objects[L1960_Arr_PlainData[i][0]]
|
||||
i = i+1
|
||||
else:
|
||||
self.report({'INFO'}, 'UVProject-Modifier allready set')
|
||||
return {"FINISHED"}
|
||||
|
||||
self.report({'INFO'}, 'Added UVProject-Modifier to mesh')
|
||||
return {"FINISHED"}
|
||||
187
Blender/L1960_Tools/_Source/L1960_Tools_1_8_4/Dekogon.py
Normal file
187
Blender/L1960_Tools/_Source/L1960_Tools_1_8_4/Dekogon.py
Normal file
@@ -0,0 +1,187 @@
|
||||
import bpy
|
||||
import re
|
||||
import os
|
||||
|
||||
### GROUP OBJECTS TO COLLECTIONS ###
|
||||
|
||||
class MESH_OT_group_objects_in_collections(bpy.types.Operator):
|
||||
"""Groups objects by name into seperate collections, usefull for Unreal Decogon import"""
|
||||
|
||||
bl_idname = "mesh.group_objects_in_collections"
|
||||
bl_label = "Groups objects by name into seperate collections, usefull for Unreal Decogon import"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def execute(self, context):
|
||||
# Erstellen einer leeren Dictionary zur Speicherung der Collections nach Basisnamen
|
||||
collection_dict = {}
|
||||
|
||||
# Durchlaufen aller Objekte in der Szene
|
||||
for obj in context.scene.objects:
|
||||
# Überprüfen, ob das Objekt ein leeres Elternobjekt ist
|
||||
if obj.type == 'EMPTY':
|
||||
# Anwenden der Regex auf den Objektnamen
|
||||
match = re.match(r'^(.*?)_(.*?)_(\d+)([a-zA-Z]+)$', obj.name)
|
||||
if match:
|
||||
prefix = match.group(1)
|
||||
name = match.group(2)
|
||||
number = match.group(3)
|
||||
letter = match.group(4)
|
||||
|
||||
# Extrahieren des Basisnamens für die Collection
|
||||
base_name = f"L1960_{name}"
|
||||
|
||||
# Hinzufügen des Objekts zur entsprechenden Liste in der Dictionary
|
||||
if base_name not in collection_dict:
|
||||
collection_dict[base_name] = {}
|
||||
if number not in collection_dict[base_name]:
|
||||
collection_dict[base_name][number] = {}
|
||||
if letter not in collection_dict[base_name][number]:
|
||||
collection_dict[base_name][number][letter] = {'empty': obj, 'children': []}
|
||||
|
||||
# Durchlaufen der Dictionary und Erstellen der Collections
|
||||
for base_name, number_dict in collection_dict.items():
|
||||
# Erstellen einer neuen Collection für den Basisnamen
|
||||
base_collection = bpy.data.collections.new(base_name)
|
||||
bpy.context.scene.collection.children.link(base_collection)
|
||||
|
||||
# Durchlaufen der sortierten Liste der Objekte und Verschieben in die Collections
|
||||
for number, letter_dict in number_dict.items():
|
||||
# Erstellen einer Collection für die Nummer und Verschieben des leeren Elternobjekts dorthin
|
||||
number_collection = bpy.data.collections.new(f"{base_name}_{number}")
|
||||
base_collection.children.link(number_collection)
|
||||
|
||||
# Durchlaufen der Buchstaben und Erstellen der Buchstaben-Collection unter der Nummer
|
||||
for letter, obj_data in letter_dict.items():
|
||||
empty = obj_data['empty']
|
||||
children = empty.children
|
||||
|
||||
letter_collection = bpy.data.collections.new(f"{base_name}_{number}{letter}")
|
||||
number_collection.children.link(letter_collection)
|
||||
|
||||
# Verschieben des leeren Elternobjekts in die entsprechende Collection
|
||||
letter_collection.objects.link(empty)
|
||||
|
||||
# Verschieben der Kinder des leeren Elternobjekts in die entsprechende Collection
|
||||
for child in children:
|
||||
letter_collection.objects.link(child)
|
||||
|
||||
# Entfernen des leeren Elternobjekts und seiner Kinder aus der Szene
|
||||
bpy.context.collection.objects.unlink(empty)
|
||||
for child in children:
|
||||
bpy.context.collection.objects.unlink(child)
|
||||
|
||||
# -------------------------------------------------------------------------------------------
|
||||
# Regular expression pattern to match any _LOD1, _LOD2, etc., but not _LOD0
|
||||
pattern = re.compile(r"_LOD[1-9]\d*$")
|
||||
|
||||
# Loop through all objects in the scene
|
||||
for obj in bpy.context.scene.objects:
|
||||
# If the object name matches the pattern, hide it
|
||||
if pattern.search(obj.name):
|
||||
obj.hide_set(True) # This hides the object in the viewport
|
||||
else:
|
||||
obj.hide_set(False) # Ensure _LOD0 objects remain visible
|
||||
|
||||
# Update the view layer to reflect changes
|
||||
bpy.context.view_layer.update()
|
||||
|
||||
self.report({'INFO'}, 'All objects sorted')
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
### ASSIGN TEXTURES ###
|
||||
|
||||
class MESH_OT_assign_textures(bpy.types.Operator):
|
||||
"""Assign Textures to Mesh´s, usefull for Unreal Decogon import"""
|
||||
|
||||
bl_idname = "mesh.assign_textures"
|
||||
bl_label = "Assign Textures to Mesh´s, usefull for Unreal Decogon import"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def execute(self, context):
|
||||
|
||||
# Define the path to the folder containing your textures
|
||||
texture_folder_path = context.scene.dekogon_file_path
|
||||
|
||||
texture_prefix = context.scene.dekogon_settings_prefix
|
||||
if texture_prefix != "":
|
||||
if texture_prefix[-1] != "_":
|
||||
texture_prefix = texture_prefix + "_"
|
||||
|
||||
texture_suffix = context.scene.dekogon_settings_suffix
|
||||
if texture_suffix != "":
|
||||
if texture_suffix[0] != "_":
|
||||
texture_suffix = "_" + texture_suffix
|
||||
|
||||
texture_filetype = context.scene.dekogon_settings_filetype
|
||||
|
||||
if not os.path.exists(texture_folder_path):
|
||||
self.report({'ERROR'}, f"The texture folder path '{texture_folder_path}' does not exist.")
|
||||
return {"FINISHED"}
|
||||
else:
|
||||
self.report({'INFO'}, f"Texture folder path: {texture_folder_path}")
|
||||
# List all files in the texture folder for debugging purposes
|
||||
#texture_files = os.listdir(texture_folder_path)
|
||||
#self.report({'INFO'}, "Files in texture folder:")
|
||||
#for f in texture_files:
|
||||
# print(f" - {f}")
|
||||
|
||||
# Iterate over all materials in the Blender file
|
||||
for material in bpy.data.materials:
|
||||
self.report({'INFO'}, f"Processing material: {material.name}")
|
||||
# Ensure the material uses nodes
|
||||
if not material.use_nodes:
|
||||
material.use_nodes = True
|
||||
self.report({'INFO'}, f"Enabled nodes for material: {material.name}")
|
||||
|
||||
# Get the node tree of the material
|
||||
if material.node_tree is None:
|
||||
self.report({'WARNING'}, f"Material {material.name} has no node tree.")
|
||||
continue
|
||||
|
||||
nodes = material.node_tree.nodes
|
||||
|
||||
# Find or create an Image Texture node
|
||||
image_texture_node = None
|
||||
for node in nodes:
|
||||
if node.type == 'TEX_IMAGE':
|
||||
image_texture_node = node
|
||||
break
|
||||
if image_texture_node is None:
|
||||
image_texture_node = nodes.new(type='ShaderNodeTexImage')
|
||||
self.report({'INFO'}, f"Created new Image Texture node for material: {material.name}")
|
||||
else:
|
||||
self.report({'INFO'}, f"Found existing Image Texture node for material: {material.name}")
|
||||
|
||||
# Construct the expected texture filename based on the material name
|
||||
texture_filename = f"{texture_prefix}{material.name}{texture_suffix}.{texture_filetype}"
|
||||
texture_filepath = os.path.join(texture_folder_path, texture_filename)
|
||||
self.report({'INFO'}, f"Looking for texture: {texture_filepath}")
|
||||
|
||||
# Check if the texture file exists
|
||||
if os.path.exists(texture_filepath):
|
||||
try:
|
||||
# Load the image and assign it to the Image Texture node
|
||||
image = bpy.data.images.load(texture_filepath)
|
||||
image_texture_node.image = image
|
||||
self.report({'INFO'}, f"Loaded texture: {texture_filename} for material: {material.name}")
|
||||
|
||||
# Link the Image Texture node to the Base Color of the Principled BSDF shader
|
||||
principled_node = None
|
||||
for node in nodes:
|
||||
if node.type == 'BSDF_PRINCIPLED':
|
||||
principled_node = node
|
||||
break
|
||||
if principled_node is not None:
|
||||
links = material.node_tree.links
|
||||
links.new(image_texture_node.outputs['Color'], principled_node.inputs['Base Color'])
|
||||
self.report({'INFO'}, f"Linked texture to Principled BSDF for material: {material.name}")
|
||||
else:
|
||||
self.report({'WARNING'}, f"No Principled BSDF node found for material: {material.name}")
|
||||
except RuntimeError as e:
|
||||
self.report({'ERROR'}, f"Failed to load image {texture_filename}: {e}")
|
||||
else:
|
||||
self.report({'WARNING'}, "Texture file not found for material {material.name}: {texture_filename}")
|
||||
|
||||
self.report({'INFO'}, 'Texture assignment complete.')
|
||||
return {"FINISHED"}
|
||||
139
Blender/L1960_Tools/_Source/L1960_Tools_1_8_4/Helper.py
Normal file
139
Blender/L1960_Tools/_Source/L1960_Tools_1_8_4/Helper.py
Normal file
@@ -0,0 +1,139 @@
|
||||
import bpy
|
||||
import bmesh
|
||||
|
||||
### FIX MATERIALS ###
|
||||
|
||||
class MESH_OT_fix_material_names(bpy.types.Operator):
|
||||
"""Fixes the material naming, if duplicated are present e.g. Material.001, Material.002 ..."""
|
||||
|
||||
bl_idname = "mesh.fix_material_names"
|
||||
bl_label = "Fixes the material naming, if duplicated are present"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def execute(self, context):
|
||||
#Remove all duplicated materials
|
||||
self.merge_duplicated_materials()
|
||||
|
||||
#Merge material slots for every mesh in the scene
|
||||
for obj in bpy.context.scene.objects:
|
||||
if obj.type == "MESH":
|
||||
self.merge_material_slots(obj)
|
||||
|
||||
|
||||
self.report({'INFO'}, 'All duplicated Materials fixed')
|
||||
return {"FINISHED"}
|
||||
|
||||
def merge_duplicated_materials(self):
|
||||
for material in bpy.data.materials:
|
||||
#Remove MI for Dekogon material names
|
||||
if material.name.split('_')[0] == 'MI':
|
||||
material.name = material.name[3:]
|
||||
#Check for .001 at end and remove
|
||||
if material.name[-3:].isnumeric():
|
||||
opti_matName = material.name[:-4]
|
||||
if bpy.data.materials.get(opti_matName): #check if og_mat exists
|
||||
material.user_remap(bpy.data.materials.get(opti_matName))
|
||||
print("Removed Material: " + material.name)
|
||||
bpy.data.materials.remove(material)
|
||||
else:
|
||||
material.name = opti_matName
|
||||
|
||||
def merge_material_slots(self, obj):
|
||||
duplicated_material_list = []
|
||||
|
||||
#create list with indexes of material slots with the same name and merge them
|
||||
for og_slot in obj.material_slots:
|
||||
for slot in obj.material_slots:
|
||||
if slot.name == og_slot.name:
|
||||
if slot.slot_index == og_slot.slot_index:
|
||||
continue
|
||||
if og_slot.slot_index in duplicated_material_list:
|
||||
continue
|
||||
duplicated_material_list.append(int(slot.slot_index))
|
||||
|
||||
#delete all material slots within list
|
||||
for slot_index in sorted(duplicated_material_list, reverse=True):
|
||||
obj.data.materials.pop(index = slot_index)
|
||||
|
||||
|
||||
### FIX NAMING CONVENTIONS ###
|
||||
|
||||
class MESH_OT_fix_naming_conventions(bpy.types.Operator):
|
||||
"""Changes . to _ to solve naming issues with workbench"""
|
||||
|
||||
bl_idname = "mesh.fix_naming_convention"
|
||||
bl_label = "Changes . to _ to solve naming issues with workbench"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def execute(self, context):
|
||||
for obj in bpy.data.objects:
|
||||
obj.name = obj.name.replace(".","_")
|
||||
|
||||
self.report({'INFO'}, 'Fixed Naming')
|
||||
return {"FINISHED"}
|
||||
|
||||
class MESH_OT_generate_empty_for_mesh(bpy.types.Operator):
|
||||
"""Generates a Empty with the objects name at it´s position"""
|
||||
|
||||
bl_idname = "mesh.generate_empty_for_mesh"
|
||||
bl_label = "Generates a Empty with the objects name at it´s position"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def execute(self, context):
|
||||
scene = bpy.context.scene
|
||||
Selection = bpy.context.selected_objects
|
||||
FilteredSelection = [obj for obj in Selection if obj.type != 'EMPTY']
|
||||
ActiveObj = bpy.context.active_object
|
||||
|
||||
for obj in FilteredSelection:
|
||||
oldEmpty = scene.objects.get("Socket_" + obj.name)
|
||||
if oldEmpty:
|
||||
oldEmpty.location = obj.location
|
||||
oldEmpty.rotation_euler = obj.rotation_euler
|
||||
else:
|
||||
obj.select_set(True)
|
||||
bpy.ops.object.empty_add(type='PLAIN_AXES', align='WORLD', location=obj.location, scale=(1, 1, 1), rotation=obj.rotation_euler)
|
||||
empty = bpy.context.active_object
|
||||
empty.name = "Socket_" + obj.name
|
||||
|
||||
#Change back to selection and select old active
|
||||
bpy.ops.object.select_all(action='DESELECT')
|
||||
|
||||
self.report({'INFO'}, 'Generated Emptys for selectes Meshes in Scene')
|
||||
return {"FINISHED"}
|
||||
|
||||
class MESH_OT_select_face_id(bpy.types.Operator):
|
||||
"""Highlights Face with given ID"""
|
||||
|
||||
bl_idname = "mesh.select_face_id"
|
||||
bl_label = "Highlight/Select Face with given Index"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def execute(self, context):
|
||||
EditObj = bpy.context.active_object
|
||||
|
||||
face_Index = int(context.scene.face_id_field)
|
||||
|
||||
if EditObj != None:
|
||||
bpy.ops.object.mode_set(mode='EDIT')
|
||||
bpy.ops.mesh.select_all(action='DESELECT')
|
||||
bm = bmesh.from_edit_mesh(EditObj.data)
|
||||
bm.faces.ensure_lookup_table()
|
||||
|
||||
for area in bpy.context.screen.areas:
|
||||
if area.type == 'VIEW_3D':
|
||||
for space in area.spaces:
|
||||
if space.type == 'VIEW_3D':
|
||||
space.shading.type = 'WIREFRAME'
|
||||
try:
|
||||
bm.faces[face_Index].select = True
|
||||
bmesh.update_edit_mesh(EditObj.data)
|
||||
|
||||
self.report({'INFO'}, f'Highlighted Face with Index: {face_Index}')
|
||||
return {"FINISHED"}
|
||||
except IndexError:
|
||||
self.report({'INFO'}, f'Index: {face_Index} out of range!')
|
||||
return {"FINISHED"}
|
||||
else:
|
||||
self.report({'INFO'}, 'Please select a Mesh first.')
|
||||
return {"FINISHED"}
|
||||
244
Blender/L1960_Tools/_Source/L1960_Tools_1_8_4/MaterialToMask.py
Normal file
244
Blender/L1960_Tools/_Source/L1960_Tools_1_8_4/MaterialToMask.py
Normal file
@@ -0,0 +1,244 @@
|
||||
import bpy
|
||||
import bmesh
|
||||
|
||||
# Callback for Enum Items
|
||||
def get_uv_layers(self, context):
|
||||
items = []
|
||||
obj = context.object
|
||||
|
||||
if obj and obj.type == 'MESH' and obj.data.uv_layers:
|
||||
for i, uv in enumerate(obj.data.uv_layers):
|
||||
items.append((str(i), uv.name, f"UV Layer {i}"))
|
||||
else:
|
||||
items.append(("NONE", "No UVs", "No UV available within Mesh"))
|
||||
|
||||
return items
|
||||
|
||||
class UVEnumProperties(bpy.types.PropertyGroup):
|
||||
uv_enum: bpy.props.EnumProperty(name="MASK UV Map", description="Select Mask UV-Layer", items=get_uv_layers, default=0)
|
||||
|
||||
class MESH_OT_merge_materials_to_mask(bpy.types.Operator):
|
||||
"""Merges 4 Materials into one Material (Mask)"""
|
||||
|
||||
bl_idname = "mesh.merge_materials_to_mask"
|
||||
bl_label = "Merges 4 Materials into one Material (Mask)"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def execute(self, context):
|
||||
scene = context.scene
|
||||
ts = scene.tool_settings
|
||||
arr_obj = context.selected_objects
|
||||
activeObj = context.active_object
|
||||
|
||||
# Get all inputs from user
|
||||
selected_uv = context.scene.settings_uv_enum_props.uv_enum
|
||||
ignore_custom = context.scene.settings_multi_ignor
|
||||
mat_nameing = context.scene.settings_mat_nameing
|
||||
island_margin_custom = context.scene.settings_uv_island_margin_slider
|
||||
|
||||
# Scale and offset for UV allignment
|
||||
SCALE = 0.5
|
||||
OFFSETS = [
|
||||
(0.0, 0.5),
|
||||
(0.5, 0.5),
|
||||
(0.0, 0.0),
|
||||
(0.5, 0.0)
|
||||
]
|
||||
IGNORE = ["glass", "glas", "grass", "gras", "atlas"]
|
||||
if ignore_custom.strip():
|
||||
IGNORE.extend(ignore_custom.split(","))
|
||||
|
||||
# No Mesh selected
|
||||
if not arr_obj:
|
||||
self.report({'WARNING'}, 'Select one mesh')
|
||||
return {"CANCELLED"}
|
||||
|
||||
# Only one Mesh selected?
|
||||
if len(arr_obj) > 1:
|
||||
self.report({'WARNING'}, 'Only one Mesh can be selected')
|
||||
return {"CANCELLED"}
|
||||
|
||||
obj = arr_obj[0]
|
||||
|
||||
# UV Maps present?
|
||||
if not obj.data.uv_layers or not selected_uv:
|
||||
self.report({'WARNING'}, 'No UV-Map selected')
|
||||
return {"CANCELLED"}
|
||||
|
||||
obj.data.uv_layers.active_index = int(selected_uv)
|
||||
|
||||
# Deactivate uv Select Sync in UV Editor. Makes Problems
|
||||
old_ts_state = ts.use_uv_select_sync
|
||||
ts.use_uv_select_sync = False
|
||||
|
||||
skip = 0
|
||||
idx_multi = None
|
||||
idx_multi_name = 1
|
||||
delete = []
|
||||
|
||||
# Loop through all Materials
|
||||
for i, slot in enumerate(obj.material_slots):
|
||||
|
||||
# Skip Materials in static ignore list or user ignore list
|
||||
if any(str(name).lower() in slot.material.name.lower() for name in IGNORE):
|
||||
self.report({'INFO'}, f'Material "{slot.material.name}" skipped.')
|
||||
skip += 1
|
||||
continue
|
||||
|
||||
# Switch to edit mode
|
||||
bpy.ops.object.mode_set(mode='EDIT')
|
||||
|
||||
# Create bmesh to work with
|
||||
bm = bmesh.from_edit_mesh(obj.data)
|
||||
uv_layer = bm.loops.layers.uv.active
|
||||
|
||||
# Deselect all
|
||||
bpy.ops.mesh.select_all(action='DESELECT')
|
||||
|
||||
if slot.material:
|
||||
# Select Mat slot
|
||||
obj.active_material_index = i
|
||||
|
||||
# Select all Faces of Mat
|
||||
bpy.ops.object.material_slot_select()
|
||||
|
||||
# If UV has assigned faces
|
||||
if any(f.select for f in bm.faces):
|
||||
# Repack UV Islands
|
||||
bpy.ops.uv.select_all(action='SELECT')
|
||||
bpy.ops.uv.pack_islands(margin=island_margin_custom)
|
||||
|
||||
# Select Offset
|
||||
group = (i - skip) % len(OFFSETS)
|
||||
offset = OFFSETS[group]
|
||||
|
||||
# Scale and offset UV
|
||||
for f in bm.faces:
|
||||
if f.select:
|
||||
for loop in f.loops:
|
||||
uv = loop[uv_layer].uv
|
||||
uv[0] = offset[0] + uv[0] * SCALE
|
||||
uv[1] = offset[1] + uv[1] * SCALE
|
||||
|
||||
# Apply Changes
|
||||
bmesh.update_edit_mesh(obj.data)
|
||||
|
||||
# Create Texture Attributes with previous material names
|
||||
match group:
|
||||
case 0:
|
||||
mat = bpy.data.materials.get(obj.material_slots[i].name)
|
||||
mat["1. Black "] = mat.name
|
||||
|
||||
# Change name and use as base to merge
|
||||
mat.name = str(mat_nameing).replace("$MeshName", obj.name.replace("L1960_", "").replace("KB3D_AMC_", "")) + "_" + str(idx_multi_name)
|
||||
idx_multi_name += 1
|
||||
idx_multi = i
|
||||
self.report({'INFO'}, f'Material "{mat.name}" created.')
|
||||
continue
|
||||
case 1:
|
||||
mat = bpy.data.materials.get(obj.material_slots[idx_multi].name)
|
||||
mat["2. Red "] = slot.material.name
|
||||
case 2:
|
||||
mat = bpy.data.materials.get(obj.material_slots[idx_multi].name)
|
||||
mat["3. Green "] = slot.material.name
|
||||
case 3:
|
||||
mat = bpy.data.materials.get(obj.material_slots[idx_multi].name)
|
||||
mat["4. Blue "] = slot.material.name
|
||||
case _:
|
||||
pass
|
||||
|
||||
# Merge Material A -> B
|
||||
self.merge_mat_A_to_B(obj, i, idx_multi)
|
||||
|
||||
# Add Material B to delete list
|
||||
delete.insert(0, i)
|
||||
|
||||
# Switch to object mode
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
|
||||
# Delete not used materials from list
|
||||
for mat in delete:
|
||||
obj.active_material_index = mat
|
||||
bpy.ops.object.material_slot_remove()
|
||||
|
||||
# Put UV first
|
||||
self.put_UV_first(obj, selected_uv)
|
||||
|
||||
# Change UV names like in Reforger Tools
|
||||
mesh = obj.data
|
||||
uv_layers = mesh.uv_layers
|
||||
for i, layer in enumerate(uv_layers):
|
||||
layer.name = f"UVMap{i + 1}"
|
||||
|
||||
# Activate Select Sync in UV Editor
|
||||
ts.use_uv_select_sync = old_ts_state
|
||||
|
||||
self.report({'INFO'}, 'Merged Materials to Multitextures.')
|
||||
return {"FINISHED"}
|
||||
|
||||
def merge_mat_A_to_B(self, obj, mat_A, mat_B):
|
||||
# check if Mat Name is index or string and convert
|
||||
if type(mat_A) is str:
|
||||
mat_A = bpy.data.materials.get(mat_A)
|
||||
mat_A = obj.material_slots.find(mat_A)
|
||||
if type(mat_B) is str:
|
||||
mat_B = bpy.data.materials.get(mat_B)
|
||||
mat_B = obj.material_slots.find(mat_B)
|
||||
|
||||
# Change to Edit Mode
|
||||
bpy.ops.object.mode_set(mode='EDIT')
|
||||
bpy.ops.mesh.select_all(action='DESELECT')
|
||||
|
||||
# Select all Faces from Mat B
|
||||
obj.active_material_index = mat_A
|
||||
bpy.ops.object.material_slot_select()
|
||||
|
||||
# Select Mat A and assign Faces from Mat B
|
||||
obj.active_material_index = mat_B
|
||||
bpy.ops.object.material_slot_assign() # Faces from B → A
|
||||
|
||||
# Switch to object mode
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
|
||||
def put_UV_first(self, obj, target_index):
|
||||
target_index = int(target_index)
|
||||
mesh = obj.data
|
||||
uv_layers = mesh.uv_layers
|
||||
|
||||
if target_index < 0 or target_index >= len(uv_layers):
|
||||
return
|
||||
|
||||
if len(uv_layers) <= 1:
|
||||
return
|
||||
|
||||
# Sicherstellen, dass wir im Object Mode sind
|
||||
if obj.mode != 'OBJECT':
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
|
||||
# Backup aller UV-Layer
|
||||
uv_backup = []
|
||||
for layer in uv_layers:
|
||||
uv_backup.append({
|
||||
"name": layer.name,
|
||||
"data": [loop.uv.copy() for loop in layer.data]
|
||||
})
|
||||
|
||||
# Neue Reihenfolge: target_index zuerst
|
||||
new_order = [target_index] + [
|
||||
i for i in range(len(uv_layers)) if i != target_index
|
||||
]
|
||||
|
||||
# Alle UV-Layer löschen (rückwärts!)
|
||||
for i in range(len(uv_layers) - 1, -1, -1):
|
||||
uv_layers.remove(uv_layers[i])
|
||||
|
||||
# UV-Layer neu erstellen
|
||||
for idx in new_order:
|
||||
info = uv_backup[idx]
|
||||
new_layer = uv_layers.new(name=info["name"])
|
||||
for i, uv in enumerate(info["data"]):
|
||||
new_layer.data[i].uv = uv
|
||||
|
||||
# Ersten UV-Layer aktiv & render setzen
|
||||
uv_layers.active_index = 0
|
||||
uv_layers[0].active_render = True
|
||||
42
Blender/L1960_Tools/_Source/L1960_Tools_1_8_4/PrepareLods.py
Normal file
42
Blender/L1960_Tools/_Source/L1960_Tools_1_8_4/PrepareLods.py
Normal file
@@ -0,0 +1,42 @@
|
||||
import bpy
|
||||
|
||||
### PREPARE LODS ###
|
||||
|
||||
class MESH_OT_prepare_lods_decimate(bpy.types.Operator):
|
||||
"""Copy current Mesh and apply decimate Modifier"""
|
||||
|
||||
bl_idname = "mesh.prepare_lods_decimate"
|
||||
bl_label = "Copy current Mesh and apply decimate Modifier"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def execute(self, context):
|
||||
|
||||
#Selected Mesh
|
||||
obj = bpy.context.active_object
|
||||
|
||||
if obj not in bpy.context.selected_objects or obj.type != "MESH":
|
||||
self.report({'WARNING'}, 'Select a Mesh to continue')
|
||||
return {"CANCELLED"}
|
||||
|
||||
if not obj.name[:-1].endswith('LOD'):
|
||||
obj.name = obj.name + '_LOD0'
|
||||
|
||||
LODnumber = context.scene.lod_slider #Get from Slider
|
||||
startLODcount = int(obj.name[-1])
|
||||
endLODcount = startLODcount + LODnumber
|
||||
|
||||
for i in range (startLODcount + 1, endLODcount):
|
||||
new_obj = obj.copy()
|
||||
new_obj.data = obj.data.copy()
|
||||
new_obj.name = obj.name[:-1] + str(i)
|
||||
bpy.context.collection.objects.link(new_obj)
|
||||
|
||||
for t in range (startLODcount, i):
|
||||
newModifierName = 'LOD_Decimate_' + str(t)
|
||||
new_obj.modifiers.new(type='DECIMATE', name=newModifierName)
|
||||
mod = new_obj.modifiers[newModifierName]
|
||||
mod.ratio = 0.49
|
||||
mod.use_collapse_triangulate = True
|
||||
|
||||
self.report({'INFO'}, 'LOD´s created')
|
||||
return {"FINISHED"}
|
||||
@@ -0,0 +1,30 @@
|
||||
from PIL import Image
|
||||
import csv
|
||||
|
||||
palettes = ["ColorPalette_01", "ColorPalette_02"]
|
||||
|
||||
for palette in palettes:
|
||||
# Bild öffnen (Pfad anpassen)
|
||||
bild = Image.open(f"{palette}.png").convert("RGB")
|
||||
|
||||
breite, hoehe = bild.size
|
||||
tiles_x, tiles_y = 32, 32
|
||||
|
||||
# Auf 32x32 verkleinern (nimmt repräsentative Pixel pro Kachel)
|
||||
klein = bild.resize((32, 32), Image.NEAREST)
|
||||
|
||||
# CSV-Datei schreiben
|
||||
with open(f"{palette}.csv", mode="w", newline="") as datei:
|
||||
writer = csv.writer(datei)
|
||||
writer.writerow(["norm_x", "norm_y", "r", "g", "b"])
|
||||
|
||||
for py in range(tiles_y):
|
||||
for px in range(tiles_x):
|
||||
# Farbe an diesem Pixel holen
|
||||
r, g, b = bild.getpixel((int(px), int(py)))
|
||||
|
||||
# Normalisierung [0,1]
|
||||
norm_x = (px / (breite)) + 1/64
|
||||
norm_y = 1.0 - ((py / (hoehe))) - 1/64
|
||||
|
||||
writer.writerow([f"{norm_x:.6f}", f"{norm_y:.6f}", r, g, b])
|
||||
222
Blender/L1960_Tools/_Source/L1960_Tools_1_8_4/__init__.py
Normal file
222
Blender/L1960_Tools/_Source/L1960_Tools_1_8_4/__init__.py
Normal file
@@ -0,0 +1,222 @@
|
||||
bl_info = {
|
||||
"name": "L1960 Tools",
|
||||
"author": "Prodeath21",
|
||||
"version": (1, 8, 4),
|
||||
"blender": (4, 2, 0),
|
||||
"location": "3D Viewport > Sidebar > 1960Life category",
|
||||
"description": "Set´s up the Projection-Modifier automatically and add´s in the Emptys if not allready created.",
|
||||
"category": "Object",
|
||||
}
|
||||
|
||||
# ----------------------------------------------
|
||||
# Import modules
|
||||
# ----------------------------------------------
|
||||
if "bpy" in locals():
|
||||
import imp
|
||||
imp.reload(Dekogon)
|
||||
imp.reload(CubeProjection)
|
||||
imp.reload(Helper)
|
||||
imp.reload(PrepareLods)
|
||||
imp.reload(AutoColorPalette)
|
||||
imp.reload(MaterialToMask)
|
||||
print("L1960 Tools: Reloaded multifiles")
|
||||
else:
|
||||
from . import Dekogon
|
||||
from . import CubeProjection
|
||||
from . import Helper
|
||||
from . import PrepareLods
|
||||
from . import AutoColorPalette
|
||||
from . import MaterialToMask
|
||||
|
||||
import bpy
|
||||
|
||||
from . Dekogon import MESH_OT_group_objects_in_collections, MESH_OT_assign_textures
|
||||
from . CubeProjection import MESH_OT_add_auto_cube_projection, MESH_OT_add_modifier_to_mesh
|
||||
from . Helper import MESH_OT_fix_material_names, MESH_OT_fix_naming_conventions, MESH_OT_generate_empty_for_mesh, MESH_OT_select_face_id
|
||||
from . PrepareLods import MESH_OT_prepare_lods_decimate
|
||||
from . AutoColorPalette import MESH_OT_set_up_mlod, EnumColorPalettes
|
||||
from . MaterialToMask import UVEnumProperties, MESH_OT_merge_materials_to_mask
|
||||
|
||||
class L1960_PT_dekogon(bpy.types.Panel):
|
||||
#where to add the panel
|
||||
bl_space_type = "VIEW_3D"
|
||||
bl_region_type = "UI"
|
||||
|
||||
#add labels
|
||||
bl_label = "1960-Life Import"
|
||||
bl_category = "1960-Life"
|
||||
bl_options = {'DEFAULT_CLOSED'}
|
||||
|
||||
def draw(self, context):
|
||||
box = self.layout.box()
|
||||
# Dekogon-Import
|
||||
box.label(text="Dekogon-Import")
|
||||
row = box.row()
|
||||
row.enabled = context.mode == 'OBJECT'
|
||||
row.operator("mesh.group_objects_in_collections", text="Group to Collections")
|
||||
row = box.row()
|
||||
split = row.split(factor=0.5)
|
||||
split.enabled = context.mode == 'OBJECT'
|
||||
split.operator("mesh.assign_textures", text="Assign Textures")
|
||||
split.prop(context.scene, "dekogon_file_path", text="")
|
||||
row = box.row()
|
||||
row.prop(context.scene, "section1",
|
||||
text="Settings",
|
||||
icon="TRIA_DOWN" if context.scene.section1 else "TRIA_RIGHT",
|
||||
emboss=False)
|
||||
if context.scene.section1:
|
||||
box.prop(context.scene, "dekogon_settings_prefix", text="Prefix")
|
||||
box.prop(context.scene, "dekogon_settings_suffix", text="Suffix")
|
||||
box.prop(context.scene, "dekogon_settings_filetype", text="File Type")
|
||||
self.layout.separator()
|
||||
|
||||
box = self.layout.box()
|
||||
# Americano-Import
|
||||
box.label(text="Materials-to-Multi")
|
||||
row = box.row()
|
||||
row.enabled = context.mode == 'OBJECT'
|
||||
row.operator("mesh.merge_materials_to_mask", text="Merge Materials to Mask")
|
||||
row = box.row()
|
||||
row.prop(context.scene, "section2",
|
||||
text="Settings",
|
||||
icon="TRIA_DOWN" if context.scene.section2 else "TRIA_RIGHT",
|
||||
emboss=False)
|
||||
if context.scene.section2:
|
||||
row = box.row()
|
||||
props = context.scene.settings_uv_enum_props
|
||||
row.prop(props, "uv_enum", text="UV Mask")
|
||||
box.prop(context.scene, "settings_multi_ignor", text="Ignore")
|
||||
box.prop(context.scene, "settings_mat_nameing", text="Naming")
|
||||
box.prop(context.scene, "settings_uv_island_margin_slider", text="Island Margin")
|
||||
|
||||
class L1960_PT_tools(bpy.types.Panel):
|
||||
#where to add the panel
|
||||
bl_space_type = "VIEW_3D"
|
||||
bl_region_type = "UI"
|
||||
|
||||
#add labels
|
||||
bl_label = "1960-Life Tools"
|
||||
bl_category = "1960-Life"
|
||||
|
||||
def draw(self, context):
|
||||
"""define the layout of the panel"""
|
||||
box = self.layout.box()
|
||||
# UV-Project helper
|
||||
box.label(text="UV-Projection")
|
||||
row = box.row()
|
||||
row.enabled = context.mode == 'OBJECT'
|
||||
row.operator("mesh.add_auto_cube_projection", text="Set up Projectors")
|
||||
row = box.row()
|
||||
row.operator("mesh.add_modifier_to_mesh", text="Add Modifier to Mesh")
|
||||
self.layout.separator()
|
||||
# Helpers
|
||||
box = self.layout.box()
|
||||
box.label(text="Various Helper")
|
||||
row = box.row()
|
||||
row.enabled = context.mode == 'OBJECT'
|
||||
row.operator("mesh.fix_material_names", text="Fix Material Name´s")
|
||||
row = box.row()
|
||||
row.operator("mesh.fix_naming_convention", text="Fix Naming Convention")
|
||||
row = box.row()
|
||||
row.enabled = context.mode == 'OBJECT'
|
||||
row.operator("mesh.generate_empty_for_mesh", text="Generate Empty")
|
||||
row = box.row()
|
||||
split = row.split(factor=0.7)
|
||||
split.operator("mesh.select_face_id", text="Show Face Index")
|
||||
split.prop(context.scene, "face_id_field", text="")
|
||||
self.layout.separator()
|
||||
# Generate LODs
|
||||
box = self.layout.box()
|
||||
box.label(text="LOD´s")
|
||||
row = box.row()
|
||||
row.operator("mesh.prepare_lods_decimate", text="Create LOD´s")
|
||||
box.prop(context.scene, "lod_slider", text="Amount")
|
||||
box = self.layout.box()
|
||||
box.prop(context.scene.color_palettes, "mlod_enum_selection", expand=True)
|
||||
row = box.row()
|
||||
row.enabled = context.mode == 'OBJECT'
|
||||
# row.operator("mesh.set_up_mlod", text="Set up MLOD")
|
||||
row.operator("mesh.set_up_mlod", text="Set up MLOD (Palette)")
|
||||
self.layout.separator()
|
||||
###############################
|
||||
# Enfusion Blender Tools Linked
|
||||
box = self.layout.box()
|
||||
box.label(text="EBT Linked")
|
||||
row = box.row()
|
||||
row.operator("ebt.sort_collections", text="Sort Objects")
|
||||
# colliders setup is allowed in both OBJECT and EDIT mode
|
||||
row = box.row()
|
||||
row.operator("ebt.collider_cache_reload", icon="FILE_REFRESH", text="")
|
||||
row.operator("ebt.collider_setup", text=" Colliders Setup")
|
||||
# Light Setup
|
||||
row = box.row()
|
||||
row.operator("ebt.setup_light", text=" Light Setup")
|
||||
# Update Materials
|
||||
row = box.row()
|
||||
col = row.column(align=True)
|
||||
col.operator(
|
||||
"ebt.update_enf_materials",
|
||||
)
|
||||
row = box.row()
|
||||
col = row.column(align=True)
|
||||
col.operator("ebt.open_in_workbench")
|
||||
row.prop(context.scene, "ebt_xob_path")
|
||||
row = box.row()
|
||||
col = row.column(align=True)
|
||||
|
||||
#register the panel with blender
|
||||
modules = [ L1960_PT_dekogon,
|
||||
L1960_PT_tools,
|
||||
MESH_OT_add_auto_cube_projection,
|
||||
MESH_OT_add_modifier_to_mesh,
|
||||
MESH_OT_merge_materials_to_mask,
|
||||
MESH_OT_fix_material_names,
|
||||
MESH_OT_group_objects_in_collections,
|
||||
MESH_OT_assign_textures,
|
||||
MESH_OT_fix_naming_conventions,
|
||||
MESH_OT_generate_empty_for_mesh,
|
||||
MESH_OT_prepare_lods_decimate,
|
||||
MESH_OT_set_up_mlod,
|
||||
EnumColorPalettes,
|
||||
MESH_OT_select_face_id,
|
||||
UVEnumProperties
|
||||
]
|
||||
|
||||
def register():
|
||||
for mod in modules:
|
||||
bpy.utils.register_class(mod)
|
||||
|
||||
bpy.types.Scene.lod_slider = bpy.props.IntProperty(name="LOD Number", default=3, min=0, max=10)
|
||||
bpy.types.Scene.color_palettes = bpy.props.PointerProperty(type=EnumColorPalettes)
|
||||
bpy.types.Scene.face_id_field = bpy.props.IntProperty(name="Face ID", default=0, min=0)
|
||||
bpy.types.Scene.section1 = bpy.props.BoolProperty(name="Expand Section", default=False)
|
||||
bpy.types.Scene.section2 = bpy.props.BoolProperty(name="Expand Section", default=False)
|
||||
bpy.types.Scene.dekogon_file_path = bpy.props.StringProperty(name="Textures", description="Path to the texture folder, textures to be applied from", subtype="DIR_PATH", default="")
|
||||
bpy.types.Scene.dekogon_settings_prefix = bpy.props.StringProperty(name="Prefix", default="TX")
|
||||
bpy.types.Scene.dekogon_settings_suffix = bpy.props.StringProperty(name="Suffix", default="ALB")
|
||||
bpy.types.Scene.dekogon_settings_filetype = bpy.props.StringProperty(name="File Type", default="tga")
|
||||
bpy.types.Scene.settings_mat_nameing = bpy.props.StringProperty(name="Naming", default="Multi_$MeshName", description="Naming for new multi materials, use $MeshName as placeholder")
|
||||
bpy.types.Scene.settings_multi_ignor = bpy.props.StringProperty(name="Ignore", default="", description="Ignore material when string is in name (split by comma) | Default: grass, glass, atlas")
|
||||
bpy.types.Scene.settings_uv_enum_props = bpy.props.PointerProperty(type=UVEnumProperties)
|
||||
bpy.types.Scene.settings_uv_island_margin_slider = bpy.props.FloatProperty(name="Island Margin", default=0.02, min=0.01, max=0.1)
|
||||
|
||||
def unregister():
|
||||
for mod in modules:
|
||||
bpy.utils.unregister_class(mod)
|
||||
|
||||
del bpy.types.Scene.lod_slider
|
||||
del bpy.types.Scene.color_palettes
|
||||
del bpy.types.Scene.face_id_field
|
||||
del bpy.types.Scene.section1
|
||||
del bpy.types.Scene.section2
|
||||
del bpy.types.Scene.dekogon_file_path
|
||||
del bpy.types.Scene.dekogon_settings_prefix
|
||||
del bpy.types.Scene.dekogon_settings_suffix
|
||||
del bpy.types.Scene.dekogon_settings_filetype
|
||||
del bpy.types.Scene.settings_mat_nameing
|
||||
del bpy.types.Scene.settings_multi_ignor
|
||||
del bpy.types.Scene.settings_uv_enum_props
|
||||
del bpy.types.Scene.settings_uv_island_margin_slider
|
||||
|
||||
if __name__== "__main__":
|
||||
register()
|
||||
1
Texturing/ConvertOGLDX/build.bat
Normal file
1
Texturing/ConvertOGLDX/build.bat
Normal file
@@ -0,0 +1 @@
|
||||
python3 -m PyInstaller -F --icon=./convertogldx.ico -c ./convertogldx.py
|
||||
3266
Texturing/ConvertOGLDX/build/convertogldx/Analysis-00.toc
Normal file
3266
Texturing/ConvertOGLDX/build/convertogldx/Analysis-00.toc
Normal file
File diff suppressed because it is too large
Load Diff
320
Texturing/ConvertOGLDX/build/convertogldx/EXE-00.toc
Normal file
320
Texturing/ConvertOGLDX/build/convertogldx/EXE-00.toc
Normal file
@@ -0,0 +1,320 @@
|
||||
('E:\\Arma Reforger '
|
||||
'Work\\1960-utils\\Texturing\\ConvertOGLDX\\dist\\convertogldx.exe',
|
||||
True,
|
||||
False,
|
||||
False,
|
||||
['E:\\Arma Reforger '
|
||||
'Work\\1960-utils\\Texturing\\ConvertOGLDX\\convertogldx.ico'],
|
||||
None,
|
||||
False,
|
||||
False,
|
||||
b'<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\n<assembly xmlns='
|
||||
b'"urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">\n <trustInfo x'
|
||||
b'mlns="urn:schemas-microsoft-com:asm.v3">\n <security>\n <requested'
|
||||
b'Privileges>\n <requestedExecutionLevel level="asInvoker" uiAccess='
|
||||
b'"false"/>\n </requestedPrivileges>\n </security>\n </trustInfo>\n '
|
||||
b'<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">\n <'
|
||||
b'application>\n <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f'
|
||||
b'0}"/>\n <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>\n '
|
||||
b' <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>\n <s'
|
||||
b'upportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>\n <supporte'
|
||||
b'dOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>\n </application>\n <'
|
||||
b'/compatibility>\n <application xmlns="urn:schemas-microsoft-com:asm.v3">'
|
||||
b'\n <windowsSettings>\n <longPathAware xmlns="http://schemas.micros'
|
||||
b'oft.com/SMI/2016/WindowsSettings">true</longPathAware>\n </windowsSett'
|
||||
b'ings>\n </application>\n <dependency>\n <dependentAssembly>\n <ass'
|
||||
b'emblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version='
|
||||
b'"6.0.0.0" processorArchitecture="*" publicKeyToken="6595b64144ccf1df" langua'
|
||||
b'ge="*"/>\n </dependentAssembly>\n </dependency>\n</assembly>',
|
||||
True,
|
||||
False,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
'E:\\Arma Reforger '
|
||||
'Work\\1960-utils\\Texturing\\ConvertOGLDX\\build\\convertogldx\\convertogldx.pkg',
|
||||
[('pyi-contents-directory _internal', '', 'OPTION'),
|
||||
('PYZ-00.pyz',
|
||||
'E:\\Arma Reforger '
|
||||
'Work\\1960-utils\\Texturing\\ConvertOGLDX\\build\\convertogldx\\PYZ-00.pyz',
|
||||
'PYZ'),
|
||||
('struct',
|
||||
'E:\\Arma Reforger '
|
||||
'Work\\1960-utils\\Texturing\\ConvertOGLDX\\build\\convertogldx\\localpycs\\struct.pyc',
|
||||
'PYMODULE'),
|
||||
('pyimod01_archive',
|
||||
'E:\\Arma Reforger '
|
||||
'Work\\1960-utils\\Texturing\\ConvertOGLDX\\build\\convertogldx\\localpycs\\pyimod01_archive.pyc',
|
||||
'PYMODULE'),
|
||||
('pyimod02_importers',
|
||||
'E:\\Arma Reforger '
|
||||
'Work\\1960-utils\\Texturing\\ConvertOGLDX\\build\\convertogldx\\localpycs\\pyimod02_importers.pyc',
|
||||
'PYMODULE'),
|
||||
('pyimod03_ctypes',
|
||||
'E:\\Arma Reforger '
|
||||
'Work\\1960-utils\\Texturing\\ConvertOGLDX\\build\\convertogldx\\localpycs\\pyimod03_ctypes.pyc',
|
||||
'PYMODULE'),
|
||||
('pyimod04_pywin32',
|
||||
'E:\\Arma Reforger '
|
||||
'Work\\1960-utils\\Texturing\\ConvertOGLDX\\build\\convertogldx\\localpycs\\pyimod04_pywin32.pyc',
|
||||
'PYMODULE'),
|
||||
('pyiboot01_bootstrap',
|
||||
'C:\\Users\\Niklas\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python310\\site-packages\\PyInstaller\\loader\\pyiboot01_bootstrap.py',
|
||||
'PYSOURCE'),
|
||||
('pyi_rth_inspect',
|
||||
'C:\\Users\\Niklas\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python310\\site-packages\\PyInstaller\\hooks\\rthooks\\pyi_rth_inspect.py',
|
||||
'PYSOURCE'),
|
||||
('pyi_rth_pkgutil',
|
||||
'C:\\Users\\Niklas\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python310\\site-packages\\PyInstaller\\hooks\\rthooks\\pyi_rth_pkgutil.py',
|
||||
'PYSOURCE'),
|
||||
('pyi_rth_multiprocessing',
|
||||
'C:\\Users\\Niklas\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python310\\site-packages\\PyInstaller\\hooks\\rthooks\\pyi_rth_multiprocessing.py',
|
||||
'PYSOURCE'),
|
||||
('pyi_rth_pkgres',
|
||||
'C:\\Users\\Niklas\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python310\\site-packages\\PyInstaller\\hooks\\rthooks\\pyi_rth_pkgres.py',
|
||||
'PYSOURCE'),
|
||||
('pyi_rth_pywintypes',
|
||||
'C:\\Users\\Niklas\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python310\\site-packages\\_pyinstaller_hooks_contrib\\hooks\\rthooks\\pyi_rth_pywintypes.py',
|
||||
'PYSOURCE'),
|
||||
('pyi_rth_pythoncom',
|
||||
'C:\\Users\\Niklas\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python310\\site-packages\\_pyinstaller_hooks_contrib\\hooks\\rthooks\\pyi_rth_pythoncom.py',
|
||||
'PYSOURCE'),
|
||||
('pyi_rth_setuptools',
|
||||
'C:\\Users\\Niklas\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python310\\site-packages\\PyInstaller\\hooks\\rthooks\\pyi_rth_setuptools.py',
|
||||
'PYSOURCE'),
|
||||
('convertogldx',
|
||||
'E:\\Arma Reforger '
|
||||
'Work\\1960-utils\\Texturing\\ConvertOGLDX\\convertogldx.py',
|
||||
'PYSOURCE'),
|
||||
('python310.dll',
|
||||
'C:\\Program '
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\python310.dll',
|
||||
'BINARY'),
|
||||
('libopenblas64__v0.3.21-gcc_10_3_0.dll',
|
||||
'C:\\Users\\Niklas\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python310\\site-packages\\numpy\\.libs\\libopenblas64__v0.3.21-gcc_10_3_0.dll',
|
||||
'BINARY'),
|
||||
('pywin32_system32\\pywintypes310.dll',
|
||||
'C:\\Users\\Niklas\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python310\\site-packages\\pywin32_system32\\pywintypes310.dll',
|
||||
'BINARY'),
|
||||
('pywin32_system32\\pythoncom310.dll',
|
||||
'C:\\Users\\Niklas\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python310\\site-packages\\pywin32_system32\\pythoncom310.dll',
|
||||
'BINARY'),
|
||||
('_decimal.pyd',
|
||||
'C:\\Program '
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\DLLs\\_decimal.pyd',
|
||||
'EXTENSION'),
|
||||
('_lzma.pyd',
|
||||
'C:\\Program '
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\DLLs\\_lzma.pyd',
|
||||
'EXTENSION'),
|
||||
('_bz2.pyd',
|
||||
'C:\\Program '
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\DLLs\\_bz2.pyd',
|
||||
'EXTENSION'),
|
||||
('_hashlib.pyd',
|
||||
'C:\\Program '
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\DLLs\\_hashlib.pyd',
|
||||
'EXTENSION'),
|
||||
('unicodedata.pyd',
|
||||
'C:\\Program '
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\DLLs\\unicodedata.pyd',
|
||||
'EXTENSION'),
|
||||
('select.pyd',
|
||||
'C:\\Program '
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\DLLs\\select.pyd',
|
||||
'EXTENSION'),
|
||||
('_socket.pyd',
|
||||
'C:\\Program '
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\DLLs\\_socket.pyd',
|
||||
'EXTENSION'),
|
||||
('win32\\win32api.pyd',
|
||||
'C:\\Users\\Niklas\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python310\\site-packages\\win32\\win32api.pyd',
|
||||
'EXTENSION'),
|
||||
('_ssl.pyd',
|
||||
'C:\\Program '
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\DLLs\\_ssl.pyd',
|
||||
'EXTENSION'),
|
||||
('_ctypes.pyd',
|
||||
'C:\\Program '
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\DLLs\\_ctypes.pyd',
|
||||
'EXTENSION'),
|
||||
('win32\\win32evtlog.pyd',
|
||||
'C:\\Users\\Niklas\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python310\\site-packages\\win32\\win32evtlog.pyd',
|
||||
'EXTENSION'),
|
||||
('_queue.pyd',
|
||||
'C:\\Program '
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\DLLs\\_queue.pyd',
|
||||
'EXTENSION'),
|
||||
('_multiprocessing.pyd',
|
||||
'C:\\Program '
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\DLLs\\_multiprocessing.pyd',
|
||||
'EXTENSION'),
|
||||
('pyexpat.pyd',
|
||||
'C:\\Program '
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\DLLs\\pyexpat.pyd',
|
||||
'EXTENSION'),
|
||||
('_overlapped.pyd',
|
||||
'C:\\Program '
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\DLLs\\_overlapped.pyd',
|
||||
'EXTENSION'),
|
||||
('_asyncio.pyd',
|
||||
'C:\\Program '
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\DLLs\\_asyncio.pyd',
|
||||
'EXTENSION'),
|
||||
('markupsafe\\_speedups.cp310-win_amd64.pyd',
|
||||
'C:\\Users\\Niklas\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python310\\site-packages\\markupsafe\\_speedups.cp310-win_amd64.pyd',
|
||||
'EXTENSION'),
|
||||
('win32com\\shell\\shell.pyd',
|
||||
'C:\\Users\\Niklas\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python310\\site-packages\\win32comext\\shell\\shell.pyd',
|
||||
'EXTENSION'),
|
||||
('win32\\win32trace.pyd',
|
||||
'C:\\Users\\Niklas\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python310\\site-packages\\win32\\win32trace.pyd',
|
||||
'EXTENSION'),
|
||||
('Pythonwin\\win32ui.pyd',
|
||||
'C:\\Users\\Niklas\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python310\\site-packages\\Pythonwin\\win32ui.pyd',
|
||||
'EXTENSION'),
|
||||
('win32\\_win32sysloader.pyd',
|
||||
'C:\\Users\\Niklas\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python310\\site-packages\\win32\\_win32sysloader.pyd',
|
||||
'EXTENSION'),
|
||||
('numpy\\core\\_multiarray_tests.cp310-win_amd64.pyd',
|
||||
'C:\\Users\\Niklas\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python310\\site-packages\\numpy\\core\\_multiarray_tests.cp310-win_amd64.pyd',
|
||||
'EXTENSION'),
|
||||
('psutil\\_psutil_windows.pyd',
|
||||
'C:\\Users\\Niklas\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python310\\site-packages\\psutil\\_psutil_windows.pyd',
|
||||
'EXTENSION'),
|
||||
('numpy\\core\\_multiarray_umath.cp310-win_amd64.pyd',
|
||||
'C:\\Users\\Niklas\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python310\\site-packages\\numpy\\core\\_multiarray_umath.cp310-win_amd64.pyd',
|
||||
'EXTENSION'),
|
||||
('win32\\win32pdh.pyd',
|
||||
'C:\\Users\\Niklas\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python310\\site-packages\\win32\\win32pdh.pyd',
|
||||
'EXTENSION'),
|
||||
('numpy\\linalg\\lapack_lite.cp310-win_amd64.pyd',
|
||||
'C:\\Users\\Niklas\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python310\\site-packages\\numpy\\linalg\\lapack_lite.cp310-win_amd64.pyd',
|
||||
'EXTENSION'),
|
||||
('numpy\\random\\mtrand.cp310-win_amd64.pyd',
|
||||
'C:\\Users\\Niklas\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python310\\site-packages\\numpy\\random\\mtrand.cp310-win_amd64.pyd',
|
||||
'EXTENSION'),
|
||||
('numpy\\random\\_sfc64.cp310-win_amd64.pyd',
|
||||
'C:\\Users\\Niklas\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python310\\site-packages\\numpy\\random\\_sfc64.cp310-win_amd64.pyd',
|
||||
'EXTENSION'),
|
||||
('numpy\\random\\_philox.cp310-win_amd64.pyd',
|
||||
'C:\\Users\\Niklas\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python310\\site-packages\\numpy\\random\\_philox.cp310-win_amd64.pyd',
|
||||
'EXTENSION'),
|
||||
('numpy\\random\\_pcg64.cp310-win_amd64.pyd',
|
||||
'C:\\Users\\Niklas\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python310\\site-packages\\numpy\\random\\_pcg64.cp310-win_amd64.pyd',
|
||||
'EXTENSION'),
|
||||
('numpy\\random\\_mt19937.cp310-win_amd64.pyd',
|
||||
'C:\\Users\\Niklas\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python310\\site-packages\\numpy\\random\\_mt19937.cp310-win_amd64.pyd',
|
||||
'EXTENSION'),
|
||||
('numpy\\random\\bit_generator.cp310-win_amd64.pyd',
|
||||
'C:\\Users\\Niklas\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python310\\site-packages\\numpy\\random\\bit_generator.cp310-win_amd64.pyd',
|
||||
'EXTENSION'),
|
||||
('numpy\\random\\_generator.cp310-win_amd64.pyd',
|
||||
'C:\\Users\\Niklas\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python310\\site-packages\\numpy\\random\\_generator.cp310-win_amd64.pyd',
|
||||
'EXTENSION'),
|
||||
('numpy\\random\\_bounded_integers.cp310-win_amd64.pyd',
|
||||
'C:\\Users\\Niklas\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python310\\site-packages\\numpy\\random\\_bounded_integers.cp310-win_amd64.pyd',
|
||||
'EXTENSION'),
|
||||
('numpy\\random\\_common.cp310-win_amd64.pyd',
|
||||
'C:\\Users\\Niklas\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python310\\site-packages\\numpy\\random\\_common.cp310-win_amd64.pyd',
|
||||
'EXTENSION'),
|
||||
('numpy\\fft\\_pocketfft_internal.cp310-win_amd64.pyd',
|
||||
'C:\\Users\\Niklas\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python310\\site-packages\\numpy\\fft\\_pocketfft_internal.cp310-win_amd64.pyd',
|
||||
'EXTENSION'),
|
||||
('numpy\\linalg\\_umath_linalg.cp310-win_amd64.pyd',
|
||||
'C:\\Users\\Niklas\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python310\\site-packages\\numpy\\linalg\\_umath_linalg.cp310-win_amd64.pyd',
|
||||
'EXTENSION'),
|
||||
('PIL\\_webp.cp310-win_amd64.pyd',
|
||||
'C:\\Users\\Niklas\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python310\\site-packages\\PIL\\_webp.cp310-win_amd64.pyd',
|
||||
'EXTENSION'),
|
||||
('PIL\\_imagingtk.cp310-win_amd64.pyd',
|
||||
'C:\\Users\\Niklas\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python310\\site-packages\\PIL\\_imagingtk.cp310-win_amd64.pyd',
|
||||
'EXTENSION'),
|
||||
('PIL\\_imagingcms.cp310-win_amd64.pyd',
|
||||
'C:\\Users\\Niklas\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python310\\site-packages\\PIL\\_imagingcms.cp310-win_amd64.pyd',
|
||||
'EXTENSION'),
|
||||
('_cffi_backend.cp310-win_amd64.pyd',
|
||||
'C:\\Users\\Niklas\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python310\\site-packages\\_cffi_backend.cp310-win_amd64.pyd',
|
||||
'EXTENSION'),
|
||||
('PIL\\_imaging.cp310-win_amd64.pyd',
|
||||
'C:\\Users\\Niklas\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python310\\site-packages\\PIL\\_imaging.cp310-win_amd64.pyd',
|
||||
'EXTENSION'),
|
||||
('_elementtree.pyd',
|
||||
'C:\\Program '
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\DLLs\\_elementtree.pyd',
|
||||
'EXTENSION'),
|
||||
('VCRUNTIME140.dll',
|
||||
'C:\\Program '
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\VCRUNTIME140.dll',
|
||||
'BINARY'),
|
||||
('VCRUNTIME140_1.dll',
|
||||
'C:\\Program '
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\VCRUNTIME140_1.dll',
|
||||
'BINARY'),
|
||||
('libcrypto-1_1.dll',
|
||||
'C:\\Program '
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\DLLs\\libcrypto-1_1.dll',
|
||||
'BINARY'),
|
||||
('libssl-1_1.dll',
|
||||
'C:\\Program '
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\DLLs\\libssl-1_1.dll',
|
||||
'BINARY'),
|
||||
('libffi-7.dll',
|
||||
'C:\\Program '
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\DLLs\\libffi-7.dll',
|
||||
'BINARY'),
|
||||
('Pythonwin\\mfc140u.dll',
|
||||
'C:\\Users\\Niklas\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python310\\site-packages\\Pythonwin\\mfc140u.dll',
|
||||
'BINARY'),
|
||||
('python3.dll',
|
||||
'C:\\Program '
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\python3.dll',
|
||||
'BINARY'),
|
||||
('numpy\\.libs\\libopenblas64__v0.3.21-gcc_10_3_0.dll',
|
||||
'C:\\Users\\Niklas\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python310\\site-packages\\numpy\\.libs\\libopenblas64__v0.3.21-gcc_10_3_0.dll',
|
||||
'BINARY'),
|
||||
('base_library.zip',
|
||||
'E:\\Arma Reforger '
|
||||
'Work\\1960-utils\\Texturing\\ConvertOGLDX\\build\\convertogldx\\base_library.zip',
|
||||
'DATA'),
|
||||
('setuptools-65.5.0.dist-info\\METADATA',
|
||||
'C:\\Program '
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\lib\\site-packages\\setuptools-65.5.0.dist-info\\METADATA',
|
||||
'DATA'),
|
||||
('setuptools-65.5.0.dist-info\\top_level.txt',
|
||||
'C:\\Program '
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\lib\\site-packages\\setuptools-65.5.0.dist-info\\top_level.txt',
|
||||
'DATA'),
|
||||
('setuptools-65.5.0.dist-info\\REQUESTED',
|
||||
'C:\\Program '
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\lib\\site-packages\\setuptools-65.5.0.dist-info\\REQUESTED',
|
||||
'DATA'),
|
||||
('setuptools-65.5.0.dist-info\\INSTALLER',
|
||||
'C:\\Program '
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\lib\\site-packages\\setuptools-65.5.0.dist-info\\INSTALLER',
|
||||
'DATA'),
|
||||
('setuptools-65.5.0.dist-info\\WHEEL',
|
||||
'C:\\Program '
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\lib\\site-packages\\setuptools-65.5.0.dist-info\\WHEEL',
|
||||
'DATA'),
|
||||
('setuptools-65.5.0.dist-info\\entry_points.txt',
|
||||
'C:\\Program '
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\lib\\site-packages\\setuptools-65.5.0.dist-info\\entry_points.txt',
|
||||
'DATA'),
|
||||
('setuptools-65.5.0.dist-info\\LICENSE',
|
||||
'C:\\Program '
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\lib\\site-packages\\setuptools-65.5.0.dist-info\\LICENSE',
|
||||
'DATA'),
|
||||
('setuptools-65.5.0.dist-info\\RECORD',
|
||||
'C:\\Program '
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\lib\\site-packages\\setuptools-65.5.0.dist-info\\RECORD',
|
||||
'DATA')],
|
||||
[],
|
||||
False,
|
||||
False,
|
||||
1760384735,
|
||||
[('run.exe',
|
||||
'C:\\Users\\Niklas\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python310\\site-packages\\PyInstaller\\bootloader\\Windows-64bit-intel\\run.exe',
|
||||
'EXECUTABLE')],
|
||||
'C:\\Program '
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\python310.dll')
|
||||
295
Texturing/ConvertOGLDX/build/convertogldx/PKG-00.toc
Normal file
295
Texturing/ConvertOGLDX/build/convertogldx/PKG-00.toc
Normal file
@@ -0,0 +1,295 @@
|
||||
('E:\\Arma Reforger '
|
||||
'Work\\1960-utils\\Texturing\\ConvertOGLDX\\build\\convertogldx\\convertogldx.pkg',
|
||||
{'BINARY': True,
|
||||
'DATA': True,
|
||||
'EXECUTABLE': True,
|
||||
'EXTENSION': True,
|
||||
'PYMODULE': True,
|
||||
'PYSOURCE': True,
|
||||
'PYZ': False,
|
||||
'SPLASH': True,
|
||||
'SYMLINK': False},
|
||||
[('pyi-contents-directory _internal', '', 'OPTION'),
|
||||
('PYZ-00.pyz',
|
||||
'E:\\Arma Reforger '
|
||||
'Work\\1960-utils\\Texturing\\ConvertOGLDX\\build\\convertogldx\\PYZ-00.pyz',
|
||||
'PYZ'),
|
||||
('struct',
|
||||
'E:\\Arma Reforger '
|
||||
'Work\\1960-utils\\Texturing\\ConvertOGLDX\\build\\convertogldx\\localpycs\\struct.pyc',
|
||||
'PYMODULE'),
|
||||
('pyimod01_archive',
|
||||
'E:\\Arma Reforger '
|
||||
'Work\\1960-utils\\Texturing\\ConvertOGLDX\\build\\convertogldx\\localpycs\\pyimod01_archive.pyc',
|
||||
'PYMODULE'),
|
||||
('pyimod02_importers',
|
||||
'E:\\Arma Reforger '
|
||||
'Work\\1960-utils\\Texturing\\ConvertOGLDX\\build\\convertogldx\\localpycs\\pyimod02_importers.pyc',
|
||||
'PYMODULE'),
|
||||
('pyimod03_ctypes',
|
||||
'E:\\Arma Reforger '
|
||||
'Work\\1960-utils\\Texturing\\ConvertOGLDX\\build\\convertogldx\\localpycs\\pyimod03_ctypes.pyc',
|
||||
'PYMODULE'),
|
||||
('pyimod04_pywin32',
|
||||
'E:\\Arma Reforger '
|
||||
'Work\\1960-utils\\Texturing\\ConvertOGLDX\\build\\convertogldx\\localpycs\\pyimod04_pywin32.pyc',
|
||||
'PYMODULE'),
|
||||
('pyiboot01_bootstrap',
|
||||
'C:\\Users\\Niklas\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python310\\site-packages\\PyInstaller\\loader\\pyiboot01_bootstrap.py',
|
||||
'PYSOURCE'),
|
||||
('pyi_rth_inspect',
|
||||
'C:\\Users\\Niklas\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python310\\site-packages\\PyInstaller\\hooks\\rthooks\\pyi_rth_inspect.py',
|
||||
'PYSOURCE'),
|
||||
('pyi_rth_pkgutil',
|
||||
'C:\\Users\\Niklas\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python310\\site-packages\\PyInstaller\\hooks\\rthooks\\pyi_rth_pkgutil.py',
|
||||
'PYSOURCE'),
|
||||
('pyi_rth_multiprocessing',
|
||||
'C:\\Users\\Niklas\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python310\\site-packages\\PyInstaller\\hooks\\rthooks\\pyi_rth_multiprocessing.py',
|
||||
'PYSOURCE'),
|
||||
('pyi_rth_pkgres',
|
||||
'C:\\Users\\Niklas\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python310\\site-packages\\PyInstaller\\hooks\\rthooks\\pyi_rth_pkgres.py',
|
||||
'PYSOURCE'),
|
||||
('pyi_rth_pywintypes',
|
||||
'C:\\Users\\Niklas\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python310\\site-packages\\_pyinstaller_hooks_contrib\\hooks\\rthooks\\pyi_rth_pywintypes.py',
|
||||
'PYSOURCE'),
|
||||
('pyi_rth_pythoncom',
|
||||
'C:\\Users\\Niklas\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python310\\site-packages\\_pyinstaller_hooks_contrib\\hooks\\rthooks\\pyi_rth_pythoncom.py',
|
||||
'PYSOURCE'),
|
||||
('pyi_rth_setuptools',
|
||||
'C:\\Users\\Niklas\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python310\\site-packages\\PyInstaller\\hooks\\rthooks\\pyi_rth_setuptools.py',
|
||||
'PYSOURCE'),
|
||||
('convertogldx',
|
||||
'E:\\Arma Reforger '
|
||||
'Work\\1960-utils\\Texturing\\ConvertOGLDX\\convertogldx.py',
|
||||
'PYSOURCE'),
|
||||
('python310.dll',
|
||||
'C:\\Program '
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\python310.dll',
|
||||
'BINARY'),
|
||||
('libopenblas64__v0.3.21-gcc_10_3_0.dll',
|
||||
'C:\\Users\\Niklas\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python310\\site-packages\\numpy\\.libs\\libopenblas64__v0.3.21-gcc_10_3_0.dll',
|
||||
'BINARY'),
|
||||
('pywin32_system32\\pywintypes310.dll',
|
||||
'C:\\Users\\Niklas\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python310\\site-packages\\pywin32_system32\\pywintypes310.dll',
|
||||
'BINARY'),
|
||||
('pywin32_system32\\pythoncom310.dll',
|
||||
'C:\\Users\\Niklas\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python310\\site-packages\\pywin32_system32\\pythoncom310.dll',
|
||||
'BINARY'),
|
||||
('_decimal.pyd',
|
||||
'C:\\Program '
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\DLLs\\_decimal.pyd',
|
||||
'EXTENSION'),
|
||||
('_lzma.pyd',
|
||||
'C:\\Program '
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\DLLs\\_lzma.pyd',
|
||||
'EXTENSION'),
|
||||
('_bz2.pyd',
|
||||
'C:\\Program '
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\DLLs\\_bz2.pyd',
|
||||
'EXTENSION'),
|
||||
('_hashlib.pyd',
|
||||
'C:\\Program '
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\DLLs\\_hashlib.pyd',
|
||||
'EXTENSION'),
|
||||
('unicodedata.pyd',
|
||||
'C:\\Program '
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\DLLs\\unicodedata.pyd',
|
||||
'EXTENSION'),
|
||||
('select.pyd',
|
||||
'C:\\Program '
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\DLLs\\select.pyd',
|
||||
'EXTENSION'),
|
||||
('_socket.pyd',
|
||||
'C:\\Program '
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\DLLs\\_socket.pyd',
|
||||
'EXTENSION'),
|
||||
('win32\\win32api.pyd',
|
||||
'C:\\Users\\Niklas\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python310\\site-packages\\win32\\win32api.pyd',
|
||||
'EXTENSION'),
|
||||
('_ssl.pyd',
|
||||
'C:\\Program '
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\DLLs\\_ssl.pyd',
|
||||
'EXTENSION'),
|
||||
('_ctypes.pyd',
|
||||
'C:\\Program '
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\DLLs\\_ctypes.pyd',
|
||||
'EXTENSION'),
|
||||
('win32\\win32evtlog.pyd',
|
||||
'C:\\Users\\Niklas\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python310\\site-packages\\win32\\win32evtlog.pyd',
|
||||
'EXTENSION'),
|
||||
('_queue.pyd',
|
||||
'C:\\Program '
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\DLLs\\_queue.pyd',
|
||||
'EXTENSION'),
|
||||
('_multiprocessing.pyd',
|
||||
'C:\\Program '
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\DLLs\\_multiprocessing.pyd',
|
||||
'EXTENSION'),
|
||||
('pyexpat.pyd',
|
||||
'C:\\Program '
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\DLLs\\pyexpat.pyd',
|
||||
'EXTENSION'),
|
||||
('_overlapped.pyd',
|
||||
'C:\\Program '
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\DLLs\\_overlapped.pyd',
|
||||
'EXTENSION'),
|
||||
('_asyncio.pyd',
|
||||
'C:\\Program '
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\DLLs\\_asyncio.pyd',
|
||||
'EXTENSION'),
|
||||
('markupsafe\\_speedups.cp310-win_amd64.pyd',
|
||||
'C:\\Users\\Niklas\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python310\\site-packages\\markupsafe\\_speedups.cp310-win_amd64.pyd',
|
||||
'EXTENSION'),
|
||||
('win32com\\shell\\shell.pyd',
|
||||
'C:\\Users\\Niklas\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python310\\site-packages\\win32comext\\shell\\shell.pyd',
|
||||
'EXTENSION'),
|
||||
('win32\\win32trace.pyd',
|
||||
'C:\\Users\\Niklas\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python310\\site-packages\\win32\\win32trace.pyd',
|
||||
'EXTENSION'),
|
||||
('Pythonwin\\win32ui.pyd',
|
||||
'C:\\Users\\Niklas\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python310\\site-packages\\Pythonwin\\win32ui.pyd',
|
||||
'EXTENSION'),
|
||||
('win32\\_win32sysloader.pyd',
|
||||
'C:\\Users\\Niklas\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python310\\site-packages\\win32\\_win32sysloader.pyd',
|
||||
'EXTENSION'),
|
||||
('numpy\\core\\_multiarray_tests.cp310-win_amd64.pyd',
|
||||
'C:\\Users\\Niklas\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python310\\site-packages\\numpy\\core\\_multiarray_tests.cp310-win_amd64.pyd',
|
||||
'EXTENSION'),
|
||||
('psutil\\_psutil_windows.pyd',
|
||||
'C:\\Users\\Niklas\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python310\\site-packages\\psutil\\_psutil_windows.pyd',
|
||||
'EXTENSION'),
|
||||
('numpy\\core\\_multiarray_umath.cp310-win_amd64.pyd',
|
||||
'C:\\Users\\Niklas\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python310\\site-packages\\numpy\\core\\_multiarray_umath.cp310-win_amd64.pyd',
|
||||
'EXTENSION'),
|
||||
('win32\\win32pdh.pyd',
|
||||
'C:\\Users\\Niklas\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python310\\site-packages\\win32\\win32pdh.pyd',
|
||||
'EXTENSION'),
|
||||
('numpy\\linalg\\lapack_lite.cp310-win_amd64.pyd',
|
||||
'C:\\Users\\Niklas\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python310\\site-packages\\numpy\\linalg\\lapack_lite.cp310-win_amd64.pyd',
|
||||
'EXTENSION'),
|
||||
('numpy\\random\\mtrand.cp310-win_amd64.pyd',
|
||||
'C:\\Users\\Niklas\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python310\\site-packages\\numpy\\random\\mtrand.cp310-win_amd64.pyd',
|
||||
'EXTENSION'),
|
||||
('numpy\\random\\_sfc64.cp310-win_amd64.pyd',
|
||||
'C:\\Users\\Niklas\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python310\\site-packages\\numpy\\random\\_sfc64.cp310-win_amd64.pyd',
|
||||
'EXTENSION'),
|
||||
('numpy\\random\\_philox.cp310-win_amd64.pyd',
|
||||
'C:\\Users\\Niklas\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python310\\site-packages\\numpy\\random\\_philox.cp310-win_amd64.pyd',
|
||||
'EXTENSION'),
|
||||
('numpy\\random\\_pcg64.cp310-win_amd64.pyd',
|
||||
'C:\\Users\\Niklas\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python310\\site-packages\\numpy\\random\\_pcg64.cp310-win_amd64.pyd',
|
||||
'EXTENSION'),
|
||||
('numpy\\random\\_mt19937.cp310-win_amd64.pyd',
|
||||
'C:\\Users\\Niklas\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python310\\site-packages\\numpy\\random\\_mt19937.cp310-win_amd64.pyd',
|
||||
'EXTENSION'),
|
||||
('numpy\\random\\bit_generator.cp310-win_amd64.pyd',
|
||||
'C:\\Users\\Niklas\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python310\\site-packages\\numpy\\random\\bit_generator.cp310-win_amd64.pyd',
|
||||
'EXTENSION'),
|
||||
('numpy\\random\\_generator.cp310-win_amd64.pyd',
|
||||
'C:\\Users\\Niklas\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python310\\site-packages\\numpy\\random\\_generator.cp310-win_amd64.pyd',
|
||||
'EXTENSION'),
|
||||
('numpy\\random\\_bounded_integers.cp310-win_amd64.pyd',
|
||||
'C:\\Users\\Niklas\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python310\\site-packages\\numpy\\random\\_bounded_integers.cp310-win_amd64.pyd',
|
||||
'EXTENSION'),
|
||||
('numpy\\random\\_common.cp310-win_amd64.pyd',
|
||||
'C:\\Users\\Niklas\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python310\\site-packages\\numpy\\random\\_common.cp310-win_amd64.pyd',
|
||||
'EXTENSION'),
|
||||
('numpy\\fft\\_pocketfft_internal.cp310-win_amd64.pyd',
|
||||
'C:\\Users\\Niklas\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python310\\site-packages\\numpy\\fft\\_pocketfft_internal.cp310-win_amd64.pyd',
|
||||
'EXTENSION'),
|
||||
('numpy\\linalg\\_umath_linalg.cp310-win_amd64.pyd',
|
||||
'C:\\Users\\Niklas\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python310\\site-packages\\numpy\\linalg\\_umath_linalg.cp310-win_amd64.pyd',
|
||||
'EXTENSION'),
|
||||
('PIL\\_webp.cp310-win_amd64.pyd',
|
||||
'C:\\Users\\Niklas\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python310\\site-packages\\PIL\\_webp.cp310-win_amd64.pyd',
|
||||
'EXTENSION'),
|
||||
('PIL\\_imagingtk.cp310-win_amd64.pyd',
|
||||
'C:\\Users\\Niklas\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python310\\site-packages\\PIL\\_imagingtk.cp310-win_amd64.pyd',
|
||||
'EXTENSION'),
|
||||
('PIL\\_imagingcms.cp310-win_amd64.pyd',
|
||||
'C:\\Users\\Niklas\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python310\\site-packages\\PIL\\_imagingcms.cp310-win_amd64.pyd',
|
||||
'EXTENSION'),
|
||||
('_cffi_backend.cp310-win_amd64.pyd',
|
||||
'C:\\Users\\Niklas\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python310\\site-packages\\_cffi_backend.cp310-win_amd64.pyd',
|
||||
'EXTENSION'),
|
||||
('PIL\\_imaging.cp310-win_amd64.pyd',
|
||||
'C:\\Users\\Niklas\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python310\\site-packages\\PIL\\_imaging.cp310-win_amd64.pyd',
|
||||
'EXTENSION'),
|
||||
('_elementtree.pyd',
|
||||
'C:\\Program '
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\DLLs\\_elementtree.pyd',
|
||||
'EXTENSION'),
|
||||
('VCRUNTIME140.dll',
|
||||
'C:\\Program '
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\VCRUNTIME140.dll',
|
||||
'BINARY'),
|
||||
('VCRUNTIME140_1.dll',
|
||||
'C:\\Program '
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\VCRUNTIME140_1.dll',
|
||||
'BINARY'),
|
||||
('libcrypto-1_1.dll',
|
||||
'C:\\Program '
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\DLLs\\libcrypto-1_1.dll',
|
||||
'BINARY'),
|
||||
('libssl-1_1.dll',
|
||||
'C:\\Program '
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\DLLs\\libssl-1_1.dll',
|
||||
'BINARY'),
|
||||
('libffi-7.dll',
|
||||
'C:\\Program '
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\DLLs\\libffi-7.dll',
|
||||
'BINARY'),
|
||||
('Pythonwin\\mfc140u.dll',
|
||||
'C:\\Users\\Niklas\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python310\\site-packages\\Pythonwin\\mfc140u.dll',
|
||||
'BINARY'),
|
||||
('python3.dll',
|
||||
'C:\\Program '
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\python3.dll',
|
||||
'BINARY'),
|
||||
('numpy\\.libs\\libopenblas64__v0.3.21-gcc_10_3_0.dll',
|
||||
'C:\\Users\\Niklas\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python310\\site-packages\\numpy\\.libs\\libopenblas64__v0.3.21-gcc_10_3_0.dll',
|
||||
'BINARY'),
|
||||
('base_library.zip',
|
||||
'E:\\Arma Reforger '
|
||||
'Work\\1960-utils\\Texturing\\ConvertOGLDX\\build\\convertogldx\\base_library.zip',
|
||||
'DATA'),
|
||||
('setuptools-65.5.0.dist-info\\METADATA',
|
||||
'C:\\Program '
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\lib\\site-packages\\setuptools-65.5.0.dist-info\\METADATA',
|
||||
'DATA'),
|
||||
('setuptools-65.5.0.dist-info\\top_level.txt',
|
||||
'C:\\Program '
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\lib\\site-packages\\setuptools-65.5.0.dist-info\\top_level.txt',
|
||||
'DATA'),
|
||||
('setuptools-65.5.0.dist-info\\REQUESTED',
|
||||
'C:\\Program '
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\lib\\site-packages\\setuptools-65.5.0.dist-info\\REQUESTED',
|
||||
'DATA'),
|
||||
('setuptools-65.5.0.dist-info\\INSTALLER',
|
||||
'C:\\Program '
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\lib\\site-packages\\setuptools-65.5.0.dist-info\\INSTALLER',
|
||||
'DATA'),
|
||||
('setuptools-65.5.0.dist-info\\WHEEL',
|
||||
'C:\\Program '
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\lib\\site-packages\\setuptools-65.5.0.dist-info\\WHEEL',
|
||||
'DATA'),
|
||||
('setuptools-65.5.0.dist-info\\entry_points.txt',
|
||||
'C:\\Program '
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\lib\\site-packages\\setuptools-65.5.0.dist-info\\entry_points.txt',
|
||||
'DATA'),
|
||||
('setuptools-65.5.0.dist-info\\LICENSE',
|
||||
'C:\\Program '
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\lib\\site-packages\\setuptools-65.5.0.dist-info\\LICENSE',
|
||||
'DATA'),
|
||||
('setuptools-65.5.0.dist-info\\RECORD',
|
||||
'C:\\Program '
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\lib\\site-packages\\setuptools-65.5.0.dist-info\\RECORD',
|
||||
'DATA')],
|
||||
'python310.dll',
|
||||
False,
|
||||
False,
|
||||
False,
|
||||
[],
|
||||
None,
|
||||
None,
|
||||
None)
|
||||
BIN
Texturing/ConvertOGLDX/build/convertogldx/PYZ-00.pyz
Normal file
BIN
Texturing/ConvertOGLDX/build/convertogldx/PYZ-00.pyz
Normal file
Binary file not shown.
2998
Texturing/ConvertOGLDX/build/convertogldx/PYZ-00.toc
Normal file
2998
Texturing/ConvertOGLDX/build/convertogldx/PYZ-00.toc
Normal file
File diff suppressed because it is too large
Load Diff
BIN
Texturing/ConvertOGLDX/build/convertogldx/base_library.zip
Normal file
BIN
Texturing/ConvertOGLDX/build/convertogldx/base_library.zip
Normal file
Binary file not shown.
BIN
Texturing/ConvertOGLDX/build/convertogldx/convertogldx.pkg
Normal file
BIN
Texturing/ConvertOGLDX/build/convertogldx/convertogldx.pkg
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Texturing/ConvertOGLDX/build/convertogldx/localpycs/struct.pyc
Normal file
BIN
Texturing/ConvertOGLDX/build/convertogldx/localpycs/struct.pyc
Normal file
Binary file not shown.
192
Texturing/ConvertOGLDX/build/convertogldx/warn-convertogldx.txt
Normal file
192
Texturing/ConvertOGLDX/build/convertogldx/warn-convertogldx.txt
Normal file
@@ -0,0 +1,192 @@
|
||||
|
||||
This file lists modules PyInstaller was not able to find. This does not
|
||||
necessarily mean this module is required for running your program. Python and
|
||||
Python 3rd-party packages include a lot of conditional or optional modules. For
|
||||
example the module 'ntpath' only exists on Windows, whereas the module
|
||||
'posixpath' only exists on Posix systems.
|
||||
|
||||
Types if import:
|
||||
* top-level: imported at the top-level - look at these first
|
||||
* conditional: imported within an if-statement
|
||||
* delayed: imported within a function
|
||||
* optional: imported within a try-except-statement
|
||||
|
||||
IMPORTANT: Do NOT post this list to the issue-tracker. Use it as a basis for
|
||||
tracking down the missing module yourself. Thanks!
|
||||
|
||||
missing module named pep517 - imported by importlib.metadata (delayed)
|
||||
missing module named 'org.python' - imported by copy (optional), xml.sax (delayed, conditional)
|
||||
missing module named pwd - imported by posixpath (delayed, conditional), subprocess (delayed, conditional, optional), shutil (delayed, optional), tarfile (optional), pathlib (delayed, optional), netrc (delayed, conditional), getpass (delayed), http.server (delayed, optional), webbrowser (delayed), distutils.util (delayed, conditional, optional), distutils.archive_util (optional), psutil (optional), setuptools._distutils.archive_util (optional), setuptools._distutils.util (delayed, conditional, optional)
|
||||
missing module named grp - imported by subprocess (delayed, conditional, optional), shutil (delayed, optional), tarfile (optional), pathlib (delayed, optional), distutils.archive_util (optional), setuptools._distutils.archive_util (optional)
|
||||
missing module named org - imported by pickle (optional)
|
||||
missing module named posix - imported by os (conditional, optional), shutil (conditional), importlib._bootstrap_external (conditional)
|
||||
missing module named resource - imported by posix (top-level)
|
||||
missing module named _frozen_importlib_external - imported by importlib._bootstrap (delayed), importlib (optional), importlib.abc (optional), zipimport (top-level)
|
||||
excluded module named _frozen_importlib - imported by importlib (optional), importlib.abc (optional), zipimport (top-level)
|
||||
missing module named _posixsubprocess - imported by subprocess (optional), multiprocessing.util (delayed)
|
||||
missing module named fcntl - imported by subprocess (optional), xmlrpc.server (optional), psutil._compat (delayed, optional)
|
||||
missing module named vms_lib - imported by platform (delayed, optional)
|
||||
missing module named 'java.lang' - imported by platform (delayed, optional)
|
||||
missing module named _winreg - imported by platform (delayed, optional), pkg_resources._vendor.appdirs (delayed, conditional)
|
||||
missing module named _scproxy - imported by urllib.request (conditional)
|
||||
missing module named termios - imported by getpass (optional), tty (top-level), psutil._compat (delayed, optional)
|
||||
missing module named usercustomize - imported by site (delayed, optional)
|
||||
missing module named sitecustomize - imported by site (delayed, optional)
|
||||
missing module named startup - imported by pyreadline3.keysyms.common (conditional), pyreadline3.keysyms.keysyms (conditional)
|
||||
missing module named sets - imported by pyreadline3.keysyms.common (optional)
|
||||
missing module named System - imported by pyreadline3.clipboard.ironpython_clipboard (top-level), pyreadline3.keysyms.ironpython_keysyms (top-level), pyreadline3.console.ironpython_console (top-level), pyreadline3.rlmain (conditional)
|
||||
missing module named console - imported by pyreadline3.console.ansi (conditional)
|
||||
missing module named clr - imported by pyreadline3.clipboard.ironpython_clipboard (top-level), pyreadline3.console.ironpython_console (top-level)
|
||||
missing module named IronPythonConsole - imported by pyreadline3.console.ironpython_console (top-level)
|
||||
missing module named _posixshmem - imported by multiprocessing.resource_tracker (conditional), multiprocessing.shared_memory (conditional)
|
||||
missing module named multiprocessing.set_start_method - imported by multiprocessing (top-level), multiprocessing.spawn (top-level)
|
||||
missing module named multiprocessing.get_start_method - imported by multiprocessing (top-level), multiprocessing.spawn (top-level)
|
||||
missing module named multiprocessing.get_context - imported by multiprocessing (top-level), multiprocessing.pool (top-level), multiprocessing.managers (top-level), multiprocessing.sharedctypes (top-level)
|
||||
missing module named multiprocessing.TimeoutError - imported by multiprocessing (top-level), multiprocessing.pool (top-level)
|
||||
missing module named java - imported by xml.sax._exceptions (conditional)
|
||||
missing module named multiprocessing.BufferTooShort - imported by multiprocessing (top-level), multiprocessing.connection (top-level)
|
||||
missing module named multiprocessing.AuthenticationError - imported by multiprocessing (top-level), multiprocessing.connection (top-level)
|
||||
missing module named asyncio.DefaultEventLoopPolicy - imported by asyncio (delayed, conditional), asyncio.events (delayed, conditional)
|
||||
missing module named pyparsing.Word - imported by pyparsing (delayed), pyparsing.unicode (delayed)
|
||||
missing module named railroad - imported by pkg_resources._vendor.pyparsing.diagram (top-level), pyparsing.diagram (top-level), setuptools._vendor.pyparsing.diagram (top-level)
|
||||
missing module named 'setuptools.extern.pyparsing' - imported by setuptools._vendor.packaging.requirements (top-level), setuptools._vendor.packaging.markers (top-level)
|
||||
missing module named _manylinux - imported by packaging._manylinux (delayed, optional), setuptools._vendor.packaging._manylinux (delayed, optional), pkg_resources._vendor.packaging._manylinux (delayed, optional)
|
||||
missing module named 'setuptools.extern.jaraco' - imported by setuptools._reqs (top-level), setuptools._entry_points (top-level), setuptools.command.egg_info (top-level), setuptools._vendor.jaraco.text (top-level)
|
||||
missing module named setuptools.extern.importlib_resources - imported by setuptools.extern (conditional), setuptools._importlib (conditional), setuptools._vendor.jaraco.text (optional)
|
||||
missing module named setuptools.extern.tomli - imported by setuptools.extern (delayed), setuptools.config.pyprojecttoml (delayed)
|
||||
missing module named setuptools.extern.importlib_metadata - imported by setuptools.extern (conditional), setuptools._importlib (conditional)
|
||||
missing module named setuptools.extern.ordered_set - imported by setuptools.extern (top-level), setuptools.dist (top-level)
|
||||
missing module named setuptools.extern.packaging - imported by setuptools.extern (top-level), setuptools.dist (top-level), setuptools.command.egg_info (top-level), setuptools.depends (top-level)
|
||||
missing module named 'typing.io' - imported by importlib.resources (top-level)
|
||||
missing module named 'setuptools.extern.more_itertools' - imported by setuptools.dist (top-level), setuptools.config.expand (delayed), setuptools._itertools (top-level), setuptools._entry_points (top-level), setuptools.msvc (top-level), setuptools._vendor.jaraco.functools (top-level)
|
||||
missing module named 'setuptools.extern.packaging.version' - imported by setuptools.config.setupcfg (top-level), setuptools.msvc (top-level)
|
||||
missing module named 'setuptools.extern.packaging.utils' - imported by setuptools.wheel (top-level)
|
||||
missing module named 'setuptools.extern.packaging.tags' - imported by setuptools.wheel (top-level)
|
||||
missing module named 'pkg_resources.extern.pyparsing' - imported by pkg_resources._vendor.packaging.markers (top-level), pkg_resources._vendor.packaging.requirements (top-level)
|
||||
missing module named 'pkg_resources.extern.importlib_resources' - imported by pkg_resources._vendor.jaraco.text (optional)
|
||||
missing module named 'pkg_resources.extern.more_itertools' - imported by pkg_resources._vendor.jaraco.functools (top-level)
|
||||
missing module named 'com.sun' - imported by pkg_resources._vendor.appdirs (delayed, conditional, optional)
|
||||
missing module named com - imported by pkg_resources._vendor.appdirs (delayed)
|
||||
missing module named 'win32com.gen_py' - imported by win32com (conditional, optional)
|
||||
missing module named pkg_resources.extern.packaging - imported by pkg_resources.extern (top-level), pkg_resources (top-level)
|
||||
missing module named pkg_resources.extern.appdirs - imported by pkg_resources.extern (top-level), pkg_resources (top-level)
|
||||
missing module named 'pkg_resources.extern.jaraco' - imported by pkg_resources (top-level), pkg_resources._vendor.jaraco.text (top-level)
|
||||
missing module named trove_classifiers - imported by setuptools.config._validate_pyproject.formats (optional)
|
||||
missing module named 'setuptools.extern.packaging.specifiers' - imported by setuptools.config.setupcfg (top-level), setuptools.config._apply_pyprojecttoml (delayed)
|
||||
missing module named 'setuptools.extern.packaging.requirements' - imported by setuptools.config.setupcfg (top-level)
|
||||
missing module named importlib_metadata - imported by setuptools._importlib (delayed, optional)
|
||||
missing module named pyimod02_importers - imported by C:\Users\Niklas\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\PyInstaller\hooks\rthooks\pyi_rth_pkgutil.py (delayed), C:\Users\Niklas\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\PyInstaller\hooks\rthooks\pyi_rth_pkgres.py (delayed)
|
||||
missing module named dummy_threading - imported by psutil._compat (optional)
|
||||
missing module named _dummy_thread - imported by cffi.lock (conditional, optional), numpy.core.arrayprint (optional)
|
||||
missing module named numpy.core.result_type - imported by numpy.core (delayed), numpy.testing._private.utils (delayed)
|
||||
missing module named numpy.core.float_ - imported by numpy.core (delayed), numpy.testing._private.utils (delayed)
|
||||
missing module named numpy.core.number - imported by numpy.core (delayed), numpy.testing._private.utils (delayed)
|
||||
missing module named numpy.core.object_ - imported by numpy.core (top-level), numpy.linalg.linalg (top-level), numpy.testing._private.utils (delayed)
|
||||
missing module named numpy.core.all - imported by numpy.core (top-level), numpy.linalg.linalg (top-level), numpy.testing._private.utils (delayed)
|
||||
missing module named numpy.core.bool_ - imported by numpy.core (delayed), numpy.testing._private.utils (delayed)
|
||||
missing module named numpy.core.inf - imported by numpy.core (delayed), numpy.testing._private.utils (delayed)
|
||||
missing module named numpy.core.array2string - imported by numpy.core (delayed), numpy.testing._private.utils (delayed)
|
||||
missing module named numpy.lib.imag - imported by numpy.lib (delayed), numpy.testing._private.utils (delayed)
|
||||
missing module named numpy.lib.real - imported by numpy.lib (delayed), numpy.testing._private.utils (delayed)
|
||||
missing module named numpy.lib.iscomplexobj - imported by numpy.lib (delayed), numpy.testing._private.utils (delayed)
|
||||
missing module named numpy.core.signbit - imported by numpy.core (delayed), numpy.testing._private.utils (delayed)
|
||||
missing module named numpy.core.isscalar - imported by numpy.core (delayed), numpy.testing._private.utils (delayed), numpy.lib.polynomial (top-level)
|
||||
missing module named numpy.core.isinf - imported by numpy.core (delayed), numpy.testing._private.utils (delayed)
|
||||
missing module named numpy.core.errstate - imported by numpy.core (top-level), numpy.linalg.linalg (top-level), numpy.testing._private.utils (delayed)
|
||||
missing module named numpy.core.isfinite - imported by numpy.core (top-level), numpy.linalg.linalg (top-level), numpy.testing._private.utils (delayed)
|
||||
missing module named numpy.core.isnan - imported by numpy.core (top-level), numpy.linalg.linalg (top-level), numpy.testing._private.utils (delayed)
|
||||
missing module named numpy.core.array - imported by numpy.core (top-level), numpy.linalg.linalg (top-level), numpy.testing._private.utils (top-level), numpy.lib.polynomial (top-level)
|
||||
missing module named numpy.core.isnat - imported by numpy.core (top-level), numpy.testing._private.utils (top-level)
|
||||
missing module named numpy.core.ndarray - imported by numpy.core (top-level), numpy.testing._private.utils (top-level), numpy.lib.utils (top-level)
|
||||
missing module named numpy.core.array_repr - imported by numpy.core (top-level), numpy.testing._private.utils (top-level)
|
||||
missing module named numpy.core.arange - imported by numpy.core (top-level), numpy.testing._private.utils (top-level), numpy.fft.helper (top-level)
|
||||
missing module named numpy.core.empty - imported by numpy.core (top-level), numpy.linalg.linalg (top-level), numpy.testing._private.utils (top-level), numpy.fft.helper (top-level)
|
||||
missing module named numpy.core.float32 - imported by numpy.core (top-level), numpy.testing._private.utils (top-level)
|
||||
missing module named numpy.core.intp - imported by numpy.core (top-level), numpy.linalg.linalg (top-level), numpy.testing._private.utils (top-level)
|
||||
missing module named numpy.core.linspace - imported by numpy.core (top-level), numpy.lib.index_tricks (top-level)
|
||||
missing module named numpy.core.iinfo - imported by numpy.core (top-level), numpy.lib.twodim_base (top-level)
|
||||
missing module named numpy.core.transpose - imported by numpy.core (top-level), numpy.lib.function_base (top-level)
|
||||
missing module named numpy.core.asarray - imported by numpy.core (top-level), numpy.linalg.linalg (top-level), numpy.lib.utils (top-level), numpy.fft._pocketfft (top-level), numpy.fft.helper (top-level)
|
||||
missing module named numpy.core.integer - imported by numpy.core (top-level), numpy.fft.helper (top-level)
|
||||
missing module named numpy.core.sqrt - imported by numpy.core (top-level), numpy.linalg.linalg (top-level), numpy.fft._pocketfft (top-level)
|
||||
missing module named numpy.core.conjugate - imported by numpy.core (top-level), numpy.fft._pocketfft (top-level)
|
||||
missing module named numpy.core.swapaxes - imported by numpy.core (top-level), numpy.linalg.linalg (top-level), numpy.fft._pocketfft (top-level)
|
||||
missing module named numpy.core.zeros - imported by numpy.core (top-level), numpy.linalg.linalg (top-level), numpy.fft._pocketfft (top-level)
|
||||
missing module named numpy.core.reciprocal - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.sort - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.argsort - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.sign - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.count_nonzero - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.divide - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.matmul - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.asanyarray - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.atleast_2d - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.product - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.amax - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.amin - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.moveaxis - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.geterrobj - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.finfo - imported by numpy.core (top-level), numpy.linalg.linalg (top-level), numpy.lib.polynomial (top-level)
|
||||
missing module named numpy.core.sum - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.multiply - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.add - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.dot - imported by numpy.core (top-level), numpy.linalg.linalg (top-level), numpy.lib.polynomial (top-level)
|
||||
missing module named numpy.core.Inf - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.newaxis - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.complexfloating - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.inexact - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.cdouble - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.csingle - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.double - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.single - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.intc - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.empty_like - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.ufunc - imported by numpy.core (top-level), numpy.lib.utils (top-level)
|
||||
missing module named numpy.core.ones - imported by numpy.core (top-level), numpy.lib.polynomial (top-level)
|
||||
missing module named numpy.core.hstack - imported by numpy.core (top-level), numpy.lib.polynomial (top-level)
|
||||
missing module named numpy.core.atleast_1d - imported by numpy.core (top-level), numpy.lib.polynomial (top-level)
|
||||
missing module named numpy.core.atleast_3d - imported by numpy.core (top-level), numpy.lib.shape_base (top-level)
|
||||
missing module named numpy.core.vstack - imported by numpy.core (top-level), numpy.lib.shape_base (top-level)
|
||||
missing module named pickle5 - imported by numpy.compat.py3k (optional)
|
||||
missing module named numpy.eye - imported by numpy (delayed), numpy.core.numeric (delayed)
|
||||
missing module named numpy.recarray - imported by numpy (top-level), numpy.ma.mrecords (top-level)
|
||||
missing module named numpy.expand_dims - imported by numpy (top-level), numpy.ma.core (top-level)
|
||||
missing module named numpy.array - imported by numpy (top-level), numpy.ma.core (top-level), numpy.ma.extras (top-level), numpy.ma.mrecords (top-level)
|
||||
missing module named numpy.iscomplexobj - imported by numpy (top-level), numpy.ma.core (top-level)
|
||||
missing module named numpy.amin - imported by numpy (top-level), numpy.ma.core (top-level)
|
||||
missing module named numpy.amax - imported by numpy (top-level), numpy.ma.core (top-level)
|
||||
missing module named numpy.float64 - imported by numpy (top-level), numpy.array_api._typing (top-level)
|
||||
missing module named numpy.float32 - imported by numpy (top-level), numpy.array_api._typing (top-level)
|
||||
missing module named numpy.uint64 - imported by numpy (top-level), numpy.array_api._typing (top-level)
|
||||
missing module named numpy.uint32 - imported by numpy (top-level), numpy.array_api._typing (top-level)
|
||||
missing module named numpy.uint16 - imported by numpy (top-level), numpy.array_api._typing (top-level)
|
||||
missing module named numpy.uint8 - imported by numpy (top-level), numpy.array_api._typing (top-level)
|
||||
missing module named numpy.int64 - imported by numpy (top-level), numpy.array_api._typing (top-level)
|
||||
missing module named numpy.int32 - imported by numpy (top-level), numpy.array_api._typing (top-level)
|
||||
missing module named numpy.int16 - imported by numpy (top-level), numpy.array_api._typing (top-level)
|
||||
missing module named numpy.int8 - imported by numpy (top-level), numpy.array_api._typing (top-level)
|
||||
missing module named numpy._typing._ufunc - imported by numpy._typing (conditional)
|
||||
missing module named numpy.bytes_ - imported by numpy (top-level), numpy._typing._array_like (top-level)
|
||||
missing module named numpy.str_ - imported by numpy (top-level), numpy._typing._array_like (top-level)
|
||||
missing module named numpy.void - imported by numpy (top-level), numpy._typing._array_like (top-level)
|
||||
missing module named numpy.object_ - imported by numpy (top-level), numpy._typing._array_like (top-level)
|
||||
missing module named numpy.datetime64 - imported by numpy (top-level), numpy._typing._array_like (top-level)
|
||||
missing module named numpy.timedelta64 - imported by numpy (top-level), numpy._typing._array_like (top-level)
|
||||
missing module named numpy.number - imported by numpy (top-level), numpy._typing._array_like (top-level)
|
||||
missing module named numpy.complexfloating - imported by numpy (top-level), numpy._typing._array_like (top-level)
|
||||
missing module named numpy.floating - imported by numpy (top-level), numpy._typing._array_like (top-level)
|
||||
missing module named numpy.integer - imported by numpy (top-level), numpy._typing._array_like (top-level), numpy.ctypeslib (top-level)
|
||||
missing module named numpy.unsignedinteger - imported by numpy (top-level), numpy._typing._array_like (top-level)
|
||||
missing module named numpy.bool_ - imported by numpy (top-level), numpy._typing._array_like (top-level), numpy.ma.core (top-level), numpy.ma.mrecords (top-level)
|
||||
missing module named numpy.generic - imported by numpy (top-level), numpy._typing._array_like (top-level)
|
||||
missing module named numpy.dtype - imported by numpy (top-level), numpy._typing._array_like (top-level), numpy.array_api._typing (top-level), numpy.ma.mrecords (top-level), numpy.ctypeslib (top-level)
|
||||
missing module named numpy.ndarray - imported by numpy (top-level), numpy._typing._array_like (top-level), numpy.ma.core (top-level), numpy.ma.extras (top-level), numpy.ma.mrecords (top-level), numpy.ctypeslib (top-level)
|
||||
missing module named numpy.ufunc - imported by numpy (top-level), numpy._typing (top-level)
|
||||
missing module named numpy.histogramdd - imported by numpy (delayed), numpy.lib.twodim_base (delayed)
|
||||
missing module named olefile - imported by PIL.FpxImagePlugin (top-level), PIL.MicImagePlugin (top-level)
|
||||
missing module named dummy_thread - imported by cffi.lock (conditional, optional)
|
||||
missing module named thread - imported by cffi.lock (conditional, optional), cffi.cparser (conditional, optional)
|
||||
missing module named cStringIO - imported by cffi.ffiplatform (optional)
|
||||
missing module named cPickle - imported by pycparser.ply.yacc (delayed, optional)
|
||||
missing module named cffi._pycparser - imported by cffi (optional), cffi.cparser (optional)
|
||||
missing module named xmlrpclib - imported by defusedxml.xmlrpc (conditional)
|
||||
31836
Texturing/ConvertOGLDX/build/convertogldx/xref-convertogldx.html
Normal file
31836
Texturing/ConvertOGLDX/build/convertogldx/xref-convertogldx.html
Normal file
File diff suppressed because it is too large
Load Diff
BIN
Texturing/ConvertOGLDX/convertogldx.ico
Normal file
BIN
Texturing/ConvertOGLDX/convertogldx.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 64 KiB |
165
Texturing/ConvertOGLDX/convertogldx.py
Normal file
165
Texturing/ConvertOGLDX/convertogldx.py
Normal file
@@ -0,0 +1,165 @@
|
||||
# normalmap_to_directx_filtered.py
|
||||
# Drag & drop image files or folders onto the EXE.
|
||||
# Default: FORCE convert to DirectX (−Y) by flipping green.
|
||||
# Suffix filter: only process files whose *basename* ends with one of: _n, _nrm, _normal (case-insensitive).
|
||||
# Flags:
|
||||
# --detect -> flip only if image looks OpenGL (+Y)
|
||||
# --all -> ignore suffix filter; process all supported images
|
||||
# --suffixes "a,b,c" -> comma-separated list of suffixes (without extensions)
|
||||
|
||||
import sys, os
|
||||
from PIL import Image
|
||||
import numpy as np
|
||||
|
||||
SUPPORTED_EXTS = {".png", ".tga", ".jpg", ".jpeg", ".tif", ".tiff", ".bmp"}
|
||||
OUT_SUBFOLDER = "DirectX_Converted"
|
||||
DEFAULT_SUFFIXES = ["_n", "_nrm", "_normal"] # case-insensitive
|
||||
|
||||
def is_image(p):
|
||||
return os.path.splitext(p)[1].lower() in SUPPORTED_EXTS
|
||||
|
||||
def iter_inputs(paths):
|
||||
for p in paths:
|
||||
if os.path.isdir(p):
|
||||
for root, _, files in os.walk(p):
|
||||
for f in files:
|
||||
fp = os.path.join(root, f)
|
||||
if is_image(fp):
|
||||
yield fp
|
||||
else:
|
||||
if is_image(p):
|
||||
yield p
|
||||
|
||||
def has_normal_suffix(path, suffixes):
|
||||
stem = os.path.splitext(os.path.basename(path))[0].lower()
|
||||
return any(stem.endswith(suf.lower()) for suf in suffixes)
|
||||
|
||||
def flip_green(img_rgba):
|
||||
r, g, b, a = img_rgba.split()
|
||||
g = g.point(lambda i: 255 - i)
|
||||
return Image.merge("RGBA", (r, g, b, a))
|
||||
|
||||
def analyze_mean_y(img_rgba):
|
||||
_, g, b, _ = img_rgba.split()
|
||||
g_np = np.array(g, dtype=np.float32)
|
||||
b_np = np.array(b, dtype=np.float32)
|
||||
y = (g_np / 255.0) * 2.0 - 1.0
|
||||
flat_mask = b_np > 240
|
||||
y_use = y[~flat_mask] if (~flat_mask).any() else y
|
||||
return float(y_use.mean())
|
||||
|
||||
def ensure_directx(img_rgba, detect_mode: bool):
|
||||
if not detect_mode:
|
||||
return flip_green(img_rgba), True, None # forced
|
||||
mean_y = analyze_mean_y(img_rgba)
|
||||
if mean_y >= 0.0:
|
||||
return flip_green(img_rgba), True, mean_y
|
||||
else:
|
||||
return img_rgba, False, mean_y
|
||||
|
||||
def output_path(src_path):
|
||||
folder, base = os.path.split(src_path)
|
||||
out_dir = os.path.join(folder, OUT_SUBFOLDER)
|
||||
os.makedirs(out_dir, exist_ok=True)
|
||||
return os.path.join(out_dir, base)
|
||||
|
||||
def save_preserving_format(out_img_rgba, src_path, had_alpha):
|
||||
_, ext = os.path.splitext(src_path)
|
||||
ext = ext.lower()
|
||||
|
||||
if not had_alpha or ext in {".jpg", ".jpeg", ".bmp"}:
|
||||
out_img = out_img_rgba.convert("RGB")
|
||||
else:
|
||||
out_img = out_img_rgba
|
||||
|
||||
dst = output_path(src_path)
|
||||
save_kwargs, fmt = {}, None
|
||||
if ext in {".jpg", ".jpeg"}:
|
||||
save_kwargs["quality"] = 95
|
||||
fmt = "JPEG"
|
||||
elif ext == ".png":
|
||||
fmt = "PNG"
|
||||
elif ext == ".tga":
|
||||
fmt = "TGA"
|
||||
elif ext in {".tif", ".tiff"}:
|
||||
fmt = "TIFF"
|
||||
elif ext == ".bmp":
|
||||
fmt = "BMP"
|
||||
else:
|
||||
dst = os.path.splitext(dst)[0] + ".png"
|
||||
fmt = "PNG"
|
||||
|
||||
out_img.save(dst, format=fmt, **save_kwargs)
|
||||
return dst
|
||||
|
||||
def process_one(path, detect_mode: bool):
|
||||
try:
|
||||
src = Image.open(path)
|
||||
had_alpha = src.mode in ("LA", "RGBA", "PA")
|
||||
img = src.convert("RGBA")
|
||||
|
||||
out_img, flipped, mean_y = ensure_directx(img, detect_mode)
|
||||
dst = save_preserving_format(out_img, path, had_alpha)
|
||||
|
||||
if detect_mode:
|
||||
status = "flipped to DirectX (−Y)" if flipped else "already DirectX (−Y)"
|
||||
extra = f" meanY={mean_y:+.4f}"
|
||||
else:
|
||||
status = "FORCED flip -> DirectX (−Y)"
|
||||
extra = ""
|
||||
print(f"[OK] {path}\n {status}{extra}\n -> {dst}")
|
||||
except Exception as e:
|
||||
print(f"[ERR] {path} :: {e}")
|
||||
|
||||
def parse_args(argv):
|
||||
detect_mode = False
|
||||
process_all = False
|
||||
suffixes = DEFAULT_SUFFIXES[:]
|
||||
paths = []
|
||||
it = iter(argv)
|
||||
for a in it:
|
||||
if a == "--detect":
|
||||
detect_mode = True
|
||||
elif a == "--all":
|
||||
process_all = True
|
||||
elif a == "--suffixes":
|
||||
try:
|
||||
raw = next(it)
|
||||
suffixes = [s.strip() for s in raw.split(",") if s.strip()]
|
||||
except StopIteration:
|
||||
print("[WARN] --suffixes expects a quoted comma-separated list; using defaults.")
|
||||
else:
|
||||
paths.append(a)
|
||||
return detect_mode, process_all, suffixes, paths
|
||||
|
||||
def main():
|
||||
detect_mode, process_all, suffixes, args = parse_args(sys.argv[1:])
|
||||
|
||||
if not args:
|
||||
print("Drag and drop image files or folders onto this EXE.")
|
||||
print("Options: --detect --all --suffixes \"_n,_nrm,_normal\"")
|
||||
return # auto-exit
|
||||
|
||||
files = list(iter_inputs(args))
|
||||
if not files:
|
||||
print("No supported images found.")
|
||||
return
|
||||
|
||||
mode_desc = "DETECT mode (flip only if +Y detected)" if detect_mode else "FORCE mode (flip everything)"
|
||||
filt_desc = "NO suffix filter (--all)" if process_all else f"Suffix filter: {', '.join(suffixes)}"
|
||||
print(f"{mode_desc}\n{filt_desc}\nFound {len(files)} file(s) before filtering.\n")
|
||||
|
||||
count_total = 0
|
||||
count_skipped = 0
|
||||
for p in files:
|
||||
if not process_all and not has_normal_suffix(p, suffixes):
|
||||
print(f"[SKIP] {p} (name lacks normal-map suffix)")
|
||||
count_skipped += 1
|
||||
continue
|
||||
count_total += 1
|
||||
process_one(p, detect_mode)
|
||||
|
||||
print(f"\nProcessed: {count_total}, Skipped: {count_skipped}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
38
Texturing/ConvertOGLDX/convertogldx.spec
Normal file
38
Texturing/ConvertOGLDX/convertogldx.spec
Normal file
@@ -0,0 +1,38 @@
|
||||
# -*- mode: python ; coding: utf-8 -*-
|
||||
|
||||
|
||||
a = Analysis(
|
||||
['convertogldx.py'],
|
||||
pathex=[],
|
||||
binaries=[],
|
||||
datas=[],
|
||||
hiddenimports=[],
|
||||
hookspath=[],
|
||||
hooksconfig={},
|
||||
runtime_hooks=[],
|
||||
excludes=[],
|
||||
noarchive=False,
|
||||
)
|
||||
pyz = PYZ(a.pure)
|
||||
|
||||
exe = EXE(
|
||||
pyz,
|
||||
a.scripts,
|
||||
a.binaries,
|
||||
a.datas,
|
||||
[],
|
||||
name='convertogldx',
|
||||
debug=False,
|
||||
bootloader_ignore_signals=False,
|
||||
strip=False,
|
||||
upx=True,
|
||||
upx_exclude=[],
|
||||
runtime_tmpdir=None,
|
||||
console=True,
|
||||
disable_windowed_traceback=False,
|
||||
argv_emulation=False,
|
||||
target_arch=None,
|
||||
codesign_identity=None,
|
||||
entitlements_file=None,
|
||||
icon=['convertogldx.ico'],
|
||||
)
|
||||
BIN
Texturing/ConvertOGLDX/dist/convertogldx.exe
vendored
Normal file
BIN
Texturing/ConvertOGLDX/dist/convertogldx.exe
vendored
Normal file
Binary file not shown.
Binary file not shown.
@@ -2238,6 +2238,10 @@
|
||||
('_pyi_rth_utils',
|
||||
'C:\\Users\\Niklas\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python310\\site-packages\\PyInstaller\\fake-modules\\_pyi_rth_utils\\__init__.py',
|
||||
'PYMODULE'),
|
||||
('_py_abc',
|
||||
'C:\\Program '
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\lib\\_py_abc.py',
|
||||
'PYMODULE'),
|
||||
('stringprep',
|
||||
'C:\\Program '
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\lib\\stringprep.py',
|
||||
@@ -2246,10 +2250,6 @@
|
||||
'C:\\Program '
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\lib\\tracemalloc.py',
|
||||
'PYMODULE'),
|
||||
('_py_abc',
|
||||
'C:\\Program '
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\lib\\_py_abc.py',
|
||||
'PYMODULE'),
|
||||
('typing',
|
||||
'C:\\Program '
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\lib\\typing.py',
|
||||
@@ -3232,35 +3232,35 @@
|
||||
'E:\\Arma Reforger '
|
||||
'Work\\1960-utils\\Texturing\\MergeTextures2\\build\\merge_textures\\base_library.zip',
|
||||
'DATA'),
|
||||
('setuptools-65.5.0.dist-info\\LICENSE',
|
||||
('setuptools-65.5.0.dist-info\\INSTALLER',
|
||||
'C:\\Program '
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\lib\\site-packages\\setuptools-65.5.0.dist-info\\LICENSE',
|
||||
'DATA'),
|
||||
('setuptools-65.5.0.dist-info\\WHEEL',
|
||||
'C:\\Program '
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\lib\\site-packages\\setuptools-65.5.0.dist-info\\WHEEL',
|
||||
'DATA'),
|
||||
('setuptools-65.5.0.dist-info\\top_level.txt',
|
||||
'C:\\Program '
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\lib\\site-packages\\setuptools-65.5.0.dist-info\\top_level.txt',
|
||||
'DATA'),
|
||||
('setuptools-65.5.0.dist-info\\METADATA',
|
||||
'C:\\Program '
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\lib\\site-packages\\setuptools-65.5.0.dist-info\\METADATA',
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\lib\\site-packages\\setuptools-65.5.0.dist-info\\INSTALLER',
|
||||
'DATA'),
|
||||
('setuptools-65.5.0.dist-info\\REQUESTED',
|
||||
'C:\\Program '
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\lib\\site-packages\\setuptools-65.5.0.dist-info\\REQUESTED',
|
||||
'DATA'),
|
||||
('setuptools-65.5.0.dist-info\\METADATA',
|
||||
'C:\\Program '
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\lib\\site-packages\\setuptools-65.5.0.dist-info\\METADATA',
|
||||
'DATA'),
|
||||
('setuptools-65.5.0.dist-info\\LICENSE',
|
||||
'C:\\Program '
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\lib\\site-packages\\setuptools-65.5.0.dist-info\\LICENSE',
|
||||
'DATA'),
|
||||
('setuptools-65.5.0.dist-info\\entry_points.txt',
|
||||
'C:\\Program '
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\lib\\site-packages\\setuptools-65.5.0.dist-info\\entry_points.txt',
|
||||
'DATA'),
|
||||
('setuptools-65.5.0.dist-info\\INSTALLER',
|
||||
'C:\\Program '
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\lib\\site-packages\\setuptools-65.5.0.dist-info\\INSTALLER',
|
||||
'DATA'),
|
||||
('setuptools-65.5.0.dist-info\\RECORD',
|
||||
'C:\\Program '
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\lib\\site-packages\\setuptools-65.5.0.dist-info\\RECORD',
|
||||
'DATA'),
|
||||
('setuptools-65.5.0.dist-info\\top_level.txt',
|
||||
'C:\\Program '
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\lib\\site-packages\\setuptools-65.5.0.dist-info\\top_level.txt',
|
||||
'DATA'),
|
||||
('setuptools-65.5.0.dist-info\\WHEEL',
|
||||
'C:\\Program '
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\lib\\site-packages\\setuptools-65.5.0.dist-info\\WHEEL',
|
||||
'DATA')])
|
||||
|
||||
@@ -277,42 +277,42 @@
|
||||
'E:\\Arma Reforger '
|
||||
'Work\\1960-utils\\Texturing\\MergeTextures2\\build\\merge_textures\\base_library.zip',
|
||||
'DATA'),
|
||||
('setuptools-65.5.0.dist-info\\LICENSE',
|
||||
('setuptools-65.5.0.dist-info\\INSTALLER',
|
||||
'C:\\Program '
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\lib\\site-packages\\setuptools-65.5.0.dist-info\\LICENSE',
|
||||
'DATA'),
|
||||
('setuptools-65.5.0.dist-info\\WHEEL',
|
||||
'C:\\Program '
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\lib\\site-packages\\setuptools-65.5.0.dist-info\\WHEEL',
|
||||
'DATA'),
|
||||
('setuptools-65.5.0.dist-info\\top_level.txt',
|
||||
'C:\\Program '
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\lib\\site-packages\\setuptools-65.5.0.dist-info\\top_level.txt',
|
||||
'DATA'),
|
||||
('setuptools-65.5.0.dist-info\\METADATA',
|
||||
'C:\\Program '
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\lib\\site-packages\\setuptools-65.5.0.dist-info\\METADATA',
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\lib\\site-packages\\setuptools-65.5.0.dist-info\\INSTALLER',
|
||||
'DATA'),
|
||||
('setuptools-65.5.0.dist-info\\REQUESTED',
|
||||
'C:\\Program '
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\lib\\site-packages\\setuptools-65.5.0.dist-info\\REQUESTED',
|
||||
'DATA'),
|
||||
('setuptools-65.5.0.dist-info\\METADATA',
|
||||
'C:\\Program '
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\lib\\site-packages\\setuptools-65.5.0.dist-info\\METADATA',
|
||||
'DATA'),
|
||||
('setuptools-65.5.0.dist-info\\LICENSE',
|
||||
'C:\\Program '
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\lib\\site-packages\\setuptools-65.5.0.dist-info\\LICENSE',
|
||||
'DATA'),
|
||||
('setuptools-65.5.0.dist-info\\entry_points.txt',
|
||||
'C:\\Program '
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\lib\\site-packages\\setuptools-65.5.0.dist-info\\entry_points.txt',
|
||||
'DATA'),
|
||||
('setuptools-65.5.0.dist-info\\INSTALLER',
|
||||
'C:\\Program '
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\lib\\site-packages\\setuptools-65.5.0.dist-info\\INSTALLER',
|
||||
'DATA'),
|
||||
('setuptools-65.5.0.dist-info\\RECORD',
|
||||
'C:\\Program '
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\lib\\site-packages\\setuptools-65.5.0.dist-info\\RECORD',
|
||||
'DATA'),
|
||||
('setuptools-65.5.0.dist-info\\top_level.txt',
|
||||
'C:\\Program '
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\lib\\site-packages\\setuptools-65.5.0.dist-info\\top_level.txt',
|
||||
'DATA'),
|
||||
('setuptools-65.5.0.dist-info\\WHEEL',
|
||||
'C:\\Program '
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\lib\\site-packages\\setuptools-65.5.0.dist-info\\WHEEL',
|
||||
'DATA')],
|
||||
[],
|
||||
False,
|
||||
False,
|
||||
1743968683,
|
||||
1759164736,
|
||||
[('run.exe',
|
||||
'C:\\Users\\Niklas\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python310\\site-packages\\PyInstaller\\bootloader\\Windows-64bit-intel\\run.exe',
|
||||
'EXECUTABLE')],
|
||||
|
||||
@@ -253,37 +253,37 @@
|
||||
'E:\\Arma Reforger '
|
||||
'Work\\1960-utils\\Texturing\\MergeTextures2\\build\\merge_textures\\base_library.zip',
|
||||
'DATA'),
|
||||
('setuptools-65.5.0.dist-info\\LICENSE',
|
||||
('setuptools-65.5.0.dist-info\\INSTALLER',
|
||||
'C:\\Program '
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\lib\\site-packages\\setuptools-65.5.0.dist-info\\LICENSE',
|
||||
'DATA'),
|
||||
('setuptools-65.5.0.dist-info\\WHEEL',
|
||||
'C:\\Program '
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\lib\\site-packages\\setuptools-65.5.0.dist-info\\WHEEL',
|
||||
'DATA'),
|
||||
('setuptools-65.5.0.dist-info\\top_level.txt',
|
||||
'C:\\Program '
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\lib\\site-packages\\setuptools-65.5.0.dist-info\\top_level.txt',
|
||||
'DATA'),
|
||||
('setuptools-65.5.0.dist-info\\METADATA',
|
||||
'C:\\Program '
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\lib\\site-packages\\setuptools-65.5.0.dist-info\\METADATA',
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\lib\\site-packages\\setuptools-65.5.0.dist-info\\INSTALLER',
|
||||
'DATA'),
|
||||
('setuptools-65.5.0.dist-info\\REQUESTED',
|
||||
'C:\\Program '
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\lib\\site-packages\\setuptools-65.5.0.dist-info\\REQUESTED',
|
||||
'DATA'),
|
||||
('setuptools-65.5.0.dist-info\\METADATA',
|
||||
'C:\\Program '
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\lib\\site-packages\\setuptools-65.5.0.dist-info\\METADATA',
|
||||
'DATA'),
|
||||
('setuptools-65.5.0.dist-info\\LICENSE',
|
||||
'C:\\Program '
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\lib\\site-packages\\setuptools-65.5.0.dist-info\\LICENSE',
|
||||
'DATA'),
|
||||
('setuptools-65.5.0.dist-info\\entry_points.txt',
|
||||
'C:\\Program '
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\lib\\site-packages\\setuptools-65.5.0.dist-info\\entry_points.txt',
|
||||
'DATA'),
|
||||
('setuptools-65.5.0.dist-info\\INSTALLER',
|
||||
'C:\\Program '
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\lib\\site-packages\\setuptools-65.5.0.dist-info\\INSTALLER',
|
||||
'DATA'),
|
||||
('setuptools-65.5.0.dist-info\\RECORD',
|
||||
'C:\\Program '
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\lib\\site-packages\\setuptools-65.5.0.dist-info\\RECORD',
|
||||
'DATA'),
|
||||
('setuptools-65.5.0.dist-info\\top_level.txt',
|
||||
'C:\\Program '
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\lib\\site-packages\\setuptools-65.5.0.dist-info\\top_level.txt',
|
||||
'DATA'),
|
||||
('setuptools-65.5.0.dist-info\\WHEEL',
|
||||
'C:\\Program '
|
||||
'Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\\lib\\site-packages\\setuptools-65.5.0.dist-info\\WHEEL',
|
||||
'DATA')],
|
||||
'python310.dll',
|
||||
False,
|
||||
|
||||
Binary file not shown.
Binary file not shown.
BIN
Texturing/MergeTextures2/dist/merge_textures.exe
vendored
BIN
Texturing/MergeTextures2/dist/merge_textures.exe
vendored
Binary file not shown.
@@ -1,85 +1,111 @@
|
||||
import os
|
||||
import sys
|
||||
from PIL import Image # type: ignore
|
||||
from PIL import Image # type: ignore
|
||||
import time
|
||||
import concurrent.futures
|
||||
from typing import Dict, List, Optional, Tuple
|
||||
|
||||
# Define suffix lists for BaseColor, Normal, RMA/ORM
|
||||
# Define suffix lists for BaseColor, Normal, packed maps, and single-channel maps
|
||||
BASECOLOR_SUFFIXES = ['_alb.', '_albedo.', '_bc.', '_basecolor.', '_b.']
|
||||
NORMAL_SUFFIXES = ['_nrm.', '_normal.', '_n.']
|
||||
RMA_SUFFIXES = ['_rma.']
|
||||
ORM_SUFFIXES = ['_orm.']
|
||||
ROUGHNESS_SUFFIXES = ['_roughness.', '_rough.', '_rgh.']
|
||||
METALLIC_SUFFIXES = ['_metallic.', '_metalness.', '_metal.', '_met.']
|
||||
AO_SUFFIXES = ['_ao.', '_ambientocclusion.', '_occlusion.']
|
||||
EMISSIVE_SUFFIXES = ['_emissive.']
|
||||
OPACITY_SUFFIXES = ['_opacity.']
|
||||
MASK_SUFFIXES = ['_mask.','_m.']
|
||||
MASK_SUFFIXES = ['_mask.', '_m.']
|
||||
|
||||
def detect_texture_type(filename):
|
||||
""" Detects the type of texture based on its suffix """
|
||||
if any(suffix in filename.lower() for suffix in BASECOLOR_SUFFIXES):
|
||||
"""Detect the type of texture based on naming suffixes."""
|
||||
lowered = filename.lower()
|
||||
if any(suffix in lowered for suffix in BASECOLOR_SUFFIXES):
|
||||
return 'BaseColor'
|
||||
elif any(suffix in filename.lower() for suffix in NORMAL_SUFFIXES):
|
||||
if any(suffix in lowered for suffix in NORMAL_SUFFIXES):
|
||||
return 'Normal'
|
||||
elif any(suffix in filename.lower() for suffix in RMA_SUFFIXES):
|
||||
if any(suffix in lowered for suffix in RMA_SUFFIXES):
|
||||
return 'RMA'
|
||||
elif any(suffix in filename.lower() for suffix in ORM_SUFFIXES):
|
||||
if any(suffix in lowered for suffix in ORM_SUFFIXES):
|
||||
return 'ORM'
|
||||
elif any(suffix in filename.lower() for suffix in EMISSIVE_SUFFIXES):
|
||||
if any(suffix in lowered for suffix in ROUGHNESS_SUFFIXES):
|
||||
return 'Roughness'
|
||||
if any(suffix in lowered for suffix in METALLIC_SUFFIXES):
|
||||
return 'Metallic'
|
||||
if any(suffix in lowered for suffix in AO_SUFFIXES):
|
||||
return 'AO'
|
||||
if any(suffix in lowered for suffix in EMISSIVE_SUFFIXES):
|
||||
return 'Emissive'
|
||||
elif any(suffix in filename.lower() for suffix in OPACITY_SUFFIXES):
|
||||
if any(suffix in lowered for suffix in OPACITY_SUFFIXES):
|
||||
return 'Opacity'
|
||||
elif any(suffix in filename.lower() for suffix in MASK_SUFFIXES):
|
||||
if any(suffix in lowered for suffix in MASK_SUFFIXES):
|
||||
return 'Mask'
|
||||
return None
|
||||
|
||||
def get_material_name(filename):
|
||||
""" Strips the 'T_' or 'TX_' prefix but keeps the suffix for texture type detection.
|
||||
Returns the full material name without the suffix for output file naming. """
|
||||
"""Strip the T_/TX_ prefix while keeping the suffix for detection and return the material name."""
|
||||
base_name = os.path.basename(filename)
|
||||
|
||||
# Remove the 'T_' or 'TX_' prefix
|
||||
if base_name.startswith('T_'):
|
||||
base_name = base_name[2:]
|
||||
elif base_name.startswith('TX_'):
|
||||
base_name = base_name[3:]
|
||||
|
||||
# Return the base_name without the suffix for output naming
|
||||
return base_name.rsplit('_', 1)[0] # Split only at the last underscore
|
||||
return base_name.rsplit('_', 1)[0]
|
||||
|
||||
def convert_single_material(material_data: Tuple[str, Dict[str, str]], output_folder: str) -> Tuple[bool, str]:
|
||||
"""Convert a single material to BCR/NMO format"""
|
||||
"""Convert a single material to BCR/NMO format."""
|
||||
material, files = material_data
|
||||
basecolor_file = files.get('BaseColor')
|
||||
normal_file = files.get('Normal')
|
||||
rma_file = files.get('RMA')
|
||||
orm_file = files.get('ORM')
|
||||
roughness_file = files.get('Roughness')
|
||||
metallic_file = files.get('Metallic')
|
||||
ao_file = files.get('AO')
|
||||
emissive_file = files.get('Emissive')
|
||||
opacity_file = files.get('Opacity')
|
||||
mask_file = files.get('Mask')
|
||||
|
||||
try:
|
||||
if convert_to_bcr_nmo(material, basecolor_file, normal_file, rma_file, orm_file, emissive_file, opacity_file, mask_file, output_folder):
|
||||
success, warnings = convert_to_bcr_nmo(
|
||||
material,
|
||||
basecolor_file,
|
||||
normal_file,
|
||||
rma_file,
|
||||
orm_file,
|
||||
roughness_file,
|
||||
metallic_file,
|
||||
ao_file,
|
||||
emissive_file,
|
||||
opacity_file,
|
||||
mask_file,
|
||||
output_folder,
|
||||
)
|
||||
if success:
|
||||
if warnings:
|
||||
return True, f"{material}: Successfully converted. Warning(s): {' '.join(warnings)}"
|
||||
return True, f"{material}: Successfully converted."
|
||||
else:
|
||||
return False, f"Skipping {material}: input file sizes do not match."
|
||||
return False, f"Skipping {material}: input file sizes do not match."
|
||||
except Exception as e:
|
||||
return False, f"Error processing {material}: {str(e)}"
|
||||
|
||||
def process_textures(input_files):
|
||||
""" Main function to process all textures in a folder and convert to BCR/NMO """
|
||||
textures = {}
|
||||
"""Main function to process all textures in a folder and convert to BCR/NMO."""
|
||||
textures: Dict[str, Dict[str, str]] = {}
|
||||
|
||||
# Group files by material name
|
||||
for filepath in input_files:
|
||||
filename = os.path.basename(filepath)
|
||||
material_name = get_material_name(filename)
|
||||
texture_type = detect_texture_type(filename)
|
||||
|
||||
if texture_type is None:
|
||||
continue
|
||||
|
||||
if material_name not in textures:
|
||||
textures[material_name] = {}
|
||||
textures[material_name][texture_type] = filepath
|
||||
|
||||
# Create a merged folder in the same directory as the input
|
||||
base_path = os.path.dirname(input_files[0])
|
||||
output_folder = os.path.join(base_path, 'merged')
|
||||
os.makedirs(output_folder, exist_ok=True)
|
||||
@@ -87,8 +113,7 @@ def process_textures(input_files):
|
||||
material_count = len(textures)
|
||||
print(f"Detected {material_count} Materials to process.")
|
||||
|
||||
# Check for required textures and filter out incomplete materials
|
||||
valid_materials = {}
|
||||
valid_materials: Dict[str, Dict[str, str]] = {}
|
||||
failed_converts = 0
|
||||
|
||||
for material, files in textures.items():
|
||||
@@ -98,7 +123,10 @@ def process_textures(input_files):
|
||||
if not files.get('Normal'):
|
||||
missing_files.append('Normal')
|
||||
if not (files.get('RMA') or files.get('ORM')):
|
||||
missing_files.append('RMA or ORM')
|
||||
if not files.get('Roughness'):
|
||||
missing_files.append('Roughness')
|
||||
if not files.get('AO'):
|
||||
missing_files.append('AO')
|
||||
|
||||
if missing_files:
|
||||
print(f"Skipping {material}: missing {', '.join(missing_files)}")
|
||||
@@ -106,16 +134,13 @@ def process_textures(input_files):
|
||||
else:
|
||||
valid_materials[material] = files
|
||||
|
||||
# Process materials in parallel
|
||||
success_count = 0
|
||||
with concurrent.futures.ThreadPoolExecutor() as executor:
|
||||
# Submit all materials for processing
|
||||
future_to_material = {
|
||||
executor.submit(convert_single_material, (material, files), output_folder): material
|
||||
for material, files in valid_materials.items()
|
||||
}
|
||||
|
||||
# Process results as they complete
|
||||
for future in concurrent.futures.as_completed(future_to_material):
|
||||
material = future_to_material[future]
|
||||
try:
|
||||
@@ -132,58 +157,102 @@ def process_textures(input_files):
|
||||
print(f"+++{success_count} of {material_count} materials successfully converted+++")
|
||||
time.sleep(3)
|
||||
|
||||
def convert_to_bcr_nmo(material, basecolor_file, normal_file, rma_file, orm_file, emissive_file, opacity_file, mask_file, output_folder):
|
||||
""" Converts given textures to BCR and NMO formats """
|
||||
def _ensure_single_channel(image_path: str):
|
||||
"""Load an arbitrary image and return a single-channel version for merging."""
|
||||
channel_image = Image.open(image_path)
|
||||
if channel_image.mode != 'L':
|
||||
channel_image = channel_image.convert('L')
|
||||
return channel_image
|
||||
|
||||
def convert_to_bcr_nmo(
|
||||
material: str,
|
||||
basecolor_file: Optional[str],
|
||||
normal_file: Optional[str],
|
||||
rma_file: Optional[str],
|
||||
orm_file: Optional[str],
|
||||
roughness_file: Optional[str],
|
||||
metallic_file: Optional[str],
|
||||
ao_file: Optional[str],
|
||||
emissive_file: Optional[str],
|
||||
opacity_file: Optional[str],
|
||||
mask_file: Optional[str],
|
||||
output_folder: str,
|
||||
) -> Tuple[bool, List[str]]:
|
||||
"""Convert the provided textures to BCR and NMO targets."""
|
||||
if basecolor_file is None or normal_file is None:
|
||||
raise ValueError('BaseColor and Normal textures are required.')
|
||||
|
||||
warnings: List[str] = []
|
||||
basecolor_img = Image.open(basecolor_file).convert('RGBA')
|
||||
normal_img = Image.open(normal_file).convert('RGBA')
|
||||
base_r, base_g, base_b, _ = basecolor_img.split()
|
||||
normal_r, normal_g, _, _ = normal_img.split()
|
||||
|
||||
roughness_channel = metallic_channel = ao_channel = None
|
||||
|
||||
if rma_file:
|
||||
rma_img = Image.open(rma_file).convert('RGBA')
|
||||
if not (basecolor_img.size == normal_img.size == rma_img.size):
|
||||
return False
|
||||
# BCR conversion
|
||||
bcr_img = Image.merge('RGBA', (basecolor_img.split()[0], basecolor_img.split()[1], basecolor_img.split()[2], rma_img.split()[0])) # Use Roughness (Alpha from RMA/ORM)
|
||||
bcr_img.save(os.path.join(output_folder, f"{material}_BCR.tga"))
|
||||
# NMO conversion
|
||||
nmo_img = Image.merge('RGBA', (normal_img.split()[0], normal_img.split()[1], rma_img.split()[1], rma_img.split()[2])) # Use Metallic, AO from RMA/ORM
|
||||
nmo_img.save(os.path.join(output_folder, f"{material}_NMO.tga"))
|
||||
packed_img = Image.open(rma_file).convert('RGBA')
|
||||
if not (basecolor_img.size == normal_img.size == packed_img.size):
|
||||
return False, warnings
|
||||
roughness_channel, metallic_channel, ao_channel, _ = packed_img.split()
|
||||
elif orm_file:
|
||||
rma_img = Image.open(orm_file).convert('RGBA')
|
||||
if not (basecolor_img.size == normal_img.size == rma_img.size):
|
||||
return False
|
||||
# BCR conversion
|
||||
bcr_img = Image.merge('RGBA', (basecolor_img.split()[0], basecolor_img.split()[1], basecolor_img.split()[2], rma_img.split()[1])) # Use Roughness (Alpha from RMA/ORM)
|
||||
bcr_img.save(os.path.join(output_folder, f"{material}_BCR.tga"))
|
||||
# NMO conversion
|
||||
nmo_img = Image.merge('RGBA', (normal_img.split()[0], normal_img.split()[1], rma_img.split()[2], rma_img.split()[0])) # Use Metallic, AO from RMA/ORM
|
||||
nmo_img.save(os.path.join(output_folder, f"{material}_NMO.tga"))
|
||||
# Optionally handle emissive and opacity maps
|
||||
packed_img = Image.open(orm_file).convert('RGBA')
|
||||
if not (basecolor_img.size == normal_img.size == packed_img.size):
|
||||
return False, warnings
|
||||
ao_channel, roughness_channel, metallic_channel, _ = packed_img.split()
|
||||
else:
|
||||
if roughness_file is None or ao_file is None:
|
||||
raise ValueError('Roughness and AO textures are required when RMA/ORM is absent.')
|
||||
roughness_channel = _ensure_single_channel(roughness_file)
|
||||
ao_channel = _ensure_single_channel(ao_file)
|
||||
if metallic_file is not None:
|
||||
metallic_channel = _ensure_single_channel(metallic_file)
|
||||
else:
|
||||
metallic_channel = Image.new('L', basecolor_img.size, 0)
|
||||
warnings.append(f"{material}: Missing Metallic texture. Using a black channel.")
|
||||
|
||||
if not (
|
||||
basecolor_img.size
|
||||
== normal_img.size
|
||||
== roughness_channel.size
|
||||
== ao_channel.size
|
||||
):
|
||||
return False, warnings
|
||||
if metallic_channel.size != basecolor_img.size:
|
||||
return False, warnings
|
||||
|
||||
if roughness_channel is None or metallic_channel is None or ao_channel is None:
|
||||
raise RuntimeError('Failed to resolve packed or single-channel textures.')
|
||||
|
||||
bcr_img = Image.merge('RGBA', (base_r, base_g, base_b, roughness_channel))
|
||||
bcr_img.save(os.path.join(output_folder, f"{material}_BCR.tga"))
|
||||
|
||||
nmo_img = Image.merge('RGBA', (normal_r, normal_g, metallic_channel, ao_channel))
|
||||
nmo_img.save(os.path.join(output_folder, f"{material}_NMO.tga"))
|
||||
|
||||
if emissive_file:
|
||||
emissive_img = Image.open(emissive_file)
|
||||
# Preserve original color mode instead of forcing RGB
|
||||
if emissive_img.mode != 'RGBA':
|
||||
emissive_img = emissive_img.convert('RGBA')
|
||||
emissive_img.save(os.path.join(output_folder, f"{material}_EM.tga"))
|
||||
|
||||
if opacity_file:
|
||||
opacity_img = Image.open(opacity_file)
|
||||
# Preserve original color mode instead of forcing grayscale
|
||||
if opacity_img.mode != 'RGBA':
|
||||
opacity_img = opacity_img.convert('RGBA')
|
||||
opacity_img.save(os.path.join(output_folder, f"{material}_OP.tga"))
|
||||
|
||||
if mask_file:
|
||||
mask_img = Image.open(mask_file)
|
||||
# Preserve original color mode instead of forcing grayscale
|
||||
if mask_img.mode != 'RGBA':
|
||||
mask_img = mask_img.convert('RGBA')
|
||||
mask_img.save(os.path.join(output_folder, f"{material}_MASK.tga"))
|
||||
|
||||
return True
|
||||
return True, warnings
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) < 2:
|
||||
print("Usage: drag and drop texture files onto the script")
|
||||
else:
|
||||
# Get the file paths from sys.argv (ignoring the first argument which is the script name)
|
||||
input_files = sys.argv[1:]
|
||||
process_textures(input_files)
|
||||
|
||||
Reference in New Issue
Block a user