cfox04

ydrexport-pivot

Dec 5th, 2021
816
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. import os
  2. import shutil
  3. import collections
  4. import bmesh
  5. import bpy
  6. from ..resources.drawable import *
  7. from ..resources.shader import ShaderManager
  8. from ..tools.meshhelper import *
  9. from ..tools.utils import *
  10. from ..tools.blenderhelper import *
  11. from ..sollumz_properties import BOUND_TYPES, SOLLUMZ_UI_NAMES, LightType, MaterialType, LODLevel, SollumType
  12. from ..ybn.ybnexport import bound_from_object, composite_from_object
  13.  
  14.  
  15. def get_used_materials(obj):
  16.  
  17.     materials = []
  18.  
  19.     for child in obj.children:
  20.         for grandchild in child.children:
  21.             if(grandchild.sollum_type == SollumType.DRAWABLE_GEOMETRY):
  22.                 mats = grandchild.data.materials
  23.                 for mat in mats:
  24.                     if(mat.sollum_type == MaterialType.SHADER):
  25.                         materials.append(mat)
  26.  
  27.     return materials
  28.  
  29.  
  30. def get_shaders_from_blender(obj):
  31.     shaders = []
  32.  
  33.     materials = get_used_materials(obj)
  34.  
  35.     for material in materials:
  36.         shader = ShaderItem()
  37.         # Maybe make this a property?
  38.         shader.name = material.shader_properties.name
  39.         shader.filename = material.shader_properties.filename
  40.         shader.render_bucket = material.shader_properties.renderbucket
  41.  
  42.         for node in material.node_tree.nodes:
  43.             if isinstance(node, bpy.types.ShaderNodeTexImage):
  44.                 param = TextureShaderParameter()
  45.                 param.name = node.name
  46.                 param.type = "Texture"
  47.                 if node.image == None:
  48.                     param.texture_name = "givemechecker"
  49.                 else:
  50.                     param.texture_name = node.image.name.split('.')[0]
  51.                 shader.parameters.append(param)
  52.             elif isinstance(node, bpy.types.ShaderNodeValue):
  53.                 if node.name[-1] == "x":
  54.                     param = VectorShaderParameter()
  55.                     param.name = node.name[:-2]
  56.                     param.type = "Vector"
  57.  
  58.                     x = node
  59.                     y = material.node_tree.nodes[node.name[:-1] + "y"]
  60.                     z = material.node_tree.nodes[node.name[:-1] + "z"]
  61.                     w = material.node_tree.nodes[node.name[:-1] + "w"]
  62.  
  63.                     param.x = x.outputs[0].default_value
  64.                     param.y = y.outputs[0].default_value
  65.                     param.z = z.outputs[0].default_value
  66.                     param.w = w.outputs[0].default_value
  67.  
  68.                     shader.parameters.append(param)
  69.  
  70.         shaders.append(shader)
  71.  
  72.     return shaders
  73.  
  74.  
  75. def texture_item_from_node(n):
  76.     texture_item = TextureItem()
  77.     if n.image:
  78.         texture_item.name = n.image.name.split('.')[0]
  79.         texture_item.width = n.image.size[0]
  80.         texture_item.height = n.image.size[1]
  81.     else:
  82.         texture_item.name = "none"
  83.         texture_item.width = 0
  84.         texture_item.height = 0
  85.  
  86.     texture_item.usage = SOLLUMZ_UI_NAMES[n.texture_properties.usage]
  87.     texture_item.extra_flags = n.texture_properties.extra_flags
  88.     texture_item.format = SOLLUMZ_UI_NAMES[n.texture_properties.format]
  89.     texture_item.miplevels = 0
  90.     texture_item.filename = texture_item.name + ".dds"
  91.     # texture_item.unk32 = 0
  92.     for prop in dir(n.texture_flags):
  93.         value = getattr(n.texture_flags, prop)
  94.         if value == True:
  95.             texture_item.usage_flags.append(prop.upper())
  96.  
  97.     return texture_item
  98.  
  99.  
  100. def texture_dictionary_from_materials(obj, exportpath):
  101.     texture_dictionary = []
  102.     messages = []
  103.  
  104.     has_td = False
  105.  
  106.     t_names = []
  107.     for mat in get_used_materials(obj):
  108.         nodes = mat.node_tree.nodes
  109.         for n in nodes:
  110.             if(isinstance(n, bpy.types.ShaderNodeTexImage)):
  111.                 if(n.texture_properties.embedded == True):
  112.                     has_td = True
  113.                     texture_item = texture_item_from_node(n)
  114.                     if texture_item.name in t_names:
  115.                         continue
  116.                     else:
  117.                         t_names.append(texture_item.name)
  118.                     texture_dictionary.append(texture_item)
  119.  
  120.                     if n.image:
  121.                         foldername = obj.name
  122.                         folderpath = os.path.join(exportpath, foldername)
  123.                         txtpath = bpy.path.abspath(n.image.filepath)
  124.                         if os.path.isfile(txtpath):
  125.                             if(os.path.isdir(folderpath) == False):
  126.                                 os.mkdir(folderpath)
  127.                             dstpath = folderpath + "\\" + \
  128.                                 os.path.basename(txtpath)
  129.                             # check if paths are the same because if they are no need to copy
  130.                             if txtpath != dstpath:
  131.                                 shutil.copyfile(txtpath, dstpath)
  132.                         else:
  133.                             messages.append(
  134.                                 f"Missing Embedded Texture: {txtpath} please supply texture! The texture will not be copied to the texture folder until entered!")
  135.                     else:
  136.                         messages.append(
  137.                             f"Material: {mat.name} is missing the {n.name} texture and will not be exported.")
  138.  
  139.     if(has_td):
  140.         return texture_dictionary, messages
  141.     else:
  142.         return None, []
  143.  
  144.  
  145. def get_blended_verts(mesh, vertex_groups, bones=None):
  146.     bone_index_map = {}
  147.     if(bones != None):
  148.         for i in range(len(bones)):
  149.             bone_index_map[bones[i].name] = i
  150.  
  151.     blend_weights = []
  152.     blend_indices = []
  153.     for v in mesh.vertices:
  154.         if len(v.groups) > 0:
  155.             bw = [0] * 4
  156.             bi = [0] * 4
  157.             valid_weights = 0
  158.             total_weights = 0
  159.             max_weights = 0
  160.             max_weights_index = -1
  161.  
  162.             for element in v.groups:
  163.                 if element.group >= len(vertex_groups):
  164.                     continue
  165.  
  166.                 vertex_group = vertex_groups[element.group]
  167.                 bone_index = bone_index_map.get(vertex_group.name, -1)
  168.                 # 1/255 = 0.0039 the minimal weight for one vertex group
  169.                 weight = round(element.weight * 255)
  170.                 if (vertex_group.lock_weight == False and bone_index != -1 and weight > 0 and valid_weights < 4):
  171.                     bw[valid_weights] = weight
  172.                     bi[valid_weights] = bone_index
  173.                     if (max_weights < weight):
  174.                         max_weights_index = valid_weights
  175.                         max_weights = weight
  176.                     valid_weights += 1
  177.                     total_weights += weight
  178.  
  179.             # weights normalization
  180.             if valid_weights > 0 and max_weights_index != -1:
  181.                 bw[max_weights_index] = bw[max_weights_index] + \
  182.                     (255 - total_weights)
  183.  
  184.             blend_weights.append(bw)
  185.             blend_indices.append(bi)
  186.         else:
  187.             blend_weights.append([0, 0, 0, 0])
  188.             blend_indices.append([0, 0, 0, 0])
  189.  
  190.     return blend_weights, blend_indices
  191.  
  192.  
  193. def get_mesh_buffers(obj, mesh, vertex_type, bones=None, export_settings=None):
  194.     # thanks dexy
  195.  
  196.     blend_weights, blend_indices = get_blended_verts(
  197.         mesh, obj.vertex_groups, bones)
  198.  
  199.     vertices = {}
  200.     indices = []
  201.  
  202.     for tri in mesh.loop_triangles:
  203.         for loop_idx in tri.loops:
  204.             loop = mesh.loops[loop_idx]
  205.             vert_idx = loop.vertex_index
  206.             mesh_layer_idx = 0
  207.  
  208.             kwargs = {}
  209.  
  210.             if "position" in vertex_type._fields:
  211.                 if mesh.vertices[vert_idx]:
  212.                     drawable = obj.parent.parent
  213.                     # Local pos of drawable empty
  214.                     origin = drawable.matrix_local.translation
  215.                     if export_settings.use_transforms:
  216.                         pos = float32_list(
  217.                             obj.matrix_world @ mesh.vertices[vert_idx].co)
  218.                             obj.matrix_world @ mesh.vertices[vert_idx].co - origin)
  219.                     else:
  220.                         pos = float32_list(
  221.                             obj.matrix_basis @ mesh.vertices[vert_idx].co)
  222.                             obj.matrix_basis @ mesh.vertices[vert_idx].co - origin)
  223.                     kwargs['position'] = tuple(pos)
  224.                 else:
  225.                     kwargs["position"] = tuple([0, 0, 0])
  226.             if "normal" in vertex_type._fields:
  227.                 if loop.normal:
  228.                     normal = float32_list(loop.normal)
  229.                     kwargs["normal"] = tuple(normal)
  230.                 else:
  231.                     kwargs["normal"] = tuple([0, 0, 0])
  232.             if "blendweights" in vertex_type._fields:
  233.                 kwargs['blendweights'] = tuple(blend_weights[vert_idx])
  234.             if "blendindices" in vertex_type._fields:
  235.                 kwargs['blendindices'] = tuple(blend_indices[vert_idx])
  236.             if "tangent" in vertex_type._fields:
  237.                 if loop.tangent:
  238.                     tangent = float32_list(loop.tangent.to_4d())
  239.                     tangent[3] = loop.bitangent_sign  # convert to float 32 ?
  240.                     kwargs["tangent"] = tuple(tangent)
  241.                 else:
  242.                     kwargs["tangent"] = tuple([0, 0, 0, 0])
  243.             for i in range(6):
  244.                 if f"texcoord{i}" in vertex_type._fields:
  245.                     key = f'texcoord{i}'
  246.                     if mesh_layer_idx < len(mesh.uv_layers):
  247.                         data = mesh.uv_layers[mesh_layer_idx].data
  248.                         uv = float32_list(
  249.                             flip_uv(data[loop_idx].uv))
  250.                         kwargs[key] = tuple(uv)
  251.                         mesh_layer_idx += 1
  252.                     else:
  253.                         kwargs[key] = (0, 0)
  254.             for i in range(2):
  255.                 if f"colour{i}" in vertex_type._fields:
  256.                     key = f'colour{i}'
  257.                     if i < len(mesh.vertex_colors):
  258.                         data = mesh.vertex_colors[i].data
  259.                         kwargs[key] = tuple(
  260.                             int(val * 255) for val in data[loop_idx].color)
  261.                     else:
  262.                         kwargs[key] = (0, 0, 0, 0)
  263.  
  264.             vertex = vertex_type(**kwargs)
  265.  
  266.             if vertex in vertices:
  267.                 idx = vertices[vertex]
  268.             else:
  269.                 idx = len(vertices)
  270.                 vertices[vertex] = idx
  271.  
  272.             indices.append(idx)
  273.  
  274.     return vertices.keys(), indices
  275.  
  276.  
  277. def get_semantic_from_object(shader, mesh):
  278.  
  279.     sematic = []
  280.  
  281.     # always has a position
  282.     sematic.append(VertexSemantic.position)
  283.     # add blend weights and blend indicies
  284.     # maybe pass is_skinned param in this function and check there ?
  285.     is_skinned = False
  286.     for v in mesh.vertices:
  287.         if len(v.groups) > 0:
  288.             is_skinned = True
  289.             break
  290.     if is_skinned:
  291.         sematic.append(VertexSemantic.blend_weight)
  292.         sematic.append(VertexSemantic.blend_index)
  293.     # add normal
  294.     # dont know what to check so always add for now??
  295.     sematic.append(VertexSemantic.normal)
  296.     # add colors
  297.     vcs = len(mesh.vertex_colors)
  298.     if vcs > 0:
  299.         for vc in mesh.vertex_colors:
  300.             if vc.name != "TintColor":
  301.                 sematic.append(VertexSemantic.color)
  302.     # add texcoords
  303.     tcs = len(mesh.uv_layers)
  304.     if tcs > 0:
  305.         if tcs > 8:  # or tcs == 0: add this restriction?? although some vertexs buffers may not have uv data???
  306.             raise Exception(f"To many uv layers or none on mesh: {mesh.name}")
  307.         for i in range(tcs):
  308.             sematic.append(VertexSemantic.texcoord)
  309.     # add tangents
  310.     if shader.required_tangent:
  311.         sematic.append(VertexSemantic.tangent)
  312.  
  313.     return "".join(sematic)
  314.  
  315.  
  316. def apply_and_triangulate_object(obj):
  317.     depsgraph = bpy.context.evaluated_depsgraph_get()
  318.     obj_eval = obj.evaluated_get(depsgraph)
  319.     mesh = bpy.data.meshes.new_from_object(
  320.         obj_eval, preserve_all_data_layers=True, depsgraph=depsgraph)
  321.     tempmesh = bmesh.new()
  322.     tempmesh.from_mesh(mesh)
  323.     bmesh.ops.triangulate(tempmesh, faces=tempmesh.faces)
  324.     tempmesh.to_mesh(mesh)
  325.     tempmesh.free()
  326.     mesh.calc_tangents()
  327.     mesh.calc_loop_triangles()
  328.     return obj_eval, mesh
  329.  
  330.  
  331. def get_shader_index(mats, mat):
  332.     for i in range(len(mats)):
  333.         if mats[i].as_pointer() == mat.as_pointer():
  334.             return i
  335.  
  336.  
  337. def geometry_from_object(obj, mats, bones=None, export_settings=None):
  338.     geometry = GeometryItem()
  339.  
  340.     geometry.shader_index = get_shader_index(mats, obj.active_material)
  341.  
  342.     obj, mesh = apply_and_triangulate_object(obj)
  343.  
  344.     bbmin, bbmax = get_bound_extents(obj, world=export_settings.use_transforms)
  345.     geometry.bounding_box_min = bbmin
  346.     geometry.bounding_box_max = bbmax
  347.  
  348.     shader_name = obj.active_material.shader_properties.name
  349.     shader = ShaderManager.shaders[shader_name]
  350.  
  351.     layout = shader.get_layout_from_semantic(
  352.         get_semantic_from_object(shader, mesh))
  353.  
  354.     geometry.vertex_buffer.layout = layout.value
  355.     vertex_buffer, index_buffer = get_mesh_buffers(
  356.         obj, mesh, layout.vertex_type, bones, export_settings)
  357.  
  358.     geometry.vertex_buffer.data = vertex_buffer
  359.     geometry.index_buffer.data = index_buffer
  360.  
  361.     return geometry
  362.  
  363.  
  364. def drawable_model_from_object(obj, bones=None, export_settings=None):
  365.     drawable_model = DrawableModelItem()
  366.  
  367.     drawable_model.render_mask = obj.drawable_model_properties.render_mask
  368.     drawable_model.flags = obj.drawable_model_properties.flags
  369.  
  370.     # rawable_model.bone_index = 0
  371.     if bones is not None:
  372.         drawable_model.has_skin = 1
  373.         drawable_model.unknown_1 = len(bones)
  374.  
  375.     for child in obj.children:
  376.         if child.sollum_type == SollumType.DRAWABLE_GEOMETRY:
  377.             if len(child.data.materials) > 1:
  378.                 # Preserve original order of materials
  379.                 mats = child.data.copy().materials
  380.                 objs = split_object(child, obj)
  381.                 for obj in objs:
  382.                     geometry = geometry_from_object(
  383.                         obj, mats, bones, export_settings)  # MAYBE WRONG ASK LOYALIST
  384.                     drawable_model.geometries.append(geometry)
  385.                 join_objects(objs)
  386.             else:
  387.                 geometry = geometry_from_object(
  388.                     child, get_used_materials(obj.parent), bones, export_settings)
  389.                 drawable_model.geometries.append(geometry)
  390.  
  391.     return drawable_model
  392.  
  393.  
  394. def bone_from_object(obj):
  395.  
  396.     bone = BoneItem()
  397.     bone.name = obj.name
  398.     bone.tag = obj.bone_properties.tag
  399.     bone.index = obj["BONE_INDEX"]
  400.  
  401.     if obj.parent != None:
  402.         bone.parent_index = obj.parent["BONE_INDEX"]
  403.         children = obj.parent.children
  404.         sibling = -1
  405.         if len(children) > 1:
  406.             for i, child in enumerate(children):
  407.                 if child["BONE_INDEX"] == obj["BONE_INDEX"] and i + 1 < len(children):
  408.                     sibling = children[i + 1]["BONE_INDEX"]
  409.                     break
  410.  
  411.         bone.sibling_index = sibling
  412.  
  413.     for flag in obj.bone_properties.flags:
  414.         if len(flag.name) == 0:
  415.             continue
  416.  
  417.         bone.flags.append(flag.name)
  418.  
  419.     if len(obj.children) > 0:
  420.         bone.flags.append("Unk0")
  421.  
  422.     mat = obj.matrix_local
  423.     if (obj.parent != None):
  424.         mat = obj.parent.matrix_local.inverted() @ obj.matrix_local
  425.  
  426.     mat_decomposed = mat.decompose()
  427.  
  428.     bone.translation = mat_decomposed[0]
  429.     bone.rotation = mat_decomposed[1]
  430.     bone.scale = mat_decomposed[2]
  431.     # transform_unk doesn't appear in openformats so oiv calcs it right
  432.     # what does it do? the bone length?
  433.     # default value for this seems to be <TransformUnk x="0" y="4" z="-3" w="0" />
  434.     bone.transform_unk = Quaternion((0, 0, 4, -3))
  435.  
  436.     return bone
  437.  
  438.  
  439. def skeleton_from_object(obj):
  440.  
  441.     if obj.type != 'ARMATURE' or len(obj.pose.bones) == 0:
  442.         return None
  443.  
  444.     skeleton = SkeletonProperty()
  445.     bones = obj.pose.bones
  446.  
  447.     ind = 0
  448.     for pbone in bones:
  449.         bone = pbone.bone
  450.         bone["BONE_INDEX"] = ind
  451.         ind = ind + 1
  452.  
  453.     for pbone in bones:
  454.         bone = bone_from_object(pbone.bone)
  455.         skeleton.bones.append(bone)
  456.  
  457.     return skeleton
  458.  
  459.  
  460. def rotation_limit_from_object(obj):
  461.     for con in obj.constraints:
  462.         if con.type == 'LIMIT_ROTATION':
  463.             joint = RotationLimitItem()
  464.             joint.bone_id = obj.bone.bone_properties.tag
  465.             joint.min = Vector((con.min_x, con.min_y, con.min_z))
  466.             joint.max = Vector((con.max_x, con.max_y, con.max_z))
  467.             return joint
  468.  
  469.     return None
  470.  
  471.  
  472. def joints_from_object(obj):
  473.     if obj.pose is None:
  474.         return None
  475.  
  476.     joints = JointsProperty()
  477.     for bone in obj.pose.bones:
  478.         joint = rotation_limit_from_object(bone)
  479.         if joint is not None:
  480.             joints.rotation_limits.append(joint)
  481.  
  482.     return joints
  483.  
  484.  
  485. def light_from_object(obj):
  486.     light = LightItem()
  487.     light.position = obj.location
  488.     light.direction = obj.rotation_euler
  489.     light.color = obj.data.color
  490.     light.flashiness = obj.data.specular_factor * 100
  491.     light.intensity = obj.data.energy
  492.     light.type = SOLLUMZ_UI_NAMES[obj.data.light_properties.type]
  493.     light.flags = obj.data.light_properties.flags
  494.     light.bone_id = obj.data.light_properties.bone_id
  495.     light.type = obj.data.light_properties.type
  496.     light.group_id = obj.data.light_properties.group_id
  497.     light.time_flags = obj.data.light_properties.time_flags
  498.     light.falloff = obj.data.light_properties.falloff
  499.     light.falloff_exponent = obj.data.light_properties.falloff_exponent
  500.     cpn = obj.data.light_properties.culling_plane_normal
  501.     light.culling_plane_normal = Vector((cpn[0], cpn[1], cpn[2]))
  502.     light.culling_plane_offset = obj.data.light_properties.culling_plane_offset
  503.     light.unknown_45 = obj.data.light_properties.unknown_45
  504.     light.unknown_46 = obj.data.light_properties.unknown_46
  505.     light.volume_intensity = obj.data.light_properties.volume_intensity
  506.     light.volume_size_scale = obj.data.light_properties.volume_size_scale
  507.     voc = obj.data.light_properties.volume_outer_color
  508.     # relocate but works for now..
  509.     color = collections.namedtuple("Color", ["r", "g", "b"])
  510.     light.volume_outer_color = color(voc[0], voc[1], voc[2])
  511.     light.light_hash = obj.data.light_properties.light_hash
  512.     light.volume_outer_intensity = obj.data.light_properties.volume_outer_intensity
  513.     light.corona_size = obj.data.light_properties.corona_size
  514.     light.volume_outer_exponent = obj.data.light_properties.volume_outer_exponent
  515.     light.light_fade_distance = obj.data.light_properties.light_fade_distance
  516.     light.shadow_fade_distance = obj.data.light_properties.shadow_fade_distance
  517.     light.specular_fade_distance = obj.data.light_properties.specular_fade_distance
  518.     light.volumetric_fade_distance = obj.data.light_properties.volumetric_fade_distance
  519.     light.shadow_near_clip = obj.data.light_properties.shadow_near_clip
  520.     light.corona_intensity = obj.data.light_properties.corona_intensity
  521.     light.corona_z_bias = obj.data.light_properties.corona_z_bias
  522.     tnt = obj.data.light_properties.tangent
  523.     light.tangent = Vector((tnt[0], tnt[1], tnt[2]))
  524.     light.cone_inner_angle = obj.data.light_properties.cone_inner_angle
  525.     light.cone_outer_angle = obj.data.light_properties.cone_outer_angle
  526.     ext = obj.data.light_properties.extent
  527.     light.extent = Vector((ext[0], ext[1], ext[2]))
  528.     light.projected_texture_hash = obj.data.light_properties.projected_texture_hash
  529.  
  530.     return light
  531.  
  532.  
  533. # REALLY NOT A FAN OF PASSING THIS EXPORT OP TO THIS AND APPENDING TO MESSAGES BUT WHATEVER
  534. def drawable_from_object(exportop, obj, exportpath, bones=None, export_settings=None):
  535.     drawable = Drawable()
  536.  
  537.     drawable.name = obj.name
  538.     drawable.bounding_sphere_center = get_bound_center(
  539.         obj, world=export_settings.use_transforms)
  540.         obj, world=export_settings.use_transforms) - obj.matrix_local.translation
  541.     drawable.bounding_sphere_radius = get_obj_radius(
  542.         obj, world=export_settings.use_transforms)
  543.     bbmin, bbmax = get_bound_extents(obj, world=export_settings.use_transforms)
  544.     drawable.bounding_box_min = bbmin
  545.     drawable.bounding_box_max = bbmax
  546.  
  547.     drawable.lod_dist_high = obj.drawable_properties.lod_dist_high
  548.     drawable.lod_dist_med = obj.drawable_properties.lod_dist_high
  549.     drawable.lod_dist_low = obj.drawable_properties.lod_dist_high
  550.     drawable.lod_dist_vlow = obj.drawable_properties.lod_dist_high
  551.  
  552.     shaders = get_shaders_from_blender(obj)
  553.  
  554.     if len(shaders) == 0:
  555.         raise Exception(
  556.             f"No materials on object: {obj.name}, will be skipped.")
  557.  
  558.     for shader in shaders:
  559.         drawable.shader_group.shaders.append(shader)
  560.  
  561.     td, messages = texture_dictionary_from_materials(
  562.         obj, os.path.dirname(exportpath))
  563.     drawable.shader_group.texture_dictionary = td
  564.     exportop.messages += messages
  565.  
  566.     if bones is None:
  567.         if obj.pose is not None:
  568.             bones = obj.pose.bones
  569.  
  570.     drawable.skeleton = skeleton_from_object(obj)
  571.     drawable.joints = joints_from_object(obj)
  572.     if obj.pose is not None:
  573.         for bone in drawable.skeleton.bones:
  574.             pbone = obj.pose.bones[bone.index]
  575.             for con in pbone.constraints:
  576.                 if con.type == 'LIMIT_ROTATION':
  577.                     bone.flags.append("LimitRotation")
  578.                     break
  579.  
  580.     highmodel_count = 0
  581.     medmodel_count = 0
  582.     lowhmodel_count = 0
  583.     vlowmodel_count = 0
  584.  
  585.     for child in obj.children:
  586.         if child.sollum_type == SollumType.DRAWABLE_MODEL:
  587.             drawable_model = drawable_model_from_object(
  588.                 child, bones, export_settings)
  589.             if child.drawable_model_properties.sollum_lod == LODLevel.HIGH:
  590.                 highmodel_count += 1
  591.                 drawable.drawable_models_high.append(drawable_model)
  592.             elif child.drawable_model_properties.sollum_lod == LODLevel.MEDIUM:
  593.                 medmodel_count += 1
  594.                 drawable.drawable_models_med.append(drawable_model)
  595.             elif child.drawable_model_properties.sollum_lod == LODLevel.LOW:
  596.                 lowhmodel_count += 1
  597.                 drawable.drawable_models_low.append(drawable_model)
  598.             elif child.drawable_model_properties.sollum_lod == LODLevel.VERYLOW:
  599.                 vlowmodel_count += 1
  600.                 drawable.drawable_models_vlow.append(drawable_model)
  601.         if child.sollum_type in BOUND_TYPES:
  602.             if child.sollum_type == SollumType.BOUND_COMPOSITE:
  603.                 drawable.bound = composite_from_object(child, export_settings)
  604.             else:
  605.                 drawable.bound = bound_from_object(child, export_settings)
  606.         elif child.type == 'LIGHT' and child.data.light_properties.type != LightType.NONE:
  607.             drawable.lights.append(light_from_object(child))
  608.  
  609.     # flags = model count for each lod
  610.     drawable.flags_high = highmodel_count
  611.     drawable.flags_med = medmodel_count
  612.     drawable.flags_low = lowhmodel_count
  613.     drawable.flags_vlow = vlowmodel_count
  614.     # drawable.unknown_9A = ?
  615.  
  616.     return drawable
  617.  
  618.  
  619. def export_ydr(exportop, obj, filepath, export_settings):
  620.     drawable_from_object(exportop, obj, filepath, None,
  621.                          export_settings).write_xml(filepath)
  622.  
RAW Paste Data