Пример #1
0
def main(moreinfo=True):
    # prompt PMX name
    core.MY_PRINT_FUNC("Please enter name of PMX input file:")
    input_filename_pmx = core.MY_FILEPROMPT_FUNC(".pmx")
    pmx = pmxlib.read_pmx(input_filename_pmx, moreinfo=moreinfo)

    # to shift the model by a set amount:
    # first, ask user for X Y Z

    # create the prompt popup
    shift_str = core.MY_GENERAL_INPUT_FUNC(
        lambda x: (is_3float(x) is not None), [
            "Enter the X,Y,Z amount to shift this model by:",
            "Three decimal values separated by commas.",
            "Empty input will quit the script."
        ])

    # if empty, quit
    if shift_str == "":
        core.MY_PRINT_FUNC("quitting")
        return None
    # use the same func to convert the input string
    shift = is_3float(shift_str)

    ####################
    # then execute the shift:
    for v in pmx.verts:
        # every vertex position
        for i in range(3):
            v.pos[i] += shift[i]
        # c, r0, r1 params of every SDEF vertex
        # these correspond to real positions in 3d space so they need to be modified
        if v.weighttype == pmxstruct.WeightMode.SDEF:
            for param in v.weight_sdef:
                for i in range(3):
                    param[i] += shift[i]

    # bone position
    for b in pmx.bones:
        for i in range(3):
            b.pos[i] += shift[i]

    # rigid body position
    for rb in pmx.rigidbodies:
        for i in range(3):
            rb.pos[i] += shift[i]

    # joint position
    for j in pmx.joints:
        for i in range(3):
            j.pos[i] += shift[i]

    # that's it? that's it!

    # write out
    output_filename_pmx = input_filename_pmx[0:-4] + "_shift.pmx"
    output_filename_pmx = core.get_unused_file_name(output_filename_pmx)
    pmxlib.write_pmx(output_filename_pmx, pmx, moreinfo=moreinfo)
    core.MY_PRINT_FUNC("Done!")
    return None
def main(moreinfo=True):
	# prompt PMX name
	core.MY_PRINT_FUNC("Please enter name of PMX input file:")
	input_filename_pmx = core.MY_FILEPROMPT_FUNC(".pmx")
	pmx = pmxlib.read_pmx(input_filename_pmx, moreinfo=moreinfo)
	
	# usually want to hide many morphs at a time, so put all this in a loop
	num_hidden = 0
	while True:
		core.MY_PRINT_FUNC("")
		# valid input is any string that can matched aginst a morph idx
		s = core.MY_GENERAL_INPUT_FUNC(lambda x: (morph_scale.get_idx_in_pmxsublist(x, pmx.morphs) is not None),
		   ["Please specify the target morph: morph #, JP name, or EN name (names are not case sensitive).",
			"Empty input will quit the script."])
		# do it again, cuz the lambda only returns true/false
		target_index = morph_scale.get_idx_in_pmxsublist(s, pmx.morphs)
		
		# when given empty text, done!
		if target_index == -1 or target_index is None:
			core.MY_PRINT_FUNC("quitting")
			break
		
		# determine the morph type
		morphtype = pmx.morphs[target_index].morphtype
		core.MY_PRINT_FUNC("Found {} morph #{}: '{}' / '{}'".format(
			morphtype, target_index, pmx.morphs[target_index].name_jp, pmx.morphs[target_index].name_en))
		core.MY_PRINT_FUNC("Was group {}, now group {}".format(
			pmx.morphs[target_index].panel, pmxstruct.MorphPanel.HIDDEN))
		# make the actual change
		pmx.morphs[target_index].panel = pmxstruct.MorphPanel.HIDDEN
		num_hidden += 1
		pass
	
	if num_hidden == 0:
		core.MY_PRINT_FUNC("Nothing was changed")
		return None
	
	# last step: remove all invalid morphs from all display panels
	for d, frame in enumerate(pmx.frames):  # for each display group,
		i = 0
		while i < len(frame.items):  # for each item in that display group,
			item = frame.items[i]
			if item.is_morph:  # if it is a morph
				# look up the morph
				morph = pmx.morphs[item.idx]
				# figure out what panel of this morph is
				# if it has an invalid panel #, delete it here
				if morph.panel == pmxstruct.MorphPanel.HIDDEN:
					frame.items.pop(i)
				else:
					i += 1
			else:
				i += 1
	
	# write out
	output_filename_pmx = input_filename_pmx[0:-4] + "_morphhide.pmx"
	output_filename_pmx = core.get_unused_file_name(output_filename_pmx)
	pmxlib.write_pmx(output_filename_pmx, pmx, moreinfo=moreinfo)
	core.MY_PRINT_FUNC("Done!")
	return None
