-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathoscurart_mesh_cache_tools.py
477 lines (384 loc) · 16.6 KB
/
oscurart_mesh_cache_tools.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
bl_info = {
"name": "Mesh Cache Tools",
"author": "Oscurart",
"version": (1, 0, 1),
"blender": (2, 70, 0),
"location": "Tools > Mesh Cache Tools",
"description": "Tools for Management Mesh Cache Process",
"warning": "",
"wiki_url": "",
"tracker_url": "https://developer.blender.org/maniphest/task/edit/form/2/",
"category": "Import-Export"}
import bpy
import os
import struct
from bpy_extras.io_utils import ImportHelper
from bpy.types import (
Operator,
Panel,
PropertyGroup,
AddonPreferences,
)
from bpy.props import (
BoolProperty,
IntProperty,
StringProperty,
PointerProperty,
CollectionProperty,
)
from bpy.app.handlers import persistent
class OscurartMeshCacheModifiersSettings(PropertyGroup):
array = BoolProperty(default=True)
bevel = BoolProperty(default=True)
boolean = BoolProperty(default=True)
build = BoolProperty(default=True)
decimate = BoolProperty(default=True)
edge_split = BoolProperty(default=True)
mask = BoolProperty(default=True)
mirror = BoolProperty(default=True)
multires = BoolProperty(default=True)
remesh = BoolProperty(default=True)
screw = BoolProperty(default=True)
skin = BoolProperty(default=True)
solidify = BoolProperty(default=True)
subsurf = BoolProperty(default=True)
triangulate = BoolProperty(default=True)
wireframe = BoolProperty(default=True)
cloth = BoolProperty(default=True)
# ----------------- AUTO LOAD PROXY
# bpy.context.scene.pc_auto_load_proxy.remove(0)
class CreaPropiedades(Operator):
bl_idname = "scene.pc_auto_load_proxy_create"
bl_label = "Create Auto Load PC Proxy List"
def execute(self, context):
for gr in bpy.data.groups:
if gr.library is not None:
i = bpy.context.scene.pc_auto_load_proxy.add()
i.name = gr.name
i.use_auto_load = False
return {'FINISHED'}
class RemuevePropiedades(Operator):
bl_idname = "scene.pc_auto_load_proxy_remove"
bl_label = "Remove Auto Load PC Proxy List"
def execute(self, context):
for i in bpy.context.scene.pc_auto_load_proxy:
bpy.context.scene.pc_auto_load_proxy.remove(0)
return {'FINISHED'}
class OscurartMeshCacheSceneAutoLoad(PropertyGroup):
name = StringProperty(
name="GroupName",
default=""
)
use_auto_load = BoolProperty(
name="Bool",
default=False
)
@persistent
def CargaAutoLoadPC(dummy):
for gr in bpy.context.scene.pc_auto_load_proxy:
if gr.use_auto_load:
for ob in bpy.data.groups[gr.name].objects:
for MOD in ob.modifiers:
if MOD.type == "MESH_CACHE":
MOD.cache_format = "PC2"
MOD.forward_axis = "POS_Y"
MOD.up_axis = "POS_Z"
MOD.flip_axis = set(())
MOD.frame_start = bpy.context.scene.pc_pc2_start
abspath = os.path.abspath(bpy.path.abspath("//" + bpy.context.scene.pc_pc2_folder))
MOD.filepath = "%s/%s.pc2" % (abspath, ob.name)
bpy.app.handlers.load_post.append(CargaAutoLoadPC)
# - PANELS -
class View3DMCPanel():
bl_space_type = 'VIEW_3D'
bl_region_type = 'TOOLS'
class OscEPc2ExporterPanel(View3DMCPanel, Panel):
bl_category = "Tools"
bl_label = "Mesh Cache Tools"
bl_options = {'DEFAULT_CLOSED'}
def draw(self, context):
layout = self.layout
scene = context.scene
row = layout.column(align=1)
row.prop(scene, "pc_pc2_folder", text="Folder")
row.operator("buttons.set_meshcache_folder", icon='FILESEL', text="Select Folder Path")
row = layout.box().column(align=1)
row.label("EXPORTER:")
row.operator("group.linked_group_to_local", text="Linked To Local", icon="LINKED")
row.operator("object.remove_subsurf_modifier", text="Remove Gen Modifiers", icon="MOD_SUBSURF")
row.prop(scene.mesh_cache_tools_settings, "array", text="Array")
row.prop(scene.mesh_cache_tools_settings, "bevel", text="Bevel")
row.prop(scene.mesh_cache_tools_settings, "boolean", text="Boolean")
row.prop(scene.mesh_cache_tools_settings, "build", text="Build")
row.prop(scene.mesh_cache_tools_settings, "decimate", text="Decimate")
row.prop(scene.mesh_cache_tools_settings, "edge_split", text="Edge Split")
row.prop(scene.mesh_cache_tools_settings, "mask", text="Mask")
row.prop(scene.mesh_cache_tools_settings, "mirror", text="Mirror")
row.prop(scene.mesh_cache_tools_settings, "multires", text="Multires")
row.prop(scene.mesh_cache_tools_settings, "remesh", text="Remesh")
row.prop(scene.mesh_cache_tools_settings, "screw", text="Screw")
row.prop(scene.mesh_cache_tools_settings, "skin", text="Skin")
row.prop(scene.mesh_cache_tools_settings, "solidify", text="Solidify")
row.prop(scene.mesh_cache_tools_settings, "subsurf", text="Subsurf")
row.prop(scene.mesh_cache_tools_settings, "triangulate", text="Triangulate")
row.prop(scene.mesh_cache_tools_settings, "wireframe", text="Wireframe")
# row = layout.column(align=1)
row.prop(scene, "pc_pc2_start", text="Frame Start")
row.prop(scene, "pc_pc2_end", text="Frame End")
row.prop(scene, "pc_pc2_exclude", text="Exclude Token:")
row.prop_search(scene, "pc_pc2_group", bpy.data, "groups", text="")
row.operator("export_shape.pc2_selection", text="Export!", icon="POSE_DATA")
row.prop(scene, "pc_pc2_world_space", text="World Space")
row = layout.box().column(align=1)
row.label("IMPORTER:")
row.operator("import_shape.pc2_selection", text="Import", icon="POSE_DATA")
row.operator("object.modifier_mesh_cache_up", text="MC Top", icon="TRIA_UP")
row = layout.box().column(align=1)
row.label("PROXY AUTO LOAD:")
row.operator("scene.pc_auto_load_proxy_create", text="Create List", icon="GROUP")
row.operator("scene.pc_auto_load_proxy_remove", text="Remove List", icon="X")
for i in scene.pc_auto_load_proxy:
if bpy.data.groups[i.name].library is not None:
row = layout.row()
row.prop(bpy.data.groups[i.name], "name", text="")
row.prop(i, "use_auto_load", text="")
def OscSetFolder(self, context, filepath):
fp = filepath if os.path.isdir(filepath) else os.path.dirname(filepath)
try:
os.chdir(os.path.dirname(bpy.data.filepath))
except Exception as e:
self.report({'WARNING'}, "Folder could not be set: {}".format(e))
return {'CANCELLED'}
rfp = os.path.relpath(fp)
for sc in bpy.data.scenes:
sc.pc_pc2_folder = rfp
return {'FINISHED'}
class OscMeshCacheButtonSet(Operator, ImportHelper):
bl_idname = "buttons.set_meshcache_folder"
bl_label = "Set Mesh Cache Folder"
filename_ext = ".txt"
def execute(self, context):
return OscSetFolder(self, context, self.filepath)
def OscFuncExportPc2(self):
start = bpy.context.scene.pc_pc2_start
end = bpy.context.scene.pc_pc2_end
folderpath = bpy.context.scene.pc_pc2_folder
framerange = end - start
for ob in bpy.data.groups[bpy.context.scene.pc_pc2_group].objects[:]:
if any(token not in ob.name for token in bpy.context.scene.pc_pc2_exclude.split(",")):
bpy.context.window_manager.progress_begin(0, 100) # progressbar
if ob.type == "MESH":
with open("%s/%s.pc2" % (os.path.normpath(folderpath), ob.name), mode="wb") as file:
# header
headerFormat = '<12siiffi'
headerStr = struct.pack(headerFormat,
b'POINTCACHE2\0', 1, len(ob.data.vertices[:]), 0, 1.0, (end + 1) - start)
file.write(headerStr)
# bake
obmat = ob.matrix_world
for i, frame in enumerate(range(start, end + 1)):
print("Percentage of %s bake: %s " % (ob.name, i * 100 / framerange))
bpy.context.window_manager.progress_update(i * 100 / framerange) # progressbarUpdate
bpy.context.scene.frame_set(frame)
me = bpy.data.meshes.new_from_object(
scene=bpy.context.scene,
object=ob,
apply_modifiers=True,
settings="RENDER",
calc_tessface=True,
calc_undeformed=False
)
# rotate
if bpy.context.scene.pc_pc2_world_space:
me.transform(obmat)
me.calc_normals()
# create archive
for vert in me.vertices[:]:
file.write(struct.pack("<3f", *vert.co))
# drain mesh
bpy.data.meshes.remove(me)
print("%s Bake finished!" % (ob.name))
bpy.context.window_manager.progress_end() # progressBarClose
print("Bake Totally Finished!")
class OscPc2ExporterBatch(Operator):
bl_idname = "export_shape.pc2_selection"
bl_label = "Export pc2 for selected Objects"
bl_description = "Export pc2 for selected Objects"
bl_options = {'REGISTER', 'UNDO'}
@classmethod
def poll(cls, context):
return(bpy.context.scene.pc_pc2_group != "" and bpy.context.scene.pc_pc2_folder != 'Set me Please!')
def execute(self, context):
OscFuncExportPc2(self)
return {'FINISHED'}
class OscRemoveSubsurf(Operator):
bl_idname = "object.remove_subsurf_modifier"
bl_label = "Remove Subdivision Surface Modifier"
bl_description = "Remove Subdivision Surface Modifier"
bl_options = {'REGISTER', 'UNDO'}
@classmethod
def poll(cls, context):
return(bpy.context.scene.pc_pc2_group != "")
def execute(self, context):
GENERATE = [
'MULTIRES', 'ARRAY', 'BEVEL', 'BOOLEAN', 'BUILD',
'DECIMATE', 'MASK', 'MIRROR', 'REMESH', 'SCREW',
'SKIN', 'SOLIDIFY', 'SUBSURF', 'TRIANGULATE'
]
for OBJ in bpy.data.groups[bpy.context.scene.pc_pc2_group].objects[:]:
for MOD in OBJ.modifiers[:]:
if MOD.type in GENERATE:
if eval("bpy.context.scene.mesh_cache_tools_settings.%s" % (MOD.type.lower())):
OBJ.modifiers.remove(MOD)
return {'FINISHED'}
class OscPc2iMporterBatch(Operator):
bl_idname = "import_shape.pc2_selection"
bl_label = "Import pc2 for selected Objects"
bl_description = "Import pc2 for selected Objects"
bl_options = {'REGISTER', 'UNDO'}
@classmethod
def poll(cls, context):
return(bpy.context.scene.pc_pc2_folder != 'Set me Please!')
def execute(self, context):
for OBJ in bpy.context.selected_objects[:]:
MOD = OBJ.modifiers.new("MeshCache", 'MESH_CACHE')
MOD.filepath = "//%s%s%s.pc2" % (bpy.context.scene.pc_pc2_folder, os.sep, OBJ.name)
MOD.cache_format = "PC2"
MOD.forward_axis = "POS_Y"
MOD.up_axis = "POS_Z"
MOD.flip_axis = set(())
MOD.frame_start = bpy.context.scene.pc_pc2_start
return {'FINISHED'}
def OscLinkedGroupToLocal():
try:
ACTOBJ = bpy.context.active_object
if not ACTOBJ.id_data.dupli_group:
return False
GROBJS = [ob for ob in ACTOBJ.id_data.dupli_group.objects[:] if ob.type == "MESH"]
for ob in ACTOBJ.id_data.dupli_group.objects[:]:
bpy.context.scene.objects.link(ob)
NEWGROUP = bpy.data.groups.new("%s_CLEAN" % (ACTOBJ.name))
bpy.context.scene.objects.unlink(ACTOBJ)
NEWOBJ = []
for ob in GROBJS:
NEWGROUP.objects.link(ob)
NEWOBJ.append(ob)
except:
return False
return True
class OscGroupLinkedToLocal(Operator):
bl_idname = "group.linked_group_to_local"
bl_label = "Group Linked To Local"
bl_description = "Group Linked To Local"
bl_options = {'REGISTER', 'UNDO'}
def execute(self, context):
group_check = OscLinkedGroupToLocal()
if not group_check:
self.report({'WARNING'},
"There is no objects to link or the object already linked. Operation Cancelled")
return {'CANCELLED'}
return {'FINISHED'}
class OscMeshCacheUp(Operator):
bl_idname = "object.modifier_mesh_cache_up"
bl_label = "Mesh Cache To Top"
bl_description = "Send Mesh Cache Modifiers top"
bl_options = {'REGISTER', 'UNDO'}
@classmethod
def poll(cls, context):
obj = context.object
return (obj and obj.type == "MESH")
def execute(self, context):
actob = bpy.context.scene.objects.active
for ob in bpy.context.selected_objects[:]:
bpy.context.scene.objects.active = ob
for mod in ob.modifiers[:]:
if mod.type == "MESH_CACHE":
for up in range(ob.modifiers.keys().index(mod.name)):
bpy.ops.object.modifier_move_up(modifier=mod.name)
bpy.context.scene.objects.active = actob
return {'FINISHED'}
# Add-ons Preferences Update Panel
# Define Panel classes for updating
panels = (
OscEPc2ExporterPanel,
)
def update_panel(self, context):
message = "Mesh Cache Tools: Updating Panel locations has failed"
try:
for panel in panels:
if "bl_rna" in panel.__dict__:
bpy.utils.unregister_class(panel)
for panel in panels:
panel.bl_category = context.user_preferences.addons[__name__].preferences.category
bpy.utils.register_class(panel)
except Exception as e:
print("\n[{}]\n{}\n\nError:\n{}".format(__name__, message, e))
pass
class OscurartMeshCacheToolsAddonPreferences(AddonPreferences):
# this must match the addon name, use '__package__'
# when defining this in a submodule of a python package.
bl_idname = __name__
category = StringProperty(
name="Category",
description="Choose a name for the category of the panel",
default="Tools",
update=update_panel,
)
def draw(self, context):
layout = self.layout
row = layout.row()
col = row.column()
col.label(text="Category:")
col.prop(self, "category", text="")
classes = (
OscurartMeshCacheModifiersSettings,
OscGroupLinkedToLocal,
OscMeshCacheButtonSet,
OscMeshCacheUp,
OscPc2ExporterBatch,
OscPc2iMporterBatch,
OscRemoveSubsurf,
OscurartMeshCacheToolsAddonPreferences,
RemuevePropiedades,
OscurartMeshCacheSceneAutoLoad,
CreaPropiedades,
OscEPc2ExporterPanel,
)
# Register
def register():
for cls in classes:
bpy.utils.register_class(cls)
from bpy.types import Scene
Scene.mesh_cache_tools_settings = PointerProperty(
type=OscurartMeshCacheModifiersSettings
)
Scene.pc_auto_load_proxy = CollectionProperty(
type=OscurartMeshCacheSceneAutoLoad
)
Scene.pc_pc2_rotx = BoolProperty(default=True, name="Rotx = 90")
Scene.pc_pc2_world_space = BoolProperty(default=True, name="World Space")
Scene.pc_pc2_modifiers = BoolProperty(default=True, name="Apply Modifiers")
Scene.pc_pc2_subsurf = BoolProperty(default=True, name="Turn Off SubSurf")
Scene.pc_pc2_start = IntProperty(default=0, name="Frame Start")
Scene.pc_pc2_end = IntProperty(default=100, name="Frame End")
Scene.pc_pc2_group = StringProperty()
Scene.pc_pc2_folder = StringProperty(default="Set me Please!")
Scene.pc_pc2_exclude = StringProperty(default="*")
update_panel(None, bpy.context)
def unregister():
for cls in classes:
bpy.utils.unregister_class(cls)
from bpy.types import Scene
del Scene.mesh_cache_tools_settings
del Scene.pc_auto_load_proxy
del Scene.pc_pc2_rotx
del Scene.pc_pc2_world_space
del Scene.pc_pc2_modifiers
del Scene.pc_pc2_subsurf
del Scene.pc_pc2_start
del Scene.pc_pc2_end
del Scene.pc_pc2_group
del Scene.pc_pc2_folder
del Scene.pc_pc2_exclude
if __name__ == "__main__":
register()