Example #1
0
def parse_vmd_morphframe(raw:bytearray, moreinfo:bool) -> List[vmdstruct.VmdMorphFrame]:
	# get all the morph-frames, store in a list of lists
	morphframe_list = []
	# is there enough file left to read a single number?
	if (len(raw) - core.get_readfrom_byte()) < struct.calcsize(fmt_number):
		core.MY_PRINT_FUNC("Warning: expected morphframe_ct field but file ended unexpectedly! Assuming 0 morphframes and continuing...")
		return morphframe_list
	
	############################
	# get the number of morph frames
	morphframe_ct = core.my_unpack(fmt_number, raw)
	if moreinfo: core.MY_PRINT_FUNC("...# of morphframes         = %d" % morphframe_ct)
	for z in range(morphframe_ct):
		try:
			# unpack the morphframe
			(mname_str, f, v) = core.my_unpack(fmt_morphframe, raw)
			morphframe_list.append(vmdstruct.VmdMorphFrame(name=mname_str, f=f, val=v))
			
			# display progress printouts
			core.print_progress_oneline(core.get_readfrom_byte() / len(raw))
		except Exception as e:
			core.MY_PRINT_FUNC(e.__class__.__name__, e)
			core.MY_PRINT_FUNC("frame=", z)
			core.MY_PRINT_FUNC("totalframes=", morphframe_ct)
			core.MY_PRINT_FUNC("section=morphframe")
			core.MY_PRINT_FUNC("Err: something went wrong while parsing, file is probably corrupt/malformed")
			raise RuntimeError()
	
	return morphframe_list
Example #2
0
def read_vmdtext_morphframe(rawlist_text: List[list]) -> List[vmdstruct.VmdMorphFrame]:
	###########################################
	# morph frames
	global readfrom_line
	morph_list = []
	# first check for bad format
	check2_match_first_item(rawlist_text, keystr_morphframect)

	morphframe_ct = rawlist_text[readfrom_line][1]
	core.MY_PRINT_FUNC("...# of morphframes         = %d" % morphframe_ct)
	readfrom_line += 1
	
	if morphframe_ct > 0:
		# ensure the key-line is where i think it is
		check3_match_keystr(rawlist_text, keystr_morphframekey)
		# if it is indeed here, then inc the readpointer
		readfrom_line += 1
		
		for i in range(morphframe_ct):
			# ensure it has the right # of items on the line
			check1_match_len(rawlist_text, len(keystr_morphframekey))
			r = rawlist_text[readfrom_line]
			newframe = vmdstruct.VmdMorphFrame(name=r[0], f=r[1], val=r[2])
			morph_list.append(newframe)
			# increment the readfrom_line pointer
			readfrom_line += 1
			# progress tracker just because
			core.print_progress_oneline(i / morphframe_ct)
	return morph_list
