-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy path__init__.py
1682 lines (1400 loc) · 59.5 KB
/
__init__.py
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
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
'''
## Todo ########
#
# V Get arguments working on OSX
# - Get localview export working (not supported)
# - Fix custom path and preload, with old scene opened wrong paths are used.
# It uses the path from file for export and path for import fro ini. Add extra update for path on EXport
# - Try scene without getConfig this is not needed as enum already loads settings
# - Added d2.80 support
# - updated user_preferences to preferences
# - Add warning when appPath is not set
# - Auto save shows CANCELLED but does work
####################
####################
## v.0.6.3
## 29-12-18
## Changed
## - Added skip local view, some scene cause errors
##
## 12-01-19
## Fixed
## - Small UI change
## - Hotkey issue
##
## Added
## - Missing skip local to popup menu
##
## Changed
## - Popup menu doesnt have 2 buttons at the bottom, makes it more clear what export is
## - Label was replace due to new WM menu
## - Export button has more logical label
## v.0.6.4
## 12-01-19
## Changed
## - Popup menu doesnt have 2 buttons at the bottom, makes it more clear what export is
## - Label was replace due to new WM menu
## - Export button has more logical label
##
## Fixed
## - Apply modifier for bl 2.80
##
## Added
## - Undo for export operation in case of error or malfunction
## v.0.6.5
## 26-02-19
## Fixed
## - Error caused by items inside collection
## - Non Mesh types where added when "selection only" was off
## v.0.6.6
## 20-03-19
## Fixed
## - Warning error Panel class
## v.0.6.7
## 20-03-20
## Changed
## - custom properties saved to addon prefs instead of in scene
## Mentioned by Brechts https://developer.blender.org/T74954#895043
## https://docs.blender.org/api/current/bpy.types.AddonPreferences.html
## Im Skipping this because i want this to be per scene
## - Changed string path to DIR_PATH
## v.0.6.8
## 2021-11-04
# Fixed
- Concate error in export operator > addon_prefs, "uvlb_winPath" caused error
- OBJ importer > global_clight_size taken out in new OBJ importer
- bl293 'apply_as" has changed
- Check local bool was not working properly. Added warning text, it has issues now and doen not transfering work done in UVlayout
- Missing options for Windows multiple options were not working and added in export
# Changed
- Added split_property > new 280 layout method
- Panel uses now sub-panel introduced in 2.80
## v.0.6.9
## 2021-11-06
# Fixed
- Autosave & close kept running when automation was off
## v.0.7.0
## 2021-11-06
# Added
- Forced reimport > when commands fails
- Optimize options > auto drops geometry, flattens, optimizes, packs, saves and returns to Blender
- Function to send tmp, edit & obj files to UVlayout. This allows user to easily open them, the ui from UVlayout is very outdated and tedious to work with.
# Changed
- If not mods are in mesh gray out menu option
- If 1 UV channel in mesh hide UV layout sub panel
- Moved panel to Tool catergory > save vertical menu from being to crowed
## v.0.7.0
## 2021-11-10
# Added
- Export custom path now in export options panel > easier accesible
# Changed
- Better check if we cancel or send file back to Blender > returns cancel or done report in bottom
## v.0.7.1 - 2021-11-10
# Changed
- get path and files moved to its own function, same code was used 6 times
## v.0.7.2 - 2024-07-23
# Fixed
- Changed parameter for OBJ importer and exporter.
## [v0.7.3] - 2024-07-24
# Fixed
- Export error if app path is not set, Panel shows red error with set app path option
## [v0.7.4] - 2024-07-25
# Fixed
- Automation Optimize, didnt do anything code fixed
- Show warning when exporting and custom path doesnt exist or is wrong
- missing check for OSX app path
# Changed
- Code cleanup
- Panel design is using split_property ala 2.8 Design
- Dialog operator now uses duplicate of panel by using wm.call_panel > easier and no double code
- Automation is either pack or optimize, running both commands wasnt doing anything since optimize also packs uvs
## [v0.7.41] - 2024-07-25
# Fixed
- missing check for OSX app path set
## [v0.7.5] - 2024-07-25
# Added
- uv channel poreview when switch number. this switches uvmap index so we actually can see preview easier
####################
## TODO
- Seams need to be updated after new import > 0.6.8 still shows old seams
- Fix automate, keeps running when checked off cmd file keeps being created when automate is checked off
- Add check for UVchannels, if there 1 then gray out menu or hide it
- Add check for modifier options, if no mod on model, gray out option
- Add function which adds manual update fo when the sending didnt go well > there is alway an out file still there
- Add options to load tmp and edit files which you can save from UVlayout, does work with blender. Send them to UVlayout
- Save custom file in dot file next to blend file, now ini file is still per app
- Add better check when UVlayout is canceled, currently it states that all is done
- Autopack sometimes closes without saving on OSX
- When switching UV Channel, make it switch in the panel so we see preview
####################
'''
bl_info = {
"name": "Headus UVLayout Bridge",
"description": "Headus UVLayout Bridge - A bridge between Blender and Headus UVlayout for quick UVs unwrapping",
"location": "3D VIEW > Properties > Headus UVlayout Panel",
"author": "Rombout Versluijs // Titus Lavrov",
"version": (0, 7, 5),
"blender": (2, 80, 0),
"wiki_url": "https://github.com/schroef/uvlayout_bridge",
"tracker_url": "https://github.com/schroef/uvlayout_bridge/issues",
"category": "UV"
}
import bpy
import collections
import os
import rna_keymap_ui
#import sys
import os.path
import subprocess
import tempfile
import time
import configparser
from sys import platform
from configparser import SafeConfigParser
from bpy.props import StringProperty, EnumProperty, BoolProperty, IntProperty
from bpy.types import Operator, AddonPreferences, Panel
from bpy_extras.io_utils import (ImportHelper, ExportHelper)
from . config.registers import get_hotkey_entry_item
#---Check OS---
# bpy.types.Scene.osSys = EnumProperty(
# items = (('0', "WIN", ''),('1', "OSX", '')),
# name = "OS check",
# description="Check what OS is used",
# default = '0')
#--SYS check Enummenus --#
scn = bpy.types.Scene
if platform == "darwin":
scn.osSys = '1'
if platform == "win32":
scn.osSys = '0'
print("OS used: %s" % platform)
# return addon preferences
def get_addon_prefs(context):
return context.preferences.addons[__name__].preferences
def app_path_set(context):
addon_prefs = get_addon_prefs(context)
if platform == "win32":
return addon_prefs.uvlb_winPath != 'Please set Application Path'
if platform == "darwin":
return addon_prefs.versionUVL != 'Please choose version'
def customPath_exists(context):
scn = context.scene
return os.path.exists(scn.uvlb_customPath)
# def object_color_type_items(self,context)
# return colors
def toggle_texture_preview(self,context):
context = bpy.context
scn = context.scene
VIEW3D_PT_shading = bpy.types.VIEW3D_PT_shading
shading = VIEW3D_PT_shading.get_shading(context)
if scn.uvlb_uvPreview == True:
if shading.color_type != 'TEXTURE':
scn.object_color_types = shading.color_type
shading.color_type = 'TEXTURE'
else:
shading.color_type = scn.object_color_types
#toggle actrive UVMAP index
ob = context.active_object
scn=context.scene
ob.data.uv_layers.active_index = scn.uvlb_uv_channel-1
def update_uvchannel_index(self,context):
'''channels uv channel index so we see preview in 3dv when switching'''
# switch uv map index
ob = context.active_object
scn=context.scene
ob.data.uv_layers.active_index = scn.uvlb_uv_channel-1
# set overlay preview
context.scene.uvlb_uvPreview = True
toggle_texture_preview(context, context)
# WIP make it toggle both ways, so if we change index in UVMAPS panel also update int prop
# b3d example GGET/SET
# https://b3d.interplanety.org/en/dynamically-setting-the-max-and-min-values-%E2%80%8B%E2%80%8Bfor-a-custorm-property-in-the-blender-python-api/
def get_uvchannels(self):
uv_channels = bpy.context.active_object.data.uv_layers
# # print(self.get('uvlb_uv_channel'))
# if self.get('uvlb_uv_channel',1) > len(uv_channels)-1:
# print("1")
# return self.get('uvlb_uv_channel')
# elif uv_channels.active_index+1 < self.get('uvlb_uv_channel'):
# print("2")
# return uv_channels.active_index +1
# elif self.get('uvlb_uv_channel',1) < uv_channels.active_index+1:
# print("3")
# return self.get('uvlb_uv_channel')
# else:
# return 1
return self.get('uvlb_uv_channel', 1)
def set_uvchannels(self, value):
uv_channels = bpy.context.active_object.data.uv_layers
if uv_channels:
if value > len(uv_channels):
value = len(uv_channels)
if value < len(uv_channels):
value = 1
else:
value = 1
self['uvlb_uv_channel'] = value
# def get_uvchannels_index(self,context):
# '''Get uv channels active_index'''
# if context.scene and context.active_object:
# ob = context.active_object
# if ob.data.uv_layers != None:
# return ob.data.uv_layers.active_index + 1
#-- LOAD / SET CONFIG FILE --#
configFol = "config"
version = "Please choose version"
def setConfig(self, context):
'''Save Custom Path in config file when property is updated
:param context: context
'''
preferences = context.preferences
addon_prefs = get_addon_prefs(context)
version = getattr(addon_prefs, "versionUVL", "")
customPath = getattr(context.scene, "uvlb_customPath", "")
pathEnable = getattr(context.scene, "uvlb_pathEnable", False)
winPath = getattr(addon_prefs, "uvlb_winPath", "")
config = configparser.ConfigParser()
configPath = os.path.join(os.path.dirname(os.path.realpath(__file__)), configFol + "/config.ini")
print("UVlayout-Bridge: %s // %s // %s" % (customPath, pathEnable, winPath))
config.read(configPath)
if not config.has_section("main"):
config.add_section('main')
config.set('main', 'version', str(version))
config.set('main', 'customPath', str(customPath))
config.set('main', 'pathEnable', str(pathEnable))
config.set('main', 'winPath', str(winPath))
with open(configPath, 'w') as configfile:
config.write(configfile)
def getVersionUVL():
'''get UVlayout version from configuration file
:return: versionUVL
:rtype: bool
'''
version = "Please choose version"
config = SafeConfigParser()
for path in bpy.utils.script_paths():
ConfigFile = os.path.join(path,"addons","uvlayout_bridge/",configFol + "/config.ini")
if os.path.exists(ConfigFile):
config.read(ConfigFile)
try:
version = config.get('main', 'version')
except:
version = "Please choose version"
return version
def getCustomPath():
'''get Custom Path version from configuration file
:return: customPath
:rtype: string
'''
customPath = "Please set path"
pathEnable = False
winPath = "Please set Application Path"
config = SafeConfigParser()
for path in bpy.utils.script_paths():
ConfigFile = os.path.join(path,"addons","uvlayout_bridge/",configFol + "/config.ini")
if os.path.exists(ConfigFile):
config.read(ConfigFile)
try:
customPath = config.get('main', 'customPath')
pathEnable = config.getboolean('main', 'pathEnable')
winPath = config.get('main', 'winPath')
except:
customPath = "Please set path"
pathEnable = False
winPath = "Please set Application Path"
return (customPath, pathEnable, winPath)
def updateIcon(self, context):
scn = bpy.types.Scene
# print("### Icons Updated ###")
# print(self.uvlb_mode)
if (self.uvlb_mode == '0'):
setattr(scn, "iconMode", 'EDITMODE_HLT')
else:
setattr(scn, "iconMode", 'MOD_SUBSURF')
if (self.uvlb_uv_mode == '0'):
setattr(scn, "iconUVMode", 'TEXTURE')
else:
setattr(scn, "iconUVMode", 'GROUP_UVS')
# Props
scn = bpy.types.Scene
#-- GET CUSTOM PATH / OSX & WIN --#
scn.uvlb_customPath = StringProperty(
name="Custom Path",
description = "Choose custom export path instead of temp directory. Is saved per scene",
subtype = 'DIR_PATH',
default = getCustomPath()[0],
update = setConfig)
scn.uvlb_pathEnable = BoolProperty(
name="Custom Path",
description = "Choose custom path instead of temp",
default = getCustomPath()[1],
update = setConfig)
#-- BRIDGE ADDON OPTIONS --#
#---UV Channel selector---
scn.uvlb_uv_channel = IntProperty(
name = "Map",
description = "Select a UV channel for editing in export. Shows UV channel when setting number for easy preview",
default = 1,
get=get_uvchannels,
set=set_uvchannels,
# get=lambda self: get_uvchannels(self),
# set=lambda self, value: set_uvchannels(self, value),
# min = 1,
# max = get_uvchannels,
update = update_uvchannel_index)
scn.object_color_types = EnumProperty(
items = (('MATERIAL', 'MATERIAL',''),
('OBJECT','OBJECT',''),
('VERTEX','VERTEX',''),
('SINGLE','SINGLE',''),
('RANDOM','RANDOM',''),
('TEXTURE','TEXTURE','')),
name = "Color Type",
description = "Overlayer object Color Type in 3dView",
default = 'MATERIAL')
scn.uvlb_uvPreview = BoolProperty(
name="UV Preview",
description = "Preview UV channel in 3dView, enables texture preview.",
default = False,
update = toggle_texture_preview)
scn.spaceName = BoolProperty(
name="Spaces in Name",
default=False)
scn.selOnly = BoolProperty(
name="Selection Only",
description = "Export selected object(s) only. Otherwise all visible object are exported.",
default=True)
scn.viewOnly = BoolProperty(
name="Selection Only",
default=False)
scn.appMod = BoolProperty(
name="Apply Modifier",
description="Applies subsurf modifer, also in Blender will this be applied. You can choose to make backup.",
default=False)
scn.cloneOb = BoolProperty(
name="Create Backup",
description="Creates copy of the model before modifiers are applied.",
default=False)
scn.useKeyMap = BoolProperty(
name="Use short popup",
description="Use Alt + Shit + U to open the popup window",
default=True)
#--Icons Enummenus --#
scn.iconMode = EnumProperty(
items = (('EDITMODE_HLT', "EDITMODE_HLT", ''),
('MOD_SUBSURF', "MOD_SUBSURF", '')),
name = "Mode",
description = "POLY or SUBD",
default = 'EDITMODE_HLT')
scn.iconMode = EnumProperty(
items = (('EDITMODE_HLT', "EDITMODE_HLT", ''),
('MOD_SUBSURF', "MOD_SUBSURF", '')),
name = "Mode",
description = "POLY or SUBD",
default = 'EDITMODE_HLT')
scn.iconUVMode = EnumProperty(
items = (('TEXTURE', "TEXTURE", ''),('GROUP_UVS', "GROUP_UVS", '')),
name = "UVMode",
description = "Edit or New",
default = 'TEXTURE')
#-- UVlayout OPTIONS --#
scn.uvlb_mode = EnumProperty(
items = (('0', "Poly", ''),
('1', "SUBD", '')),
name = "Mode",
description = "If the mesh being loaded is the control cage for a subdivision surface, then make sure that SUBD is selected. The subdivided surface will then be used in the flattening calculations, rather than the control cage itself, producing more accurate results. If the mesh isn't a subdivision surface, then select Poly. Mind that objects with low poly count can look different in UVlayout. The mesh isnt changed it only looks different in 3d view.",
default = '0',
update=updateIcon)
scn.uvlb_uv_mode = EnumProperty(
items = (('0', "New", ''),('1', "Edit", '')),
name = "UV Mode",
description = "If your mesh already has UVs and you want to reflatten them to reduce distortion, select Edit. Otherwise, select New to delete any existing UVs and start with a clean slate.",
default = '0',
update=updateIcon)
scn.uvlb_uv_weld = BoolProperty(
name="Weld UV's",
description = "If the loaded mesh has seams (green edges) between adjacent polys, reload with this option ticked. It'll weld all co-incident UVs together, but could break the OBJ Update tool and point correspondences between morph targets.",
default=False)
scn.uvlb_uv_clean = BoolProperty(
name="Clean",
description = "If the loaded mesh has non-manifold edges (i.e. an edge is shared by more than two faces) then ticking this option will fix the problem geometry as its loaded. The clean will also remove duplicate faces. A summary of the changes made will be displayed once the file has been loaded.",
default=False)
scn.uvlb_uv_detach = BoolProperty(
name="Detach Flipped UVs",
description = "Tick this option if you want flipped polys in UV space to be detached into separate shells.",
default=False)
scn.uvlb_uv_geom = BoolProperty(
name="Weld Geom Vertexes",
description = "If there are geometry seams (blue edges) between seemingly continuous surfaces, then reload with this ticked to weld those up. Currently this triangulates the mesh also, so its recommended you only do this if you really have to.",
default=False)
scn.uvlb_autoComm = BoolProperty(
name="Automation:",
description = "Use a couple commands to automate workflow. Can be a bit buggy!",
default=False)
scn.uvlb_autoPack = BoolProperty(
name="Packing",
description = "Packs model or all models automatically.",
default=False)
scn.uvlb_autoOptimize = BoolProperty(
name="Optimize",
description = "Drop all geometry, flatten, optimize, pack and save it ",
default=False)
scn.uvlb_autoSave = BoolProperty(
name="Auto Return",
description = "Automatically sends the model back to Blender when all actions are done. Dont interupt this action, takes a small bit of time.",
default=False)
scn.uvlb_help = BoolProperty(
name="Help",
description = "Hover over each button or menu for short detailed description of functions.",
default=False)
scn.uvlb_autoCOMS = EnumProperty(
# items = (('1', "Drop", ''),('2', "Flatten", ''),('3', "Optimize", ''),('4', "Drop-Flatten-Optimize", ''),('5', "Pack", ''),('6', "Drop-Flatten-Optimize-Pack", '')),
items = (('0', "Choose", 'Choose'),('1', "Pack", 'Packs all UVs'),('2', "Optimize", 'Flatten, optimizes and packs')),
name = "Commands",
description = "Some of the options you can check under \"Pack\", will cause an error. Some commands are buggy and will crash the window. You need to redo the export from Blender and try again :(",
default = '0')
# default = '0')
# scn.checkLocal = BoolProperty(
# name = "Skip Local",
# default = False,
# description="If issue with localview arrises skip it. NOT RECOMMENDED! You can loose work because, sometimes causes work done not to transfer over.")
scn.forced_reimport = BoolProperty(
name = "Forced Reimport",
default = False,
description="Forces reimport of the out file from UVlayout. Sometimes import mismatches timing of UVlayout causing to not import proper output file.")
def is_local(context):
#for ob in bpy.context.scene.objects:
for ob in bpy.context.scene.collection.objects:
#bpy.context.view_layer.objects.active = bpy.data.objects[ob.name]
## 2.80
view = context.space_data
is_local_view = (view.local_view is not None)
# print("ob: %s - %s" % (ob.name, is_local_view))
#if ob.layers_local_view[0]:
## 2.80
if is_local_view:
return True
else:
pass
def CheckSelection():
objSelected = False
if bpy.context.selected_objects != []:
objSelected = True
return objSelected
def get_path_files():
preferences = bpy.context.preferences
addon_prefs = get_addon_prefs(bpy.context)
scn = bpy.context.scene
#---Variables---
if platform == "win32":
UVLayoutPath = addon_prefs.uvlb_winPath
else:
UVLayoutPath = ''
if scn.uvlb_pathEnable:
path = scn.uvlb_customPath
else:
path = "" + tempfile.gettempdir()
# path = "" + tempfile.gettempdir()
# print("path %s" % path)
path = '/'.join(path.split('\\'))
if platform == "win32":
path = path+'/'
file_Name = path + "Blender2UVLayout_TMP.obj"
file_outName = path + "Blender2UVLayout_TMP.out"
file_setName = path +"Blender2UVLayout_TMP.set"
file_cmdName = path + "Blender2UVLayout_TMP.cmd"
file_commands = "subd"
uvl_exit_str = "exit"
pathFiles = scn, addon_prefs, UVLayoutPath, file_Name,file_outName, file_setName, file_cmdName, uvl_exit_str, uvlObjs, Objs
return pathFiles
global expObjs, expMeshes, uvlObjs, Objs
expObjs = []
expMeshes = []
uvlObjs = []
Objs = []
def import_to_blender(file_Name,file_outName, file_setName, file_cmdName, uvl_exit_str, uvlObjs, Objs):
# print("Import path: %s - File:%s" % (file_Name))
# print("isosfile file_name: %s" % os.path.isfile(file_outName))
# print("isosfile file_name == true: %s" % os.path.isfile(file_outName) == True)
if os.path.isfile(file_outName) == True:
#time.sleep(1)
if bpy.app.version[0] < 3:
bpy.ops.import_scene.obj(filepath = file_outName,
axis_forward = 'Y',
axis_up = 'Z',
filter_glob = "*.obj;*.mtl",
use_edges = False,
use_smooth_groups = False,
use_split_objects = True,
use_split_groups = True,
use_groups_as_vgroups = True,
use_image_search = False,
split_mode = 'ON',
)
#bl 4.0
if bpy.app.version[0] == 4 and bpy.app.version[1] >= 0:
bpy.ops.wm.obj_import(filepath = file_outName,
forward_axis = 'Y',
up_axis = 'Z',
filter_glob = "*.obj;*.mtl",
use_split_objects = True,
use_split_groups = True,
import_vertex_groups = True,
)
# print("IMPORT OBJ")
#---Close UVLAYOUT ---
f = open(file_cmdName, "w+")
f.write(''.join([uvl_exit_str]))
f.close()
# print("Transfer UVs and CleanUP")
#---Transfer UVs and CleanUP---
for ob in bpy.context.selected_objects:
uvlObjs.append(ob)
bpy.ops.object.select_all(action='DESELECT')
# print("JOIN UVS")
for ob in uvlObjs:
try:
# print(ob.name)
#---Get source object name
refName=ob.name.split('__UVL')
#---Select source object---
## 2.80
bpy.data.objects[refName[0]].select_set(state=True)
#---Select UVL object
## 2.80
bpy.context.view_layer.objects.active = bpy.data.objects[ob.name]
#---Transfer UVs from UVL object to Source object
bpy.ops.object.join_uvs()
bpy.ops.object.select_all(action='DESELECT')
except Exception as error:
print("[DEBUG ]UVleayout Error: %s" % error)
bpy.ops.object.select_all(action='DESELECT')
# print("REMOVE IMPORTED MESH")
for ob in uvlObjs:
# print("remove ob UVL: %s" % ob.name)
# print("remove ob data UVL: %s" % ob.data.name)
#bpy.data.meshes.remove(ob.data,True)
## 2.80
bpy.data.meshes.remove(ob.data, do_unlink=True)
bpy.ops.object.select_all(action='DESELECT')
# print("SET MODES MESH OBJECT")
for ob in Objs:
#---Make new seams
## 2.80
ob.select_set(state=True)
## 2.80
bpy.context.view_layer.objects.active = ob
bpy.ops.object.mode_set(mode='EDIT')
bpy.ops.object.mode_set(mode='EDIT')
bpy.ops.mesh.select_all(action='SELECT')
# Added clear seams bl293
bpy.ops.mesh.mark_seam(clear=True)
bpy.ops.uv.seams_from_islands()
bpy.ops.object.editmode_toggle()
return True
else:
return False
#-- Headus uvLayout Export/Import --#
def UVL_IO():
scn, addon_prefs, UVLayoutPath, file_Name,file_outName, file_setName, file_cmdName, uvl_exit_str, uvlObjs, Objs = get_path_files()
# reset forced reimport
scn.forced_reimport = False
expObjs = []
expMeshes = []
uvlObjs = []
Objs = []
#--Check visible objects
#def layers_intersect(a, b, name_a="layers", name_b=None):
#def layers_intersect(a, b, name_a="collections", name_b=None):
# return any(l0 and l1 for l0, l1 in zip(getattr(a, name_a), getattr(b, name_b or name_a)))
## 2.80
def find_collection(context, obj):
collections = obj.users_collection
if len(collections) > 0:
return collections[0]
return context.scene.collection
def gather_objects(scene):
objexcl = set()
def no_export(obj):
return (not obj.hide_viewport) and (not obj.hide_select) and obj.visible_get() #and find_collection(bpy.context, obj)
def is_selected(obj):
#return obj.select
return obj.select_get()
def add_obj(obj):
if obj.type == 'MESH':
if obj not in objexcl:
scn.viewOnly = True
if scn.selOnly:
scn.viewOnly = False
if (is_selected(obj)):
objexcl.discard(obj)
print ("Objects sel only: %s" % obj)
else:
objexcl.add(obj)
print ("Objects include: %s" % obj)
return
for obj in scene.objects:
#for obj in scene.collection.objects:
if obj.type == 'MESH':
if (not no_export(obj)):
objexcl.discard(obj)
continue
add_obj(obj)
return objexcl
objexcl = gather_objects(bpy.context.scene)
for ob in objexcl:
#--Select object only visible and set selection
## 2.80
bpy.data.objects[ob.name].select_set(state=True)
print ("Objects exclude: %s" % ob.name)
scn.selOnly = True
#--Get selected objects---
for ob in bpy.context.selected_objects:
if ob.type == 'MESH':
#---If space in name replace by underscore
params = [" "] #list of search parameters
# [ o for o in bpy.context.scene.objects if o.active ]
if any(x for x in params if x in ob.name): #search for params items in object name
ob.name = ob.name.replace(" ","_")
scn.spaceName = True
if ob.type == 'MESH':
## 2.80
if len(ob.data.uv_layers) < bpy.context.scene.uvlb_uv_channel:
for n in range(bpy.context.scene.uvlb_uv_channel):
## 2.80
ob.data.uv_layers.new()
## 2.80
ob.data.uv_layers.active_index = (bpy.context.scene.uvlb_uv_channel - 1)
Objs.append(ob)
#---Lists buildUP---
#---Create and prepare objects for export---
for ob in Objs:
for mod in ob.modifiers:
if scn.appMod:
if scn.cloneOb:
newObj = ob.copy()
newObj.data = ob.data.copy()
newObj.name = ob.name + "_Backup"
newObj.animation_data_clear()
#scn.objects.link(newObj)
## 2.80
scn.collection.objects.link(newObj)
if mod.type == 'SUBSURF':
print ("Obj Name: %s - Mod Applied: %s" % (ob.name, mod.type))
# print(bpy.app.version[1])
if bpy.app.version[0] >= 3 or (bpy.app.version[0] >= 2 and bpy.app.version[1] >= 90):
bpy.ops.object.modifier_apply(modifier="Subsurf")
else:
bpy.ops.object.modifier_apply(apply_as='DATA', modifier="Subdivision")
newObj = ob.copy()
newObj.data = ob.data.copy()
newObj.animation_data_clear()
newObj.name = ob.name + "__UVL"
#bpy.context.scene.objects.link(newObj)
## 2.80
bpy.context.scene.collection.objects.link(newObj)
expObjs.append(newObj)
expMeshes.append(newObj.data)
#---Texture channels cleanup exept uvlb_uv_channel
for ob in expMeshes:
active_index = (bpy.context.scene.uvlb_uv_channel - 1)
## 2.80
texName=ob.uv_layers[active_index].name
## 2.80
uv_layers = ob.uv_layers
ObjTexs=[]
for t in uv_layers:
ObjTexs.append(t.name)
for u in ObjTexs:
if u != texName:
uv_layers.remove(uv_layers[u])
#---Select objects for EXPORT
bpy.ops.object.select_all(action='DESELECT')
for ob in expObjs:
## 2.80
bpy.data.objects[ob.name].select_set(state=True)
# print(bpy.app.version)
#---EXPORT---
print("Export File:%s" % (file_Name))
if bpy.app.version[0] < 3:
bpy.ops.export_scene.obj(filepath=file_Name,
check_existing = True,
axis_forward = 'Y',
axis_up = 'Z',
filter_glob = "*.obj;*.mtl",
use_selection = scn.selOnly,
use_animation = False,
use_mesh_modifiers = scn.appMod,
# use_mesh_modifiers_render = False,
use_edges = False,
use_smooth_groups = False,
use_smooth_groups_bitflags = False,
use_normals = True,
use_uvs = True,
use_materials = True,
use_triangles = False,
use_nurbs = False,
use_vertex_groups = False,
use_blen_objects = False,
group_by_object = True,
group_by_material = False,
keep_vertex_order = True,
global_scale = 1,
path_mode = 'AUTO')
# bl 4.0
# https://docs.blender.org/api/current/bpy.ops.wm.html#bpy.ops.wm.obj_export
if bpy.app.version[0] == 4 and bpy.app.version[1] >= 0:
bpy.ops.wm.obj_export(filepath=file_Name,
check_existing = True,
forward_axis = 'Y',
up_axis = 'Z',
filter_glob = "*.obj;*.mtl",
export_animation = False,
apply_modifiers = scn.appMod,
export_selected_objects = scn.selOnly,
export_uv = True,
export_normals = True,
export_colors = True,
export_materials = True,
export_triangulated_mesh = False,
export_curves_as_nurbs = False,
export_object_groups = True,
export_material_groups = False,
export_vertex_groups = False,
export_smooth_groups = False,
smooth_group_bitflags = False,
global_scale = 1,
path_mode = 'AUTO')
#--Reset Sel only
if scn.viewOnly:
scn.selOnly = False
#---OBJs Clean up and deselect before import
for ob in expMeshes:
#bpy.data.meshes.remove(ob,True)
## 2.80
bpy.data.meshes.remove(ob, do_unlink=True)
bpy.ops.object.select_all(action='DESELECT')
#
#-Set uvLayout mode
if (bpy.context.scene.uvlb_mode == '0'):
uvlb_mode = 'Poly,'
if (bpy.context.scene.uvlb_mode == '1'):
uvlb_mode = 'SUBD,'
#-Set UVs mode
if (bpy.context.scene.uvlb_uv_mode == '0'):
uvlb_uv_mode = 'New,'
if (bpy.context.scene.uvlb_uv_mode == '1'):
uvlb_uv_mode = 'Edit,'
#-Set Weld UVs
if scn.uvlb_uv_weld:
uvlb_uv_weld = 'Weld,'
if not scn.uvlb_uv_weld:
uvlb_uv_weld = ''
#-Set Clean
if scn.uvlb_uv_clean:
uvlb_uv_clean = 'Clean,'
if not scn.uvlb_uv_clean:
uvlb_uv_clean = ''
#-Set Detach UVs
if scn.uvlb_uv_detach:
uvlb_uv_deach = 'Detach flipped,'
if not scn.uvlb_uv_detach:
uvlb_uv_deach = ''
#-Set Weld GEOM Vertexes
if scn.uvlb_uv_geom:
uvlb_uv_geom = 'Geom vertexes'
if not scn.uvlb_uv_geom:
uvlb_uv_geom = ''
#-- OS CHECK--
if platform == "darwin":
versionUVL = getattr(addon_prefs, "versionUVL")
dropSet = 0
if os.path.isfile(file_setName) == False:
if dropSet == 0:
# loadAction = 'run UVLayout|Pack|Pack All' + '\n' +'run UVLayout|Plugin|Save'
# loadAction = "drop \ n auto obj \n auto dxf "
loadAction = uvlb_mode + uvlb_uv_mode + uvlb_uv_weld + uvlb_uv_clean + uvlb_uv_deach + uvlb_uv_geom
f = open(file_setName, "w+")
# print("Commands Sent: %s - %s" % (uvlb_mode, uvlb_uv_mode))
f.write(''.join([loadAction]))
f.close()
dropSet = 1
# time.sleep(2)
uvlayoutpath = []
appOpen = '/Applications/headus-UVLayout-'+versionUVL+'.app/Contents/MacOS/uvlayout-maya'
uvlayoutpath.append(appOpen)
uvlayoutpath.append(file_Name)
# print("UVLayoutPath %s" % uvlayoutpath)
# print("Modes:" + uvlb_mode + uvlb_uv_mode + uvlb_uv_weld + uvlb_uv_clean + uvlb_uv_deach + uvlb_uv_geom)
uvlayout_proc = subprocess.Popen(uvlayoutpath)
elif platform == "win32":
# print("UVLayoutPath %s" % UVLayoutPath)
# print("Modes:" + uvlb_mode + uvlb_uv_mode + uvlb_uv_weld + uvlb_uv_clean + uvlb_uv_deach + uvlb_uv_geom)
# uvlayout_proc = subprocess.Popen(args=[UVLayoutPath + 'uvlayout.exe', ' -debug -plugin,' + uvlb_mode + uvlb_uv_mode + uvlb_uv_weld + uvlb_uv_clean + uvlb_uv_deach + uvlb_uv_geom, file_Name])
# https://stackoverflow.com/questions/60290732/subprocess-with-a-variable-that-contains-a-whitespace-path
# cmd = f'"{tar_exe}" -tf "{image_file}"'
# cmd = f'{UVLayoutPath}uvlayout.exe -log -plugin, {uvlb_mode}{uvlb_uv_mode}{uvlb_uv_weld}{uvlb_uv_clean}{uvlb_uv_deach}{uvlb_uv_geom}{file_Name}'
# print(cmd)
# versionUVL = getattr(addon_prefs, "versionUVL")
# uvlayout_proc = subprocess.Popen(args=[cmd], shell=True)
# uvlayoutpath = 'C:/program files \9x86\)/headus UVlayout v2'+versionUVL+'/uvlayout.exe'
# uvlayout_proc = subprocess.Popen(args=[UVLayoutPath, '-plugin,' + uvlb_mode + uvlb_uv_mode + uvlb_uv_weld + uvlb_uv_clean + uvlb_uv_deach + uvlb_uv_geom, file_Name])
uvlayout_proc = subprocess.Popen(args=[UVLayoutPath + 'uvlayout.exe', '-plugin,' + uvlb_mode + uvlb_uv_mode + uvlb_uv_weld + uvlb_uv_clean + uvlb_uv_deach + uvlb_uv_geom, file_Name])
dropCom = 0
result = False
#---IMPORT---
while not os.path.isfile(file_outName) and uvlayout_proc.poll() != 0:
#-- SEND AUTOMATION COMMANDS ---
if (os.path.isfile(file_cmdName) == False) and scn.uvlb_autoComm:
if dropCom == 0:
time.sleep(0)
print("Commands Send")
comm = ''
# Not used fo now
if scn.uvlb_autoCOMS == '1':