def main(moreinfo=True):
    # prompt PMX name
    core.MY_PRINT_FUNC("Please enter name of PMX input file:")
    input_filename_pmx = core.MY_FILEPROMPT_FUNC(".pmx")
    pmx = pmxlib.read_pmx(input_filename_pmx, moreinfo=moreinfo)

    # to shift the model by a set amount:
    # first, ask user for X Y Z

    # create the prompt popup
    scale_str = core.MY_GENERAL_INPUT_FUNC(
        lambda x: (model_shift.is_3float(x) is not None), [
            "Enter the X,Y,Z amount to scale this model by:",
            "Three decimal values separated by commas.",
            "Empty input will quit the script."
        ])

    # if empty, quit
    if scale_str == "":
        core.MY_PRINT_FUNC("quitting")
        return None
    # use the same func to convert the input string
    scale = model_shift.is_3float(scale_str)

    uniform_scale = (scale[0] == scale[1] == scale[2])
    if not uniform_scale:
        core.MY_PRINT_FUNC(
            "Warning: when scaling by non-uniform amounts, rigidbody sizes will not be modified"
        )

    ####################
    # what does it mean to scale the entire model?
    # scale vertex position, sdef params
    # ? scale vertex normal vectors, then normalize? need to convince myself of this interaction
    # scale bone position, tail offset
    # scale fixedaxis and localaxis vectors, then normalize
    # scale vert morph, bone morph
    # scale rigid pos, size
    # scale joint pos, movelimits

    for v in pmx.verts:
        # vertex position
        for i in range(3):
            v.pos[i] *= scale[i]
        # vertex normal
        for i in range(3):
            if scale[i] != 0:
                v.norm[i] /= scale[i]
            else:
                v.norm[i] = 100000
        # then re-normalize the normal vector
        v.norm = core.normalize_distance(v.norm)
        # c, r0, r1 params of every SDEF vertex
        # these correspond to real positions in 3d space so they need to be modified
        if v.weighttype == pmxstruct.WeightMode.SDEF:
            for param in v.weight_sdef:
                for i in range(3):
                    param[i] *= scale[i]

    for b in pmx.bones:
        # bone position
        for i in range(3):
            b.pos[i] *= scale[i]
        # bone tail if using offset mode
        if not b.tail_usebonelink:
            for i in range(3):
                b.tail[i] *= scale[i]
        # scale fixedaxis and localaxis vectors, then normalize
        if b.has_fixedaxis:
            for i in range(3):
                b.fixedaxis[i] *= scale[i]
            # then re-normalize
            b.fixedaxis = core.normalize_distance(b.fixedaxis)
        # scale fixedaxis and localaxis vectors, then normalize
        if b.has_localaxis:
            for i in range(3):
                b.localaxis_x[i] *= scale[i]
            for i in range(3):
                b.localaxis_z[i] *= scale[i]
            # then re-normalize
            b.localaxis_x = core.normalize_distance(b.localaxis_x)
            b.localaxis_z = core.normalize_distance(b.localaxis_z)

    for m in pmx.morphs:
        # vertex morph and bone morph (only translate, not rotate)
        if m.morphtype in (pmxstruct.MorphType.VERTEX,
                           pmxstruct.MorphType.BONE):
            morph_scale.morph_scale(m, scale, bone_mode=1)

    for rb in pmx.rigidbodies:
        # rigid body position
        for i in range(3):
            rb.pos[i] *= scale[i]
        # rigid body size
        # NOTE: rigid body size is a special conundrum
        # spheres have only one dimension, capsules have two, and only boxes have 3
        # what's the "right" way to scale a sphere by 1,5,1? there isn't a right way!
        # boxes and capsules can be rotated and stuff so their axes dont line up with world axes, too
        # is it at least possible to rotate bodies so they are still aligned with their bones?
        # eh, why even bother with any of that. 95% of the time full-model scale will be uniform scaling.
        # only scale the rigidbody size if doing uniform scaling: that is guaranteed to be safe!
        if uniform_scale:
            for i in range(3):
                rb.size[i] *= scale[i]

    for j in pmx.joints:
        # joint position
        for i in range(3):
            j.pos[i] *= scale[i]
        # joint min slip
        for i in range(3):
            j.movemin[i] *= scale[i]
        # joint max slip
        for i in range(3):
            j.movemax[i] *= scale[i]

    # that's it? that's it!

    # write out
    output_filename_pmx = input_filename_pmx[0:-4] + "_scale.pmx"
    output_filename_pmx = core.get_unused_file_name(output_filename_pmx)
    pmxlib.write_pmx(output_filename_pmx, pmx, moreinfo=moreinfo)
    core.MY_PRINT_FUNC("Done!")
    return None
