work
save startup blend for animation tab & whatnot
This commit is contained in:
@@ -19,12 +19,12 @@
|
||||
import datetime
|
||||
import json
|
||||
import logging
|
||||
import numpy as np
|
||||
import os
|
||||
import platform
|
||||
import re
|
||||
import shutil
|
||||
import sys
|
||||
import tempfile
|
||||
import uuid
|
||||
from typing import Optional
|
||||
|
||||
@@ -43,7 +43,6 @@ from . import (
|
||||
search,
|
||||
)
|
||||
|
||||
|
||||
bk_logger = logging.getLogger(__name__)
|
||||
|
||||
ABOVE_NORMAL_PRIORITY_CLASS = 0x00008000
|
||||
@@ -123,8 +122,26 @@ def selection_set(sel):
|
||||
bpy.context.view_layer.objects.active = sel[0]
|
||||
for ob in sel[1]:
|
||||
ob.select_set(True)
|
||||
except Exception as e:
|
||||
bk_logger.exception(f"failed to select objects: {str(e)}")
|
||||
except Exception:
|
||||
bk_logger.exception("Failed to select objects:")
|
||||
|
||||
|
||||
def get_asset_data_from_ob(ob) -> Optional[dict]:
|
||||
"""Return the BlenderKit asset_data dict for an object.
|
||||
|
||||
Checks the object's own IDProperty first. When the object is a
|
||||
collection-instance EMPTY (imported from a local asset library) it falls
|
||||
back to the asset_data stored on the instanced collection, which
|
||||
unpack_asset_bg.py writes there during local-library processing.
|
||||
"""
|
||||
if ob is None:
|
||||
return None
|
||||
ad = ob.get("asset_data")
|
||||
if ad is not None:
|
||||
return ad
|
||||
if ob.instance_collection is not None:
|
||||
return ob.instance_collection.get("asset_data")
|
||||
return None
|
||||
|
||||
|
||||
def get_active_model() -> Optional[bpy.types.Object]:
|
||||
@@ -309,6 +326,11 @@ def get_search_props():
|
||||
if not hasattr(wm, "blenderkit_addon"):
|
||||
return
|
||||
props = wm.blenderkit_addon
|
||||
|
||||
if uiprops.asset_type == "AUTHOR":
|
||||
if not hasattr(wm, "blenderkit_author"):
|
||||
return
|
||||
props = wm.blenderkit_author
|
||||
return props
|
||||
|
||||
|
||||
@@ -383,6 +405,8 @@ def get_active_asset():
|
||||
return get_active_nodegroup()
|
||||
elif ui_props.asset_type == "ADDON":
|
||||
return None # Addons don't have an active asset concept
|
||||
elif ui_props.asset_type == "AUTHOR":
|
||||
return None # Authors don't have an active asset concept
|
||||
|
||||
return None
|
||||
|
||||
@@ -422,6 +446,8 @@ def get_upload_props():
|
||||
return b.blenderkit
|
||||
elif ui_props.asset_type == "ADDON":
|
||||
return None # Addons don't have upload props
|
||||
elif ui_props.asset_type == "AUTHOR":
|
||||
return None # Authors don't have upload props
|
||||
return None
|
||||
|
||||
|
||||
@@ -444,6 +470,41 @@ def get_active_brush():
|
||||
return brush
|
||||
|
||||
|
||||
def get_brush_icon_path(brush) -> str:
|
||||
"""Get the path to the brush icon image.
|
||||
|
||||
In Blender <= 4.5, brushes have icon_filepath. In Blender 5.0+, icon_filepath
|
||||
was removed and brush preview is stored as in-memory pixels (brush.preview).
|
||||
For 5.0+ we save the preview pixels to a temp PNG file.
|
||||
"""
|
||||
if bpy.app.version <= (4, 5, 0):
|
||||
return bpy.path.abspath(brush.icon_filepath)
|
||||
|
||||
if brush.preview is None:
|
||||
return ""
|
||||
width, height = brush.preview.image_size
|
||||
if width == 0 or height == 0:
|
||||
return ""
|
||||
|
||||
filepath = os.path.join(
|
||||
tempfile.gettempdir(), f"blenderkit_brush_{brush.name}_icon.png"
|
||||
)
|
||||
img = bpy.data.images.new(
|
||||
name=f".bk_brush_preview_{brush.name}",
|
||||
width=width,
|
||||
height=height,
|
||||
alpha=True,
|
||||
)
|
||||
try:
|
||||
img.pixels.foreach_set(brush.preview.image_pixels_float)
|
||||
img.filepath_raw = filepath
|
||||
img.file_format = "PNG"
|
||||
img.save()
|
||||
finally:
|
||||
bpy.data.images.remove(img)
|
||||
return filepath
|
||||
|
||||
|
||||
def get_scene_id():
|
||||
"""gets scene id and possibly also generates a new one"""
|
||||
bpy.context.scene["uuid"] = bpy.context.scene.get("uuid", str(uuid.uuid4()))
|
||||
@@ -474,6 +535,7 @@ def get_preferences_as_dict():
|
||||
"global_dir": user_preferences.global_dir,
|
||||
"project_subdir": user_preferences.project_subdir,
|
||||
"unpack_files": user_preferences.unpack_files,
|
||||
"write_asset_metadata": user_preferences.write_asset_metadata,
|
||||
# GUI
|
||||
"show_on_start": user_preferences.show_on_start,
|
||||
"thumb_size": user_preferences.thumb_size,
|
||||
@@ -482,6 +544,7 @@ def get_preferences_as_dict():
|
||||
"search_in_header": user_preferences.search_in_header,
|
||||
"tips_on_start": user_preferences.tips_on_start,
|
||||
"announcements_on_start": user_preferences.announcements_on_start,
|
||||
"assetbar_follows_cursor": user_preferences.assetbar_follows_cursor,
|
||||
# NETWORK
|
||||
"client_port": user_preferences.client_port,
|
||||
"ip_version": user_preferences.ip_version,
|
||||
@@ -525,6 +588,7 @@ def get_preferences() -> datas.Prefs:
|
||||
global_dir=user_preferences.global_dir, # type: ignore[union-attr]
|
||||
project_subdir=user_preferences.project_subdir, # type: ignore[union-attr]
|
||||
unpack_files=user_preferences.unpack_files, # type: ignore[union-attr]
|
||||
write_asset_metadata=user_preferences.write_asset_metadata, # type: ignore[union-attr]
|
||||
# GUI
|
||||
show_on_start=user_preferences.show_on_start, # type: ignore[union-attr]
|
||||
thumb_size=user_preferences.thumb_size, # type: ignore[union-attr]
|
||||
@@ -533,6 +597,7 @@ def get_preferences() -> datas.Prefs:
|
||||
search_in_header=user_preferences.search_in_header, # type: ignore[union-attr]
|
||||
tips_on_start=user_preferences.tips_on_start, # type: ignore[union-attr]
|
||||
announcements_on_start=user_preferences.announcements_on_start, # type: ignore[union-attr]
|
||||
assetbar_follows_cursor=user_preferences.assetbar_follows_cursor, # type: ignore[union-attr]
|
||||
# NETWORK
|
||||
client_port=user_preferences.client_port, # type: ignore[union-attr]
|
||||
ip_version=user_preferences.ip_version, # type: ignore[union-attr]
|
||||
@@ -562,7 +627,15 @@ def save_prefs(user_preferences, context, **kwargs):
|
||||
if bpy.app.background is True or bpy.app.factory_startup is True:
|
||||
return
|
||||
|
||||
previous_global_dir = (
|
||||
global_vars.PREFS.get("global_dir")
|
||||
if isinstance(global_vars.PREFS, dict)
|
||||
else None
|
||||
)
|
||||
global_vars.PREFS = get_preferences_as_dict()
|
||||
paths.ensure_asset_library_path(
|
||||
global_vars.PREFS.get("global_dir"), previous_global_dir
|
||||
)
|
||||
if user_preferences.preferences_lock is True:
|
||||
return
|
||||
|
||||
@@ -637,6 +710,8 @@ def img_to_preview(img, copy_original=False):
|
||||
if not copy_original:
|
||||
return
|
||||
|
||||
import numpy as np
|
||||
|
||||
# Only process if image has alpha channel and needs filling
|
||||
if img.channels == 4 and (
|
||||
img.alpha_mode == "STRAIGHT" or img.alpha_mode == "PREMUL"
|
||||
@@ -800,7 +875,7 @@ def copy_asset(fp1, fp2):
|
||||
"""Synchronizes the asset between directories, including it's texture subdirectories."""
|
||||
if 1:
|
||||
bk_logger.debug("copy asset")
|
||||
bk_logger.debug(fp1 + " " + fp2)
|
||||
bk_logger.debug("%s %s", fp1, fp2)
|
||||
if not os.path.exists(fp2):
|
||||
shutil.copyfile(fp1, fp2)
|
||||
bk_logger.debug("copied")
|
||||
@@ -989,6 +1064,58 @@ def get_dimensions(obs):
|
||||
return dim, bbmin, bbmax
|
||||
|
||||
|
||||
def get_scene_dimensions(scene: bpy.types.Scene) -> tuple[Vector, Vector, Vector]:
|
||||
"""Calculate world-space bounds for the entire scene."""
|
||||
|
||||
minx = miny = minz = float("inf")
|
||||
maxx = maxy = maxz = float("-inf")
|
||||
has_geometry = False
|
||||
depsgraph = bpy.context.evaluated_depsgraph_get()
|
||||
|
||||
def accumulate(coord: Vector) -> None:
|
||||
nonlocal minx, miny, minz, maxx, maxy, maxz, has_geometry
|
||||
has_geometry = True
|
||||
minx = min(minx, coord.x)
|
||||
miny = min(miny, coord.y)
|
||||
minz = min(minz, coord.z)
|
||||
maxx = max(maxx, coord.x)
|
||||
maxy = max(maxy, coord.y)
|
||||
maxz = max(maxz, coord.z)
|
||||
|
||||
mesh_like_types = {"MESH", "CURVE", "SURFACE", "META", "FONT", "GPENCIL"}
|
||||
|
||||
for ob in scene.objects:
|
||||
object_eval = ob.evaluated_get(depsgraph)
|
||||
mw = object_eval.matrix_world
|
||||
|
||||
if ob.type in mesh_like_types:
|
||||
to_mesh = getattr(object_eval, "to_mesh", None)
|
||||
mesh = to_mesh() if callable(to_mesh) else None
|
||||
if mesh:
|
||||
for vert in mesh.vertices:
|
||||
accumulate(mw @ vert.co)
|
||||
to_mesh_clear = getattr(object_eval, "to_mesh_clear", None)
|
||||
if callable(to_mesh_clear):
|
||||
to_mesh_clear()
|
||||
elif ob.type == "VOLUME":
|
||||
for corner in object_eval.bound_box:
|
||||
accumulate(mw @ Vector(corner))
|
||||
elif hasattr(object_eval, "bound_box") and object_eval.bound_box:
|
||||
for corner in object_eval.bound_box:
|
||||
accumulate(mw @ Vector(corner))
|
||||
else:
|
||||
accumulate(mw @ Vector((0.0, 0.0, 0.0)))
|
||||
|
||||
if not has_geometry:
|
||||
zero = Vector((0.0, 0.0, 0.0))
|
||||
return zero.copy(), zero.copy(), zero.copy()
|
||||
|
||||
bbmin = Vector((minx, miny, minz))
|
||||
bbmax = Vector((maxx, maxy, maxz))
|
||||
dim = Vector((maxx - minx, maxy - miny, maxz - minz))
|
||||
return dim, bbmin, bbmax
|
||||
|
||||
|
||||
def get_simple_headers() -> dict[str, str]:
|
||||
headers = {
|
||||
"accept": "application/json",
|
||||
@@ -1147,7 +1274,7 @@ def name_update(props, context=None):
|
||||
fname = fname.replace("'", "")
|
||||
fname = fname.replace('"', "")
|
||||
if ui_props.asset_type == "HDR" or fname == "":
|
||||
bk_logger.info(f"Skiping the rename")
|
||||
bk_logger.info("Skipping the rename")
|
||||
return # don't rename HDR's or with empty name
|
||||
else:
|
||||
asset = get_active_asset()
|
||||
@@ -1273,6 +1400,8 @@ def asset_from_newer_blender_version(asset_data, blender_version=None):
|
||||
# addons don't have a blender version, so we return False
|
||||
if asset_data["assetType"] == "addon":
|
||||
return False, ""
|
||||
if asset_data["assetType"] == "author":
|
||||
return False, ""
|
||||
asset_ver = asset_data["sourceAppVersion"].split(".")
|
||||
if blender_version is None:
|
||||
blender_version = bpy.app.version
|
||||
@@ -1543,7 +1672,7 @@ def check_globaldir_permissions():
|
||||
)
|
||||
return False
|
||||
if not os.path.isdir(global_dir):
|
||||
bk_logger.info(f"Global dir does not exist. Creating it at {global_dir}")
|
||||
bk_logger.info("Global dir does not exist. Creating it at %s", global_dir)
|
||||
try:
|
||||
os.mkdir(global_dir)
|
||||
except Exception as e:
|
||||
|
||||
Reference in New Issue
Block a user