161778238f23b70721310ed6c2d4669e95af6895
[blender-addons-contrib.git] / io_scene_fpx / fpx_import.py
1 # ##### BEGIN GPL LICENSE BLOCK #####
2 #
3 #  This program is free software; you can redistribute it and/or
4 #  modify it under the terms of the GNU General Public License
5 #  as published by the Free Software Foundation; either version 2
6 #  of the License, or (at your option) any later version.
7 #
8 #  This program is distributed in the hope that it will be useful,
9 #  but WITHOUT ANY WARRANTY; without even the implied warranty of
10 #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 #  GNU General Public License for more details.
12 #
13 #  You should have received a copy of the GNU General Public License
14 #  along with this program; if not, write to the Free Software Foundation,
15 #  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 #
17 # ##### END GPL LICENSE BLOCK #####
18
19 # <pep8 compliant>
20
21 ###############################################################################
22 #234567890123456789012345678901234567890123456789012345678901234567890123456789
23 #--------1---------2---------3---------4---------5---------6---------7---------
24
25
26 # ##### BEGIN COPYRIGHT BLOCK #####
27 #
28 # initial script copyright (c)2013 Alexander Nussbaumer
29 #
30 # ##### END COPYRIGHT BLOCK #####
31
32
33 #import python stuff
34 import io
35 from mathutils import (
36         Euler,
37         Vector,
38         Matrix,
39         )
40 from math import (
41         radians,
42         )
43 from os import (
44         path,
45         listdir,
46         rmdir,
47         remove,
48         )
49 from sys import (
50         exc_info,
51         )
52 from time import (
53         time,
54         )
55
56
57 # import io_scene_fpx stuff
58 if repr(globals()).find("bpy") != -1:
59     from io_scene_fpx.fpx_strings import (
60             fpx_str,
61             )
62     from io_scene_fpx.fpx_spec import (
63             Fpm_File_Reader,
64             Fpl_File_Reader,
65             Fpt_File_Reader,
66             Fpm_Model_Type,
67             Fpl_Library_Type,
68             FptElementType,
69             Fpt_PackedLibrary_Type,
70             )
71     from io_scene_fpx.fpx_ui import (
72             FpxUI,
73             )
74     from io_scene_fpx.fpx_utils import (
75             FpxUtilities,
76             )
77 else:
78     from fpx_strings import (
79             fpx_str,
80             )
81     from fpx_spec import (
82             Fpm_File_Reader,
83             Fpl_File_Reader,
84             Fpt_File_Reader,
85             Fpm_Model_Type,
86             Fpl_Library_Type,
87             FptElementType,
88             Fpt_PackedLibrary_Type,
89             )
90     from fpx_ui import (
91             FpxUI,
92             )
93     from fpx_utils import (
94             FpxUtilities,
95             )
96
97
98 #import blender stuff
99 from bpy import (
100         ops,
101         app,
102         #data,
103         )
104 import bmesh
105 from bpy_extras.image_utils import (
106         load_image,
107         )
108
109
110 ###############################################################################
111 FORMAT_SCENE = "{}.s"
112 FORMAT_GROUP = "{}.g"
113 FORMAT_IMAGE = "{}.i"
114 FORMAT_TEXTURE = "{}.tex"
115 # keep material name like it is (prevent name "snakes" on re-import)
116 #FORMAT_MATERIAL = "{}.mat"
117 FORMAT_MATERIAL = "{}"
118 FORMAT_ACTION = "{}.act"
119 FORMAT_MESH = "{}.m"
120 FORMAT_MESH_OBJECT = "{}.mo"
121 FORMAT_EMPTY_OBJECT = "{}.eo"
122 FORMAT_DUPLI_OBJECT = "{}.do"
123 FORMAT_CURVE = "{}.c"
124 FORMAT_CURVE_OBJECT = "{}.co"
125 FORMAT_ARMATURE = "{}.a"
126 FORMAT_ARMATURE_OBJECT = "{}.ao"
127 FORMAT_ARMATURE_NLA = "{}.an"
128
129 #FORMAT_RESOURCE = "{}\\{}"
130 FORMAT_RESOURCE = "{{{}}}.{}"
131
132 PREFIX_LOCAL = "1"
133 PREFIX_EMBEDDED = "0"
134
135 FORMAT_MODEL_SECONDARY = "{}.low"
136 FORMAT_MODEL_MASK = "{}.mask"
137 FORMAT_MODEL_MIRROR = "{}.mirror"
138 FORMAT_MODEL_START = "{}.start"
139 FORMAT_MODEL_END = "{}.end"
140 FORMAT_MODEL_CAP1 = "{}.cap1"
141 FORMAT_MODEL_CAP2 = "{}.cap2"
142 FORMAT_MODEL_RING = "{}.ring{:02d}"
143
144 TRANSLITE_OBJECT = 2
145 ###############################################################################
146 class FpmImporter():
147     """ Load a Future Pinball Model FPM File """
148     LAYERS_PRIMARY_MODEL = (
149             True, False, False, False, False,
150             False, False, False, False, False,
151             False, False, False, False, False,
152             False, False, False, False, False
153             )
154     LAYERS_SECONDARY_MODEL = (
155             False, True, False, False, False,
156             False, False, False, False, False,
157             False, False, False, False, False,
158             False, False, False, False, False
159             )
160     LAYERS_MASK_MODEL = (
161             False, False, True, False, False,
162             False, False, False, False, False,
163             False, False, False, False, False,
164             False, False, False, False, False
165             )
166     LAYERS_REFLECTION_MODEL = (
167             False, False, False, True, False,
168             False, False, False, False, False,
169             False, False, False, False, False,
170             False, False, False, False, False
171             )
172     LAYERS_COLLISION_MODEL = (
173             False, False, False, False, True,
174             False, False, False, False, False,
175             False, False, False, False, False,
176             False, False, False, False, False
177             )
178
179     def __init__(self,
180             report,
181             verbose=FpxUI.PROP_DEFAULT_VERBOSE,
182             keep_temp=FpxUI.PROP_DEFAULT_KEEP_TEMP,
183             use_all_models_of_folder=FpxUI.PROP_DEFAULT_ALL_MODELS,
184             use_scene_per_model=FpxUI.PROP_DEFAULT_SCENE,
185             name_extra=FpxUI.PROP_DEFAULT_NAME_EXTRA,
186             use_model_filter=FpxUI.PROP_DEFAULT_USE_MODEL_FILTER,
187             use_model_adjustment=FpxUI.PROP_DEFAULT_MODEL_ADJUST_FPM,
188             keep_name=False,
189             ):
190         self.report = report
191         self.verbose = verbose
192         self.keep_temp = keep_temp
193         self.use_all_models_of_folder = use_all_models_of_folder
194         self.use_scene_per_model = use_scene_per_model
195         self.name_extra = name_extra
196         self.use_model_filter = use_model_filter
197         self.use_model_adjustment = use_model_adjustment
198         self.keep_name = keep_name
199
200     def read(self, blender_context, filepath):
201         """ read fpm file and convert fpm content to bender content """
202         t1 = time()
203         t2 = None
204
205         fpx_reader = None
206
207         self.__context = blender_context
208         self.__blend_data = blender_context.blend_data
209
210         self.__table_width = 0.0
211         self.__table_length = 0.0
212         self.__translite_width = 0.0
213         self.__translite_length = 0.0
214
215         try:
216             self.folder_name, file_name = path.split(filepath)
217
218             debug_data = []
219
220             files = None
221             if self.use_all_models_of_folder:
222                 files = [path.join(self.folder_name, f) for f in listdir(self.folder_name) if f.endswith(".fpm")]
223             else:
224                 files = [filepath, ]
225
226             for file in files:
227                 self.folder_name, file_name = path.split(filepath)
228                 try:
229                     with io.FileIO(file, 'rb') as raw_io:
230                         # read and inject fpm data from disk to internal structure
231                         fpx_reader = Fpm_File_Reader(raw_io)
232                         fpx_reader.read_model()
233                         raw_io.close()
234                 finally:
235                     pass
236
237                 # if option is set, this time will enlarges the io time
238                 #if self.verbose and reader:
239                 #    fpx_reader.print_internal()
240                 t2 = time()
241
242                 if fpx_reader:
243                     temp_name = path.join(app.tempdir, "__grab__fpm__")
244                     dst_path, dst_sub_path_names = fpx_reader.grab_content(temp_name)
245
246                     model_name = fpx_reader.PinModel.get_value("name")
247                     model_name = FpxUtilities.toGoodName(model_name) ####
248                     #model_name = path.split(file)[1]
249                     #model_name = model_name.lower()
250                     #if model_name.endswith(".fpm"):
251                     #    model_name = model_name[:-4]
252
253                     if self.name_extra:
254                         model_name = FORMAT_RESOURCE.format(self.name_extra, model_name)
255
256
257                     model_filepath = dst_sub_path_names.get("modeldata")
258                     debug_data.append("type={}, model_filepath='{}'".format(dst_sub_path_names.get("type"), model_filepath))
259                     if model_filepath:
260                         self.read_ex(blender_context, dst_sub_path_names, model_name, debug_data)
261
262                     # cleanup
263                     if not self.keep_temp:
264                         try:
265                             rmdir(dst_path)
266                         except:
267                             pass
268
269             if self.verbose in FpxUI.VERBOSE_NORMAL:
270                 print()
271                 print("##########################################################")
272                 print("Import from FPM to Blender")
273                 for item in debug_data:
274                     print("#DEBUG", item)
275                 print("##########################################################")
276
277         except Exception as ex:
278             type, value, traceback = exc_info()
279             if self.verbose in FpxUI.VERBOSE_NORMAL:
280                 print("read fpm - exception in try block\n  type: '{0}'\n"
281                         "  value: '{1}'".format(type, value, traceback))
282
283             if t2 is None:
284                 t2 = time()
285
286             raise
287
288         else:
289             pass
290
291         finally:
292             self.__context = None
293             self.__blend_data = None
294
295         t3 = time()
296         if self.verbose in FpxUI.VERBOSE_NORMAL:
297             print(fpx_str['SUMMARY_IMPORT'].format(
298                     (t3 - t1), (t2 - t1), (t3 - t2)))
299
300         return {"FINISHED"}
301
302     ###########################################################################
303     def read_ex(self, blender_context, dst_sub_path_names, model_name, debug_data):
304         model_filepath = dst_sub_path_names.get("primary_model_data")
305         if model_filepath:
306             if self.use_scene_per_model:
307                 blender_scene = blender_context.blend_data.scenes.new(FORMAT_SCENE.format(model_name))
308                 blender_context.screen.scene = blender_scene
309             else:
310                 blender_scene = blender_context.scene
311                 # setup current Scene to default units
312                 FpxUtilities.set_scene_to_default(blender_scene)
313
314             blender_scene.layers = self.LAYERS_PRIMARY_MODEL
315             #{'FINISHED'}
316             #{'CANCELLED'}
317             if 'FINISHED' in ops.import_scene.ms3d(filepath=model_filepath, use_animation=True):
318                 name = blender_context.active_object.name
319                 src_ext = "ms3d"
320                 index = name.rfind(".{}.".format(src_ext))
321                 if index < 0:
322                     index = name.rfind(".")
323                     #if index < 0:
324                     #    return
325
326                 src_name = "{}.{}".format(name[:index], src_ext)
327
328                 remove_material(blender_context)
329                 if not self.keep_name:
330                     rename_active_ms3d(blender_context, src_name, model_name)
331
332                 if self.use_model_adjustment:
333                     adjust_position(blender_context, blender_scene, dst_sub_path_names)
334
335                 if FpxUI.USE_MODEL_FILTER_SECONDARY in self.use_model_filter:
336                     model_filepath = dst_sub_path_names.get("secondary_model_data")
337                     if model_filepath:
338                         blender_scene.layers = self.LAYERS_SECONDARY_MODEL
339                         if 'FINISHED' in ops.import_scene.ms3d(filepath=model_filepath, use_animation=False):
340                             remove_material(blender_context)
341                             if not self.keep_name:
342                                 rename_active_ms3d(blender_context, src_name, model_name, "secondary")
343
344                 if FpxUI.USE_MODEL_FILTER_MASK in self.use_model_filter:
345                     model_filepath = dst_sub_path_names.get("mask_model_data")
346                     if model_filepath:
347                         blender_scene.layers = self.LAYERS_MASK_MODEL
348                         if 'FINISHED' in ops.import_scene.ms3d(filepath=model_filepath, use_animation=False):
349                             remove_material(blender_context)
350                             if not self.keep_name:
351                                 rename_active_ms3d(blender_context, src_name, model_name, "mask")
352
353                 if FpxUI.USE_MODEL_FILTER_REFLECTION in self.use_model_filter:
354                     model_filepath = dst_sub_path_names.get("reflection_model_data")
355                     if model_filepath:
356                         blender_scene.layers = self.LAYERS_REFLECTION_MODEL
357                         if 'FINISHED' in ops.import_scene.ms3d(filepath=model_filepath, use_animation=False):
358                             remove_material(blender_context)
359                             if not self.keep_name:
360                                 rename_active_ms3d(blender_context, src_name, model_name, "reflection")
361
362                 if FpxUI.USE_MODEL_FILTER_COLLISION in self.use_model_filter:
363                     ## TODO
364                     pass
365
366                 blender_scene.layers = self.LAYERS_PRIMARY_MODEL
367
368         # setup all current 3d Views of the current scene to metric units
369         FpxUtilities.set_scene_to_metric(blender_context)
370
371         # cleanup
372         if not self.keep_temp:
373             for key, file in dst_sub_path_names.items():
374                 if key in {'type', 'sub_dir', }:
375                     continue
376                 try:
377                     remove(file)
378                 except:
379                     pass
380
381             sub_dir_path = dst_sub_path_names.get('sub_dir')
382             if sub_dir_path:
383                 try:
384                     rmdir(sub_dir_path)
385                 except:
386                     pass
387
388
389
390 ###############################################################################
391 class FplImporter():
392     """ Load a Future Pinball Library FPL File """
393     def __init__(self,
394             report,
395             verbose=FpxUI.PROP_DEFAULT_VERBOSE,
396             keep_temp=FpxUI.PROP_DEFAULT_KEEP_TEMP,
397             use_all_libraries_of_folder=FpxUI.PROP_DEFAULT_ALL_LIBRARIES,
398             use_library_filter=FpxUI.PROP_DEFAULT_USE_LIBRARY_FILTER,
399             use_model_filter=FpxUI.PROP_DEFAULT_USE_MODEL_FILTER,
400             use_model_adjustment=FpxUI.PROP_DEFAULT_MODEL_ADJUST_FPL,
401             keep_name=False,
402             ):
403         self.report = report
404         self.verbose = verbose
405         self.keep_temp = keep_temp
406         self.use_all_libraries_of_folder = use_all_libraries_of_folder
407         self.use_library_filter = use_library_filter
408         self.use_model_filter = use_model_filter
409         self.use_model_adjustment = use_model_adjustment
410         self.keep_name = keep_name
411
412     def read(self, blender_context, filepath):
413         """ read fpl file and convert fpm content to bender content """
414         t1 = time()
415         t2 = None
416
417         fpx_reader = None
418
419         self.__context = blender_context
420         self.__blend_data = blender_context.blend_data
421         active_scene = self.__context.screen.scene
422
423         try:
424             self.folder_name, file_name = path.split(filepath)
425
426             debug_data = []
427
428             if self.use_all_libraries_of_folder:
429                 files = [path.join(self.folder_name, f) for f in listdir(self.folder_name) if f.endswith(".fpl")]
430             else:
431                 files = [filepath, ]
432
433             for file in files:
434                 self.folder_name, file_name = path.split(file)
435                 try:
436                     with io.FileIO(file, 'rb') as raw_io:
437                         # read and inject fpl data from disk to internal structure
438                         fpx_reader = Fpl_File_Reader(raw_io)
439                         fpx_reader.read_library()
440                         raw_io.close()
441                 finally:
442                     pass
443
444                 # if option is set, this time will enlarges the io time
445                 #if self.verbose and reader:
446                 #    fpx_reader.print_internal()
447                 t2 = time()
448
449                 if fpx_reader:
450                     temp_name = path.join(app.tempdir, "__grab__fpl__")
451                     dst_path, dst_sub_path_names = fpx_reader.grab_content(temp_name)
452
453                     for key, item in dst_sub_path_names.items():
454                         if key is not None and key.startswith('type_'):
455                             type = item
456                             key_name = key[5:]
457                             #print("#DEBUG", key_name, type)
458
459                             if type not in self.use_library_filter:
460                                 continue
461
462                             item_path = dst_sub_path_names.get(key_name)
463
464                             if type == Fpl_Library_Type.TYPE_MODEL:
465                                 #print("#DEBUG", type, key_name)
466                                 FpmImporter(
467                                         report=self.report,
468                                         verbose=self.verbose,
469                                         keep_temp=self.keep_temp,
470                                         use_scene_per_model=True,
471                                         name_extra=file_name,
472                                         use_model_filter=self.use_model_filter,
473                                         use_model_adjustment=self.use_model_adjustment,
474                                     ).read(
475                                             blender_context=self.__context,
476                                             filepath=item_path,
477                                         )
478                                 if not self.keep_name:
479                                     rename_active_fpm(self.__context, FORMAT_RESOURCE.format(file_name, key_name))
480
481                             elif type == Fpl_Library_Type.TYPE_GRAPHIC:
482                                 #print("#DEBUG", type, key_name)
483                                 blend_image = self.__blend_data.images.load(item_path)
484                                 blend_image.name = FpxUtilities.toGoodName(FORMAT_RESOURCE.format(file_name, FORMAT_IMAGE.format(key_name)))
485                                 blend_image.pack()
486                                 blend_image.use_fake_user = True
487                                 item_dir, item_file = path.split(item_path)
488                                 blend_image.filepath_raw = "//unpacked_resource/{}".format(item_file)
489
490                         else:
491                             pass
492
493
494                     # cleanup
495                     if not self.keep_temp:
496                         cleanup_sub_dirs = []
497
498                         for key, file in dst_sub_path_names.items():
499                             if key is not None and key.startswith('sub_dir'):
500                                 cleanup_sub_dirs.append(file)
501                                 continue
502
503                             if key in {'type', None, } or key.startswith('type'):
504                                 continue
505
506                             try:
507                                 remove(file)
508                             except:
509                                 pass
510
511                         sub_dir_path = dst_sub_path_names.get('sub_dir')
512                         if sub_dir_path:
513                             try:
514                                 rmdir(sub_dir_path)
515                             except:
516                                 pass
517
518                         for sub_dir_path in cleanup_sub_dirs:
519                             try:
520                                 rmdir(sub_dir_path)
521                             except:
522                                 pass
523
524                         try:
525                             rmdir(dst_path)
526                         except:
527                             pass
528
529             if self.verbose in FpxUI.VERBOSE_NORMAL:
530                 print()
531                 print("##########################################################")
532                 print("Import from FPM to Blender")
533                 for item in debug_data:
534                     print("#DEBUG", item)
535                 print("##########################################################")
536
537         except Exception as ex:
538             type, value, traceback = exc_info()
539             if self.verbose in FpxUI.VERBOSE_NORMAL:
540                 print("read fpl - exception in try block\n  type: '{0}'\n"
541                         "  value: '{1}'".format(type, value, traceback))
542
543             if t2 is None:
544                 t2 = time()
545
546             raise
547
548         else:
549             pass
550
551         finally:
552             self.__context.screen.scene = active_scene
553             self.__context = None
554             self.__blend_data = None
555
556         t3 = time()
557         if self.verbose in FpxUI.VERBOSE_NORMAL:
558             print(fpx_str['SUMMARY_IMPORT'].format(
559                     (t3 - t1), (t2 - t1), (t3 - t2)))
560
561         return {"FINISHED"}
562
563     ###########################################################################
564
565
566 ###############################################################################
567 class FptImporter():
568     """ Load a Future Pinball Table FPT File """
569     LAYERS_WIRE_RING = (
570             True, True, False, False, True,
571             False, False, False, False, False,
572             False, False, True, False, False,
573             False, False, False, False, False
574             )
575     LAYERS_LIGHT_SPHERE = (
576             True, True, False, False, True,
577             False, False, False, False, False,
578             True, False, False, False, False,
579             False, False, False, False, False
580             )
581     BLENDER_OBJECT_NAME = 0
582
583     def __init__(self,
584             report,
585             verbose=FpxUI.PROP_DEFAULT_VERBOSE,
586             keep_temp=FpxUI.PROP_DEFAULT_KEEP_TEMP,
587             path_libraries=FpxUI.PROP_DEFAULT_LIBRARIES_PATH,
588             convert_to_mesh=FpxUI.PROP_DEFAULT_CONVERT_TO_MESH,
589             resolution_wire_bevel=FpxUI.PROP_DEFAULT_RESOLUTION_WIRE_BEVEL,
590             resolution_wire=FpxUI.PROP_DEFAULT_RESOLUTION_WIRE,
591             resolution_rubber_bevel=FpxUI.PROP_DEFAULT_RESOLUTION_RUBBER_BEVEL,
592             resolution_rubber=FpxUI.PROP_DEFAULT_RESOLUTION_RUBBER,
593             resolution_shape=FpxUI.PROP_DEFAULT_RESOLUTION_SHAPE,
594             use_hermite_handle=FpxUI.PROP_DEFAULT_USE_HERMITE_HANDLE,
595             use_library_filter=FpxUI.PROP_DEFAULT_USE_LIBRARY_FILTER,
596             use_model_filter=FpxUI.PROP_DEFAULT_USE_MODEL_FILTER,
597             use_model_adjustment=FpxUI.PROP_DEFAULT_MODEL_ADJUST_FPT,
598             keep_name=False,
599             ):
600         self.report = report
601         self.verbose = verbose
602         self.keep_temp = keep_temp
603         self.path_libraries = path_libraries
604         self.convert_to_mesh = convert_to_mesh
605         self.resolution_wire_bevel = resolution_wire_bevel
606         self.resolution_wire = resolution_wire
607         self.resolution_rubber_bevel = resolution_rubber_bevel
608         self.resolution_rubber = resolution_rubber
609         self.resolution_shape = resolution_shape
610         self.use_hermite_handle = use_hermite_handle
611         self.use_library_filter = use_library_filter
612         self.use_model_filter = use_model_filter
613         self.use_model_adjustment = use_model_adjustment
614         self.keep_name = keep_name
615
616         self.blend_resource_file = get_blend_resource_file_name()
617
618         self.debug_light_extrude = 0.2
619         self.debug_lightball_size = 2.0
620         self.debug_lightball_height = 4.5
621         self.debug_create_full_ramp_wires = False
622         self.debug_missing_resources = set()
623
624     ###########################################################################
625     # create empty blender fp_table
626     # read fpt file
627     # fill blender with fp_table content
628     def read(self, blender_context, filepath, ):
629         """ read fpt file and convert fpt content to bender content """
630         t1 = time()
631         t2 = None
632
633         fpx_reader = None
634
635         self.__context = blender_context
636         self.__blend_data = blender_context.blend_data
637
638         try:
639             try:
640                 with io.FileIO(filepath, 'rb') as raw_io:
641                     # read and inject fpt data from disk to internal structure
642                     fpx_reader = Fpt_File_Reader(raw_io)
643                     fpx_reader.read_table()
644                     raw_io.close()
645             finally:
646                 pass
647
648             # if option is set, this time will enlarges the io time
649             #if self.options.verbose and reader:
650             #    fpx_reader.print_internal()
651
652             t2 = time()
653             if fpx_reader:
654                 temp_name = path.join(app.tempdir, "__grab__fpt__")
655                 dst_path, dst_sub_path_names = fpx_reader.grab_content(temp_name)
656
657                 # setup current Scene to default units
658                 ##FpxUtilities.set_scene_to_default(self.__context.scene)
659
660                 self.folder_name, file_name = path.split(filepath)
661
662                 # search linked libraries
663                 self.fpx_images = {}
664                 self.GetLinked(fpx_reader.Image, self.fpx_images, Fpt_PackedLibrary_Type.TYPE_IMAGE, dst_sub_path_names)
665
666                 self.fpx_image_lists = {}
667                 for image_list in fpx_reader.ImageList.values():
668                     key = image_list.get_value("name")
669                     images = image_list.get_value("images")
670                     self.fpx_image_lists[key] = images
671
672                 self.fpx_pinmodels = {}
673                 self.GetLinked(fpx_reader.PinModel, self.fpx_pinmodels, Fpt_PackedLibrary_Type.TYPE_MODEL, dst_sub_path_names)
674
675                 for key, item in self.fpx_images.items():
676                     print("#DEBUG image:", key, item)
677
678                 for key, item in self.fpx_image_lists.items():
679                     print("#DEBUG image_list:", key, item)
680
681                 for key, item in self.fpx_pinmodels.items():
682                     print("#DEBUG pinmodel:", key, item)
683
684                 # build pincab
685                 self.CreatePinCab(fpx_reader.Table_Data)
686
687                 # handle table elements
688                 for key, fpx_item in fpx_reader.Table_Element.items():
689                     if fpx_item:
690                         object_appers_on = fpx_item.get_value("object_appers_on")
691                         if object_appers_on == TRANSLITE_OBJECT:
692                             continue
693                         #print("#DEBUG", object_appers_on, key, fpx_item)
694
695                         fpx_item_name = fpx_item.get_value("name")
696                         fpx_item_name = FpxUtilities.toGoodName(fpx_item_name) ####
697                         if not fpx_item_name:
698                             continue
699
700                         fpx_id = fpx_item.get_obj_value("id")
701
702                         ## get the height level (wall and/or surface) on what the item will be placed
703                         fpx_surface_name = fpx_item.get_value("surface")
704                         fpx_surface = None
705                         fpx_position_z = None
706                         fpx_position_zw = None
707                         if fpx_surface_name:
708                             fpx_wall = fpx_reader.Walls.get(FpxUtilities.toGoodName(fpx_surface_name))
709                             if fpx_wall:
710                                 fpx_position_zw = fpx_wall.get_value("height")
711                                 fpx_surface_name = fpx_wall.get_value("surface")
712                                 if fpx_surface_name:
713                                     fpx_surface = fpx_reader.Walls.get(FpxUtilities.toGoodName(fpx_surface_name))
714                             else:
715                                 fpx_surface = fpx_reader.Surfaces.get(FpxUtilities.toGoodName(fpx_surface_name))
716                             if fpx_surface:
717                                 fpx_position_z = fpx_surface.get_value("top_height")
718
719                         if fpx_position_zw is None:
720                             fpx_position_zw = 0.0
721                         if fpx_position_z is None:
722                             fpx_position_z = 0.0
723
724                         fpx_position_z += fpx_position_zw
725
726                         fpx_offset = fpx_item.get_value("offset")
727                         if fpx_offset:
728                             fpx_position_z += fpx_offset
729
730                         ## gather common information
731                         blender_object = None
732                         fpx_shape_points = fpx_item.get_value("shape_point")
733                         fpx_ramp_points =  fpx_item.get_value("ramp_point")
734                         fpx_position_xy = fpx_item.get_value("position")
735                         fpx_render_object = fpx_item.get_value("render_object")
736                         fpx_transparency = fpx_item.get_value("transparency")
737                         fpx_layer = fpx_item.get_value("layer")
738                         fpx_sphere_mapping = fpx_item.get_value("sphere_mapping")
739                         fpx_crystal = fpx_item.get_value("crystal")
740                         fpx_base = None # TODO:
741
742                         layers = self.FpxLayerToBlenderLayers(fpx_layer, fpx_id, fpx_render_object, fpx_transparency, fpx_sphere_mapping, fpx_crystal, fpx_base)
743
744                         # handle curve objects with shape_points
745                         if fpx_shape_points:
746                             if fpx_id == FptElementType.SURFACE:
747                                 blender_object = self.CreateSurface(fpx_item, fpx_item_name, layers, fpx_shape_points)
748                             elif fpx_id == FptElementType.LIGHT_SHAPEABLE:
749                                 blender_object = self.CreateLightShapeable(fpx_item, fpx_item_name, layers, fpx_shape_points, fpx_position_z)
750                             elif fpx_id == FptElementType.RUBBER_SHAPEABLE:
751                                 blender_object = self.CreateRubberShapeable(fpx_item, fpx_item_name, layers, fpx_shape_points, fpx_position_z)
752                             elif fpx_id == FptElementType.GUIDE_WALL:
753                                 blender_object = self.CreateGuideWall(fpx_item, fpx_item_name, layers, fpx_shape_points, fpx_position_z)
754                             elif fpx_id == FptElementType.GUIDE_WIRE:
755                                 blender_object = self.CreateGuideWire(fpx_item, fpx_item_name, layers, fpx_shape_points, fpx_position_z)
756                             else:
757                                 blender_object = None
758                         # handle curve objects with ramp_points
759                         elif fpx_ramp_points:
760                             if fpx_id == FptElementType.RAMP_WIRE:
761                                 blender_object = self.CreateWireRamp(fpx_item, fpx_item_name, layers, fpx_ramp_points, fpx_position_z, fpx_id)
762                             elif fpx_id == FptElementType.RAMP_RAMP:
763                                 blender_object = self.CreateRamp(fpx_item, fpx_item_name, layers, fpx_ramp_points, fpx_position_z)
764                             else:
765                                 blender_object = None
766                         else:
767                             if fpx_id == FptElementType.LIGHT_LIGHTIMAGE:
768                                 blender_object = self.CreateLightImage(fpx_item, fpx_item_name, layers, fpx_position_xy, fpx_position_z)
769                             else:
770                                 blender_object = None
771
772                         # put the just created object (curve) to its layer
773                         #if blender_object:
774                         #    blender_object.layers = layers
775
776                         if fpx_position_xy:
777                             fpx_rotation = fpx_item.get_value("rotation")
778                             if fpx_rotation:
779                                 blender_rotation = Euler((0.0, 0.0, radians(self.angle_correction(fpx_rotation))), 'XZY')
780                             else:
781                                 blender_rotation = Euler((0.0, 0.0, radians(self.angle_correction(0.0))), 'XZY')
782
783                             if fpx_id in {FptElementType.CONTROL_FLIPPER, FptElementType.CONTROL_DIVERTER, }:
784                                 fpx_start_angle = fpx_item.get_value("start_angle")
785                                 if fpx_start_angle is None:
786                                     fpx_start_angle = 0
787                                 m0 = blender_rotation.to_matrix()
788                                 m1 = Euler((0.0, 0.0, radians(self.angle_correction(fpx_start_angle) + 90)), 'XZY').to_matrix()
789                                 blender_rotation = (m0 * m1).to_euler('XZY')
790
791                             blender_position = self.geometry_correction((fpx_position_xy[0], fpx_position_xy[1], fpx_position_z))
792
793                             blender_empty_object = self.__blend_data.objects.new(FORMAT_EMPTY_OBJECT.format(fpx_item_name), None)
794                             blender_empty_object.location = blender_position
795                             blender_empty_object.rotation_mode = 'XZY'
796                             blender_empty_object.rotation_euler = blender_rotation
797                             blender_empty_object.empty_draw_type = 'ARROWS'
798                             blender_empty_object.empty_draw_size = 10.0
799                             self.__context.scene.objects.link(blender_empty_object)
800                             blender_empty_object.layers = layers
801
802                             blender_empty_object.fpt.name = fpx_item_name
803
804                             # handle model object (try to create an instance of existing group)
805                             fpx_model_name = fpx_item.get_value("model")
806                             if fpx_model_name:
807                                 fpx_model_beam_width = fpx_item.get_value("beam_width")
808                                 if fpx_model_beam_width:
809                                     offset = 3.75
810                                     self.attach_dupli_group(blender_empty_object, layers, fpx_model_name, "model", Vector((0.0 , ((fpx_model_beam_width / 2.0) + offset), 0.0)), -90)
811                                     self.attach_dupli_group(blender_empty_object, layers, fpx_model_name, "model", Vector((0.0 , -((fpx_model_beam_width / 2.0) + offset), 0.0)), 90)
812                                 else:
813                                     self.attach_dupli_group(blender_empty_object, layers, fpx_model_name, "model")
814
815                             fpx_model_name_cap = fpx_item.get_value("model_cap")
816                             if fpx_model_name_cap:
817                                 self.attach_dupli_group(blender_empty_object, layers, fpx_model_name_cap, "model_cap")
818
819                             fpx_model_name_base = fpx_item.get_value("model_base")
820                             if fpx_model_name_base:
821                                 self.attach_dupli_group(blender_empty_object, layers, fpx_model_name_base, "model_base")
822                                 self.attach_dupli_group(blender_empty_object, layers, "bumperring", 'LOCAL', Vector((0.0 , 0.0, 4.0)))
823                                 self.attach_dupli_group(blender_empty_object, layers, "bumperskirt", 'LOCAL', Vector((0.0 , 0.0, 3.5)))
824
825                             fpx_model_name_start = fpx_item.get_value("model_start")
826                             if fpx_model_name_start:
827                                 self.attach_dupli_group(blender_empty_object, layers, fpx_model_name_start, "model_start")
828
829                             fpx_model_name_end = fpx_item.get_value("model_end")
830                             if fpx_model_name_end:
831                                 self.attach_dupli_group(blender_empty_object, layers, fpx_model_name_end, "model_end")
832
833                             if fpx_id == FptElementType.RUBBER_ROUND:
834                                 blender_object = self.CreateRubberRound(fpx_item, fpx_item_name, layers, fpx_position_xy, fpx_position_z)
835
836                             if fpx_id:
837                                 blender_empty_object.fpt.id = FptElementType.VALUE_INT_TO_NAME.get(fpx_id)
838
839                             if fpx_id == FptElementType.LIGHT_ROUND:
840                                 blender_object = self.CreateLightRound(fpx_item, fpx_item_name, layers, fpx_position_xy, fpx_position_z)
841                                 if blender_object:
842                                     blender_object.layers = layers
843
844                             ## #DEBUG : light dummies
845                             if fpx_id in FptElementType.SET_LIGHT_OBJECTS: # and not blender_empty_object.children:
846                                 if ops.mesh.primitive_ico_sphere_add.poll():
847                                     blender_object = ops.mesh.primitive_ico_sphere_add(subdivisions=2, size=self.debug_lightball_size, location=blender_empty_object.location + Vector((0.0, 0.0, self.debug_lightball_height)), layers=FptImporter.LAYERS_LIGHT_SPHERE)
848
849                     # cleanup
850                     if not self.keep_temp:
851                         cleanup_sub_dirs = []
852
853                         for key, file in dst_sub_path_names.items():
854                             if key is not None and key.startswith('sub_dir'):
855                                 cleanup_sub_dirs.append(file)
856                                 continue
857
858                             if key in {'type', 'data', None, } or key.startswith('type') or key.startswith('data'):
859                                 continue
860
861                             try:
862                                 remove(file)
863                             except:
864                                 pass
865
866                         sub_dir_path = dst_sub_path_names.get('sub_dir')
867                         if sub_dir_path:
868                             try:
869                                 rmdir(sub_dir_path)
870                             except:
871                                 pass
872
873                         for sub_dir_path in cleanup_sub_dirs:
874                             try:
875                                 rmdir(sub_dir_path)
876                             except:
877                                 pass
878
879                         try:
880                             rmdir(dst_path)
881                         except:
882                             pass
883
884                 # setup all current 3d Views of the current scene to metric units
885                 FpxUtilities.set_scene_to_metric(self.__context)
886
887             if self.verbose in FpxUI.VERBOSE_NORMAL:
888                 print()
889                 print("##########################################################")
890                 print("Import from FPT to Blender")
891                 print("##########################################################")
892
893         except Exception as ex:
894             type, value, traceback = exc_info()
895             if self.verbose in FpxUI.VERBOSE_NORMAL:
896                 print("read fpt - exception in try block\n  type: '{0}'\n"
897                         "  value: '{1}'".format(type, value, traceback))
898
899             if t2 is None:
900                 t2 = time()
901
902             raise
903
904         else:
905             pass
906
907         finally:
908             self.__context = None
909             self.__blend_data = None
910
911         t3 = time()
912         if self.verbose in FpxUI.VERBOSE_NORMAL:
913             print(fpx_str['SUMMARY_IMPORT'].format(
914                     (t3 - t1), (t2 - t1), (t3 - t2)))
915
916         return {"FINISHED"}
917
918     def append_texture_material(self, blender_object, fpx_image_name, uv_layer=None):
919         fpx_image_object = self.fpx_images.get(fpx_image_name)
920         if fpx_image_object:
921             blender_image = self.__blend_data.images.get(fpx_image_object[self.BLENDER_OBJECT_NAME])
922             if blender_image:
923                 if uv_layer:
924                     bm_name = "uv_{}".format(FORMAT_MATERIAL.format(fpx_image_name))
925                 else:
926                     bm_name = "gen_{}".format(FORMAT_MATERIAL.format(fpx_image_name))
927                 blender_material = self.__blend_data.materials.get(bm_name)
928                 if not blender_material:
929                     print("#DEBUG create material", bm_name)
930                     blender_material = self.__blend_data.materials.new(bm_name)
931                     blender_material.use_transparency = True
932                     blender_material.use_raytrace = False
933                     blender_material.use_transparent_shadows = True
934                     blender_material.alpha = 0.0
935                     render_engine = self.__context.scene.render.engine
936                     #blender internal
937                     #self.__context.scene.render.engine = 'BLENDER_RENDER'
938                     if uv_layer:
939                         bt_name = "uv_{}".format(FORMAT_TEXTURE.format(fpx_image_name))
940                     else:
941                         bt_name = "gen_{}".format(FORMAT_TEXTURE.format(fpx_image_name))
942                     blender_texture = self.__blend_data.textures.get(bt_name)
943                     if not blender_texture:
944                         print("#DEBUG create texture", bt_name)
945                         blender_texture = self.__blend_data.textures.new(bt_name, 'IMAGE')
946                         blender_texture.image = blender_image
947                     tex_slot = blender_material.texture_slots.create(0)
948                     tex_slot.texture = blender_texture
949                     tex_slot.use_map_alpha = True
950                     if uv_layer:
951                         tex_slot.texture_coords = 'UV'
952                         tex_slot.uv_layer = uv_layer
953                     #blender_material.use_shadeless = True #DEBUG
954
955                     """
956                     # blender cycles
957                     self.__context.scene.render.engine = 'CYCLES'
958                     blender_material.use_nodes = True
959                     blender_material = self.__blend_data.materials.get(blender_material.name)
960                     node_0 = blender_material.node_tree.nodes.new('OUTPUT_MATERIAL')
961                     node_1 = blender_material.node_tree.nodes.new('BSDF_GLOSSY')
962                     node_1.inputs['Roughness'].default_value = 0.25
963                     link1_0 = blender_material.node_tree.links.new(node_1.outputs['BSDF'], node_0.inputs['Surface'])
964                     node_2 = blender_material.node_tree.nodes.new('TEX_IMAGE')
965                     node_2.image = blender_image
966                     link2_1 = blender_material.node_tree.links.new(node_2.outputs['Color'], node_1.inputs['Color'])
967                     node_3 = blender_material.node_tree.nodes.new('TEX_COORD')
968                     if uv_layer:
969                         out3 = node_3.outputs['UV']
970                     else:
971                         out3 = node_3.outputs['Generated']
972                     link3_2 = blender_material.node_tree.links.new(out3, node_2.inputs['Vector'])
973
974                     # blender game
975                     self.__context.scene.render.engine = 'BLENDER_GAME'
976                     #TODO
977
978                     self.__context.scene.render.engine = render_engine
979                     """
980
981                 blender_object.data.materials.append(blender_material)
982
983     ###########################################################################
984     def CreatePinCab(self, fpx_table_data):
985         name = fpx_table_data.get_value("name")
986         name = FpxUtilities.toGoodName(name) ####
987
988         dy = fpx_table_data.get_value("length")
989         dx = fpx_table_data.get_value("width")
990         z0 = fpx_table_data.get_value("glass_height_front")
991         z1 = fpx_table_data.get_value("glass_height_rear")
992         dtx = fpx_table_data.get_value("translite_height")
993         dtz = fpx_table_data.get_value("translite_width")
994         texture_table = fpx_table_data.get_value("playfield_texture")
995         texture_translite = fpx_table_data.get_value("translite_image")
996
997         if not dtx:
998             dtx = 676.0
999         if not dtz:
1000             dtz = 676.0
1001
1002         self.__translite_width = dtx
1003         self.__translite_length = dtz
1004
1005         self.__table_width = dx
1006         self.__table_length = dy
1007
1008         mesh = self.__blend_data.meshes.new(FORMAT_MESH.format(name))
1009         obj = self.__blend_data.objects.new(FORMAT_MESH_OBJECT.format(name), mesh)
1010         self.__context.scene.objects.link(obj)
1011
1012         #inner playfield
1013         bm = bmesh.new()
1014         uv_layer = bm.loops.layers.uv.new("UVMap")
1015         tex_layer = bm.faces.layers.tex.new(uv_layer.name)
1016         bmv_list = []
1017         bmv = bm.verts.new(self.geometry_correction((0.0, 0.0, 0.0)))
1018         bmv_list.append(bmv)
1019         bmv = bm.verts.new(self.geometry_correction((0.0, dy, 0.0)))
1020         bmv_list.append(bmv)
1021         bmv = bm.verts.new(self.geometry_correction((dx, dy, 0.0)))
1022         bmv_list.append(bmv)
1023         bmv = bm.verts.new(self.geometry_correction((dx, 0.0, 0.0)))
1024         bmv_list.append(bmv)
1025         bmf = bm.faces.new(bmv_list)
1026         bmluv = bmf.loops[0][uv_layer]
1027         bmluv.uv = (0.0, 1.0)
1028         bmluv = bmf.loops[1][uv_layer]
1029         bmluv.uv = (0.0, 0.0)
1030         bmluv = bmf.loops[2][uv_layer]
1031         bmluv.uv = (1.0, 0.0)
1032         bmluv = bmf.loops[3][uv_layer]
1033         bmluv.uv = (1.0, 1.0)
1034         if texture_table:
1035             fpx_image_object = self.fpx_images.get(texture_table)
1036             if fpx_image_object:
1037                 bmf[tex_layer].image = self.__blend_data.images.get(fpx_image_object[self.BLENDER_OBJECT_NAME])
1038                 self.append_texture_material(obj, texture_table, uv_layer.name)
1039         bm.to_mesh(mesh)
1040         bm.free()
1041
1042         mesh_box = self.__blend_data.meshes.new(FORMAT_MESH.format("{}.playfield".format(name)))
1043         obj_box = self.__blend_data.objects.new(FORMAT_MESH_OBJECT.format("{}.playfield".format(name)), mesh_box)
1044         obj_box.parent = obj
1045         self.__context.scene.objects.link(obj_box)
1046
1047         bm = bmesh.new()
1048         #inner back
1049         bmv_list = []
1050         bmv = bm.verts.new(self.geometry_correction((0.0, 0.0, 0.0)))
1051         bmv_list.append(bmv)
1052         bmv = bm.verts.new(self.geometry_correction((dx, 0.0, 0.0)))
1053         bmv_list.append(bmv)
1054         bmv = bm.verts.new(self.geometry_correction((dx, 0.0, z1)))
1055         bmv_list.append(bmv)
1056         bmv = bm.verts.new(self.geometry_correction((0.0, 0.0, z1)))
1057         bmv_list.append(bmv)
1058         bmf = bm.faces.new(bmv_list)
1059
1060         #inner front
1061         bmv_list = []
1062         bmv = bm.verts.new(self.geometry_correction((0.0, dy, 0.0)))
1063         bmv_list.append(bmv)
1064         bmv = bm.verts.new(self.geometry_correction((0.0, dy, z0)))
1065         bmv_list.append(bmv)
1066         bmv = bm.verts.new(self.geometry_correction((dx, dy, z0)))
1067         bmv_list.append(bmv)
1068         bmv = bm.verts.new(self.geometry_correction((dx, dy, 0.0)))
1069         bmv_list.append(bmv)
1070         bmf = bm.faces.new(bmv_list)
1071
1072         #inner left
1073         bmv_list = []
1074         bmv = bm.verts.new(self.geometry_correction((0.0, 0.0, 0.0)))
1075         bmv_list.append(bmv)
1076         bmv = bm.verts.new(self.geometry_correction((0.0, 0.0, z1)))
1077         bmv_list.append(bmv)
1078         bmv = bm.verts.new(self.geometry_correction((0.0, dy, z0)))
1079         bmv_list.append(bmv)
1080         bmv = bm.verts.new(self.geometry_correction((0.0, dy, 0.0)))
1081         bmv_list.append(bmv)
1082         bmf = bm.faces.new(bmv_list)
1083
1084         #inner right
1085         bmv_list = []
1086         bmv = bm.verts.new(self.geometry_correction((dx, 0.0, 0.0)))
1087         bmv_list.append(bmv)
1088         bmv = bm.verts.new(self.geometry_correction((dx, dy, 0.0)))
1089         bmv_list.append(bmv)
1090         bmv = bm.verts.new(self.geometry_correction((dx, dy, z0)))
1091         bmv_list.append(bmv)
1092         bmv = bm.verts.new(self.geometry_correction((dx, 0.0, z1)))
1093         bmv_list.append(bmv)
1094         bmf = bm.faces.new(bmv_list)
1095
1096         bm.to_mesh(mesh_box)
1097         bm.free()
1098
1099         ##
1100         mesh_translite = self.__blend_data.meshes.new(FORMAT_MESH.format("{}.translite".format(name)))
1101         obj_translite = self.__blend_data.objects.new(FORMAT_MESH_OBJECT.format("{}.translite".format(name)), mesh_translite)
1102         obj_translite.parent = obj
1103         self.__context.scene.objects.link(obj_translite)
1104
1105         #inner translite
1106         bm = bmesh.new()
1107         uv_layer = bm.loops.layers.uv.new("UVMap")
1108         tex_layer = bm.faces.layers.tex.new(uv_layer.name)
1109         bmv_list = []
1110         bmv = bm.verts.new(self.geometry_correction(((dx - dtx) / 2.0, 0.0, z1 + 20.0)))
1111         bmv_list.append(bmv)
1112         bmv = bm.verts.new(self.geometry_correction(((dx + dtx) / 2.0, 0.0, z1 + 20.0)))
1113         bmv_list.append(bmv)
1114         bmv = bm.verts.new(self.geometry_correction(((dx + dtx) / 2.0, 0.0, z1 + 20.0 + dtz)))
1115         bmv_list.append(bmv)
1116         bmv = bm.verts.new(self.geometry_correction(((dx - dtx) / 2.0, 0.0, z1 + 20.0 + dtz)))
1117         bmv_list.append(bmv)
1118         bmf = bm.faces.new(bmv_list)
1119         bmluv = bmf.loops[0][uv_layer]
1120         bmluv.uv = (0.0, 0.0)
1121         bmluv = bmf.loops[1][uv_layer]
1122         bmluv.uv = (1.0, 0.0)
1123         bmluv = bmf.loops[2][uv_layer]
1124         bmluv.uv = (1.0, 1.0)
1125         bmluv = bmf.loops[3][uv_layer]
1126         bmluv.uv = (0.0, 1.0)
1127         if texture_translite:
1128             fpx_image_object = self.fpx_images.get(texture_translite)
1129             if fpx_image_object:
1130                 bmf[tex_layer].image = self.__blend_data.images.get(fpx_image_object[self.BLENDER_OBJECT_NAME])
1131                 self.append_texture_material(obj_translite, texture_translite, uv_layer.name)
1132         bm.to_mesh(mesh_translite)
1133         bm.free()
1134
1135         return obj
1136
1137     def CreateSurface(self, fpx_item, name, layers, fpx_points):
1138         top = fpx_item.get_value("top_height")
1139         bottom = fpx_item.get_value("bottom_height")
1140         cookie_cut = fpx_item.get_value("cookie_cut")
1141         texture = fpx_item.get_value("top_texture")
1142
1143         obj, cu, act_spline = self.create_curve(name, layers, self.resolution_shape)
1144         if texture:
1145             self.append_texture_material(obj, texture)
1146         if cookie_cut:
1147             cu.use_auto_texspace = False
1148             cu.texspace_location = Vector((self.__table_width / 2.0, self.__table_length / 2.0, 0))
1149             cu.texspace_size = Vector((self.__table_width / 2.0, self.__table_length / 2.0, 0))
1150
1151         modifier_edge_split = obj.modifiers.new("edge_split", type='EDGE_SPLIT')
1152
1153         if top is None:
1154             top = 0.0
1155         if bottom is None:
1156             bottom = 0.0
1157         cu.extrude = (top - bottom) / 2.0
1158         cu.dimensions = '2D'
1159
1160         act_spline.use_cyclic_u = True
1161         self.create_curve_points(act_spline, fpx_points)
1162
1163         obj.location = Vector((obj.location.x, obj.location.y, (top - cu.extrude)))
1164         return obj
1165
1166     def CreateRubberShapeable(self, fpx_item, name, layers, fpx_points, surface):
1167         obj, cu, act_spline = self.create_curve(name, layers, self.resolution_shape)
1168
1169         bevel_name = "__fpx_rubber_shapeable_bevel__"
1170         rubber_bevel = self.__blend_data.objects.get(bevel_name)
1171         if rubber_bevel is None:
1172             if ops.curve.primitive_bezier_circle_add.poll():
1173                 ops.curve.primitive_bezier_circle_add()
1174                 rubber_bevel = self.__context.active_object
1175                 rubber_bevel.name = bevel_name
1176                 rubber_bevel.data.dimensions = '2D'
1177                 rubber_bevel.data.resolution_u = self.resolution_rubber
1178                 rubber_bevel.data.splines[0].resolution_u = self.resolution_rubber
1179                 scale = 2.4
1180                 rubber_bevel.scale = Vector((scale,scale,scale))
1181         cu.bevel_object = rubber_bevel
1182
1183         offset = 2.5
1184         act_spline.use_cyclic_u = True
1185         self.create_curve_points(act_spline, fpx_points, (surface + offset))
1186
1187         return obj
1188
1189     def CreateRubberRound(self, fpx_item, name, layers, position_xy, surface):
1190         subtype = fpx_item.get_value("subtype")
1191
1192         #diameter = [44, 18.5, 13.5, 12, ]
1193         diameter = [13.5, 18.5, 12, 44, ]
1194
1195         bevel_name = "__fpx_guide_rubber_bevel__"
1196         wire_bevel = self.__blend_data.objects.get(bevel_name)
1197         if wire_bevel is None:
1198             cu0 = self.__blend_data.curves.new(bevel_name, 'CURVE')
1199             wire_bevel = self.__blend_data.objects.new(bevel_name, cu0)
1200             self.__context.scene.objects.link(wire_bevel)
1201             cu0.dimensions = '2D'
1202             cu0.resolution_u = self.resolution_rubber_bevel
1203
1204             h = 'AUTO'
1205             cu0.splines.new('BEZIER')
1206             p0 = Vector((0.0, 0.0, 0.0))
1207             s0 = 5.0 / 2.0
1208             spline0 = cu0.splines[-1]
1209             spline0.resolution_u = self.resolution_rubber_bevel
1210             spline0.use_cyclic_u = True
1211             spline0.bezier_points.add(3)
1212             spline0.bezier_points[0].co = p0 + Vector((0.0, -s0, 0.0))
1213             spline0.bezier_points[0].handle_left_type = h
1214             spline0.bezier_points[0].handle_right_type = h
1215             spline0.bezier_points[1].co = p0 + Vector((-s0, 0.0, 0.0))
1216             spline0.bezier_points[1].handle_left_type = h
1217             spline0.bezier_points[1].handle_right_type = h
1218             spline0.bezier_points[2].co = p0 + Vector((0.0, s0, 0.0))
1219             spline0.bezier_points[2].handle_left_type = h
1220             spline0.bezier_points[2].handle_right_type = h
1221             spline0.bezier_points[3].co = p0 + Vector((s0, 0.0, 0.0))
1222             spline0.bezier_points[3].handle_left_type = h
1223             spline0.bezier_points[3].handle_right_type = h
1224
1225         obj, cu1, spline1 = self.create_curve(name, layers, self.resolution_rubber)
1226
1227         h = 'AUTO'
1228         p1 = self.geometry_correction((position_xy[0], position_xy[1], surface + 2.5))
1229         s1 = (diameter[subtype] - 5.0) / 2.0
1230         spline1.use_cyclic_u = True
1231         spline1.resolution_u = self.resolution_rubber * 2
1232         spline1.bezier_points.add(3)
1233         spline1.bezier_points[0].co = p1 + Vector((0.0, -s1, 0.0))
1234         spline1.bezier_points[0].handle_left_type = h
1235         spline1.bezier_points[0].handle_right_type = h
1236         spline1.bezier_points[1].co = p1 + Vector((-s1, 0.0, 0.0))
1237         spline1.bezier_points[1].handle_left_type = h
1238         spline1.bezier_points[1].handle_right_type = h
1239         spline1.bezier_points[2].co = p1 + Vector((0.0, s1, 0.0))
1240         spline1.bezier_points[2].handle_left_type = h
1241         spline1.bezier_points[2].handle_right_type = h
1242         spline1.bezier_points[3].co = p1 + Vector((s1, 0.0, 0.0))
1243         spline1.bezier_points[3].handle_left_type = h
1244         spline1.bezier_points[3].handle_right_type = h
1245
1246         cu1.bevel_object = wire_bevel
1247
1248         return obj
1249
1250     def CreateGuideWire(self, fpx_item, name, layers, fpx_points, surface):
1251         height = fpx_item.get_value("height")
1252         width = fpx_item.get_value("width")
1253
1254         obj, cu, act_spline = self.create_curve(name, layers, self.resolution_wire)
1255
1256         if height is None:
1257             height = 0.0
1258         if width is not None:
1259             bevel_name = "__fpx_guide_wire_bevel_{}__".format(width)
1260             wire_bevel = self.__blend_data.objects.get(bevel_name)
1261             if wire_bevel is None:
1262                 if ops.curve.primitive_bezier_circle_add.poll():
1263                     ops.curve.primitive_bezier_circle_add()
1264                     wire_bevel = self.__context.active_object
1265                     wire_bevel.name = bevel_name
1266                     wire_bevel.data.dimensions = '2D'
1267                     wire_bevel.data.resolution_u = self.resolution_wire_bevel
1268                     wire_bevel.data.splines[0].resolution_u = self.resolution_wire_bevel
1269                     scale = width / 2.0
1270                     wire_bevel.scale = Vector((scale,scale,scale))
1271             cu.bevel_object = wire_bevel
1272             cu.use_fill_caps = True
1273         else:
1274             width = 0.0
1275
1276         act_spline.use_cyclic_u = False
1277         self.create_curve_points(act_spline, fpx_points, (surface + height + width / 2.0))
1278
1279         # create pole caps
1280         co1 = act_spline.bezier_points[0].co
1281         h_left1 = act_spline.bezier_points[0].handle_left
1282         h_right1 = act_spline.bezier_points[0].handle_right
1283         co2 = act_spline.bezier_points[-1].co
1284         h_left2 = act_spline.bezier_points[-1].handle_left
1285         h_right2 = act_spline.bezier_points[-1].handle_right
1286         self.create_wire_pole(cu.splines, co1, h_left1, h_right1, surface, width)
1287         self.create_wire_pole(cu.splines, co2, h_right2, h_left2, surface, width)
1288
1289         # merge wire curve with pole caps
1290         self.__context.scene.objects.active = obj
1291         self.merge_caps(cu.splines, width)
1292
1293         cu.splines[0].type = 'NURBS' # looks better for wires
1294         cu.twist_mode = 'MINIMUM'
1295
1296         return obj
1297
1298     def CreateGuideWall(self, fpx_item, name, layers, fpx_points, surface):
1299         height = fpx_item.get_value("height")
1300         width = fpx_item.get_value("width")
1301         cookie_cut = fpx_item.get_value("cookie_cut")
1302         texture = fpx_item.get_value("top_texture")
1303
1304         obj, cu, act_spline = self.create_curve(name, layers, self.resolution_shape)
1305         if texture:
1306             self.append_texture_material(obj, texture)
1307         if cookie_cut:
1308             cu.use_auto_texspace = False
1309             cu.texspace_location = Vector((self.__table_width / 2.0, self.__table_length / 2.0, 0))
1310             cu.texspace_size = Vector((self.__table_width / 2.0, self.__table_length / 2.0, 0))
1311
1312         modifier_solidify = obj.modifiers.new("width", type='SOLIDIFY')
1313         modifier_solidify.thickness = width
1314         modifier_solidify.offset = 0.0
1315         modifier_solidify.use_even_offset = True
1316
1317         modifier_edge_split = obj.modifiers.new("edge_split", type='EDGE_SPLIT')
1318
1319         if height is None:
1320             height = 0.0
1321         cu.extrude = height / 2.0
1322         cu.dimensions = '2D'
1323
1324         act_spline.use_cyclic_u = False
1325         self.create_curve_points(act_spline, fpx_points)
1326
1327         obj.location = Vector((obj.location.x, obj.location.y, (surface + cu.extrude)))
1328         return obj
1329
1330     def CreateLightRound(self, fpx_item, name, layers, position_xy, surface):
1331         diameter = fpx_item.get_value("diameter")
1332         cookie_cut = fpx_item.get_value("cookie_cut")
1333         texture = fpx_item.get_value("lens_texture")
1334
1335         obj, cu, spline = self.create_curve(name, layers, self.resolution_shape)
1336         if texture:
1337             self.append_texture_material(obj, texture)
1338         if cookie_cut:
1339             cu.use_auto_texspace = False
1340             cu.texspace_location = Vector((self.__table_width / 2.0, self.__table_length / 2.0, 0))
1341             cu.texspace_size = Vector((self.__table_width / 2.0, self.__table_length / 2.0, 0))
1342
1343         modifier_edge_split = obj.modifiers.new("edge_split", type='EDGE_SPLIT')
1344
1345         h = 'AUTO'
1346         p0 = self.geometry_correction((position_xy[0], position_xy[1], 0.0))
1347         d = diameter / 2.0
1348         spline.bezier_points.add(3)
1349         spline.bezier_points[0].co = p0 + Vector((0.0, -d, 0.0))
1350         spline.bezier_points[0].handle_left_type = h
1351         spline.bezier_points[0].handle_right_type = h
1352         spline.bezier_points[1].co = p0 + Vector((-d, 0.0, 0.0))
1353         spline.bezier_points[1].handle_left_type = h
1354         spline.bezier_points[1].handle_right_type = h
1355         spline.bezier_points[2].co = p0 + Vector((0.0, d, 0.0))
1356         spline.bezier_points[2].handle_left_type = h
1357         spline.bezier_points[2].handle_right_type = h
1358         spline.bezier_points[3].co = p0 + Vector((d, 0.0, 0.0))
1359         spline.bezier_points[3].handle_left_type = h
1360         spline.bezier_points[3].handle_right_type = h
1361         spline.use_cyclic_u = True
1362
1363         cu.extrude = self.debug_light_extrude
1364         cu.dimensions = '2D'
1365
1366         obj.location = Vector((obj.location.x, obj.location.y, surface))
1367         return obj
1368
1369     def CreateLightShapeable(self, fpx_item, name, layers, fpx_points, surface):
1370         cookie_cut = fpx_item.get_value("cookie_cut")
1371         texture = fpx_item.get_value("lens_texture")
1372
1373         obj, cu, act_spline = self.create_curve(name, layers, self.resolution_shape)
1374         if texture:
1375             self.append_texture_material(obj, texture)
1376         if cookie_cut:
1377             cu.use_auto_texspace = False
1378             cu.texspace_location = Vector((self.__table_width / 2.0, self.__table_length / 2.0, 0))
1379             cu.texspace_size = Vector((self.__table_width / 2.0, self.__table_length / 2.0, 0))
1380
1381         modifier_edge_split = obj.modifiers.new("edge_split", type='EDGE_SPLIT')
1382
1383         cu.extrude = self.debug_light_extrude
1384         cu.dimensions = '2D'
1385
1386         act_spline.use_cyclic_u = True
1387         self.create_curve_points(act_spline, fpx_points)
1388
1389         obj.location = Vector((obj.location.x, obj.location.y, surface))
1390         return obj
1391
1392     def CreateLightImage(self, fpx_item, name, layers, position_xy, surface):
1393         height = fpx_item.get_value("height")
1394         width = fpx_item.get_value("width")
1395         rotation = fpx_item.get_value("rotation")
1396         image_list = fpx_item.get_value("image_list")
1397
1398         mesh = self.__blend_data.meshes.new(FORMAT_MESH.format(name))
1399         obj = self.__blend_data.objects.new(FORMAT_MESH_OBJECT.format(name), mesh)
1400         self.__context.scene.objects.link(obj)
1401
1402         z = surface + self.debug_light_extrude
1403         bm = bmesh.new()
1404         uv_layer = bm.loops.layers.uv.new("UVMap")
1405         tex_layer = bm.faces.layers.tex.new(uv_layer.name)
1406         bmv_list = []
1407         bmv = bm.verts.new(self.geometry_correction((-width / 2.0, height / 2.0, 0.0)))
1408         bmv_list.append(bmv)
1409         bmv = bm.verts.new(self.geometry_correction((width / 2.0, height / 2.0, 0.0)))
1410         bmv_list.append(bmv)
1411         bmv = bm.verts.new(self.geometry_correction((width / 2.0, -height / 2.0, 0.0)))
1412         bmv_list.append(bmv)
1413         bmv = bm.verts.new(self.geometry_correction((-width / 2.0, -height / 2.0, 0.0)))
1414         bmv_list.append(bmv)
1415         bmf = bm.faces.new(bmv_list)
1416         bmluv = bmf.loops[0][uv_layer]
1417         bmluv.uv = (0.0, 1.0)
1418         bmluv = bmf.loops[1][uv_layer]
1419         bmluv.uv = (0.0, 0.0)
1420         bmluv = bmf.loops[2][uv_layer]
1421         bmluv.uv = (1.0, 0.0)
1422         bmluv = bmf.loops[3][uv_layer]
1423         bmluv.uv = (1.0, 1.0)
1424         if image_list:
1425             image_list_data = self.fpx_image_lists.get(image_list)
1426             if image_list_data:
1427                 fpx_image_name = image_list_data[0] # -1 for light on
1428                 fpx_image_object = self.fpx_images.get(fpx_image_name)
1429                 if fpx_image_object:
1430                     bmf[tex_layer].image = self.__blend_data.images.get(fpx_image_object[self.BLENDER_OBJECT_NAME])
1431                     self.append_texture_material(obj, fpx_image_name, uv_layer.name)
1432         bm.to_mesh(mesh)
1433         bm.free()
1434
1435         obj.location = self.geometry_correction((position_xy[0], position_xy[1], z))
1436         obj.rotation_mode = 'XZY'
1437         obj.rotation_euler = Euler((0.0, 0.0, radians(self.angle_correction(rotation))), obj.rotation_mode)
1438         return obj
1439
1440     def CreateWireRamp(self, fpx_item, name, layers, fpx_points, surface, fpx_id):
1441         start_height = fpx_item.get_value("start_height")
1442         end_height = fpx_item.get_value("end_height")
1443         model_name_start = fpx_item.get_value("model_start")
1444         model_name_end = fpx_item.get_value("model_end")
1445
1446         if start_height is None:
1447             start_height = 0.0
1448         if end_height is None:
1449             end_height = 0.0
1450
1451         wire_bevel = self.prepare_wire_ramp_bevel()
1452
1453         #"ramp_point"
1454         obj, cu, act_spline = self.create_curve(name, layers, self.resolution_wire)
1455
1456         cu.bevel_object = wire_bevel
1457         cu.use_fill_caps = True
1458
1459         act_spline.use_cyclic_u = False
1460         self.create_ramp_curve_points(act_spline, fpx_points, surface, start_height, end_height)
1461
1462         # ramp start
1463         if model_name_start:
1464             blender_empty_object = self.__blend_data.objects.new(FORMAT_EMPTY_OBJECT.format(FORMAT_MODEL_CAP1.format(name)), None)
1465             blender_empty_object.location = cu.splines[-1].bezier_points[0].co
1466             blender_empty_object.rotation_mode = 'XZY'
1467             v = (cu.splines[-1].bezier_points[0].handle_left - cu.splines[-1].bezier_points[0].co)
1468             blender_empty_object.rotation_euler = Euler((0, 0, Vector((v.x, v.y)).angle_signed(Vector((1.0, 0.0)))), 'XZY')
1469             blender_empty_object.empty_draw_type = 'ARROWS'
1470             blender_empty_object.empty_draw_size = 10.0
1471             self.__context.scene.objects.link(blender_empty_object)
1472             blender_empty_object.fpt.name = FORMAT_EMPTY_OBJECT.format(FORMAT_MODEL_START.format(name))
1473             if fpx_id:
1474                 blender_empty_object.fpt.id = FptElementType.VALUE_INT_TO_NAME.get(fpx_id)
1475             self.attach_dupli_group(blender_empty_object, FptImporter.LAYERS_WIRE_RING, model_name_start, "model_start")
1476             blender_empty_object.layers = FptImporter.LAYERS_WIRE_RING
1477
1478         # ramp end
1479         if model_name_end:
1480             blender_empty_object = self.__blend_data.objects.new(FORMAT_EMPTY_OBJECT.format(FORMAT_MODEL_CAP2.format(name)), None)
1481             blender_empty_object.location = cu.splines[-1].bezier_points[-1].co
1482             blender_empty_object.rotation_mode = 'XZY'
1483             v = (cu.splines[-1].bezier_points[-1].handle_right - cu.splines[-1].bezier_points[-1].co)
1484             blender_empty_object.rotation_euler = Euler((0, 0, Vector((v.x, v.y)).angle_signed(Vector((1.0, 0.0)))), 'XZY')
1485             blender_empty_object.empty_draw_type = 'ARROWS'
1486             blender_empty_object.empty_draw_size = 10.0
1487             self.__context.scene.objects.link(blender_empty_object)
1488             blender_empty_object.fpt.name = FORMAT_EMPTY_OBJECT.format(FORMAT_MODEL_END.format(name))
1489             if fpx_id:
1490                 blender_empty_object.fpt.id = FptElementType.VALUE_INT_TO_NAME.get(fpx_id)
1491             self.attach_dupli_group(blender_empty_object, FptImporter.LAYERS_WIRE_RING, model_name_end, "model_end")
1492             blender_empty_object.layers = FptImporter.LAYERS_WIRE_RING
1493
1494         # create rings
1495         wire_ring_model = [
1496                 None, # NoRing
1497                 'wirering01', # FullRing = 1
1498                 'wirering02', # OpenUp = 2
1499                 'wirering04', # OpenRight = 3
1500                 'wirering03', # OpenDown = 4
1501                 'wirering05', # OpenLeft = 5
1502                 'wirering06', # HalfLeft = 6
1503                 'wirering07', # HalfRight = 7
1504                 'wirering08', # Joiner = 8
1505                 'wirering09', # HalfDown = 9
1506                 'wirering10', # HalfUp = 10
1507                 'wirering14', # OpenUPLeft = 11
1508                 'wirering13', # OpenDownLeft = 12
1509                 'wirering12', # OpenDownRight = 13
1510                 'wirering11', # OpenUPRight = 14
1511                 'wirering15', # Split = 15
1512                 'wirering17', # QuarterRight = 16
1513                 'wirering16', # QuarterLeft = 17
1514                 'wirering19', # CresentRight = 18
1515                 'wirering18', # CresentLeft = 19
1516                 ]
1517
1518         left_wires_bevel = self.prepare_wire_ramp_side_bevel(2)
1519         right_wires_bevel = self.prepare_wire_ramp_side_bevel(3)
1520         left_upper_wires_bevel = self.prepare_wire_ramp_side_bevel(4)
1521         right_upper_wires_bevel = self.prepare_wire_ramp_side_bevel(5)
1522         top_wires_bevel = self.prepare_wire_ramp_side_bevel(6)
1523
1524         last_bezier_point = None
1525         last_fpx_point = None
1526
1527         last_left_wire = None
1528         last_right_wire = None
1529         last_left_upper_wire = None
1530         last_right_upper_wire = None
1531         last_top_wire = None
1532
1533         for index, fpx_point in enumerate(fpx_points):
1534             bezier_point = act_spline.bezier_points[index]
1535
1536             if self.debug_create_full_ramp_wires:
1537                 pass
1538             else:
1539                 """
1540                 there are problems, see [#36007] http://projects.blender.org/tracker/index.php?func=detail&aid=36007&group_id=9&atid=498
1541                 """
1542                 if index:
1543                     if last_fpx_point.get_value("left_guide"):
1544                         last_left_wire = self.create_wire_ramp_guide_piece(name, obj, layers, left_wires_bevel, 2, index, last_bezier_point, bezier_point, last_left_wire)
1545                     else:
1546                         last_left_wire = None
1547
1548                     if last_fpx_point.get_value("right_guide"):
1549                         last_right_wire = self.create_wire_ramp_guide_piece(name, obj, layers, right_wires_bevel, 3, index, last_bezier_point, bezier_point, last_right_wire)
1550                     else:
1551                         last_right_wire = None
1552
1553                     if last_fpx_point.get_value("left_upper_guide"):
1554                         last_left_upper_wire = self.create_wire_ramp_guide_piece(name, obj, layers, left_upper_wires_bevel, 4, index, last_bezier_point, bezier_point, last_left_upper_wire)
1555                     else:
1556                         last_left_upper_wire = None
1557
1558                     if last_fpx_point.get_value("right_upper_guide"):
1559                         last_right_upper_wire = self.create_wire_ramp_guide_piece(name, obj, layers, right_upper_wires_bevel, 5, index, last_bezier_point, bezier_point, last_right_upper_wire)
1560                     else:
1561                         last_right_upper_wire = None
1562
1563                     if last_fpx_point.get_value("top_wire"):
1564                         last_top_wire = self.create_wire_ramp_guide_piece(name, obj, layers, top_wires_bevel, 6, index, last_bezier_point, bezier_point, last_top_wire)
1565                     else:
1566                         last_top_wire = None
1567
1568
1569             last_bezier_point = bezier_point
1570             last_fpx_point = fpx_point
1571
1572             #fpx_point.get_value("mark_as_ramp_end_point")
1573
1574             type = fpx_point.get_value("ring_type")
1575             raw_model_name = wire_ring_model[type]
1576             if raw_model_name is None:
1577                 continue
1578
1579             blender_empty_object = self.__blend_data.objects.new(FORMAT_EMPTY_OBJECT.format(FORMAT_MODEL_RING.format(name, index)), None)
1580             blender_empty_object.location = bezier_point.co
1581             blender_empty_object.rotation_mode = 'XZY'
1582             v = (bezier_point.handle_right - bezier_point.co)
1583             blender_empty_object.rotation_euler = Euler((0, 0, Vector((v.x, v.y)).angle_signed(Vector((1.0, 0.0)))), 'XZY')
1584             blender_empty_object.empty_draw_type = 'ARROWS'
1585             blender_empty_object.empty_draw_size = 10.0
1586             self.__context.scene.objects.link(blender_empty_object)
1587             blender_empty_object.fpt.name = FORMAT_MODEL_RING.format(name, index)
1588             if fpx_id:
1589                 blender_empty_object.fpt.id = FptElementType.VALUE_INT_TO_NAME.get(fpx_id)
1590             self.attach_dupli_group(blender_empty_object, FptImporter.LAYERS_WIRE_RING, raw_model_name, 'LOCAL')
1591             blender_empty_object.layers = FptImporter.LAYERS_WIRE_RING
1592
1593         #cu.splines[0].type = 'NURBS' # looks better for wires
1594         #cu.twist_mode = 'MINIMUM'
1595         return obj
1596
1597     def create_wire_ramp_guide_piece(self, name, parent_obj, layers, wire_bevel, wire_index, point_index, last_bezier_point_template, bezier_point_template, last_object):
1598         if last_object:
1599             #reuse previouse curve
1600             spline = last_object.data.splines[0]
1601             spline.bezier_points.add(1)
1602             bezier_point = spline.bezier_points[-1]
1603             bezier_point.co = bezier_point_template.co
1604             bezier_point.radius = bezier_point_template.radius
1605             bezier_point.handle_left_type = bezier_point_template.handle_left_type
1606             bezier_point.handle_right_type = bezier_point_template.handle_right_type
1607             bezier_point.handle_left = bezier_point_template.handle_left
1608             bezier_point.handle_right = bezier_point_template.handle_right
1609             bezier_point.tilt = bezier_point_template.tilt
1610             obj = last_object
1611         else:
1612             #start to make a new curve
1613             sub_name = "{}_{}_{}".format(name, wire_index, point_index-1)
1614
1615             obj, cu, spline = self.create_curve(sub_name, layers, self.resolution_wire)
1616             obj.fpt.name = sub_name
1617             obj.parent = parent_obj
1618             cu.bevel_object = wire_bevel
1619             cu.use_fill_caps = True
1620             spline.use_cyclic_u = False
1621
1622             spline.bezier_points.add(1)
1623             bezier_point = spline.bezier_points[0]
1624             bezier_point.co = last_bezier_point_template.co
1625             bezier_point.radius = last_bezier_point_template.radius
1626             bezier_point.handle_left_type = last_bezier_point_template.handle_left_type
1627             bezier_point.handle_right_type = last_bezier_point_template.handle_right_type
1628             bezier_point.handle_left = last_bezier_point_template.handle_left
1629             bezier_point.handle_right = last_bezier_point_template.handle_right
1630             bezier_point.tilt = last_bezier_point_template.tilt
1631
1632             bezier_point = spline.bezier_points[1]
1633             bezier_point.co = bezier_point_template.co
1634             bezier_point.radius = bezier_point_template.radius
1635             bezier_point.handle_left_type = bezier_point_template.handle_left_type
1636             bezier_point.handle_right_type = bezier_point_template.handle_right_type
1637             bezier_point.handle_left = bezier_point_template.handle_left
1638             bezier_point.handle_right = bezier_point_template.handle_right
1639             bezier_point.tilt = bezier_point_template.tilt
1640
1641         return obj
1642
1643     def CreateRamp(self, fpx_item, name, layers, fpx_points, surface):
1644         start_height = fpx_item.get_value("start_height")
1645         end_height = fpx_item.get_value("end_height")
1646         start_width = fpx_item.get_value("start_width")
1647         end_width = fpx_item.get_value("end_width")
1648         height_left = fpx_item.get_value("left_side_height")
1649         height_right = fpx_item.get_value("right_side_height")
1650
1651         if start_width is None:
1652             start_width = 0.0
1653         if end_width is None:
1654             end_width = 0.0
1655
1656         if height_left is None:
1657             height_left = 0.0
1658         if height_right is None:
1659             height_right = 0.0
1660
1661         bevel_name = "__fpx_guide_ramp_wire_bevel_{}_{}_{}__".format(start_width, height_left, height_right, )
1662         wire_bevel = self.__blend_data.objects.get(bevel_name)
1663         if wire_bevel is None:
1664             cu = self.__blend_data.curves.new(bevel_name, 'CURVE')
1665             wire_bevel = self.__blend_data.objects.new(bevel_name, cu)
1666             self.__context.scene.objects.link(wire_bevel)
1667             cu.dimensions = '2D'
1668             cu.resolution_u = self.resolution_shape
1669
1670             h = 'VECTOR'
1671             cu.splines.new('BEZIER')
1672             spline0 = cu.splines[-1]
1673             spline0.resolution_u = self.resolution_shape
1674             p0 = Vector((0.0, 0.0, 0.0))
1675             spline0.use_cyclic_u = False
1676             spline0.bezier_points.add(3)
1677             spline0.bezier_points[0].co = p0 + Vector((-start_width / 2.0, height_left, 0.0))
1678             spline0.bezier_points[0].handle_left_type = h
1679             spline0.bezier_points[0].handle_right_type = h
1680             spline0.bezier_points[1].co = p0 + Vector((-start_width / 2.0, 0.0, 0.0))
1681             spline0.bezier_points[1].handle_left_type = h
1682             spline0.bezier_points[1].handle_right_type = h
1683             spline0.bezier_points[2].co = p0 + Vector((start_width / 2.0, 0.0, 0.0))
1684             spline0.bezier_points[2].handle_left_type = h
1685             spline0.bezier_points[2].handle_right_type = h
1686             spline0.bezier_points[3].co = p0 + Vector((start_width / 2.0, height_right, 0.0))
1687             spline0.bezier_points[3].handle_left_type = h
1688             spline0.bezier_points[3].handle_right_type = h
1689
1690         #"ramp_point"
1691         obj, cu, act_spline = self.create_curve(name, layers, self.resolution_wire)
1692
1693         modifier_solidify = obj.modifiers.new("solidify", type='SOLIDIFY')
1694         modifier_solidify.offset = 0.0
1695         modifier_solidify.thickness = 1.0
1696         modifier_edge_split = obj.modifiers.new("edge_split", type='EDGE_SPLIT')
1697
1698         cu.bevel_object = wire_bevel
1699         cu.use_fill_caps = False
1700
1701
1702         if start_height is None:
1703             start_height = 0.0
1704         if end_height is None:
1705             end_height = 0.0
1706
1707         self.create_ramp_curve_points(act_spline, fpx_points, surface, start_height, end_height, start_width, end_width)
1708
1709         return obj
1710
1711     def create_wire_pole(self, cu_splines, co, t, ti, surface, width):
1712         d = (t - co)
1713         dn = d.normalized()
1714         w = width / 2.0
1715         dw = dn * w
1716         co_dw = co + dw
1717
1718         cu_splines.new('BEZIER')
1719         act_spline = cu_splines[-1]
1720         act_spline.use_cyclic_u = False
1721
1722         point_0 = act_spline.bezier_points[-1]
1723         point_0.co = Vector((co_dw.x, co_dw.y, co.z - w))
1724         point_0.handle_left_type = 'ALIGNED'
1725         point_0.handle_right_type = 'ALIGNED'
1726         point_0.handle_left = Vector((point_0.co.x, point_0.co.y, point_0.co.z + w))
1727         point_0.handle_right = Vector((point_0.co.x, point_0.co.y, point_0.co.z - w))
1728
1729         act_spline.bezier_points.add()
1730         point_1 = act_spline.bezier_points[-1]
1731         point_1.co = Vector((co_dw.x, co_dw.y, surface))
1732         point_1.handle_left_type = 'ALIGNED'
1733         point_1.handle_right_type = 'ALIGNED'
1734         point_1.handle_left = Vector((point_1.co.x, point_1.co.y, point_1.co.z + (co.z - surface) / 4.0))
1735         point_1.handle_right = Vector((point_1.co.x, point_1.co.y, point_1.co.z - (co.z - surface) / 4.0))
1736
1737     def merge_caps(self, cu_splines, width):
1738         w = width / 2.0
1739
1740         # adjust endpoint of curve
1741         b_point = cu_splines[0].bezier_points[0]
1742         co = b_point.co.copy()
1743         h_left = b_point.handle_left.copy()
1744         h_right = b_point.handle_right.copy()
1745         b_point.handle_left_type = 'ALIGNED'
1746         b_point.handle_right_type = 'ALIGNED'
1747         b_point.handle_left = co + ((h_left - co).normalized() * w)
1748         b_point.handle_right = co + ((h_right - co).normalized() * w)
1749         # select endpoint of curve and start-point of pole-cap
1750         cu_splines[0].bezier_points[0].select_control_point = True
1751         cu_splines[1].bezier_points[0].select_control_point = True
1752         # merge curve an pole
1753         FpxUtilities.enable_edit_mode(True, self.__context)
1754         if ops.curve.make_segment.poll():
1755             ops.curve.make_segment()
1756         FpxUtilities.enable_edit_mode(False, self.__context)
1757
1758         # adjust endpoint of curve
1759         b_point = cu_splines[0].bezier_points[-1]
1760         co = b_point.co.copy()
1761         h_left = b_point.handle_left.copy()
1762         h_right = b_point.handle_right.copy()
1763         b_point.handle_left_type = 'ALIGNED'
1764         b_point.handle_right_type = 'ALIGNED'
1765         b_point.handle_left = co + ((h_left - co).normalized() * w)
1766         b_point.handle_right = co + ((h_right - co).normalized() * w)
1767         # select endpoint of curve and start-point of pole-cap
1768         cu_splines[0].bezier_points[-1].select_control_point = True
1769         cu_splines[1].bezier_points[0].select_control_point = True
1770         # merge curve an pole
1771         FpxUtilities.enable_edit_mode(True, self.__context)
1772         if ops.curve.make_segment.poll():
1773             ops.curve.make_segment()
1774         FpxUtilities.enable_edit_mode(False, self.__context)
1775
1776     def create_curve(self, name, layers, curve_resolution):
1777         cu = self.__blend_data.curves.new(FORMAT_CURVE.format(name), 'CURVE')
1778         obj = self.__blend_data.objects.new(FORMAT_CURVE_OBJECT.format(name), cu)
1779         self.__context.scene.objects.link(obj)
1780
1781         cu.dimensions = '3D'
1782         cu.twist_mode = 'Z_UP'
1783         cu.splines.new('BEZIER')
1784         spline = cu.splines[-1]
1785         spline.resolution_u = curve_resolution
1786         cu.resolution_u = curve_resolution
1787
1788         obj.layers = layers
1789         return obj, cu, spline
1790
1791     def create_ramp_curve_points(self, spline, fpx_points, z, z0, z1, w0=1.0, w1=1.0):
1792         ramp_length_sum = 0.0
1793         ramp_length = []
1794         last_point = None
1795         for fpx_point in fpx_points:
1796             fpx_position_xy = Vector(fpx_point.get_value("position"))
1797             if last_point:
1798                 length = (fpx_position_xy - last_point).length
1799                 ramp_length_sum += length
1800             ramp_length.append(ramp_length_sum)
1801             last_point = fpx_position_xy
1802
1803         # create_curve_points & radius
1804         spline.bezier_points.add(len(fpx_points) - 1)
1805
1806         for index, fpx_point in enumerate(fpx_points):
1807             fpx_position_xy = fpx_point.get_value("position")
1808             fpx_smooth = fpx_point.get_value("smooth")
1809
1810             factor = (ramp_length[index] / ramp_length_sum)
1811             offset = (z1 - z0) * factor
1812
1813             bezier_point = spline.bezier_points[index]
1814             bezier_point.co = self.geometry_correction((fpx_position_xy[0], fpx_position_xy[1], (z + z0 + offset)))
1815             bezier_point.radius = (w0 + ((w1 - w0) * factor)) / w0
1816
1817             if fpx_smooth:
1818                 handle_type = 'AUTO'
1819             else:
1820                 handle_type = 'VECTOR'
1821
1822             bezier_point.handle_left_type = handle_type
1823             bezier_point.handle_right_type = handle_type
1824
1825         if self.use_hermite_handle:
1826             self.set_catmull_rom_hermite_bezier_handle(spline)
1827
1828     def create_curve_points(self, spline, fpx_points, z=0.0):
1829         spline.bezier_points.add(len(fpx_points) - 1)
1830
1831         for index, fpx_point in enumerate(fpx_points):
1832             fpx_position_xy = fpx_point.get_value("position")
1833             fpx_smooth = fpx_point.get_value("smooth")
1834
1835             bezier_point = spline.bezier_points[index]
1836             bezier_point.co = self.geometry_correction((fpx_position_xy[0], fpx_position_xy[1], z))
1837
1838             if fpx_smooth:
1839                 handle_type = 'AUTO'
1840             else:
1841                 handle_type = 'VECTOR'
1842
1843             bezier_point.handle_left_type = handle_type
1844             bezier_point.handle_right_type = handle_type
1845
1846         if self.use_hermite_handle:
1847             self.set_catmull_rom_hermite_bezier_handle(spline)
1848
1849     def set_catmull_rom_hermite_bezier_handle(self, spline):
1850         if spline.type != 'BEZIER':
1851             return
1852         count_bezier_point = len(spline.bezier_points)
1853         max_index_bezier_point = count_bezier_point - 1
1854         min_index_bezier_point = 0
1855
1856         ## Catmull-Rom
1857         catmull_rom_vectors = []
1858         for index_bezier_point in range(count_bezier_point):
1859             if index_bezier_point > 0 and index_bezier_point < max_index_bezier_point:
1860                 point_prev = spline.bezier_points[index_bezier_point - 1].co
1861                 point_next = spline.bezier_points[index_bezier_point + 1].co
1862                 catmull_rom_vector = (point_next - point_prev) / 2.0
1863             elif not spline.use_cyclic_u and index_bezier_point == 0:
1864                 point_prev = spline.bezier_points[index_bezier_point].co
1865                 point_next = spline.bezier_points[index_bezier_point + 1].co
1866                 catmull_rom_vector = (point_next - point_prev) / 2.0
1867             elif not spline.use_cyclic_u and index_bezier_point == max_index_bezier_point:
1868                 point_prev = spline.bezier_points[index_bezier_point - 1].co
1869                 point_next = spline.bezier_points[index_bezier_point].co
1870                 catmull_rom_vector = (point_next - point_prev) / 2.0
1871             elif spline.use_cyclic_u and index_bezier_point == 0:
1872                 point_prev = spline.bezier_points[max_index_bezier_point].co
1873                 point_next = spline.bezier_points[index_bezier_point + 1].co
1874                 catmull_rom_vector = (point_next - point_prev) / 2.0
1875             elif spline.use_cyclic_u and index_bezier_point == max_index_bezier_point:
1876                 point_prev = spline.bezier_points[index_bezier_point - 1].co
1877                 point_next = spline.bezier_points[min_index_bezier_point].co
1878                 catmull_rom_vector = (point_next - point_prev) / 2.0
1879             else:
1880                 catmull_rom_vector = Vector()
1881             catmull_rom_vectors.append(catmull_rom_vector)
1882
1883         ## Hermite to Cubic Bezier right handles
1884         for index_bezier_point in range(count_bezier_point):
1885             bezier_point = spline.bezier_points[index_bezier_point]
1886             point = bezier_point.co
1887             if bezier_point.handle_right_type in {'VECTOR', }:
1888                 if index_bezier_point < max_index_bezier_point:
1889                     bezier_point_next = spline.bezier_points[index_bezier_point + 1]
1890                     point_next = bezier_point_next.co
1891                     catmull_rom_vector = (point_next - point) / 2.0
1892                 elif spline.use_cyclic_u and index_bezier_point == max_index_bezier_point:
1893                     bezier_point_next = spline.bezier_points[min_index_bezier_point]
1894                     point_next = bezier_point_next.co
1895                     catmull_rom_vector = (point_next - point) / 2.0
1896                 else:
1897                     bezier_point_prev = spline.bezier_points[index_bezier_point - 1]
1898                     point_prev = bezier_point_prev.co
1899                     catmull_rom_vector = (point - point_prev) / 2.0
1900             else:
1901                 catmull_rom_vector = catmull_rom_vectors[index_bezier_point]
1902             bezier_handle_point = point + (catmull_rom_vector / 3.0)
1903             bezier_point.handle_right_type = 'FREE'
1904             bezier_point.handle_right = bezier_handle_point
1905
1906         ## Hermite to Cubic Bezier left handles
1907         for index_bezier_point in range(count_bezier_point):
1908             bezier_point = spline.bezier_points[index_bezier_point]
1909             point = bezier_point.co
1910             if bezier_point.handle_left_type in {'VECTOR', }:
1911                 bezier_point.handle_left_type = 'FREE'
1912                 if index_bezier_point > 0:
1913                     bezier_point_prev = spline.bezier_points[index_bezier_point - 1]
1914                     point_prev = bezier_point_prev.co
1915                     catmull_rom_vector = (point - point_prev) / 2.0
1916                 elif spline.use_cyclic_u and index_bezier_point == min_index_bezier_point:
1917                     bezier_point_prev = spline.bezier_points[max_index_bezier_point]
1918                     point_prev = bezier_point_prev.co
1919                     catmull_rom_vector = (point - point_prev) / 2.0
1920                 else:
1921                     bezier_point_next = spline.bezier_points[index_bezier_point + 1]
1922                     point_next = bezier_point_next.co
1923                     catmull_rom_vector = (point_next - point) / 2.0
1924             else:
1925                 bezier_point.handle_left_type = 'ALIGNED'
1926                 bezier_point.handle_right_type = 'ALIGNED'
1927                 catmull_rom_vector = catmull_rom_vectors[index_bezier_point]
1928             bezier_handle_point = point - (catmull_rom_vector / 3.0)
1929             #bezier_point.handle_left_type = 'FREE'
1930             bezier_point.handle_left = bezier_handle_point
1931
1932     def create_wire_ramp_bevel(self, curve, wire_index):
1933         wire_diameter = [Vector((0.0, -2.0, 0.0)), Vector((-2.0, 0.0, 0.0)), Vector((0.0, 2.0, 0.0)), Vector((2.0, 0.0, 0.0))]
1934         wire_position = [Vector((-11.0, -2.0, 0.0)), Vector((11.0, -2.0, 0.0)), Vector((-17.0, 11, 0.0)), Vector((17.0, 11.0, 0.0)), Vector((-11.0, 24.0, 0.0)), Vector((11.0, 24.0, 0.0)), Vector((0.0, 33.0, 0.0))]
1935         w0 = Vector((0.0, 0.0, 0.0))
1936         handle = 'AUTO'
1937         curve.splines.new('BEZIER')
1938         p0 = wire_position[wire_index] + w0
1939         spline = curve.splines[-1]
1940         spline.resolution_u = self.resolution_wire_bevel
1941         spline.use_cyclic_u = True
1942         spline.bezier_points.add(3)
1943         spline.bezier_points[0].co = p0 + wire_diameter[0]
1944         spline.bezier_points[0].handle_left_type = handle
1945         spline.bezier_points[0].handle_right_type = handle
1946         spline.bezier_points[1].co = p0 + wire_diameter[1]
1947         spline.bezier_points[1].handle_left_type = handle
1948         spline.bezier_points[1].handle_right_type = handle
1949         spline.bezier_points[2].co = p0 + wire_diameter[2]
1950         spline.bezier_points[2].handle_left_type = handle
1951         spline.bezier_points[2].handle_right_type = handle
1952         spline.bezier_points[3].co = p0 + wire_diameter[3]
1953         spline.bezier_points[3].handle_left_type = handle
1954         spline.bezier_points[3].handle_right_type = handle
1955
1956     def prepare_wire_ramp_bevel(self):
1957         bevel_name = "__fpx_guide_ramp_wire_bevel__"
1958         wire_bevel = self.__blend_data.objects.get(bevel_name)
1959         if wire_bevel is None:
1960             cu = self.__blend_data.curves.new(bevel_name, 'CURVE')
1961             wire_bevel = self.__blend_data.objects.new(bevel_name, cu)
1962             self.__context.scene.objects.link(wire_bevel)
1963             cu.dimensions = '2D'
1964             cu.resolution_u = self.resolution_wire_bevel
1965
1966             self.create_wire_ramp_bevel(cu, 0) # base left inner
1967             self.create_wire_ramp_bevel(cu, 1) # base right inner
1968
1969             if self.debug_create_full_ramp_wires:
1970                 """
1971                 there are problems, see [#36007] http://projects.blender.org/tracker/index.php?func=detail&aid=36007&group_id=9&atid=498
1972                 """
1973                 self.create_wire_ramp_bevel(cu, 2) # left inner
1974                 self.create_wire_ramp_bevel(cu, 3) # right inner
1975                 self.create_wire_ramp_bevel(cu, 4) # upper left inner
1976                 self.create_wire_ramp_bevel(cu, 5) # upper right inner
1977                 self.create_wire_ramp_bevel(cu, 6) # top outer
1978             else:
1979                 pass
1980
1981         return wire_bevel
1982
1983     def prepare_wire_ramp_side_bevel(self, wire_index):
1984         bevel_name = "__fpx_guide_ramp_wire_bevel_{}__".format(wire_index)
1985         wire_bevel = self.__blend_data.objects.get(bevel_name)
1986         if wire_bevel is None:
1987             cu = self.__blend_data.curves.new(bevel_name, 'CURVE')
1988             wire_bevel = self.__blend_data.objects.new(bevel_name, cu)
1989             self.__context.scene.objects.link(wire_bevel)
1990             cu.dimensions = '2D'
1991             cu.resolution_u = self.resolution_wire_bevel
1992
1993             self.create_wire_ramp_bevel(cu, wire_index)
1994
1995         return wire_bevel
1996
1997     ###########################################################################
1998     def geometry_correction(self, value):
1999         return Vector((value[0], -value[1], value[2]))
2000
2001     def angle_correction(self, value):
2002         return -90 - value
2003
2004     def attach_dupli_group(self, blender_empty_object, layers, fpx_model_name, fpx_type_name, offset=Vector(), angle=0):
2005         fpx_model_name = FpxUtilities.toGoodName(fpx_model_name) ####
2006         if fpx_model_name in self.debug_missing_resources:
2007             return
2008
2009         if fpx_type_name == 'RAW':
2010             blender_group_name = FpxUtilities.toGoodName(FORMAT_GROUP.format(fpx_model_name))
2011             self.LoadObjectLite(blender_group_name, Fpt_PackedLibrary_Type.TYPE_MODEL)
2012         if fpx_type_name == 'LOCAL':
2013             blender_group_name = FpxUtilities.toGoodName(FORMAT_RESOURCE.format(PREFIX_LOCAL, FORMAT_GROUP.format(fpx_model_name)))
2014             self.LoadObjectLite(blender_group_name, Fpt_PackedLibrary_Type.TYPE_MODEL)
2015         else:
2016             fpx_model_object = self.fpx_pinmodels.get(fpx_model_name)
2017             if not fpx_model_object:
2018                 if self.verbose in FpxUI.VERBOSE_NORMAL:
2019                     print("#DEBUG attach_dupli_group, fpx_pinmodel not found!", fpx_model_name, fpx_type_name)
2020                     self.debug_missing_resources.add(fpx_model_name)
2021                 return
2022             blender_group_name = fpx_model_object[self.BLENDER_OBJECT_NAME]
2023
2024         if self.__blend_data.groups.get(blender_group_name):
2025             blender_empty_object_new = self.__blend_data.objects.new(FORMAT_DUPLI_OBJECT.format(blender_empty_object.name), None)
2026             blender_empty_object_new.location = offset
2027             blender_empty_object_new.rotation_mode = blender_empty_object.rotation_mode
2028             blender_empty_object_new.rotation_euler = Euler((0, 0, radians(angle)), blender_empty_object.rotation_mode)
2029             blender_empty_object_new.empty_draw_type = blender_empty_object.empty_draw_type
2030             blender_empty_object_new.empty_draw_size = blender_empty_object.empty_draw_size
2031             self.__context.scene.objects.link(blender_empty_object_new)
2032
2033             blender_empty_object_new.parent = blender_empty_object
2034
2035             blender_empty_object_new.dupli_type = 'GROUP'
2036             blender_empty_object_new.dupli_group = self.__blend_data.groups[blender_group_name]
2037
2038             blender_empty_object_new.layers = layers
2039         else:
2040             print("#DEBUG attach_dupli_group, blender_group not found!", fpx_model_name, fpx_type_name, blender_group_name)
2041             self.debug_missing_resources.add(fpx_model_name)
2042
2043         # add name to fpt property
2044         blender_empty_object.fpt.add_model(fpx_type_name, fpx_model_name)
2045
2046     ###########################################################################
2047     def FpxLayerToBlenderLayers(self, layer, id=None, render=None, alpha=None, sphere_mapping=None, crystal=None, base=None):
2048         if layer is None:
2049             layer = 0x000
2050
2051         if id is None:
2052             id = 0
2053
2054         if render is None:
2055             render = True
2056
2057         if alpha is None:
2058             alpha = 10
2059
2060         if crystal is None:
2061             crystal = False
2062
2063         if base is None:
2064             base = False
2065
2066         layers = []
2067         for index in range(20):
2068             # layers, left block, top row
2069             if index == 0:
2070                 layers.append(True)
2071             elif index == 1 and (render and alpha > 0): # visible objects
2072                 layers.append(True)
2073             elif index == 2 and (not render or alpha <= 0): # invisible objects
2074                 layers.append(True)
2075             elif index == 3 and id in FptElementType.SET_CURVE_OBJECTS: # curve object
2076                 layers.append(True)
2077             elif index == 4 and id in FptElementType.SET_MESH_OBJECTS: # mesh object
2078                 layers.append(True)
2079
2080             # layers, left block, bottom row
2081             elif index == 10 and id in FptElementType.SET_LIGHT_OBJECTS: # light object
2082                 layers.append(True)
2083             elif index == 11 and id in FptElementType.SET_RUBBER_OBJECTS: # rubber object
2084                 layers.append(True)
2085             elif index == 12 and ((id in FptElementType.SET_SPHERE_MAPPING_OBJECTS and sphere_mapping) or id in FptElementType.SET_WIRE_OBJECTS): # chrome object
2086                 layers.append(True)
2087             elif index == 13 and (crystal or (alpha > 0 and alpha < 10)): # crystal and transparent but visible objects
2088                 layers.append(True)
2089             elif index == 14: # TODO: base mesh object
2090                 layers.append(False)
2091
2092             # layers, right block, top row
2093             elif index == 5 and (layer & 0x002) == 0x002: # layer 2
2094                 layers.append(True)
2095             elif index == 6 and (layer & 0x008) == 0x008: # layer 4
2096                 layers.append(True)
2097             elif index == 7 and (layer & 0x020) == 0x020: # layer 6
2098                 layers.append(True)
2099             elif index == 8 and (layer & 0x080) == 0x080: # layer 8
2100                 layers.append(True)
2101             elif index == 9 and (layer & 0x200) == 0x200: # layer 0
2102                 layers.append(True)
2103
2104             # layers, right block, bottom row
2105             elif index == 15 and (layer & 0x001) == 0x001: # layer 1
2106                 layers.append(True)
2107             elif index == 16 and (layer & 0x004) == 0x004: # layer 3
2108                 layers.append(True)
2109             elif index == 17 and (layer & 0x010) == 0x010: # layer 5
2110                 layers.append(True)
2111             elif index == 18 and (layer & 0x040) == 0x040: # layer 7
2112                 layers.append(True)
2113             elif index == 19 and (layer & 0x100) == 0x100: # layer 9
2114                 layers.append(True)
2115
2116             else:
2117                 layers.append(False)
2118         return tuple(layers)
2119
2120     def LoadObjectLite(self, name, type):
2121         """
2122         name: 'fpmodel.fpl\\<object>.g', 'fpmodel.fpl\\<object>.i'
2123         type: 'IMAGE', 'MODEL'
2124         """
2125         obj = self.LoadFromEmbedded(name, type)
2126
2127         if not obj:
2128             obj = self.LoadFromBlendLibrary(name, type, self.blend_resource_file)
2129
2130         if not obj:
2131             print("#DEBUG resource finally not found", name, type, lib)
2132
2133         return obj
2134
2135     def LoadObject(self, name, type, lib):
2136         """
2137         name: 'fpmodel.fpl\\<object>.g', 'fpmodel.fpl\\<object>.i'
2138         type: 'IMAGE', 'MODEL'
2139         lib_name: fpmodel.fpl
2140         path_name: '.\\', 'C:\\FuturePinball\\Libraries\\', '<addons>\\io_scene_fpx\\'
2141         """
2142         #print("#DEBUG LoadObject", name, type, lib)
2143
2144         obj = self.LoadFromEmbedded(name, type)
2145
2146         if not obj and lib:
2147             obj = self.LoadFromPathLibrary(name, type, lib, self.folder_name)
2148
2149         if not obj:
2150             obj = self.LoadFromBlendLibrary(name, type, self.blend_resource_file)
2151
2152         if not obj and lib:
2153             obj = self.LoadFromPathLibrary(name, type, lib, self.path_libraries)
2154
2155         if not obj:
2156             print("#DEBUG resource finally not found", name, type, lib)
2157
2158         return obj
2159
2160     def LoadFromEmbedded(self, name, type):
2161         #print("#DEBUG LoadFromEmbedded", name, type)
2162
2163         if type == Fpt_PackedLibrary_Type.TYPE_IMAGE:
2164             data_from_dict = self.__blend_data.images
2165         elif type == Fpt_PackedLibrary_Type.TYPE_MODEL:
2166             #print("#DEBUG LoadFromEmbedded groups", [g for g in self.__blend_data.groups])
2167             data_from_dict = self.__blend_data.groups
2168         else:
2169             return None
2170         return data_from_dict.get(name)
2171
2172     def LoadFromBlendLibrary(self, name, type, file):
2173         """
2174         name: 'fpmodel.fpl\\<object>.g'
2175         type: 'IMAGE', 'MODEL'
2176         file: '<addons>\\io_scene_fpx\\fpx_resource.blend'
2177         """
2178         #print("#DEBUG LoadFromBlendLibrary", name, type, file)
2179
2180         with self.__blend_data.libraries.load(file) as (data_from, data_to):
2181             # imports data from library
2182             if type == Fpt_PackedLibrary_Type.TYPE_IMAGE:
2183                 data_from_list = data_from.images
2184                 name_temp = name
2185
2186                 if name_temp not in data_from.images:
2187                     return None
2188                 # embed image data from library
2189                 data_to.images = [name_temp, ]
2190
2191             elif type == Fpt_PackedLibrary_Type.TYPE_MODEL:
2192                 if name.endswith(".g"):
2193                     name_scene = "{}.s".format(name[:-2])
2194                     if name_scene not in data_from.scenes:
2195                         return None
2196                     # embed scene data from library
2197                     data_to.scenes = [name_scene, ]
2198
2199                 if name not in data_from.groups:
2200                     return None
2201                 # embed group data from library
2202                 data_to.groups = [name, ]
2203
2204             else:
2205                 return None
2206
2207         # try to get internal data
2208         return self.LoadFromEmbedded(name, type)
2209
2210     def LoadFromPathLibrary(self, name, type, lib, folder):
2211         """
2212         name: 'fpmodel.fpl\\<object>.g'
2213         type: 'IMAGE', 'MODEL'
2214         lib:  'fpmodel.fpl'
2215         folder: '.\\'
2216         """
2217         #print("#DEBUG LoadFromPathLibrary", name, type, lib, folder)
2218
2219         filepath = path.join(folder, lib)
2220         if path.exists(filepath):
2221             FplImporter(
2222                     report=self.report,
2223                     verbose=self.verbose,
2224                     keep_temp=self.keep_temp,
2225                     use_library_filter=self.use_library_filter,
2226                     use_model_filter=self.use_model_filter,
2227                     use_model_adjustment=self.use_model_adjustment,
2228                     keep_name=False,
2229                     ).read(
2230                             self.__context,
2231                             filepath,
2232                             )
2233
2234             return self.LoadFromEmbedded(name, type)
2235
2236         return None
2237
2238     def GetLinked(self, dictIn, dictOut, type, dst_sub_path_names):
2239         """
2240         loads external resources
2241         """
2242         if type not in self.use_library_filter:
2243             return
2244
2245         for key, fpx_item in dictIn.items():
2246             if not fpx_item:
2247                 continue
2248
2249             fpx_item_name = fpx_item.get_value("name")
2250             fpx_item_name = FpxUtilities.toGoodName(fpx_item_name) ####
2251
2252             if type == Fpt_PackedLibrary_Type.TYPE_IMAGE:
2253                 blender_resource_name_format = FORMAT_IMAGE.format(FORMAT_RESOURCE)
2254             elif type == Fpt_PackedLibrary_Type.TYPE_MODEL:
2255                 blender_resource_name_format = FORMAT_GROUP.format(FORMAT_RESOURCE)
2256             else:
2257                 ## TODO
2258                 continue
2259
2260             lib_name = None
2261
2262             if fpx_item.get_value("linked"):
2263                 #print("#DEBUG GetLinked linked > ", type, fpx_item_name)
2264
2265                 linked_path = fpx_item.get_value("linked_path").lower()
2266                 library_file, file_name = linked_path.split(Fpt_File_Reader.SEPARATOR)
2267                 library_file = FpxUtilities.toGoodName(library_file)
2268                 file_name = FpxUtilities.toGoodName(file_name)
2269
2270                 lib_name = library_file
2271
2272                 if file_name.endswith(".fpm") or file_name.endswith(".jpg") or file_name.endswith(".bmp") or file_name.endswith(".tga"):
2273                     file_name = file_name[:-4]
2274
2275                 if library_file == "":
2276                     prefix_library_file = PREFIX_LOCAL
2277                 else:
2278                     prefix_library_file = library_file
2279
2280                 blender_resource_name = FpxUtilities.toGoodName(blender_resource_name_format.format(prefix_library_file, file_name))
2281
2282                 dictOut[fpx_item_name] = [ blender_resource_name, ]
2283
2284             else:
2285                 #print("#DEBUG GetLinked intern > ", type, fpx_item_name)
2286
2287                 blender_resource_name = FpxUtilities.toGoodName(blender_resource_name_format.format(PREFIX_EMBEDDED, fpx_item_name))
2288                 dictOut[fpx_item_name] = [ blender_resource_name, ]
2289                 item_data = dst_sub_path_names.get("data_{}".format(fpx_item_name))
2290                 if item_data:
2291                     #print("#DEBUG", fpx_item_name, item_data[1]["sub_dir"])
2292                     active_scene = self.__context.screen.scene
2293                     FpmImporter(
2294                             report=self.report,
2295                             verbose=self.verbose,
2296                             keep_temp=self.keep_temp,
2297                             use_scene_per_model=True,
2298                             name_extra="",
2299                             use_model_filter=self.use_model_filter,
2300                             use_model_adjustment=self.use_model_adjustment,
2301                             keep_name=False,
2302                         ).read_ex(
2303                                 blender_context=self.__context,
2304                                 dst_sub_path_names=item_data[1],
2305                                 model_name=FpxUtilities.toGoodName(FORMAT_RESOURCE.format(PREFIX_EMBEDDED, fpx_item_name)),
2306                                 debug_data=[],
2307                                 )
2308                     #rename_active_fpm(self.__context, blender_resource_name)
2309                     self.__context.screen.scene = active_scene
2310
2311             self.LoadObject(blender_resource_name, type, lib_name)
2312
2313     ###########################################################################
2314
2315 ###############################################################################
2316 def get_min_max(blender_object):
2317     min_x = max_x = min_y = max_y = min_z = max_z = None
2318
2319     for vert in blender_object.data.vertices:
2320         x, y, z = vert.co
2321
2322         if min_x is None:
2323             min_x = max_x = x
2324             min_y = max_y = y
2325             min_z = max_z = z
2326             continue
2327
2328         if x < min_x:
2329             min_x = x
2330         elif x > max_x:
2331             max_x = x
2332
2333         if y < min_y:
2334             min_y = y
2335         elif y > max_y:
2336             max_y = y
2337
2338         if z < min_z:
2339             min_z = z
2340         elif z > max_z:
2341             max_z = z
2342
2343     return min_x, min_y, min_z, max_x, max_y, max_z
2344
2345 def adjust_position(blender_context, blender_scene, fpx_model, fpx_model_type=None):
2346     if not blender_context.active_object:
2347         return
2348     fpx_type = fpx_model.get("type")
2349     has_mask = fpx_model.get("mask_model_data")
2350
2351     blender_object = blender_context.active_object
2352     blender_parent = blender_object.parent
2353
2354     # Fpm_Model_Type.OBJECT_OBJECT = 0
2355     ## Fpm_Model_Type.OBJECT_PEG = 1
2356     ## Fpm_Model_Type.OBJECT_ORNAMENT = 8
2357
2358     # Fpm_Model_Type.CONTROL_BUMPER_BASE = 3
2359     # Fpm_Model_Type.CONTROL_BUMPER_CAP = 4
2360
2361     ## Fpm_Model_Type.CONTROL_FLIPPER = 2
2362     # Fpm_Model_Type.CONTROL_PLUNGER = 7
2363     # Fpm_Model_Type.CONTROL_KICKER = 9
2364     # Fpm_Model_Type.CONTROL_DIVERTER = 18
2365     # Fpm_Model_Type.CONTROL_AUTOPLUNGER = 19
2366     # Fpm_Model_Type.CONTROL_POPUP = 20
2367     # Fpm_Model_Type.CONTROL_EMKICKER = 24
2368
2369     # Fpm_Model_Type.TARGET_TARGET = 5
2370     # Fpm_Model_Type.TARGET_DROP = 6
2371     # Fpm_Model_Type.TARGET_VARI = 26
2372
2373     # Fpm_Model_Type.TRIGGER_TRIGGER = 12
2374     # Fpm_Model_Type.TRIGGER_GATE = 15
2375     # Fpm_Model_Type.TRIGGER_SPINNER = 16
2376     # Fpm_Model_Type.TRIGGER_OPTO = 25
2377
2378     ## Fpm_Model_Type.LIGHT_FLASHER = 13
2379     ## Fpm_Model_Type.LIGHT_BULB = 14
2380
2381     ## Fpm_Model_Type.TOY_SPINNINGDISK = 23
2382     ## Fpm_Model_Type.TOY_CUSTOM = 17
2383
2384     # Fpm_Model_Type.GUIDE_LANE = 10
2385     # Fpm_Model_Type.RUBBER_MODEL = 11
2386     # Fpm_Model_Type.RAMP_MODEL = 21
2387     # Fpm_Model_Type.RAMP_WIRE_CAP = 22
2388
2389     # fpx_model_type=None
2390     # fpx_model_type="lo"
2391     # fpx_model_type="ma"
2392     # fpx_model_type="mi"
2393
2394     # bumper ring = top + 31
2395     #
2396     #
2397
2398     blender_location = None
2399     if fpx_type in {
2400             Fpm_Model_Type.OBJECT_PEG, #
2401             Fpm_Model_Type.OBJECT_ORNAMENT, # mask
2402             Fpm_Model_Type.CONTROL_BUMPER_BASE, #
2403             Fpm_Model_Type.CONTROL_FLIPPER, #
2404             Fpm_Model_Type.CONTROL_DIVERTER, #
2405             Fpm_Model_Type.CONTROL_AUTOPLUNGER,
2406             Fpm_Model_Type.CONTROL_KICKER, #
2407             Fpm_Model_Type.LIGHT_FLASHER, # mask
2408             Fpm_Model_Type.LIGHT_BULB, #
2409             Fpm_Model_Type.TRIGGER_OPTO, #
2410             Fpm_Model_Type.TOY_CUSTOM,
2411             }:
2412         static_offset = 0
2413         if has_mask:
2414             #align to top
2415             #blender_location = Vector((blender_parent.location.x, blender_parent.location.y, -blender_object.dimensions.z / 2.0))
2416             blender_location = Vector((blender_parent.location.x, blender_parent.location.y, get_min_max(blender_object)[2] + static_offset))
2417         else:
2418             # align to bottom
2419             #blender_location = Vector((blender_parent.location.x, blender_parent.location.y, blender_object.dimensions.z / 2.0))
2420             blender_location = Vector((blender_parent.location.x, blender_parent.location.y, get_min_max(blender_object)[5] + static_offset))
2421
2422     elif fpx_type in {
2423             Fpm_Model_Type.CONTROL_BUMPER_CAP, #
2424             }:
2425         # align to bottom + static offset
2426         static_offset = 31.5
2427         #blender_location = Vector((blender_parent.location.x, blender_parent.location.y, (blender_object.dimensions.z / 2.0) + static_offset))
2428         blender_location = Vector((blender_parent.location.x, blender_parent.location.y, get_min_max(blender_object)[5] + static_offset))
2429     elif fpx_type in {
2430             Fpm_Model_Type.TOY_SPINNINGDISK, #
2431             }:
2432         # align to top + static offset
2433         static_offset = 0.25
2434         #blender_location = Vector((blender_parent.location.x, blender_parent.location.y, (-blender_object.dimensions.z / 2.0) + static_offset))
2435         blender_location = Vector((blender_parent.location.x, blender_parent.location.y, get_min_max(blender_object)[2] + static_offset))
2436     elif fpx_type in {
2437             Fpm_Model_Type.TRIGGER_TRIGGER, #
2438             }:
2439         # dont touch
2440         pass
2441     elif fpx_type in {
2442             Fpm_Model_Type.TRIGGER_SPINNER, #
2443             }:
2444         # static offset
2445         static_offset = 3
2446         blender_location = Vector((blender_parent.location.x, blender_parent.location.y, blender_parent.location.z + static_offset))
2447     elif fpx_type in {
2448             Fpm_Model_Type.TRIGGER_GATE, #
2449             }:
2450         # align to top + static offset
2451         static_offset = 6
2452         #blender_location = Vector((blender_parent.location.x, blender_parent.location.y, (-blender_object.dimensions.z / 2.0) + static_offset))
2453         blender_location = Vector((blender_parent.location.x, blender_parent.location.y, get_min_max(blender_object)[2] + static_offset))
2454     elif fpx_type in {
2455             Fpm_Model_Type.CONTROL_POPUP, #
2456             }:
2457         # align to top
2458         static_offset = 0
2459         #blender_location = Vector((blender_parent.location.x, blender_parent.location.y, (-blender_object.dimensions.z / 2.0) + static_offset))
2460         blender_location = Vector((blender_parent.location.x, blender_parent.location.y, get_min_max(blender_object)[2] + static_offset))
2461     elif fpx_type in {
2462             Fpm_Model_Type.TARGET_DROP, #
2463             }:
2464         # static offset
2465         static_offset = 12.5
2466         blender_location = Vector((blender_parent.location.x, blender_parent.location.y, blender_parent.location.z + static_offset))
2467     elif fpx_type in {
2468             Fpm_Model_Type.TARGET_TARGET, #
2469             }:
2470         # static offset
2471         static_offset = 15
2472         blender_location = Vector((blender_parent.location.x, blender_parent.location.y, blender_parent.location.z + static_offset))
2473     elif fpx_type in {
2474             Fpm_Model_Type.RAMP_WIRE_CAP, #
2475             }:
2476         # static offset
2477         static_offset = 13
2478         blender_location = Vector((blender_parent.location.x, blender_parent.location.y, blender_parent.location.z + static_offset))
2479     elif fpx_type in {
2480             Fpm_Model_Type.OBJECT_OBJECT, # wire ring
2481             }:
2482         # static offset
2483         static_offset = 11
2484         blender_location = Vector((blender_parent.location.x, blender_parent.location.y, blender_parent.location.z + static_offset))
2485     elif fpx_type in {
2486             Fpm_Model_Type.RUBBER_MODEL, #
2487             Fpm_Model_Type.GUIDE_LANE, #
2488             Fpm_Model_Type.RAMP_MODEL, #
2489             }:
2490         # align to bottom + static offset
2491         static_offset = 0
2492         blender_location = Vector((blender_parent.location.x, blender_parent.location.y, get_min_max(blender_object)[5] + static_offset))
2493     else:
2494         pass
2495
2496     if blender_location:
2497         blender_scene.objects.active = blender_parent
2498         blender_scene.objects.active.location = blender_location
2499         blender_scene.update()
2500
2501 def remove_material(blender_context):
2502     if not blender_context.active_object:
2503         return
2504     active_object = blender_context.active_object
2505     blender_data = blender_context.blend_data
2506
2507     used_materials = []
2508     used_textures = []
2509     used_images = []
2510
2511     for material_slot in active_object.material_slots:
2512         if not material_slot or not material_slot.material:
2513             continue
2514         material = material_slot.material
2515         used_materials.append(material)
2516         for texture_slot in material.texture_slots:
2517             if not texture_slot or not texture_slot.texture:
2518                 continue
2519             texture = texture_slot.texture
2520             used_textures.append(texture)
2521             if texture.type == 'IMAGE' and texture.image:
2522                 used_images.append(texture.image)
2523                 texture.image = None
2524             texture_slot.texture = None
2525         material_slot.material = None
2526
2527     if ops.object.material_slot_remove.poll:
2528         ops.object.material_slot_remove()
2529
2530     for material in used_materials:
2531         material.user_clear()
2532         blender_data.materials.remove(material)
2533
2534     for texture in used_textures:
2535         texture.user_clear()
2536         blender_data.textures.remove(texture)
2537
2538     for image in used_images:
2539         image.user_clear()
2540         blender_data.images.remove(image)
2541
2542 def rename_active_ms3d(blender_context, src_name, dst_name, dst_type=None):
2543     #print("#DEBUG rename_active_ms3d >", blender_context.active_object, src_name, dst_name, dst_type)
2544     if not blender_context.active_object:
2545         return
2546
2547     data = blender_context.blend_data
2548
2549     src_empty_object_name = FORMAT_EMPTY_OBJECT.format(src_name)
2550     src_mesh_object_name = FORMAT_MESH_OBJECT.format(src_name)
2551     src_mesh_name = FORMAT_MESH.format(src_name)
2552     src_armature_name = FORMAT_ARMATURE.format(src_name)
2553     src_armature_object_name = FORMAT_ARMATURE_OBJECT.format(src_name)
2554     src_action_name = FORMAT_ACTION.format(src_name)
2555     src_group_name = FORMAT_GROUP.format(src_name)
2556
2557     if dst_type:
2558         dst_name = "{}.{}".format(dst_name, dst_type)
2559
2560     dst_empty_object_name = FpxUtilities.toGoodName(FORMAT_EMPTY_OBJECT.format(dst_name))
2561     dst_mesh_object_name = FpxUtilities.toGoodName(FORMAT_MESH_OBJECT.format(dst_name))
2562     dst_mesh_name = FpxUtilities.toGoodName(FORMAT_MESH.format(dst_name))
2563     dst_armature_name = FpxUtilities.toGoodName(FORMAT_ARMATURE.format(dst_name))
2564     dst_armature_object_name = FpxUtilities.toGoodName(FORMAT_ARMATURE_OBJECT.format(dst_name))
2565     dst_action_name = FpxUtilities.toGoodName(FORMAT_ACTION.format(dst_name))
2566     dst_group_name = FpxUtilities.toGoodName(FORMAT_GROUP.format(dst_name))
2567
2568     obj = blender_context.blend_data.objects.get(src_empty_object_name)
2569     if obj:
2570         obj.name = dst_empty_object_name
2571
2572     obj = data.objects.get(src_mesh_object_name)
2573     if obj:
2574         obj.name = dst_mesh_object_name
2575         mod = obj.modifiers.get(src_armature_name)
2576         if mod:
2577             mod.name = dst_armature_name
2578
2579     obj = data.objects.get(src_armature_object_name)
2580     if obj:
2581         obj.name = dst_armature_object_name
2582
2583     obj = data.meshes.get(src_mesh_name)
2584     if obj:
2585         obj.name = dst_mesh_name
2586
2587     obj = data.armatures.get(src_armature_name)
2588     if obj:
2589         obj.name = dst_armature_name
2590
2591     obj = data.actions.get(src_action_name)
2592     if obj:
2593         obj.name = dst_action_name
2594
2595     obj = data.groups.get(src_group_name)
2596     if obj:
2597         obj.name = dst_group_name
2598
2599 def rename_active_fpm(blender_context, dst_name):
2600     #print("#DEBUG rename_active_fpm >", blender_context.active_object, dst_name)
2601     if not blender_context.active_object:
2602         return
2603     blender_name = blender_context.active_object.name
2604     fpm_ext = "fpm"
2605     index = blender_name.find(".{}.".format(fpm_ext))
2606     if index < 0:
2607         index = blender_name.rfind(".")
2608         if index < 0:
2609             return
2610
2611     src_name = blender_name[:index]
2612
2613     #print("#DEBUG rename_active_fpm 2>", src_name, dst_name)
2614
2615     #if src_name.endswith(".fpm"):
2616     #    src_name = src_name[:-4]
2617
2618     src_scene_name = blender_context.scene.name
2619
2620     blender_scene = blender_context.blend_data.scenes.get(src_scene_name)
2621     if blender_scene:
2622         blender_scene.name = FORMAT_SCENE.format(dst_name).lower()
2623
2624     for object_type in {'', '.secondary', '.mask', '.reflection', '.collision', }:
2625         fpm_ext_ex = "{}{}".format(src_name, object_type)
2626         rename_active_ms3d(blender_context, fpm_ext_ex, dst_name, object_type);
2627
2628 def get_blend_resource_file_name():
2629     from importlib import ( find_loader, )
2630     from os import ( path, )
2631
2632     module_path = find_loader('io_scene_fpx').path
2633     module_path, module_file = path.split(module_path)
2634
2635     resource_blend = path.join(module_path, 'fpx_resource.blend')
2636
2637     if not path.exists(resource_blend):
2638         print("#DEBUG", "resource not found!")
2639
2640     return resource_blend
2641
2642
2643
2644 ###############################################################################
2645
2646
2647 ###############################################################################
2648 #234567890123456789012345678901234567890123456789012345678901234567890123456789
2649 #--------1---------2---------3---------4---------5---------6---------7---------
2650 # ##### END OF FILE #####