Пример #4
0
def main(moreinfo=True):
    # prompt PMX name
    core.MY_PRINT_FUNC("Please enter name of PMX input file:")
    input_filename_pmx = core.MY_FILEPROMPT_FUNC(".pmx")
    pmx = pmxlib.read_pmx(input_filename_pmx, moreinfo=moreinfo)

    core.MY_PRINT_FUNC("")
    # valid input is any string that can matched aginst a morph idx
    s = core.MY_GENERAL_INPUT_FUNC(
        lambda x: get_idx_in_pmxsublist(x, pmx.morphs) is not None, [
            "Please specify the target morph: morph #, JP name, or EN name (names are not case sensitive).",
            "Empty input will quit the script."
        ])
    # do it again, cuz the lambda only returns true/false
    target_index = get_idx_in_pmxsublist(s, pmx.morphs)

    # when given empty text, done!
    if target_index == -1 or target_index is None:
        core.MY_PRINT_FUNC("quitting")
        return None

    # determine the morph type
    morphtype = pmx.morphs[target_index].morphtype
    core.MY_PRINT_FUNC("Found {} morph #{}: '{}' / '{}'".format(
        morphtype, target_index, pmx.morphs[target_index].name_jp,
        pmx.morphs[target_index].name_en))

    # if it is a bone morph, ask for translation/rotation/both
    bone_mode = 0
    if morphtype == pmxstruct.MorphType.BONE:
        bone_mode = core.MY_SIMPLECHOICE_FUNC((1, 2, 3), [
            "Bone morph detected: do you want to scale the motion(translation), rotation, or both?",
            "1 = motion(translation), 2 = rotation, 3 = both"
        ])

    # ask for factor: keep looping this prompt until getting a valid float
    def is_float(x):
        try:
            v = float(x)
            return True
        except ValueError:
            core.MY_PRINT_FUNC("Please enter a decimal number")
            return False

    factor_str = core.MY_GENERAL_INPUT_FUNC(
        is_float, "Enter the factor that you want to scale this morph by:")
    if factor_str == "":
        core.MY_PRINT_FUNC("quitting")
        return None
    factor = float(factor_str)

    # important values: target_index, factor, morphtype, bone_mode
    # first create the new morph that is a copy of current
    if SCALE_MORPH_IN_PLACE:
        newmorph = pmx.morphs[target_index]
    else:
        newmorph = copy.deepcopy(pmx.morphs[target_index])
        # then modify the names
        name_suffix = "*" + (str(factor)[0:6])
        newmorph.name_jp += name_suffix
        newmorph.name_en += name_suffix
    # now scale the actual values

    r = morph_scale(newmorph, factor, bone_mode)

    if not r:
        core.MY_PRINT_FUNC("quitting")
        return None

    pmx.morphs.append(newmorph)

    # write out
    output_filename_pmx = input_filename_pmx[0:-4] + ("_%dscal.pmx" %
                                                      target_index)
    output_filename_pmx = core.get_unused_file_name(output_filename_pmx)
    pmxlib.write_pmx(output_filename_pmx, pmx, moreinfo=moreinfo)
    core.MY_PRINT_FUNC("Done!")
    return None
