-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy path__init__.py
More file actions
334 lines (271 loc) · 10.9 KB
/
__init__.py
File metadata and controls
334 lines (271 loc) · 10.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
"""
GTA V Scaleform Minimap Calculator
=================================
A Blender add-on for exporting curves as SVGs for GTA V Scaleform minimaps.
This add-on provides tools for converting between Blender, GTA V world, and
Scaleform coordinate systems, making it easier to create accurate minimap
representations of in-game locations.
Author: rubyys
Version: 1.0.1
Blender: 4.4.0+
"""
bl_info = {
"name": "GTA V Scaleform Minimap Calculator",
"author": "rubyys",
"version": (1, 0, 1),
"blender": (4, 4, 0),
"location": "View3D > Sidebar > Scaleform",
"description": "Export Blender curves to SVG for GTA V Scaleform minimap with coordinate conversion",
"category": "Import-Export",
}
import bpy
import os
import sys
from importlib import reload
from bpy.app.handlers import persistent
# Add module path if running as script
if __name__ == "__main__":
script_dir = os.path.dirname(os.path.abspath(__file__))
if script_dir not in sys.path:
sys.path.append(script_dir)
# Create a global reference to bl_info
_bl_info = bl_info.copy()
# Import all modules (after creating _bl_info)
from . import constants
from . import geometry
from . import utils
from . import core
from . import ui
# Scene handler functions moved directly to this file to avoid circular imports
@persistent
def on_file_load(dummy):
"""
Handler called when a new file is loaded.
This ensures visualizations are cleared when opening a new project.
"""
# Clear all caches to ensure we don't have stale data
from .utils.cache import clear_all_caches
clear_all_caches()
# Disable any active visualization
if bpy.context:
try:
# Import here to avoid circular imports
from .ui.visualization import disable_visualization, clear_visualization_data
# First disable the visualization
disable_visualization(bpy.context)
# Then clear all visualization data
clear_visualization_data()
# Force a redraw of all 3D viewports
for window in bpy.context.window_manager.windows:
for area in window.screen.areas:
if area.type == 'VIEW_3D':
area.tag_redraw()
except Exception as e:
print(f"Error during visualization cleanup on file load: {e}")
# Reset the visualization enabled property if it exists
try:
for scene in bpy.data.scenes:
if hasattr(scene, "scaleform_vis_enabled"):
scene.scaleform_vis_enabled = False
except Exception as e:
print(f"Error resetting visualization property: {e}")
@persistent
def on_scene_change(dummy):
"""
Handler called when switching between scenes.
This ensures visualizations match the current scene.
"""
# Disable any active visualization in old scene
if bpy.context:
try:
# Import here to avoid circular imports
from .ui.visualization import disable_visualization, clear_visualization_data
# First disable the visualization
disable_visualization(bpy.context)
# Then clear all visualization data
clear_visualization_data()
# Force a redraw of all 3D viewports
for window in bpy.context.window_manager.windows:
for area in window.screen.areas:
if area.type == 'VIEW_3D':
area.tag_redraw()
except Exception as e:
print(f"Error during visualization cleanup on scene change: {e}")
# Make sure the UI reflects the correct state
try:
if hasattr(bpy.context, "scene") and bpy.context.scene and hasattr(bpy.context.scene, "scaleform_vis_enabled"):
bpy.context.scene.scaleform_vis_enabled = False
except Exception as e:
print(f"Error updating visualization UI state: {e}")
# Added new handler for more reliable cleanup
@persistent
def on_load_pre(dummy):
"""
Handler called just before a new file is loaded.
This ensures visualizations are cleared before opening a new project.
"""
# Clear all caches first
from .utils.cache import clear_all_caches
clear_all_caches()
# Try to disable visualization before loading new file
if bpy.context:
try:
from .ui.visualization import disable_visualization, clear_visualization_data
disable_visualization(bpy.context)
clear_visualization_data()
except Exception as e:
print(f"Error during pre-load visualization cleanup: {e}")
def register_scene_handlers():
"""Register the scene and file handlers."""
# Check if handlers are already registered to avoid duplicates
if on_load_pre not in bpy.app.handlers.load_pre:
bpy.app.handlers.load_pre.append(on_load_pre)
if on_file_load not in bpy.app.handlers.load_post:
bpy.app.handlers.load_post.append(on_file_load)
# For Blender 4.x, use the appropriate handler
# Blender 4.0+ uses depsgraph_update_post instead of scene_update_post
if hasattr(bpy.app.handlers, "depsgraph_update_post"):
if on_scene_change not in bpy.app.handlers.depsgraph_update_post:
bpy.app.handlers.depsgraph_update_post.append(on_scene_change)
elif hasattr(bpy.app.handlers, "scene_update_post"):
if on_scene_change not in bpy.app.handlers.scene_update_post:
bpy.app.handlers.scene_update_post.append(on_scene_change)
def unregister_scene_handlers():
"""Unregister the scene and file handlers."""
# Remove all handler references
if on_load_pre in bpy.app.handlers.load_pre:
bpy.app.handlers.load_pre.remove(on_load_pre)
if on_file_load in bpy.app.handlers.load_post:
bpy.app.handlers.load_post.remove(on_file_load)
# Try both handler types for compatibility
if hasattr(bpy.app.handlers, "depsgraph_update_post"):
if on_scene_change in bpy.app.handlers.depsgraph_update_post:
bpy.app.handlers.depsgraph_update_post.remove(on_scene_change)
if hasattr(bpy.app.handlers, "scene_update_post"):
if on_scene_change in bpy.app.handlers.scene_update_post:
bpy.app.handlers.scene_update_post.remove(on_scene_change)
def reload_modules():
"""Reload all modules for development."""
# Reload in dependency order
reload(constants)
# Geometry package
reload(geometry.base)
reload(geometry.matrix)
reload(geometry.utils)
reload(geometry)
# Utils package
reload(utils.cache)
reload(utils.helpers)
reload(utils)
# Core package
reload(core.calculator)
reload(core.processor)
reload(core.exporter)
reload(core)
# UI package last
reload(ui.properties)
reload(ui.visualization)
reload(ui.operators)
reload(ui.panels)
reload(ui)
def register():
"""Register the add-on with Blender."""
# Force unregister first to prevent double registration
force_unregister()
# Reload modules in development mode
if hasattr(bpy.app, "debug") and bpy.app.debug:
reload_modules()
# Step 1: Register property group class
bpy.utils.register_class(ui.ScaleformCalculatorSettings)
# Step 2: Register pointer property for scene
bpy.types.Scene.scaleform_settings = bpy.props.PointerProperty(
type=ui.ScaleformCalculatorSettings
)
# Step 3: Register additional scene properties
ui.register()
# Step 4: Register UI classes in correct order
for cls in ui.classes:
if cls.__name__ != "ScaleformCalculatorSettings" and not hasattr(
bpy.types, cls.__name__
):
try:
bpy.utils.register_class(cls)
except Exception as e:
print(f"Error registering {cls.__name__}: {e}")
# Step 5: Register scene handlers for visualization cleanup
register_scene_handlers()
# Step 6: Ensure no visualization is active initially
try:
from .ui.visualization import clear_visualization_data
clear_visualization_data()
except Exception as e:
print(f"Error clearing visualization data during registration: {e}")
print(
f"Registered {_bl_info['name']} v{'.'.join(str(v) for v in _bl_info['version'])}"
)
def unregister():
"""Unregister the add-on from Blender."""
# First disable any active visualizations
try:
from .ui.visualization import disable_visualization, clear_visualization_data
if bpy.context:
disable_visualization(bpy.context)
clear_visualization_data()
except Exception as e:
print(f"Error cleaning up visualization during unregister: {e}")
# Then unregister scene handlers to prevent errors during cleanup
unregister_scene_handlers()
# Clear all caches
utils.clear_all_caches()
# Step 1: Unregister UI classes in reverse order
for cls in reversed(ui.classes):
try:
if cls.__name__ != "ScaleformCalculatorSettings" and hasattr(
bpy.types, cls.__name__
):
bpy.utils.unregister_class(cls)
except Exception as e:
print(f"Error unregistering {cls.__name__}: {e}")
# Step 2: Unregister additional scene properties
ui.unregister()
# Step 3: Unregister the pointer property
if hasattr(bpy.types.Scene, "scaleform_settings"):
del bpy.types.Scene.scaleform_settings
# Step 4: Unregister the property group class
try:
bpy.utils.unregister_class(ui.ScaleformCalculatorSettings)
except Exception as e:
print(f"Error unregistering ScaleformCalculatorSettings: {e}")
print(f"Unregistered {_bl_info['name']}")
def force_unregister():
"""Force unregister if already registered to prevent double registration."""
try:
# First disable any active visualizations
try:
from .ui.visualization import disable_visualization, clear_visualization_data
if bpy.context:
disable_visualization(bpy.context)
clear_visualization_data()
except Exception as e:
print(f"Error cleaning up visualization during force unregister: {e}")
# Import locally to avoid import errors during first installation
from . import ui
# First unregister properties
try:
ui.unregister()
except:
pass
# Unregister scene settings property
if hasattr(bpy.types.Scene, "scaleform_settings"):
del bpy.types.Scene.scaleform_settings
# Unregister UI classes in reverse order
for cls in reversed(ui.classes):
try:
if hasattr(bpy.types, cls.__name__):
bpy.utils.unregister_class(cls)
except:
pass
except Exception as e:
print(f"Error during force unregister: {e}")
if __name__ == "__main__":
register()