Skip to content

Commit

Permalink
github
Browse files Browse the repository at this point in the history
  • Loading branch information
NevilArt committed Jan 1, 2025
1 parent c7718fb commit a33f3db
Show file tree
Hide file tree
Showing 14 changed files with 1,266 additions and 271 deletions.
6 changes: 5 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
# 0, 1, 3, 20240823
# 0, 1, 3, 20241226
* Marker Copy/Paste added.
* Render preset tool updated.

# 0, 1, 3, 202408234
* Topo Symmetrize tool that keep UV data (under the EditMesh/Mesh menu)
* Camera target select search from last constraint and ignore disable ones this makes better result.
* Alingt Target to camera matchs the target to camera direction (Camera/Target/Align).
Expand Down
1 change: 1 addition & 0 deletions CONTRIBUTORS.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
* [email protected]
* [email protected]
* [email protected]
* youngjaekim

* Nattapong Khwanpray
* Florian Schreiber
Expand Down
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,10 @@ If you found this product useful and want to support this project you can Donate
* [Download Older Version for Blender 2.80 ~ 3.5](https://github.com/NevilArt/BsMax_2_80)

## Recent Updates and Changes
* Marker Copy/Paste added.
* Render preset tool updated.
* New Render preset tool has update and bug fixed.
* Add-on preference save method changed.
* All setting and saved preset files are collection in to datafile directory.
* Open datafile directory button added to BsMax prefrence panel.
* [Change log ...](https://github.com/NevilArt/BsMax/blob/master/CHANGELOG.md)

## Special Thanks
Expand Down
130 changes: 70 additions & 60 deletions __init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,54 +15,56 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
############################################################################
# 2024/07/21

import bpy
import sys
import os

from bpy.types import AddonPreferences, Operator
from bpy.props import EnumProperty, BoolProperty, FloatProperty
from time import sleep
from _thread import start_new_thread
from bpy.utils import register_class, unregister_class
# 2024/12/27

bl_info = {
'name': "BsMax",
'description': "BsMax UI simulations and Tool pack (Blender 3.6LTS ~ 4.2LTS)",
'author': "Naser Merati (Nevil)",
'version': (0, 1, 3, 20241225),
'description': "BsMax UI simulations and Tool pack (Blender 3.6LTS ~ 4.3)",
'author': "Nevil Tan (Naser Merati)",
'version': (0, 1, 3, 20250101),
'blender': (3, 6, 0), # Minimum Version
'location': "Almost Everywhere in Blender",
'doc_url': 'https://github.com/NevilArt/BsMax/wiki',
'tracker_url': 'https://github.com/NevilArt/BsMax/issues',
'category': "Interface"
}

# TODO switch prefrence saving data to jason
import bpy
import sys
import os

# Add public classes, variables and functions path if not in list.
path = os.path.dirname(os.path.realpath(__file__))
if path not in sys.path:
sys.path.append(path)

from .bsmax.math import isfloat
from bpy.types import AddonPreferences, Operator
from bpy.props import EnumProperty, BoolProperty, FloatProperty
from time import sleep
from _thread import start_new_thread
from bpy.utils import register_class, unregister_class

from .bsmax import register_bsmax, unregister_bsmax
from .keymaps import register_keymaps, unregister_keymaps
from .menu import register_menu, unregister_menu
from .primitive import register_primitives, unregister_primitives
from .startup import register_startup, unregister_startup
from .tools import register_tools, unregister_tools
from bsmax.data_file import (
get_datafiles_path,
write_dictionary_to_json_file,
read_json_file_to_dictionary,
open_folder_in_explorer
)

# import templates

addons = bpy.context.preferences.addons
wiki = 'https://github.com/NevilArt/BsMax/wiki/'
iniFileName = bpy.utils.user_resource('SCRIPTS') + '\\addons\\BsMax.ini'

def wiki():
return 'https://github.com/NevilArt/BsMax/wiki/'

# Addon preferences
def update_preferences(cls, _, action):
global addons
addons = bpy.context.preferences.addons
preferences = addons[__name__].preferences
""" Quick Selection """
if cls.mode == 'QUICK' and action == 'APLICATION':
Expand Down Expand Up @@ -124,12 +126,11 @@ def update_preferences(cls, _, action):


def row_prop(cls, col, name, page):
global wiki
row = col.row()
row.prop(cls, name)
srow = row.row()
srow.scale_x = 1
srow.operator('wm.url_open', icon='HELP').url= wiki + page
srow.operator('wm.url_open', icon='HELP').url= wiki() + page


def draw_simple_panel(cls, layout):
Expand Down Expand Up @@ -187,51 +188,41 @@ def draw_option_panel(cls, layout):
row = box.row()
row.prop(cls, 'experimental')

def get_bsmax_json_file_name():
return get_datafiles_path() + os.sep + 'BsMax.json'


def save_preferences(preferences):
global iniFileName
string = ''
file_name = get_bsmax_json_file_name()
dictionary = {}

for prop in preferences.bl_rna.properties:
if not prop.is_readonly:
key = prop.identifier
if key != 'bl_idname':
val = str(getattr(preferences, key))
string += key + '=' + val + os.linesep
if prop.is_readonly:
continue

key = prop.identifier
if key == 'bl_idname':
continue

dictionary[key] = getattr(preferences, key)

ini = open(iniFileName, 'w')
ini.write(string)
ini.close()
write_dictionary_to_json_file(dictionary, file_name)


def load_preferences(preferences):
global iniFileName
file_name = get_bsmax_json_file_name()

if not os.path.exists(iniFileName):
if not os.path.exists(file_name):
return

string = open(iniFileName).read()
props = string.splitlines()

for prop in props:
key = prop.split('=')

if len(key) != 2:
continue

if isfloat(key[1]):
value = float(key[1])

elif key[1] in {'True', 'False'}:
value = key[1] == 'True'

else:
value = key[1].upper()

if hasattr(preferences, key[0]):
current_value = getattr(preferences, key[0])

dictionary = read_json_file_to_dictionary(file_name)

for key, value in dictionary.items():
if hasattr(preferences, key):
current_value = getattr(preferences, key)
# apply value only if has changed
if value != current_value:
setattr(preferences, key[0], value)
setattr(preferences, key, value)


class BsMax_AddonPreferences(AddonPreferences):
Expand Down Expand Up @@ -537,6 +528,11 @@ def draw(self, _):
text="Save Preferences Setting",
icon='FILE_TICK'
)

row.operator(
'bsmax.open_data_file_directory',
text="", icon='FILEBROWSER'
)

if self.options:
draw_option_panel(self, box)
Expand All @@ -551,11 +547,21 @@ class BsMax_OT_Save_Preferences(Operator):
bl_options = {'REGISTER', 'INTERNAL'}

def execute(self, _):
global addons
addons = bpy.context.preferences.addons
save_preferences(addons[__name__].preferences)
return{'FINISHED'}


class BsMax_OT_Open_Data_File_Directory(Operator):
bl_idname = 'bsmax.open_data_file_directory'
bl_label = "Open datafile directory"
bl_options = {'REGISTER', 'INTERNAL'}

def execute(self, _):
open_folder_in_explorer(get_datafiles_path() + os.sep)
return{'FINISHED'}


def register_delay(preferences):
sleep(0.2)
register_keymaps(preferences)
Expand All @@ -564,12 +570,15 @@ def register_delay(preferences):

classes = {
BsMax_OT_Save_Preferences,
BsMax_OT_Open_Data_File_Directory,
BsMax_AddonPreferences
}


def register():
global classes, addons
global classes

addons = bpy.context.preferences.addons
for cls in classes:
register_class(cls)

Expand All @@ -586,7 +595,8 @@ def register():


def unregister():
global classes, addons
global classes
addons = bpy.context.preferences.addons
save_preferences(addons[__name__].preferences)

unregister_keymaps()
Expand Down
26 changes: 17 additions & 9 deletions bsmax/actions.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
############################################################################
# 2024/03/04
# 2024/12/27

import bpy

Expand Down Expand Up @@ -84,10 +84,14 @@ def set_as_active_object(ctx, obj):
return:
None
"""
if obj:
bpy.ops.object.select_all(action='DESELECT')
obj.select_set(state=True)
ctx.view_layer.objects.active = obj
if not obj:
return

for obj in ctx.selected_objects:
obj.select_set(False)

obj.select_set(state=True)
ctx.view_layer.objects.active = obj


def set_create_target(obj, target, distance=(0.0, 0.0, -2.0), align=True):
Expand Down Expand Up @@ -186,7 +190,10 @@ def set_origen(ctx, obj, location):
saved_location = scene.cursor.location.copy()
saved_rotation = scene.cursor.rotation_euler.copy()
scene.cursor.location = location
bpy.ops.object.select_all(action='DESELECT')

for obj in ctx.selected_objects:
obj.select_set(False)

ctx.view_layer.objects.active = obj
obj.select_set(state=True)
bpy.ops.object.origin_set(type='ORIGIN_CURSOR', center='MEDIAN')
Expand All @@ -211,16 +218,17 @@ def match_transform(ctx, obj, target):
target_location = target.matrix_world.to_translation()
target_rotation = target.matrix_world.to_euler()
target_scale = target.matrix_world.to_scale()

# store and set the mode
use_transform_state = ctx.scene.tool_settings.use_transform_data_origin
ctx.scene.tool_settings.use_transform_data_origin = True

# arrange selection
bpy.ops.object.select_all(action='DESELECT')
for obj in ctx.selected_objects:
obj.select_set(False)
obj.select_set(state=True)
ctx.view_layer.objects.active = obj

#TODO Rotation part not perfect but work for most cases
# match the rotation axis by axis
obj_rotation = obj.matrix_world.to_euler()
Expand Down
65 changes: 65 additions & 0 deletions bsmax/data_file.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
############################################################################
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
############################################################################
# 2024/12/27

import bpy
import os
import subprocess
import platform
import json


def get_datafiles_path():
""" return datafile path and create if not exist """
datafiles_path = bpy.utils.user_resource("SCRIPTS", path="addons")

datafiles_path += os.sep + 'BsMax-datafiles'

if not os.path.isdir(datafiles_path):
os.mkdir(datafiles_path)

return datafiles_path


def open_folder_in_explorer(path):
if not os.path.isdir(path):
return

if platform.system() == "Windows":
os.startfile(path)

elif platform.system() == "Darwin":
subprocess.call(["open", path])

elif platform.system() == "Linux":
subprocess.call(["xdg-open", path])


def write_dictionary_to_json_file(data, file_path):
try:
with open(file_path, 'w', encoding='utf-8') as json_file:
json.dump(data, json_file, ensure_ascii=False, indent=4)
return True
except:
return False


def read_json_file_to_dictionary(file_path):
try:
with open(file_path, 'r', encoding='utf-8') as json_file:
data = json.load(json_file)
return data
except:
return {}
Loading

0 comments on commit a33f3db

Please sign in to comment.