Пример #5
0
def main(moreinfo=True):
    # prompt PMX name
    core.MY_PRINT_FUNC("Please enter name of PMX input file:")
    input_filename_pmx = core.MY_FILEPROMPT_FUNC(".pmx")
    pmx = pmxlib.read_pmx(input_filename_pmx, moreinfo=moreinfo)

    # usually want to add/remove endpoints for many bones at once, so put all this in a loop
    num_changed = 0
    while True:
        core.MY_PRINT_FUNC("")
        # valid input is any string that can matched aginst a bone idx
        s = core.MY_GENERAL_INPUT_FUNC(
            lambda x:
            (morph_scale.get_idx_in_pmxsublist(x, pmx.bones) is not None), [
                "Please specify the target bone: bone #, JP name, or EN name (names are not case sensitive).",
                "Empty input will quit the script."
            ])
        # do it again, cuz the lambda only returns true/false
        target_index = morph_scale.get_idx_in_pmxsublist(s, pmx.bones)

        # when given empty text, done!
        if target_index == -1 or target_index is None:
            core.MY_PRINT_FUNC("quitting")
            break
        target_bone = pmx.bones[target_index]

        # print the bone it found
        core.MY_PRINT_FUNC("Found bone #{}: '{}' / '{}'".format(
            target_index, target_bone.name_jp, target_bone.name_en))

        if target_bone.tail_type:
            core.MY_PRINT_FUNC(
                "Was tailmode 'bonelink', changing to mode 'offset'")
            if target_bone.tail == -1:
                core.MY_PRINT_FUNC(
                    "Error: bone is not linked to anything, skipping")
                continue
            # find the location of the bone currently pointing at
            endpos = pmx.bones[target_bone.tail].pos
            # determine the equivalent offset vector
            offset = [endpos[i] - target_bone.pos[i] for i in range(3)]
            # write it into the bone
            target_bone.tail_type = False
            target_bone.tail = offset
            # done unlinking endpoint!
            pass

        else:
            core.MY_PRINT_FUNC(
                "Was tailmode 'offset', changing to mode 'bonelink' and adding new endpoint bone"
            )
            if target_bone.tail == [0, 0, 0]:
                core.MY_PRINT_FUNC(
                    "Error: bone has offset of [0,0,0], skipping")
                continue
            # determine the position of the new endpoint bone
            endpos = [
                target_bone.pos[i] + target_bone.tail[i] for i in range(3)
            ]
            # create the new bone
            newbone = pmxstruct.PmxBone(
                name_jp=target_bone.name_jp + endpoint_suffix_jp,
                name_en=target_bone.name_en + endpoint_suffix_en,
                pos=endpos,
                parent_idx=target_index,
                deform_layer=target_bone.deform_layer,
                deform_after_phys=target_bone.deform_after_phys,
                has_rotate=False,
                has_translate=False,
                has_visible=False,
                has_enabled=True,
                has_ik=False,
                has_localaxis=False,
                has_fixedaxis=False,
                has_externalparent=False,
                inherit_rot=False,
                inherit_trans=False,
                tail_type=True,
                tail=-1)
            # set the target to point at the new bone
            target_bone.tail_type = True
            target_bone.tail = len(pmx.bones)
            # append the new bone
            pmx.bones.append(newbone)
            # done adding endpoint!
            pass

        num_changed += 1
        pass

    if num_changed == 0:
        core.MY_PRINT_FUNC("Nothing was changed")
        return None

    core.MY_PRINT_FUNC("")

    # write out
    output_filename_pmx = input_filename_pmx[0:-4] + "_endpoints.pmx"
    output_filename_pmx = core.get_unused_file_name(output_filename_pmx)
    pmxlib.write_pmx(output_filename_pmx, pmx, moreinfo=moreinfo)
    core.MY_PRINT_FUNC("Done!")
    return None
