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
def read_vmd(vmd_filename: str, moreinfo=False) -> vmdstruct.Vmd: vmd_filename_clean = core.get_clean_basename(vmd_filename) + ".vmd" # creates object (header, boneframe_list, morphframe_list, camframe_list, lightframe_list, shadowframe_list, ikdispframe_list) # assumes the calling function already verified correct file extension core.MY_PRINT_FUNC("Begin reading VMD file '%s'" % vmd_filename_clean) vmd_bytes = core.read_binfile_to_bytes(vmd_filename) core.MY_PRINT_FUNC("...total size = %sKB" % round(len(vmd_bytes) / 1024)) core.MY_PRINT_FUNC("Begin parsing VMD file '%s'" % vmd_filename_clean) core.reset_unpack() core.set_encoding("shift_jis") # !!!! this does eliminate all the garbage data MMD used to pack strings so this isnt 100% reversable !!! # read the bytes object and return all the data from teh VMD broken up into a list of lists # also convert things from packed formats to human-readable scales # (quaternion to euler, radians to degrees, floats to ints, etc) # also generate the bonedict and morphdict core.print_progress_oneline(0) A = parse_vmd_header(vmd_bytes, moreinfo) B = parse_vmd_boneframe(vmd_bytes, moreinfo) C = parse_vmd_morphframe(vmd_bytes, moreinfo) D = parse_vmd_camframe(vmd_bytes, moreinfo) E = parse_vmd_lightframe(vmd_bytes, moreinfo) F = parse_vmd_shadowframe(vmd_bytes, moreinfo) G = parse_vmd_ikdispframe(vmd_bytes, moreinfo) if moreinfo: core.print_failed_decodes() bytes_remain = len(vmd_bytes) - core.get_readfrom_byte() if bytes_remain != 0: # padding with my SIGNATURE is acceptable, anything else is strange leftover = vmd_bytes[core.get_readfrom_byte():] if leftover == bytes(SIGNATURE, encoding="shift_jis"): core.MY_PRINT_FUNC( "...note: this VMD file was previously modified with this tool!" ) else: core.MY_PRINT_FUNC( "Warning: finished parsing but %d bytes are left over at the tail!" % bytes_remain) core.MY_PRINT_FUNC( "The file may be corrupt or maybe it contains unknown/unsupported data formats" ) core.MY_PRINT_FUNC(leftover) core.MY_PRINT_FUNC("Done parsing VMD file '%s'" % vmd_filename_clean) vmd = vmdstruct.Vmd(A, B, C, D, E, F, G) # this is where sorting happens, if it happens if GUARANTEE_FRAMES_SORTED: # bones & morphs: primarily sorted by NAME, with FRAME# as tiebreaker. the second sort is the primary one. vmd.boneframes.sort(key=lambda x: x.f) # frame# vmd.boneframes.sort(key=lambda x: x.name) # name vmd.morphframes.sort(key=lambda x: x.f) vmd.morphframes.sort(key=lambda x: x.name) # all of these only sort by frame number. vmd.camframes.sort(key=lambda x: x.f) # frame# vmd.lightframes.sort(key=lambda x: x.f) vmd.shadowframes.sort(key=lambda x: x.f) vmd.ikdispframes.sort(key=lambda x: x.f) return vmd
def parse_vmd_boneframe(raw:bytearray, moreinfo:bool) -> List[vmdstruct.VmdBoneFrame]: # get all the bone-frames, store in a list of lists boneframe_list = [] # verify that there is 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 boneframe_ct field but file ended unexpectedly! Assuming 0 boneframes and continuing...") return boneframe_list ############################ # get the number of bone-frames boneframe_ct = core.my_unpack(fmt_number, raw) if moreinfo: core.MY_PRINT_FUNC("...# of boneframes = %d" % boneframe_ct) for z in range(boneframe_ct): try: # unpack the bone-frame into variables (bname_str, f, xp, yp, zp, xrot_q, yrot_q, zrot_q, wrot_q) = core.my_unpack(fmt_boneframe_no_interpcurve, raw) # break inter_curve into its individual pieces, knowing that the 3rd and 4th bytes in line1 are overwritten with phys # therefore we need to get their data from line2 which is left-shifted by 1 byte, but otherwise a copy (x_ax, y_ax, phys1, phys2, x_ay, y_ay, z_ay, r_ay, x_bx, y_bx, z_bx, r_bx, x_by, y_by, z_by, r_by, z_ax, r_ax) = core.my_unpack(fmt_boneframe_interpcurve, raw) # convert the quaternion angles to euler angles (xrot, yrot, zrot) = core.quaternion_to_euler([wrot_q, xrot_q, yrot_q, zrot_q]) # interpret the physics enable/disable bytes if (phys1, phys2) == (z_ax, r_ax): # if they match the values they should be, they were never overwritten in the first place??? phys_off = False elif (phys1, phys2) == (0, 0): # phys stays on phys_off = False elif (phys1, phys2) == (99, 15): # phys turns off phys_off = True else: core.MY_PRINT_FUNC("Warning: found unusual values where I expected to find physics enable/disable! Assuming this means physics off") core.MY_PRINT_FUNC(bname_str, "f=", str(f), "(phys1,phys2)=", str((phys1, phys2))) phys_off = True # store them all on the list # create a list to hold all the boneframe data, then append it onto the return-list interp_list = [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] this_boneframe = vmdstruct.VmdBoneFrame( name=bname_str, f=f, pos=[xp,yp,zp], rot=[xrot,yrot,zrot], phys_off=phys_off, interp=interp_list ) boneframe_list.append(this_boneframe) # 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=", boneframe_ct) core.MY_PRINT_FUNC("section=boneframe") core.MY_PRINT_FUNC("Err: something went wrong while parsing, file is probably corrupt/malformed") raise RuntimeError() return boneframe_list
def parse_vmd_camframe(raw: bytearray, moreinfo: bool) -> List[vmdstruct.VmdCamFrame]: camframe_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 camframe_ct field but file ended unexpectedly! Assuming 0 camframes and continuing..." ) return camframe_list ############################ # get the number of cam frames camframe_ct = core.my_unpack(fmt_number, raw) if moreinfo: core.MY_PRINT_FUNC("...# of camframes = %d" % camframe_ct) for z in range(camframe_ct): try: # unpack into variables (f, d, xp, yp, zp, xr, yr, zr, x_ax, x_bx, x_ay, x_by, y_ax, y_bx, y_ay, y_by, z_ax, z_bx, z_ay, z_by, r_ax, r_bx, r_ay, r_by, dist_ax, dist_bx, dist_ay, dist_by, ang_ax, ang_bx, ang_ay, ang_by, fov, per) = core.my_unpack(fmt_camframe, raw) interp_list = [ x_ax, x_bx, x_ay, x_by, y_ax, y_bx, y_ay, y_by, z_ax, z_bx, z_ay, z_by, r_ax, r_bx, r_ay, r_by, dist_ax, dist_bx, dist_ay, dist_by, ang_ax, ang_bx, ang_ay, ang_by ] this_camframe = vmdstruct.VmdCamFrame( f=f, dist=d, pos=[xp, yp, zp], rot=[ math.degrees(j) for j in (xr, yr, zr) ], # angle comes in as radians, convert radians to degrees interp=interp_list, fov=fov, perspective=per) camframe_list.append(this_camframe) # 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=", camframe_ct) core.MY_PRINT_FUNC("section=camframe") core.MY_PRINT_FUNC( "Err: something went wrong while parsing, file is probably corrupt/malformed" ) raise RuntimeError() return camframe_list
def parse_vmd_ikdispframe(raw: bytearray, moreinfo: bool) -> List[vmdstruct.VmdIkdispFrame]: ikdispframe_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 ikdispframe_ct field but file ended unexpectedly! Assuming 0 ikdispframes and continuing..." ) return ikdispframe_list ############################ # if it exists, get the number of ikdisp frames ikdispframe_ct = core.my_unpack(fmt_number, raw) if moreinfo: core.MY_PRINT_FUNC("...# of ik/disp frames = %d" % ikdispframe_ct) for i in range(ikdispframe_ct): try: (f, disp, numbones) = core.my_unpack(fmt_ikdispframe, raw) ikbones = [] for j in range(numbones): (ikname, enable) = core.my_unpack(fmt_ikframe, raw) ikbones.append(vmdstruct.VmdIkbone(name=ikname, enable=enable)) ikdispframe_list.append( vmdstruct.VmdIkdispFrame(f=f, disp=disp, ikbones=ikbones)) except Exception as e: core.MY_PRINT_FUNC(e.__class__.__name__, e) core.MY_PRINT_FUNC("frame=", i) core.MY_PRINT_FUNC("totalframes=", ikdispframe_ct) core.MY_PRINT_FUNC("section=ikdispframe") core.MY_PRINT_FUNC( "Err: something went wrong while parsing, file is probably corrupt/malformed" ) raise RuntimeError() return ikdispframe_list
def parse_vmd_shadowframe(raw: bytearray, moreinfo: bool) -> List[vmdstruct.VmdShadowFrame]: shadowframe_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 shadowframe_ct field but file ended unexpectedly! Assuming 0 shadowframes and continuing..." ) return shadowframe_list ############################ # if it exists, get the number of shadowframes shadowframe_ct = core.my_unpack(fmt_number, raw) if moreinfo: core.MY_PRINT_FUNC("...# of shadowframes = %d" % shadowframe_ct) for i in range(shadowframe_ct): try: (f, m, v) = core.my_unpack(fmt_shadowframe, raw) v = round(10000 - (v * 100000)) # stored as 0.0 to 0.1 ??? why would it use this range!? also its range-inverted # [0,9999] -> [0.1, 0.0] shadowframe_list.append( vmdstruct.VmdShadowFrame(f=f, mode=m, val=v)) except Exception as e: core.MY_PRINT_FUNC(e.__class__.__name__, e) core.MY_PRINT_FUNC("frame=", i) core.MY_PRINT_FUNC("totalframes=", shadowframe_ct) core.MY_PRINT_FUNC("section=shadowframe") core.MY_PRINT_FUNC( "Err: something went wrong while parsing, file is probably corrupt/malformed" ) raise RuntimeError() return shadowframe_list
def parse_vmd_lightframe(raw: bytearray, moreinfo: bool) -> List[vmdstruct.VmdLightFrame]: lightframe_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 lightframe_ct field but file ended unexpectedly! Assuming 0 lightframes and continuing..." ) return lightframe_list ############################ # if it exists, get the number of lightframes lightframe_ct = core.my_unpack(fmt_number, raw) if moreinfo: core.MY_PRINT_FUNC("...# of lightframes = %d" % lightframe_ct) for i in range(lightframe_ct): try: (f, r, g, b, x, y, z) = core.my_unpack(fmt_lightframe, raw) # the r g b actually come back as floats [0.0-1.0), representing (int)/256, i'll convert them back to ints lightframe_list.append( vmdstruct.VmdLightFrame( f=f, color=[round(j * 256) for j in (r, g, b)], pos=[x, y, z])) except Exception as e: core.MY_PRINT_FUNC(e.__class__.__name__, e) core.MY_PRINT_FUNC("frame=", i) core.MY_PRINT_FUNC("totalframes=", lightframe_ct) core.MY_PRINT_FUNC("section=lightframe") core.MY_PRINT_FUNC( "Err: something went wrong while parsing, file is probably corrupt/malformed" ) raise RuntimeError() return lightframe_list