Example #3
0
def read_vpd(vpd_filepath: str, moreinfo=False) -> vmdstruct.Vmd:
    """
	Read a VPD text file and convert it to a VMD object with all boneframes and morphframes at time=0.
	
	:param vpd_filepath: destination filepath/name, relative from CWD or absolute
	:param moreinfo: if true, get extra printouts with more info about stuff
	:return: VMD object
	"""
    cleanname = core.get_clean_basename(vpd_filepath) + ".vpd"
    core.MY_PRINT_FUNC("Begin reading VPD file '%s'" % cleanname)

    # read textfile to linelist, no CSV fields to untangle here
    lines = core.read_txtfile_to_list(vpd_filepath, use_jis_encoding=True)

    # verify magic header "Vocaloid Pose Data file"
    if lines[0] != "Vocaloid Pose Data file":
        core.MY_PRINT_FUNC(
            "warning: did not find expected magic header! this might not be a real VPD file!"
        )
    # get rid of the header
    lines.pop(0)

    # this var is a state machine that keeps track of what I expect to find next
    # if i find anything other than blankspace or what I expect, then err & die
    parse_state = 0

    # save this so I know when I'm done reading all the bones the header promised
    num_bones = 0

    # temp vars to hold stuff from previous lines
    temp_title = "qwertyuiop"
    temp_name = "foobar"
    temp_pos = tuple()
    temp_rot = tuple()
    temp_value = 0.0

    # this is the VMD object that will be ultimately returned
    vmd_boneframes = []
    vmd_morphframes = []

    # iterate over the remaining lines until end-of-file
    for d, line in enumerate(lines):
        # vertical whitespace is always acceptable
        if not line or line.isspace(): continue

        # if line is not blank, it had better be something good:
        if parse_state == 0:  # 0 = model title
            m = title_re.match(line)  # regex match from beginning of line
            if m is None:
                core.MY_PRINT_FUNC(
                    "Parse err line %d state %d: failed to find model title" %
                    (d + 2, parse_state))
                core.MY_PRINT_FUNC("line = '%s'" % line)
                raise RuntimeError()
            temp_title = m.group(
                1)  # if valid match, then grab the actual title
            if moreinfo:
                core.MY_PRINT_FUNC("...model name   = JP:'%s'" % temp_title)
            parse_state = 10  # next thing to look for is #bones

        elif parse_state == 10:  # 10 = #bones
            m = f1_re.match(line)  # regex match from beginning of line
            if m is None:
                core.MY_PRINT_FUNC(
                    "Parse err line %d state %d: failed to find number of bones"
                    % (d + 2, parse_state))
                core.MY_PRINT_FUNC("line = '%s'" % line)
                raise RuntimeError()
            num_bones = int(float(m.group(
                1)))  # if a valid match, then grab the actual # of bones
            if moreinfo:
                core.MY_PRINT_FUNC("...# of boneframes          = %d" %
                                   num_bones)
            if num_bones == 0:
                parse_state = 30  # if there are 0 bones then immediately begin with the morphs
            else:
                parse_state = 20  # otherwise look for bones next

        elif parse_state == 20:  # 20 = boneA, name
            m = bone_re.match(line)  # regex match from beginning of line
            if m is None:
                core.MY_PRINT_FUNC(
                    "Parse err line %d state %d: failed to find bone name" %
                    (d + 2, parse_state))
                core.MY_PRINT_FUNC("line = '%s'" % line)
                raise RuntimeError()
            idx, name = m.group(1, 2)  # get idx and name
            temp_name = name
            # can i use idx for anything? or is it totally useless?
            parse_state = 21  # next look for quaternion rotation

        elif parse_state == 21:  # 21 = boneB, xyz pos
            m = f3_re.match(line)  # regex match from beginning of line
            if m is None:
                core.MY_PRINT_FUNC(
                    "Parse err line %d state %d: failed to find bone XYZ position"
                    % (d + 2, parse_state))
                core.MY_PRINT_FUNC("line = '%s'" % line)
                raise RuntimeError()
            pos = m.group(1, 2, 3)  # get all 3 components
            temp_pos = [float(f) for f in pos]  # convert strings to floats
            parse_state = 22  # next look for quaternion rotation

        elif parse_state == 22:  # 22 = boneC, xyzw quaternion rotation
            m = f4_re.match(line)  # regex match from beginning of line
            if m is None:
                core.MY_PRINT_FUNC(
                    "Parse err line %d state %d: failed to find bone XYZW rotation"
                    % (d + 2, parse_state))
                core.MY_PRINT_FUNC("line = '%s'" % line)
                raise RuntimeError()
            quat = m.group(1, 2, 3, 4)  # get all 4 components
            quat = [float(f) for f in quat]  # convert strings to floats
            quat.insert(
                0, quat.pop(-1))  # WXYZW -> XYZW, AKA move tail (w) to head
            temp_rot = core.quaternion_to_euler(
                quat)  # convert quaternion to euler angles
            parse_state = 23  # next look for closing curly

        elif parse_state == 23:  # 23 = boneD, closing curly
            m = close_re.match(line)  # regex match from beginning of line
            if m is None:
                core.MY_PRINT_FUNC(
                    "Parse err line %d state %d: bone item not properly closed"
                    % (d + 2, parse_state))
                core.MY_PRINT_FUNC("line = '%s'" % line)
                raise RuntimeError()
            # finish the bone-obj and add to VMD structure
            # this_boneframe = [bname_str, f, xp, yp, zp, xrot, yrot, zrot, phys_off, x_ax, y_ax, z_ax, r_ax, x_ay, y_ay,
            # 				  z_ay, r_ay, x_bx, y_bx, z_bx, r_bx, x_by, y_by, z_by, r_by]
            newframe = vmdstruct.VmdBoneFrame(
                name=temp_name,
                f=0,
                pos=temp_pos,
                rot=list(temp_rot),
                phys_off=False,
                interp=list(core.bone_interpolation_default_linear))
            vmd_boneframes.append(newframe)
            if len(vmd_boneframes) == num_bones:
                parse_state = 30  # if i got all the bones i expected, move to morphs
            else:
                parse_state = 20  # otherwise, get another bone

        elif parse_state == 30:  # 30 = morphA, name
            m = morph_re.match(line)  # regex match from beginning of line
            if m is None:
                core.MY_PRINT_FUNC(
                    "Parse err line %d state %d: failed to find morph name" %
                    (d + 2, parse_state))
                core.MY_PRINT_FUNC("line = '%s'" % line)
                raise RuntimeError()
            idx, name = m.group(1, 2)  # get idx and name
            temp_name = name
            # can i use idx for anything? or is it totally useless?
            parse_state = 31  # next look for value

        elif parse_state == 31:  # 31 = morphB, value
            m = f1_re.match(line)  # regex match from beginning of line
            if m is None:
                core.MY_PRINT_FUNC(
                    "Parse err line %d state %d: failed to find morph value" %
                    (d + 2, parse_state))
                core.MY_PRINT_FUNC("line = '%s'" % line)
                raise RuntimeError()
            v = m.group(1)  # get value
            temp_value = float(v)  # convert strings to floats
            parse_state = 32  # next look for close

        elif parse_state == 32:  # 32 = morphC, closing curly
            m = close_re.match(line)  # regex match from beginning of line
            if m is None:
                core.MY_PRINT_FUNC(
                    "Parse err line %d state %d: morph item not properly closed"
                    % (d + 2, parse_state))
                core.MY_PRINT_FUNC("line = '%s'" % line)
                raise RuntimeError()
            # finish the morph-obj and add to VMD structure
            # morphframe_list.append([mname_str, f, v])
            newframe = vmdstruct.VmdMorphFrame(name=temp_name,
                                               f=0,
                                               val=temp_value)
            vmd_morphframes.append(newframe)
            parse_state = 30  # loop morphs until end-of-file

        else:
            core.MY_PRINT_FUNC("this should not happen, err & die")
            raise RuntimeError()

    if moreinfo:
        core.MY_PRINT_FUNC("...# of morphframes         = %d" %
                           len(vmd_morphframes))

    # verify we did not hit end-of-file unexpectedly, looking-for-morphA is only valid ending state
    if parse_state != 30:
        core.MY_PRINT_FUNC("Parse err state %d: hit end-of-file unexpectedly" %
                           parse_state)
        raise RuntimeError()

    # after hitting end-of-file, assemble the parts of the final returnable VMD-list thing
    # builds object 	(header, boneframe_list, morphframe_list, camframe_list, lightframe_list, shadowframe_list, ikdispframe_list)
    vmd_retme = vmdstruct.Vmd(
        vmdstruct.VmdHeader(version=2, modelname=temp_title), vmd_boneframes,
        vmd_morphframes, list(), list(), list(), list())

    core.MY_PRINT_FUNC("Done reading VPD file '%s'" % cleanname)

    return vmd_retme