Пример #6
0
def main(moreinfo=True):
    # prompt PMX name
    core.MY_PRINT_FUNC("Please enter name of PMX input file:")
    input_filename_pmx = core.MY_FILEPROMPT_FUNC(".pmx")
    pmx = pmxlib.read_pmx(input_filename_pmx, moreinfo=moreinfo)

    ##################################
    # user flow:
    # ask for the helper bone (to be merged)
    # ask for the destination bone (merged onto)
    # try to infer proper merge factor, if it cannot infer then prompt user
    # then write out to file
    ##################################

    dest_idx = 0
    while True:
        # any input is considered valid
        s = core.MY_GENERAL_INPUT_FUNC(lambda x: True, [
            "Please specify the DESTINATION bone that weights will be transferred to.",
            "Enter bone #, JP name, or EN name (names are case sensitive).",
            "Empty input will quit the script."
        ])
        # if empty, leave & do nothing
        if s == "":
            dest_idx = -1
            break
        # then get the bone index from this
        # search JP names first
        dest_idx = core.my_list_search(pmx.bones, lambda x: x.name_jp == s)
        if dest_idx is not None: break  # did i find a match?
        # search EN names next
        dest_idx = core.my_list_search(pmx.bones, lambda x: x.name_en == s)
        if dest_idx is not None: break  # did i find a match?
        # try to cast to int next
        try:
            dest_idx = int(s)
            if 0 <= dest_idx < len(pmx.bones):
                break  # is this within the proper bounds?
            else:
                core.MY_PRINT_FUNC("valid bone indexes are 0-%d" %
                                   (len(pmx.bones) - 1))
        except ValueError:
            pass
        core.MY_PRINT_FUNC("unable to find matching bone for name '%s'" % s)

    if dest_idx == -1:
        core.MY_PRINT_FUNC("quitting")
        return None

    dest_tag = "bone #{} JP='{}' / EN='{}'".format(dest_idx,
                                                   pmx.bones[dest_idx].name_jp,
                                                   pmx.bones[dest_idx].name_jp)
    source_idx = 0
    while True:
        # any input is considered valid
        s = core.MY_GENERAL_INPUT_FUNC(lambda x: True, [
            "Please specify the SOURCE bone that will be merged onto %s." %
            dest_tag,
            "Enter bone #, JP name, or EN name (names are case sensitive).",
            "Empty input will quit the script."
        ])
        # if empty, leave & do nothing
        if s == "":
            source_idx = -1
            break
        # then get the morph index from this
        # search JP names first
        source_idx = core.my_list_search(pmx.bones, lambda x: x.name_jp == s)
        if source_idx is not None: break  # did i find a match?
        # search EN names next
        source_idx = core.my_list_search(pmx.bones, lambda x: x.name_en == s)
        if source_idx is not None: break  # did i find a match?
        # try to cast to int next
        try:
            source_idx = int(s)
            if 0 <= source_idx < len(pmx.bones):
                break  # is this within the proper bounds?
            else:
                core.MY_PRINT_FUNC("valid bone indexes are 0-%d" %
                                   (len(pmx.bones) - 1))
        except ValueError:
            pass
        core.MY_PRINT_FUNC("unable to find matching bone for name '%s'" % s)

    if source_idx == -1:
        core.MY_PRINT_FUNC("quitting")
        return None

    # print to confirm
    core.MY_PRINT_FUNC(
        "Merging bone #{} JP='{}' / EN='{}' ===> bone #{} JP='{}' / EN='{}'".
        format(source_idx, pmx.bones[source_idx].name_jp,
               pmx.bones[source_idx].name_en, dest_idx,
               pmx.bones[dest_idx].name_jp, pmx.bones[dest_idx].name_en))
    # now try to infer the merge factor

    f = 0.0
    if pmx.bones[source_idx].inherit_rot and pmx.bones[
            source_idx].inherit_parent_idx == dest_idx and pmx.bones[
                source_idx].inherit_ratio != 0:
        # if using partial rot inherit AND inheriting from dest_idx AND ratio != 0, use that
        # think this is good, if twistbones exist they should be children of preferred
        f = pmx.bones[source_idx].inherit_ratio
    elif pmx.bones[source_idx].parent_idx == dest_idx:
        # if they have a direct parent-child relationship, then factor is 1
        f = 1
    else:
        # otherwise, prompt for the factor
        factor_str = core.MY_GENERAL_INPUT_FUNC(
            is_float,
            "Unable to infer relationship, please specify a merge factor:")
        if factor_str == "":
            core.MY_PRINT_FUNC("quitting")
            return None
        f = float(factor_str)

    # do the actual transfer
    transfer_bone_weights(pmx, dest_idx, source_idx, f)

    # run the weight-cleanup function
    dummy = normalize_weights(pmx)

    # write out
    output_filename_pmx = input_filename_pmx[0:-4] + "_weightmerge.pmx"
    output_filename_pmx = core.get_unused_file_name(output_filename_pmx)
    pmxlib.write_pmx(output_filename_pmx, pmx, moreinfo=moreinfo)
    core.MY_PRINT_FUNC("Done!")
    return None
