Skip to content

Commit

Permalink
update to 1.3.0
Browse files Browse the repository at this point in the history
  • Loading branch information
tingjoybits committed May 12, 2022
1 parent fcc80d8 commit 41c8b62
Show file tree
Hide file tree
Showing 24 changed files with 250 additions and 111 deletions.
28 changes: 21 additions & 7 deletions Brush_Manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,8 @@
from .t3dn_bip.ops import InstallPillow
from .t3dn_bip.utils import support_pillow

try:
Addon_Name = __name__.split('.')[1]
except IndexError:
Addon_Name = __name__

Addon_Name = __package__


def prefs():
Expand All @@ -58,6 +56,9 @@ def prefs():
'Pose', 'Rotate', 'Scrape/Peaks', 'SculptDraw', 'Simplify',
'Slide Relax', 'Smooth', 'Snake Hook', 'Thumb'
]
if bpy.app.version >= (3, 2, 0):
BRUSHES_SCULPT_NAMES += ['Paint', 'Smear Sculpt']

BRUSHES_IPAINT_NAMES = ['Clone', 'Fill', 'Mask', 'Smear', 'Soften', 'TexDraw']

BRUSHES_GPAINT_NAMES = [
Expand Down Expand Up @@ -117,6 +118,9 @@ def evaluate_brush_tools(brushes, mode=''):
if t_label == 'Draw':
brush_tool_names.append((t_label, 'SculptDraw'))
continue
if t_label == 'Smear':
brush_tool_names.append((t_label, 'Smear Sculpt'))
continue
for brush in BRUSHES_SCULPT_NAMES:
if brush.split('/')[0] == t_label:
brush_tool_names.append((t_label, brush))
Expand Down Expand Up @@ -607,6 +611,8 @@ def update_category_first_preview_item(self, context):


def update_brush_list(self, context):
if context.mode not in BM_Modes.in_modes:
return None
global _directory
prefs = context.preferences.addons[Addon_Name].preferences
create_default_smear_tools()
Expand All @@ -619,6 +625,8 @@ def update_brush_list(self, context):


def update_fav_list(self, context):
if context.mode not in BM_Modes.in_modes:
return None
global _fav_list
prefs = context.preferences.addons[Addon_Name].preferences
fav_brushes = get_favorite_brushes()
Expand Down Expand Up @@ -723,8 +731,10 @@ def get_current_file_brushes(mode=''):
try:
if not check_brush_type(brush, mode):
continue
if brush.name == 'Paint' and not check_vertex_paint_brushes():
continue
if brush.name == 'Paint':
if bpy.app.version < (3, 2, 0) and\
not check_vertex_paint_brushes():
continue
brushes.append(brush.name)
except AttributeError:
continue
Expand Down Expand Up @@ -1025,7 +1035,11 @@ def create_default_sculpt_tools():

def create_default_smear_tools():
global IS_INIT_SMEAR
if bpy.context.mode != 'PAINT_WEIGHT' and bpy.context.mode != 'PAINT_VERTEX':
if bpy.context.mode != 'PAINT_WEIGHT' and\
bpy.context.mode != 'PAINT_VERTEX' and\
bpy.context.mode != 'SCULPT':
return None
if bpy.context.mode == 'SCULPT' and bpy.app.version < (3, 2, 0):
return None
if IS_INIT_SMEAR.get(bpy.context.mode):
return None
Expand Down
13 changes: 12 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ It also has themes for brushes preview and this add-on makes easy to apply a new

Support Blender version: **2.83+**

<!---
[![Donate](https://www.paypalobjects.com/en_US/i/btn/btn_donateCC_LG.gif)](https://www.paypal.com/donate/?hosted_button_id=C77W5ZVC6R562)
--->

# Installation

- [**DOWNLOAD LATEST RELEASE**](https://github.com/tingjoybits/Brush_Manager/releases/latest/download/Brush_Manager129.zip)<- file
- [**DOWNLOAD LATEST RELEASE**](https://github.com/tingjoybits/Brush_Manager/releases/latest/download/Brush_Manager130.zip)<- file
- Open Blender and select Edit->Preferences
- Click Add-ons category and then 'Install...' button
- Select the downloaded archive file from download link (The archive downloaded from 'Code' button won't work, please use the releases)
Expand Down Expand Up @@ -45,6 +47,15 @@ https://tingjoybits.gumroad.com/

# Change Log

**Brush Manager 1.3.0**

- Added support for two default paint brushes in the Sculpt mode, which are 'Paint' and 'Smear' gained an official release out of experimental development in Blender 3.2.0 version. This update includes new icons for these brushes.
- Updated 3D Ninjas Blender Image Preview library to latest 1.0.11 version. (Still the superior solution to the faster icons preview)
- Various fixes.

![](icon_themes/round%20basic/paint.png)
![](icon_themes/round%20basic/smear.png)

**Brush Manager 1.2.9**

- Integrated 3DN BIP or 3D Ninjas Blender Image Preview library, which allows real fast preview image loads in Blender. Now brush icons will load instantly from the very start if 3DN BIP library is turned on in the Settings. Installation of python module 'Pillow' is required. More info about library at the developers page https://github.com/3dninjas/3dn-bip/
Expand Down
2 changes: 1 addition & 1 deletion __init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
"description": "Manage and organize of the brushes library",
"author": "TingJoyBits",
"blender": (2, 83, 0),
"version": (1, 2, 9),
"version": (1, 3, 0),
"location": "Properties Editor > Active Tool tab > Brushes Panel",
"doc_url": "https://github.com/tingjoybits/Brush_Manager",
"category": "Interface"
Expand Down
Binary file added icon_themes/round basic/paint.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added icon_themes/round basic/smear.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added icon_themes/round ceramic/paint.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added icon_themes/round ceramic/smear.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added icon_themes/round dark/paint.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added icon_themes/round dark/smear.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added icon_themes/round metal lead/paint.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added icon_themes/round metal lead/smear.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion t3dn_bip/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
'''Load image previews in parallel and in any resolution. Supports BIP files.'''

__version__ = '1.0.8'
__version__ = '0.0.0'
Binary file added t3dn_bip/__pycache__/__init__.cpython-310.pyc
Binary file not shown.
Binary file added t3dn_bip/__pycache__/formats.cpython-310.pyc
Binary file not shown.
Binary file added t3dn_bip/__pycache__/ops.cpython-310.pyc
Binary file not shown.
Binary file added t3dn_bip/__pycache__/previews.cpython-310.pyc
Binary file not shown.
Binary file added t3dn_bip/__pycache__/settings.cpython-310.pyc
Binary file not shown.
Binary file added t3dn_bip/__pycache__/threads.cpython-310.pyc
Binary file not shown.
Binary file added t3dn_bip/__pycache__/utils.cpython-310.pyc
Binary file not shown.
25 changes: 20 additions & 5 deletions t3dn_bip/formats.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,16 @@
class _BIPFormat:
'''BIP format info.'''

def __init__(self, magic: bytes):
def __init__(self, exts: list, magic: bytes):
self.exts = exts
self.magic = magic


class _PILFormat:
'''PIL format info.'''

def __init__(self, magic: bytes, tests: list):
def __init__(self, exts: list, magic: bytes, tests: list):
self.exts = exts
self.magic = magic
self.tests = tests
self.supported = False
Expand All @@ -27,12 +29,25 @@ def __init__(self, magic: bytes, tests: list):
]

BIP_FORMATS = {
'BIP2': _BIPFormat(magic=b'BIP2'),
'BIP2': _BIPFormat(
exts=['.bip', '.bip2'],
magic=b'BIP2',
),
}

PIL_FORMATS = {
'PNG': _PILFormat(magic=b'\x89\x50\x4e\x47', tests=_png_tests),
'JPG': _PILFormat(magic=b'\xff\xd8', tests=_jpg_tests),
'PNG':
_PILFormat(
exts=['.png'],
magic=b'\x89\x50\x4e\x47',
tests=_png_tests,
),
'JPG':
_PILFormat(
exts=['.jpg', '.jpeg', '.jpe', '.jif', '.jfif'],
magic=b'\xff\xd8',
tests=_jpg_tests,
),
}

MAGIC_LENGTH = max(
Expand Down
105 changes: 23 additions & 82 deletions t3dn_bip/previews.py
Original file line number Diff line number Diff line change
@@ -1,25 +1,20 @@
import bpy
import bpy.utils.previews
from bpy.types import ImagePreview
from multiprocessing.dummy import Pool
from multiprocessing import cpu_count
from threading import Event
from queue import Queue
from traceback import print_exc
from time import time
from typing import ItemsView, Iterator, KeysView, ValuesView
from .utils import support_pillow, can_load, load_file, tag_redraw
from .utils import support_pillow, can_load, load_file
from .formats import unsupported_formats

WARNINGS = True
from .threads import load_async
from . import settings


class ImagePreviewCollection:
'''Dictionary-like class of previews.'''

def __init__(self, max_size: tuple = (128, 128), lazy_load: bool = True):
'''Create collection and start internal timer.'''
if WARNINGS:
if settings.WARNINGS:
if not support_pillow():
print('Pillow is not installed, therefore:')
print('- BIP images load without scaling.')
Expand Down Expand Up @@ -47,12 +42,7 @@ def __init__(self, max_size: tuple = (128, 128), lazy_load: bool = True):
self._lazy_load = lazy_load

if self._lazy_load:
self._pool = Pool(processes=cpu_count())
self._event = None
self._queue = Queue()

if not bpy.app.timers.is_registered(self._timer):
bpy.app.timers.register(self._timer, persistent=True)
self._abort_signal = None

def __len__(self) -> int:
'''Return the amount of previews in the collection.'''
Expand Down Expand Up @@ -123,10 +113,12 @@ def load(self, name: str, filepath: str, filetype: str) -> ImagePreview:

preview = self.new(name)

self._pool.apply_async(
func=self._load_async,
args=(name, filepath, self._get_event()),
error_callback=print,
load_async(
self._collection,
name,
filepath,
self._max_size,
self._get_abort_signal(),
)

return preview
Expand Down Expand Up @@ -158,83 +150,32 @@ def _load_eager(self, name: str, filepath: str) -> ImagePreview:

return preview

def _load_async(self, name: str, filepath: str, event: Event):
'''Load image contents from file and queue preview load.'''
if not event.is_set():
data = load_file(filepath, self._max_size)

if not event.is_set():
self._queue.put((name, data, event))

def _timer(self):
'''Load queued image contents into previews.'''
now = time()
redraw = False
delay = 0.1

while time() - now < 0.1:
try:
args = self._queue.get(block=False)
except:
break

try:
self._load_queued(*args)
except:
print_exc()
else:
redraw = True

else:
delay = 0.0

if redraw:
tag_redraw()

return delay

def _load_queued(self, name: str, data: dict, event: Event):
'''Load queued image contents into preview.'''
if not event.is_set():
if name in self:
preview = self[name]
preview.icon_size = data['icon_size']
preview.icon_pixels = data['icon_pixels']
preview.image_size = data['image_size']
preview.image_pixels = data['image_pixels']

def clear(self):
'''Clear all previews.'''
if self._lazy_load:
self._set_event()

with self._queue.mutex:
self._queue.queue.clear()
self._set_abort_signal()

self._collection.clear()

def close(self):
'''Close the collection and clear all previews.'''
if self._lazy_load:
self._set_event()

if bpy.app.timers.is_registered(self._timer):
bpy.app.timers.unregister(self._timer)
self._set_abort_signal()

self._collection.close()

def _get_event(self) -> Event:
'''Get the clear event, make one if necesssary.'''
if self._event is None:
self._event = Event()
def _get_abort_signal(self) -> Event:
'''Get the abort signal, make one if necesssary.'''
if self._abort_signal is None:
self._abort_signal = Event()

return self._event
return self._abort_signal

def _set_event(self):
'''Set the clear event, then remove the reference.'''
if self._event is not None:
self._event.set()
self._event = None
def _set_abort_signal(self):
'''Set the abort signal, then remove the reference.'''
if self._abort_signal is not None:
self._abort_signal.set()
self._abort_signal = None


def new(
Expand Down
8 changes: 8 additions & 0 deletions t3dn_bip/settings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Print warnings about which features are supported.
WARNINGS = True

# Use magic bytes to check file type, instead of extension.
USE_MAGIC = False

# Max number of threads used for loading image contents.
MAX_THREADS = 4
Loading

0 comments on commit 41c8b62

Please sign in to comment.