Пример #7
0
def main(moreinfo=True):
    # prompt PMX name
    core.MY_PRINT_FUNC("Please enter name of PMX input file:")
    input_filename_pmx = core.MY_FILEPROMPT_FUNC(".pmx")
    pmx = pmxlib.read_pmx(input_filename_pmx, moreinfo=moreinfo)

    core.MY_PRINT_FUNC("")
    # valid input is any string that can matched aginst a morph idx
    s = core.MY_GENERAL_INPUT_FUNC(
        lambda x: morph_scale.get_idx_in_pmxsublist(x, pmx.morphs) is not None,
        [
            "Please specify the target morph: morph #, JP name, or EN name (names are not case sensitive).",
            "Empty input will quit the script."
        ])
    # do it again, cuz the lambda only returns true/false
    target_index = morph_scale.get_idx_in_pmxsublist(s, pmx.morphs)

    # when given empty text, done!
    if target_index == -1 or target_index is None:
        core.MY_PRINT_FUNC("quitting")
        return None

    morphtype = pmx.morphs[target_index].morphtype
    # 1=vert
    # 3=UV
    # 8=material
    core.MY_PRINT_FUNC("Found {} morph #{}: '{}' / '{}'".format(
        morphtype, target_index, pmx.morphs[target_index].name_jp,
        pmx.morphs[target_index].name_en))

    if morphtype == pmxstruct.MorphType.VERTEX:  # vertex
        # for each item in this morph:
        item: pmxstruct.PmxMorphItemVertex  # type annotation for pycharm
        for d, item in enumerate(pmx.morphs[target_index].items):
            # apply the offset
            pmx.verts[item.vert_idx].pos[0] += item.move[0]
            pmx.verts[item.vert_idx].pos[1] += item.move[1]
            pmx.verts[item.vert_idx].pos[2] += item.move[2]
            # invert the morph
        morph_scale.morph_scale(pmx.morphs[target_index], -1)
    elif morphtype == pmxstruct.MorphType.UV:  # UV
        item: pmxstruct.PmxMorphItemUV  # type annotation for pycharm
        for d, item in enumerate(pmx.morphs[target_index].items):
            # (vert_idx, A, B, C, D)
            # apply the offset
            pmx.verts[item.vert_idx].uv[0] += item.move[0]
            pmx.verts[item.vert_idx].uv[1] += item.move[1]
            # invert the morph
        morph_scale.morph_scale(pmx.morphs[target_index], -1)
    elif morphtype in (pmxstruct.MorphType.UV_EXT1,
                       pmxstruct.MorphType.UV_EXT2,
                       pmxstruct.MorphType.UV_EXT3,
                       pmxstruct.MorphType.UV_EXT4):  # UV1 UV2 UV3 UV4
        whichuv = morphtype.value - pmxstruct.MorphType.UV_EXT1.value
        item: pmxstruct.PmxMorphItemUV  # type annotation for pycharm
        for d, item in enumerate(pmx.morphs[target_index].items):
            # apply the offset
            pmx.verts[item.vert_idx].addl_vec4s[whichuv][0] += item.move[0]
            pmx.verts[item.vert_idx].addl_vec4s[whichuv][1] += item.move[1]
            pmx.verts[item.vert_idx].addl_vec4s[whichuv][2] += item.move[2]
            pmx.verts[item.vert_idx].addl_vec4s[whichuv][3] += item.move[3]
            # invert the morph
        morph_scale.morph_scale(pmx.morphs[target_index], -1)
    elif morphtype == pmxstruct.MorphType.MATERIAL:  # material
        core.MY_PRINT_FUNC("WIP")
        # todo
        # to invert a material morph means inverting the material's visible/notvisible state as well as flipping the morph
        # hide morph add -> show morph add
        # hide morph mult -> show morph add
        # show morph add -> hide morph mult
        core.MY_PRINT_FUNC("quitting")
        return None
    else:
        core.MY_PRINT_FUNC("Unhandled morph type")
        core.MY_PRINT_FUNC("quitting")
        return None

    # write out
    output_filename_pmx = input_filename_pmx[0:-4] + ("_%dinv.pmx" %
                                                      target_index)
    output_filename_pmx = core.get_unused_file_name(output_filename_pmx)
    pmxlib.write_pmx(output_filename_pmx, pmx, moreinfo=moreinfo)
    core.MY_PRINT_FUNC("Done!")
    return None