From e3c387d0cf8e7d5167f6f847bd0cd79441900b41 Mon Sep 17 00:00:00 2001 From: Nik Date: Mon, 10 Jul 2023 16:36:49 +0200 Subject: [PATCH] patterns/3ds: Added 3DS Max pattern --- README.md | 1 + patterns/3ds.hexpat | 1138 +++++++++++++++++++++++ tests/patterns/test_data/3ds.hexpat.3ds | Bin 0 -> 32485 bytes 3 files changed, 1139 insertions(+) create mode 100644 patterns/3ds.hexpat create mode 100644 tests/patterns/test_data/3ds.hexpat.3ds diff --git a/README.md b/README.md index 56c0f4f..761f37a 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,7 @@ Everything will immediately show up in ImHex's Content Store and gets bundled wi | Name | MIME | Path | Description | |------|------|------|-------------| +| 3DS | | [`patterns/3ds.hexpat`](patterns/3ds.hexpat) | Autodesk 3DS Max Model file | | 7Z | | [`patterns/7z.hexpat`](patterns/7z.hexpat) | 7z File Format | | AFE2 | | [`patterns/afe2.hexpat`](patterns/afe2.hexpat) | Nintendo Switch Atmosphère CFW Fatal Error log | | AR | `application/x-archive` | [`patterns/ar.hexpat`](patterns/ar.hexpat) | Static library archive files | diff --git a/patterns/3ds.hexpat b/patterns/3ds.hexpat new file mode 100644 index 0000000..73d80e8 --- /dev/null +++ b/patterns/3ds.hexpat @@ -0,0 +1,1138 @@ +#include +#include + +#pragma MIME image/x-3ds + +// Heavily based off of ZiZi's 010 Editor 3DS Template +enum ChunkIdentifier : u16 { + NULL_CHUNK = 0x0000, + ChunkType = 0x0995, + ChunkUnique = 0x0996, + NotChunk = 0x0997, + Container = 0x0998, + IsChunk = 0x0999, + + /* Dummy Chunk that sometimes appears in 3ds files created by prerelease 3D Studio R2 */ + DUMMY = 0xFFFF, + + /* Chunk Types for Open*, Write*, Close* functions */ + POINT_ARRAY_ENTRY = 0xF110, + POINT_FLAG_ARRAY_ENTRY = 0xF111, + FACE_ARRAY_ENTRY = 0xF120, + MSH_MAT_GROUP_ENTRY = 0xF130, + TEX_VERTS_ENTRY = 0xF140, + SMOOTH_GROUP_ENTRY = 0xF150, + POS_TRACK_TAG_KEY = 0xF020, + ROT_TRACK_TAG_KEY = 0xF021, + SCL_TRACK_TAG_KEY = 0xF022, + FOV_TRACK_TAG_KEY = 0xF023, + ROLL_TRACK_TAG_KEY = 0xF024, + COL_TRACK_TAG_KEY = 0xF025, + MORPH_TRACK_TAG_KEY = 0xF026, + HOT_TRACK_TAG_KEY = 0xF027, + FALL_TRACK_TAG_KEY = 0xF028, + + /* 3DS File Chunk IDs */ + COLOR_F = 0x0010, // r,g,b: Single precision float + COLOR_24 = 0x0011, // r,g,b: Byte + LIN_COLOR_24 = 0x0012, // r,g,b: Byte (gamma corrected) + LIN_COLOR_F = 0x0013, // r,g,b: Single precision float (gamma corrected) + + INT_PERCENTAGE = 0x0030, // u16 integer + FLOAT_PERCENTAGE = 0x0031, // Single precision float + + M3DMAGIC = 0x4D4D, + SMAGIC = 0x2D2D, + LMAGIC = 0x2D3D, + MLIBMAGIC = 0x3DAA, + MATMAGIC = 0x3DFF, + M3D_VERSION = 0x0002, + MDATA = 0x3D3D, + MESH_VERSION = 0x3D3E, + WORLD_VIEWPORT_DATA = 0x7011, + WORLD_VIEWPORT_DATA3 = 0x7012, + WORLD_VIEWPORT_SIZE = 0x7020, + WORLD_VIEWPORT_LAYOUT = 0x7001, + MASTER_SCALE = 0x0100, + BIT_MAP = 0x1100, // Background bitmap filename + USE_BIT_MAP = 0x1101, // Use background bitmap + SOLID_BGND = 0x1200, // Background color + USE_SOLID_BGND = 0x1201, // Use background color + V_GRADIENT = 0x1300, // Background gradient colors + USE_V_GRADIENT = 0x1301, // Use background gradient colors + LO_SHADOW_BIAS = 0x1400, + HI_SHADOW_BIAS = 0x1410, + SHADOW_MAP_SIZE = 0x1420, + SHADOW_SAMPLES = 0x1430, + SHADOW_RANGE = 0x1440, + SHADOW_FILTER = 0x1450, + RAY_BIAS = 0x1460, + USE_RAYTRACE = 0x1470, + O_CONSTS = 0x1500, + + AMBIENT_LIGHT = 0x2100, + + FOG = 0x2200, + USE_FOG = 0x2201, + FOG_BGND = 0x2210, + DISTANCE_CUE = 0x2300, + USE_DISTANCE_CUE = 0x2301, + WORLD_LAYERED_FOG = 0x2302, + WORLD_USE_LAYERED_FOG = 0x2303, + + DEFAULT_VIEW = 0x3000, + VIEW_TOP = 0x3010, + VIEW_BOTTOM = 0x3020, + VIEW_LEFT = 0x3030, + VIEW_RIGHT = 0x3040, + VIEW_FRONT = 0x3050, + VIEW_BACK = 0x3060, + VIEW_USER = 0x3070, + VIEW_CAMERA = 0x3080, + VIEW_WINDOW = 0x3090, + + NAMED_OBJECT = 0x4000, + OBJ_HIDDEN = 0x4010, + OBJ_VIS_LOFTER = 0x4011, + OBJ_DOESNT_CAST = 0x4012, + OBJ_MATTE = 0x4013, + OBJ_FAST = 0x4014, + OBJ_PROCEDURAL = 0x4015, + OBJ_FROZEN = 0x4016, + OBJ_DONT_RCVSHADOW = 0x4017, + + N_TRI_OBJECT = 0x4100, + POINT_ARRAY = 0x4110, + POINT_FLAG_ARRAY = 0x4111, + FACE_ARRAY = 0x4120, + MSH_MAT_GROUP = 0x4130, + OLD_MAT_GROUP = 0x4131, + SMOOTH_GROUP = 0x4150, + TEX_VERTS = 0x4140, + MESH_MATRIX = 0x4160, + MESH_COLOR = 0x4165, + MESH_TEXTURE_INFO = 0x4170, + PROC_NAME = 0x4181, + PROC_DATA = 0x4182, + MSH_BOXMAP = 0x4190, + + N_D_L_OLD = 0x4400, + + N_CAM_OLD = 0x4500, + + N_DIRECT_LIGHT = 0x4600, + DL_SPOTLIGHT = 0x4610, + DL_RAYSHAD = 0x4627, + DL_SHADOWED = 0x4630, + DL_LOCAL_SHADOW = 0x4640, + DL_LOCAL_SHADOW2 = 0x4641, + DL_SEE_CONE = 0x4650, + DL_SPOT_RECTANGULAR = 0x4651, + DL_SPOT_OVERSHOOT = 0x4652, + DL_SPOT_PROJECTOR = 0x4653, + DL_EXCLUDE = 0x4654, + DL_RANGE = 0x4655, /* Not used in R3 */ + DL_SPOT_ROLL = 0x4656, + DL_SPOT_ASPECT = 0x4657, + DL_RAY_BIAS = 0x4658, + DL_OFF = 0x4620, + DL_ATTENUATE = 0x4625, + DL_INNER_RANGE = 0x4659, + DL_OUTER_RANGE = 0x465A, + DL_MULTIPLIER = 0x465B, + + N_AMBIENT_LIGHT = 0x4680, + + N_CAMERA = 0x4700, + CAM_SEE_CONE = 0x4710, + CAM_RANGES = 0x4720, + + HIERARCHY = 0x4F00, + PARENT_OBJECT = 0x4F10, + PIVOT_OBJECT = 0x4F20, + PIVOT_LIMITS = 0x4F30, + PIVOT_ORDER = 0x4F40, + XLATE_RANGE = 0x4F50, + + POLY_2D = 0x5000, + + /* Flags in shaper file that tell whether polys make up an ok shape */ + SHAPE_OK = 0x5010, + SHAPE_NOT_OK = 0x5011, + + SHAPE_HOOK = 0x5020, + + PATH_3D = 0x6000, + PATH_MATRIX = 0x6005, + SHAPE_2D = 0x6010, + M_SCALE = 0x6020, + M_TWIST = 0x6030, + M_TEETER = 0x6040, + M_FIT = 0x6050, + M_BEVEL = 0x6060, + XZ_CURVE = 0x6070, + YZ_CURVE = 0x6080, + INTERPCT = 0x6090, + DEFORM_LIMIT = 0x60A0, + + /* Flags for Modeler options */ + USE_CONTOUR = 0x6100, + USE_TWEEN = 0x6110, + USE_SCALE = 0x6120, + USE_TWIST = 0x6130, + USE_TEETER = 0x6140, + USE_FIT = 0x6150, + USE_BEVEL = 0x6160, + + /* Viewport description chunks */ + VIEWPORT_LAYOUT_OLD = 0x7000, + VIEWPORT_DATA_OLD = 0x7010, + VIEWPORT_LAYOUT = 0x7001, + VIEWPORT_DATA = 0x7011, + VIEWPORT_DATA_3 = 0x7012, + VIEWPORT_SIZE = 0x7020, + NETWORK_VIEW = 0x7030, + + /* External Application Data */ + XDATA_SECTION = 0x8000, + XDATA_ENTRY = 0x8001, + XDATA_APPNAME = 0x8002, + XDATA_STRING = 0x8003, + XDATA_FLOAT = 0x8004, + XDATA_DOUBLE = 0x8005, + XDATA_SHORT = 0x8006, + XDATA_LONG = 0x8007, + XDATA_VOID = 0x8008, + XDATA_GROUP = 0x8009, + XDATA_RFU6 = 0x800A, + XDATA_RFU5 = 0x800B, + XDATA_RFU4 = 0x800C, + XDATA_RFU3 = 0x800D, + XDATA_RFU2 = 0x800E, + XDATA_RFU1 = 0x800F, + + PARENT_NAME = 0x80F0, + + /* Material Chunk IDs */ + MAT_ENTRY = 0xAFFF, + MAT_NAME = 0xA000, + MAT_AMBIENT = 0xA010, + MAT_DIFFUSE = 0xA020, + MAT_SPECULAR = 0xA030, + MAT_SHININESS = 0xA040, + MAT_SHIN2PCT = 0xA041, + MAT_SHIN3PCT = 0xA042, + MAT_TRANSPARENCY = 0xA050, + MAT_XPFALL = 0xA052, + MAT_REFBLUR = 0xA053, + + MAT_SELF_ILLUM = 0xA080, + MAT_TWO_SIDE = 0xA081, + MAT_DECAL = 0xA082, + MAT_ADDITIVE = 0xA083, + MAT_SELF_ILPCT = 0xA084, + MAT_WIRE = 0xA085, + MAT_SUPERSMP = 0xA086, + MAT_WIRESIZE = 0xA087, + MAT_FACEMAP = 0xA088, + MAT_XPFALLIN = 0xA08A, + MAT_PHONGSOFT = 0xA08C, + MAT_WIREABS = 0xA08E, + + MAT_SHADING = 0xA100, + + MAT_TEXMAP = 0xA200, + MAT_MAPNAME = 0xA300, + MAT_ACUBIC = 0xA310, + + MAT_MAP_TILINGOLD = 0xA350, + MAT_MAP_TILING = 0xA351, + MAT_MAP_TEXBLUR_OLD = 0xA352, + MAT_MAP_TEXBLUR = 0xA353, + MAT_MAP_USCALE = 0xA354, + MAT_MAP_VSCALE = 0xA356, + MAT_MAP_UOFFSET = 0xA358, + MAT_MAP_VOFFSET = 0xA35A, + MAT_MAP_ANG = 0xA35C, + MAT_MAP_COL1 = 0xA360, + MAT_MAP_COL2 = 0xA362, + MAT_MAP_RCOL = 0xA364, + MAT_MAP_GCOL = 0xA366, + MAT_MAP_BCOL = 0xA368, + + MAT_SPECMAP = 0xA204, + MAT_OPACMAP = 0xA210, + MAT_REFLMAP = 0xA220, + MAT_BUMPMAP = 0xA230, + MAT_USE_REFBLUR = 0xA250, + MAT_BUMP_PERCENT = 0xA252, + + MAT_SXP_TEXT_DATA = 0xA320, + MAT_SXP_TEXT2_DATA = 0xA321, + MAT_SXP_OPAC_DATA = 0xA322, + MAT_SXP_BUMP_DATA = 0xA324, + MAT_SXP_SPEC_DATA = 0xA325, + MAT_SXP_SHIN_DATA = 0xA326, + MAT_SXP_SELFI_DATA = 0xA328, + MAT_SXP_TEXT_MASKDATA = 0xA32A, + MAT_SXP_TEXT2_MASKDATA = 0xA32C, + MAT_SXP_OPAC_MASKDATA = 0xA32E, + MAT_SXP_BUMP_MASKDATA = 0xA330, + MAT_SXP_SPEC_MASKDATA = 0xA332, + MAT_SXP_SHIN_MASKDATA = 0xA334, + MAT_SXP_SELFI_MASKDATA = 0xA336, + MAT_SXP_REFL_MASKDATA = 0xA338, + + MAT_TEX2MAP = 0xA33A, + MAT_SHINMAP = 0xA33C, + MAT_SELFIMAP = 0xA33D, + MAT_TEXMASK = 0xA33E, + MAT_TEX2MASK = 0xA340, + MAT_OPACMASK = 0xA342, + MAT_BUMPMASK = 0xA344, + MAT_SHINMASK = 0xA346, + MAT_SPECMASK = 0xA348, + MAT_SELFIMASK = 0xA34A, + MAT_REFLMASK = 0xA34C, + + /* Keyframe Chunk IDs */ + KFDATA = 0xB000, + KFHDR = 0xB00A, + AMBIENT_NODE_TAG = 0xB001, + OBJECT_NODE_TAG = 0xB002, + CAMERA_NODE_TAG = 0xB003, + TARGET_NODE_TAG = 0xB004, + LIGHT_NODE_TAG = 0xB005, + L_TARGET_NODE_TAG = 0xB006, + SPOTLIGHT_NODE_TAG = 0xB007, + + KFSEG = 0xB008, + KFCURTIME = 0xB009, + + NODE_HDR = 0xB010, + INSTANCE_NAME = 0xB011, + PRESCALE = 0xB012, + PIVOT = 0xB013, + BOUNDBOX = 0xB014, + MORPH_SMOOTH = 0xB015, + POS_TRACK_TAG = 0xB020, + ROT_TRACK_TAG = 0xB021, + SCL_TRACK_TAG = 0xB022, + FOV_TRACK_TAG = 0xB023, + ROLL_TRACK_TAG = 0xB024, + COL_TRACK_TAG = 0xB025, + MORPH_TRACK_TAG = 0xB026, + HOT_TRACK_TAG = 0xB027, + FALL_TRACK_TAG = 0xB028, + HIDE_TRACK_TAG = 0xB029, + NODE_ID = 0xB030, + + + CMAGIC = 0xC23D, + + C_MDRAWER = 0xC010, + C_TDRAWER = 0xC020, + C_SHPDRAWER = 0xC030, + C_MODDRAWER = 0xC040, + C_RIPDRAWER = 0xC050, + C_TXDRAWER = 0xC060, + C_PDRAWER = 0xC062, + C_MTLDRAWER = 0xC064, + C_FLIDRAWER = 0xC066, + C_CUBDRAWER = 0xC067, + C_MFILE = 0xC070, + C_SHPFILE = 0xC080, + C_MODFILE = 0xC090, + C_RIPFILE = 0xC0A0, + C_TXFILE = 0xC0B0, + C_PFILE = 0xC0B2, + C_MTLFILE = 0xC0B4, + C_FLIFILE = 0xC0B6, + C_PALFILE = 0xC0B8, + C_TX_STRING = 0xC0C0, + C_CONSTS = 0xC0D0, + C_SNAPS = 0xC0E0, + C_GRIDS = 0xC0F0, + C_ASNAPS = 0xC100, + C_GRID_RANGE = 0xC110, + C_RENDTYPE = 0xC120, + C_PROGMODE = 0xC130, + C_PREVMODE = 0xC140, + C_MODWMODE = 0xC150, + C_MODMODEL = 0xC160, + C_ALL_LINES = 0xC170, + C_BACK_TYPE = 0xC180, + C_MD_CS = 0xC190, + C_MD_CE = 0xC1A0, + C_MD_SML = 0xC1B0, + C_MD_SMW = 0xC1C0, + C_LOFT_WITH_TEXTURE = 0xC1C3, + C_LOFT_L_REPEAT = 0xC1C4, + C_LOFT_W_REPEAT = 0xC1C5, + C_LOFT_UV_NORMALIZE = 0xC1C6, + C_WELD_LOFT = 0xC1C7, + C_MD_PDET = 0xC1D0, + C_MD_SDET = 0xC1E0, + C_RGB_RMODE = 0xC1F0, + C_RGB_HIDE = 0xC200, + C_RGB_MAPSW = 0xC202, + C_RGB_TWOSIDE = 0xC204, + C_RGB_SHADOW = 0xC208, + C_RGB_AA = 0xC210, + C_RGB_OVW = 0xC220, + C_RGB_OVH = 0xC230, + C_RGB_PICTYPE = 0xC240, + C_RGB_OUTPUT = 0xC250, + C_RGB_TODISK = 0xC253, + C_RGB_COMPRESS = 0xC254, + C_JPEG_COMPRESSION = 0xC255, + C_RGB_DISPDEV = 0xC256, + C_RGB_HARDDEV = 0xC259, + C_RGB_PATH = 0xC25A, + C_BITMAP_DRAWER = 0xC25B, + C_RGB_FILE = 0xC260, + C_RGB_OVASPECT = 0xC270, + + C_RGB_ANIMTYPE = 0xC271, + C_RENDER_ALL = 0xC272, + C_REND_FROM = 0xC273, + C_REND_TO = 0xC274, + C_REND_NTH = 0xC275, + C_PAL_TYPE = 0xC276, + C_RND_TURBO = 0xC277, + C_RND_MIP = 0xC278, + C_BGND_METHOD = 0xC279, + C_AUTO_REFLECT = 0xC27A, + C_VP_FROM = 0xC27B, + C_VP_TO = 0xC27C, + C_VP_NTH = 0xC27D, + C_REND_TSTEP = 0xC27E, + C_VP_TSTEP = 0xC27F, + + C_SRDIAM = 0xC280, + C_SRDEG = 0xC290, + C_SRSEG = 0xC2A0, + C_SRDIR = 0xC2B0, + C_HETOP = 0xC2C0, + C_HEBOT = 0xC2D0, + C_HEHT = 0xC2E0, + C_HETURNS = 0xC2F0, + C_HEDEG = 0xC300, + C_HESEG = 0xC310, + C_HEDIR = 0xC320, + C_QUIKSTUFF = 0xC330, + C_SEE_LIGHTS = 0xC340, + C_SEE_CAMERAS = 0xC350, + C_SEE_3D = 0xC360, + C_MESHSEL = 0xC370, + C_MESHUNSEL = 0xC380, + C_POLYSEL = 0xC390, + C_POLYUNSEL = 0xC3A0, + C_SHPLOCAL = 0xC3A2, + C_MSHLOCAL = 0xC3A4, + C_NUM_FORMAT = 0xC3B0, + C_ARCH_DENOM = 0xC3C0, + C_IN_DEVICE = 0xC3D0, + C_MSCALE = 0xC3E0, + C_COMM_PORT = 0xC3F0, + C_TAB_BASES = 0xC400, + C_TAB_DIVS = 0xC410, + C_MASTER_SCALES = 0xC420, + C_SHOW_1STVERT = 0xC430, + C_SHAPER_OK = 0xC440, + C_LOFTER_OK = 0xC450, + C_EDITOR_OK = 0xC460, + C_KEYFRAMER_OK = 0xC470, + C_PICKSIZE = 0xC480, + C_MAPTYPE = 0xC490, + C_MAP_DISPLAY = 0xC4A0, + C_TILE_XY = 0xC4B0, + C_MAP_XYZ = 0xC4C0, + C_MAP_SCALE = 0xC4D0, + C_MAP_MATRIX_OLD = 0xC4E0, + C_MAP_MATRIX = 0xC4E1, + C_MAP_WID_HT = 0xC4F0, + C_OBNAME = 0xC500, + C_CAMNAME = 0xC510, + C_LTNAME = 0xC520, + C_CUR_MNAME = 0xC525, + C_CURMTL_FROM_MESH = 0xC526, + C_GET_SHAPE_MAKE_FACES = 0xC527, + C_DETAIL = 0xC530, + C_VERTMARK = 0xC540, + C_MSHAX = 0xC550, + C_MSHCP = 0xC560, + C_USERAX = 0xC570, + C_SHOOK = 0xC580, + C_RAX = 0xC590, + C_STAPE = 0xC5A0, + C_LTAPE = 0xC5B0, + C_ETAPE = 0xC5C0, + C_KTAPE = 0xC5C8, + C_SPHSEGS = 0xC5D0, + C_GEOSMOOTH = 0xC5E0, + C_HEMISEGS = 0xC5F0, + C_PRISMSEGS = 0xC600, + C_PRISMSIDES = 0xC610, + C_TUBESEGS = 0xC620, + C_TUBESIDES = 0xC630, + C_TORSEGS = 0xC640, + C_TORSIDES = 0xC650, + C_CONESIDES = 0xC660, + C_CONESEGS = 0xC661, + C_NGPARMS = 0xC670, + C_PTHLEVEL = 0xC680, + C_MSCSYM = 0xC690, + C_MFTSYM = 0xC6A0, + C_MTTSYM = 0xC6B0, + C_SMOOTHING = 0xC6C0, + C_MODICOUNT = 0xC6D0, + C_FONTSEL = 0xC6E0, + C_TESS_TYPE = 0xC6f0, + C_TESS_TENSION = 0xC6f1, + + C_SEG_START = 0xC700, + C_SEG_END = 0xC705, + C_CURTIME = 0xC710, + C_ANIMLENGTH = 0xC715, + C_PV_FROM = 0xC720, + C_PV_TO = 0xC725, + C_PV_DOFNUM = 0xC730, + C_PV_RNG = 0xC735, + C_PV_NTH = 0xC740, + C_PV_TYPE = 0xC745, + C_PV_METHOD = 0xC750, + C_PV_FPS = 0xC755, + C_VTR_FRAMES = 0xC765, + C_VTR_HDTL = 0xC770, + C_VTR_HD = 0xC771, + C_VTR_TL = 0xC772, + C_VTR_IN = 0xC775, + C_VTR_PK = 0xC780, + C_VTR_SH = 0xC785, + +/* Material chunks */ + C_WORK_MTLS = 0xC790, /* Old-style -- now ignored */ + C_WORK_MTLS_2 = 0xC792, /* Old-style -- now ignored */ + C_WORK_MTLS_3 = 0xC793, /* Old-style -- now ignored */ + C_WORK_MTLS_4 = 0xC794, /* Old-style -- now ignored */ + C_WORK_MTLS_5 = 0xCB00, /* Old-style -- now ignored */ + C_WORK_MTLS_6 = 0xCB01, /* Old-style -- now ignored */ + C_WORK_MTLS_7 = 0xCB02, /* Old-style -- now ignored */ + C_WORK_MTLS_8 = 0xCB03, /* Old-style -- now ignored */ + C_WORKMTL = 0xCB04, + C_SXP_TEXT_DATA = 0xCB10, + C_SXP_TEXT2_DATA = 0xCB20, + C_SXP_OPAC_DATA = 0xCB11, + C_SXP_BUMP_DATA = 0xCB12, + C_SXP_SPEC_DATA = 0xCB24, + C_SXP_SHIN_DATA = 0xCB13, + C_SXP_SELFI_DATA = 0xCB28, + C_SXP_TEXT_MASKDATA = 0xCB30, + C_SXP_TEXT2_MASKDATA = 0xCB32, + C_SXP_OPAC_MASKDATA = 0xCB34, + C_SXP_BUMP_MASKDATA = 0xCB36, + C_SXP_SPEC_MASKDATA = 0xCB38, + C_SXP_SHIN_MASKDATA = 0xCB3A, + C_SXP_SELFI_MASKDATA = 0xC3C, + C_SXP_REFL_MASKDATA = 0xCB3E, + + C_BGTYPE = 0xC7A1, + C_MEDTILE = 0xC7B0, + +/* Contrast */ + C_LO_CONTRAST = 0xC7D0, + C_HI_CONTRAST = 0xC7D1, + +/* 3d frozen display */ + C_FROZ_DISPLAY = 0xC7E0, + +/* Booleans */ + C_BOOLWELD = 0xc7f0, + C_BOOLTYPE = 0xc7f1, + + C_ANG_THRESH = 0xC900, + C_SS_THRESH = 0xC901, + C_TEXTURE_BLUR_DEFAULT = 0xC903, + + C_MAPDRAWER = 0xCA00, + C_MAPDRAWER1 = 0xCA01, + C_MAPDRAWER2 = 0xCA02, + C_MAPDRAWER3 = 0xCA03, + C_MAPDRAWER4 = 0xCA04, + C_MAPDRAWER5 = 0xCA05, + C_MAPDRAWER6 = 0xCA06, + C_MAPDRAWER7 = 0xCA07, + C_MAPDRAWER8 = 0xCA08, + C_MAPDRAWER9 = 0xCA09, + C_MAPDRAWER_ENTRY = 0xCA10, + +/* System Options */ + C_BACKUP_FILE = 0xCA20, + C_DITHER_256 = 0xCA21, + C_SAVE_LAST = 0xCA22, + C_USE_ALPHA = 0xCA23, + C_TGA_DEPTH = 0xCA24, + C_REND_FIELDS = 0xCA25, + C_REFLIP = 0xCA26, + C_SEL_ITEMTOG = 0xCA27, + C_SEL_RESET = 0xCA28, + C_STICKY_KEYINF = 0xCA29, + C_WELD_THRESHOLD = 0xCA2A, + C_ZCLIP_POINT = 0xCA2B, + C_ALPHA_SPLIT = 0xCA2C, + C_KF_SHOW_BACKFACE = 0xCA30, + C_OPTIMIZE_LOFT = 0xCA40, + C_TENS_DEFAULT = 0xCA42, + C_CONT_DEFAULT = 0xCA44, + C_BIAS_DEFAULT = 0xCA46, + + C_DXFNAME_SRC = 0xCA50, + C_AUTO_WELD = 0xCA60, + C_AUTO_UNIFY = 0xCA70, + C_AUTO_SMOOTH = 0xCA80, + C_DXF_SMOOTH_ANG = 0xCA90, + C_SMOOTH_ANG = 0xCAA0, + +/* Special network-use chunks */ + C_NET_USE_VPOST = 0xCC00, + C_NET_USE_GAMMA = 0xCC10, + C_NET_FIELD_ORDER = 0xCC20, + + C_BLUR_FRAMES = 0xCD00, + C_BLUR_SAMPLES = 0xCD10, + C_BLUR_DUR = 0xCD20, + C_HOT_METHOD = 0xCD30, + C_HOT_CHECK = 0xCD40, + C_PIXEL_SIZE = 0xCD50, + C_DISP_GAMMA = 0xCD60, + C_FBUF_GAMMA = 0xCD70, + C_FILE_OUT_GAMMA = 0xCD80, + C_FILE_IN_GAMMA = 0xCD82, + C_GAMMA_CORRECT = 0xCD84, + C_APPLY_DISP_GAMMA = 0xCD90, /* OBSOLETE */ + C_APPLY_FBUF_GAMMA = 0xCDA0, /* OBSOLETE */ + C_APPLY_FILE_GAMMA = 0xCDB0, /* OBSOLETE */ + C_FORCE_WIRE = 0xCDC0, + C_RAY_SHADOWS = 0xCDD0, + C_MASTER_AMBIENT = 0xCDE0, + C_SUPER_SAMPLE = 0xCDF0, + C_OBJECT_MBLUR = 0xCE00, + C_MBLUR_DITHER = 0xCE10, + C_DITHER_24 = 0xCE20, + C_SUPER_BLACK = 0xCE30, + C_SAFE_FRAME = 0xCE40, + C_VIEW_PRES_RATIO = 0xCE50, + C_BGND_PRES_RATIO = 0xCE60, + C_NTH_SERIAL_NUM = 0xCE70, + + /* Video Post */ + VPDATA = 0xd000, + + P_QUEUE_ENTRY = 0xd100, + P_QUEUE_IMAGE = 0xd110, + P_QUEUE_USEIGAMMA = 0xd114, + P_QUEUE_PROC = 0xd120, + P_QUEUE_SOLID = 0xd130, + P_QUEUE_GRADIENT = 0xd140, + P_QUEUE_KF = 0xd150, + P_QUEUE_MOTBLUR = 0xd152, + P_QUEUE_MB_REPEAT = 0xd153, + P_QUEUE_NONE = 0xd160, + + P_QUEUE_RESIZE = 0xd180, + P_QUEUE_OFFSET = 0xd185, + P_QUEUE_ALIGN = 0xd190, + + P_CUSTOM_SIZE = 0xd1a0, + + P_ALPH_NONE = 0xd210, + P_ALPH_PSEUDO = 0xd220, /* Old chunk */ + P_ALPH_OP_PSEUDO = 0xd221, /* Old chunk */ + P_ALPH_BLUR = 0xd222, /* Replaces pseudo */ + P_ALPH_PCOL = 0xd225, + P_ALPH_C0 = 0xd230, + P_ALPH_OP_KEY = 0xd231, + P_ALPH_KCOL = 0xd235, + P_ALPH_OP_NOCONV = 0xd238, + P_ALPH_IMAGE = 0xd240, + P_ALPH_ALPHA = 0xd250, + P_ALPH_QUES = 0xd260, + P_ALPH_QUEIMG = 0xd265, + P_ALPH_CUTOFF = 0xd270, + P_ALPHANEG = 0xd280, + + P_TRAN_NONE = 0xd300, + P_TRAN_IMAGE = 0xd310, + P_TRAN_FRAMES = 0xd312, + P_TRAN_FADEIN = 0xd320, + P_TRAN_FADEOUT = 0xd330, + P_TRANNEG = 0xd340, + + P_RANGES = 0xd400, + + P_PROC_DATA = 0xd500 +}; + +struct Vector2f { + float x, y; +} [[static]]; + +struct Vector3f { + float x, y, z; +} [[static]]; + +bitfield FaceFlags { + CA_Visible : 1; + BC_Visible : 1; + AB_Visible : 1; + Mapped : 1; + padding : 9; + CA_Selected : 1; + BC_Selected : 1; + AB_Selected : 1; +}; + +struct Face { + u16 v0, v1,v2; + FaceFlags flags; +}; + +bitfield VertexFlags { + padding : 13; + selected3 : 1; + selected2 : 1; + selected1 : 1; +}; + +bitfield KeyFlags1 { + Show_Path : 1; + Smooth : 1; + padding : 2; + Motion_Blur : 1; + padding : 1; + Morph_Mat : 1; +}; + +bitfield KeyFlags2 { + padding : 10; + Hidden : 1; +}; + +struct RGB { + T r, g, b; +}; + +bitfield Spline { + Use_Tension : 1; + Use_Continuity : 1; + Use_Bias : 1; + Use_Ease_To : 1; + Use_Ease_From : 1; + + padding : 3; + + if (Use_Tension == 1) + float Tension; + if (Use_Continuity == 1) + float Continuity; + if (Use_Bias == 1) + float Bias; + if (Use_Ease_To == 1) + float Ease_To; + if (Use_Ease_From == 1) + float Ease_From; + + padding : 8; +}; + +struct VectorKey { + u32 index; + Spline splineData; + Vector3f value; +}; + +struct RotationKey { + u32 index; + Spline splineData; + float angle; + Vector3f vector; +}; + +struct AngleKey { + u32 index; + Spline splineData; + float angle; +}; + +struct MorphKey{ + u32 index; + Spline splineData; + char objectName[]; +}; + +struct HideKey { + u32 index; + Spline splineData; +}; + +struct Keys { + u32 count; + match (identifier) { + ( + ChunkIdentifier::POS_TRACK_TAG | + ChunkIdentifier::SCL_TRACK_TAG | + ChunkIdentifier::COL_TRACK_TAG + ) : { + VectorKey data[count]; + } + + ( + ChunkIdentifier::ROT_TRACK_TAG + ) : { + RotationKey data[count]; + } + + ( + ChunkIdentifier::FOV_TRACK_TAG | + ChunkIdentifier::ROLL_TRACK_TAG | + ChunkIdentifier::HOT_TRACK_TAG | + ChunkIdentifier::FALL_TRACK_TAG + ) : { + AngleKey data[count]; + } + + ( + ChunkIdentifier::MORPH_TRACK_TAG + ) : { + MorphKey data[count]; + } + + ( + ChunkIdentifier::HIDE_TRACK_TAG + ) : { + HideKey data[count]; + } + } +}; + +enum TrackMode : u16 { + MODE_SINGLE = 0, + MODE_REPEAT = 1, + MODE_LOOP = 2, +}; + +bitfield TrackFlags { + TrackMode Mode : 2; + padding : 1; + Lock_X : 1; + Lock_Y : 1; + Lock_Z : 1; + padding : 1; + Unlink_X : 1; + Unlink_Y : 1; + Unlink_Z : 1; +}; + +struct Chunk { + ChunkIdentifier identifier; + u32 chunkSize; + u32 dataLength = chunkSize - 6 [[export]]; + u32 chunkEnd = $ + dataLength; + + if (chunkSize > 0) { + std::print("{}", identifier); + match (identifier) { + ( + ChunkIdentifier::M3DMAGIC | + ChunkIdentifier::MDATA | + ChunkIdentifier::N_TRI_OBJECT | + ChunkIdentifier::KFDATA | + ChunkIdentifier::AMBIENT_NODE_TAG | + ChunkIdentifier::OBJECT_NODE_TAG | + ChunkIdentifier::CAMERA_NODE_TAG | + ChunkIdentifier::TARGET_NODE_TAG | + ChunkIdentifier::LIGHT_NODE_TAG | + ChunkIdentifier::L_TARGET_NODE_TAG | + ChunkIdentifier::SPOTLIGHT_NODE_TAG | + ChunkIdentifier::MAT_ENTRY | + ChunkIdentifier::MAT_AMBIENT | + ChunkIdentifier::MAT_DIFFUSE | + ChunkIdentifier::MAT_SPECULAR | + ChunkIdentifier::MAT_SHININESS | + ChunkIdentifier::MAT_SHIN2PCT | + ChunkIdentifier::MAT_SHIN3PCT | + ChunkIdentifier::MAT_TRANSPARENCY | + ChunkIdentifier::MAT_XPFALL | + ChunkIdentifier::MAT_REFBLUR | + ChunkIdentifier::MAT_SELF_ILPCT | + ChunkIdentifier::MAT_TEXMAP | + ChunkIdentifier::MAT_SPECMAP | + ChunkIdentifier::MAT_OPACMAP | + ChunkIdentifier::MAT_REFLMAP | + ChunkIdentifier::MAT_BUMPMAP | + ChunkIdentifier::MAT_BUMP_PERCENT | + ChunkIdentifier::MAT_TEX2MAP | + ChunkIdentifier::MAT_SHINMAP | + ChunkIdentifier::MAT_SELFIMAP | + ChunkIdentifier::MAT_TEXMASK | + ChunkIdentifier::MAT_TEX2MASK | + ChunkIdentifier::MAT_OPACMASK | + ChunkIdentifier::MAT_BUMPMASK | + ChunkIdentifier::MAT_SHINMASK | + ChunkIdentifier::MAT_SPECMASK | + ChunkIdentifier::MAT_SELFIMASK | + ChunkIdentifier::MAT_REFLMASK | + ChunkIdentifier::WORLD_VIEWPORT_DATA | + ChunkIdentifier::WORLD_VIEWPORT_DATA3 | + ChunkIdentifier::WORLD_VIEWPORT_LAYOUT | + ChunkIdentifier::SOLID_BGND | + ChunkIdentifier::AMBIENT_LIGHT + ): { + Chunk chunks[while($ < chunkEnd)]; + } + + ( + ChunkIdentifier::M3D_VERSION | + ChunkIdentifier::MESH_VERSION + ): { + u32 version; + } + + ( + ChunkIdentifier::LO_SHADOW_BIAS | + ChunkIdentifier::HI_SHADOW_BIAS | + ChunkIdentifier::SHADOW_FILTER | + ChunkIdentifier::RAY_BIAS | + ChunkIdentifier::FLOAT_PERCENTAGE | + ChunkIdentifier::MASTER_SCALE | + ChunkIdentifier::MAT_MAP_TEXBLUR | + ChunkIdentifier::MAT_MAP_USCALE | + ChunkIdentifier::MAT_MAP_VSCALE | + ChunkIdentifier::MAT_MAP_UOFFSET | + ChunkIdentifier::MAT_MAP_VOFFSET | + ChunkIdentifier::MAT_MAP_ANG | + ChunkIdentifier::MAT_WIRESIZE | + ChunkIdentifier::DL_SPOT_ROLL | + ChunkIdentifier::MORPH_SMOOTH + ): { + float value; + } + + ( + ChunkIdentifier::V_GRADIENT + ) : { + float position; + Chunk chunks[while($ < chunkEnd)]; + } + + ( + ChunkIdentifier::NAMED_OBJECT + ) : { + char name[]; + Chunk chunks[while($ < chunkEnd)]; + } + + ( + ChunkIdentifier::POINT_ARRAY + ) : { + u16 count; + Vector3f vectices[count] [[hex::visualize("3d", this, null)]]; + } + + ( + ChunkIdentifier::TEX_VERTS + ) : { + u16 count; + Vector2f coords[count]; + } + + ( + ChunkIdentifier::MESH_MATRIX + ) : { + Vector3f x, y, z, w; + } + + ( + ChunkIdentifier::FACE_ARRAY + ) : { + u16 count; + Face faces[count]; + Chunk chunks[while($ < chunkEnd)]; + } + + ( + ChunkIdentifier::POINT_FLAG_ARRAY + ) : { + u16 count; + VertexFlags flags[count]; + } + + ( + ChunkIdentifier::SMOOTH_GROUP + ) : { + u32 groups[dataLength / sizeof(u32)]; + } + + ( + ChunkIdentifier::MESH_COLOR + ) : { + u8 value; + } + + ( + ChunkIdentifier::MSH_MAT_GROUP + ) : { + char name[]; + u16 count; + u16 groups[count]; + } + + ( + ChunkIdentifier::KFHDR + ) : { + u16 revision; + char name[]; + u32 animationLength; + } + + ( + ChunkIdentifier::KFSEG + ) : { + u32 start, end; + } + + ( + ChunkIdentifier::KFCURTIME + ) : { + u32 frameIndex; + } + + ( + ChunkIdentifier::NODE_ID + ) : { + type::Hex id; + } + + ( + ChunkIdentifier::NODE_HDR + ) : { + char name[]; + padding[1]; + KeyFlags1 flags1; + KeyFlags2 flags2; + type::Hex parentId; + } + + ( + ChunkIdentifier::PIVOT + ) : { + Vector3f value; + } + + ( + ChunkIdentifier::BOUNDBOX + ) : { + Vector3f min, max; + } + + ( + ChunkIdentifier::COLOR_24 | + ChunkIdentifier::LIN_COLOR_24 + ) : { + RGB color; + } + + ( + ChunkIdentifier::COLOR_F | + ChunkIdentifier::LIN_COLOR_F + ) : { + RGB color; + } + + ( + ChunkIdentifier::INT_PERCENTAGE | + ChunkIdentifier::MAT_BUMP_PERCENT + ) : { + u16 value; + } + + ( + ChunkIdentifier::SHADOW_MAP_SIZE | + ChunkIdentifier::MAT_SHADING + ) : { + u16 value; + } + + ( + ChunkIdentifier::POS_TRACK_TAG | + ChunkIdentifier::ROT_TRACK_TAG | + ChunkIdentifier::SCL_TRACK_TAG | + ChunkIdentifier::FOV_TRACK_TAG | + ChunkIdentifier::ROLL_TRACK_TAG | + ChunkIdentifier::COL_TRACK_TAG | + ChunkIdentifier::MORPH_TRACK_TAG | + ChunkIdentifier::HOT_TRACK_TAG | + ChunkIdentifier::FALL_TRACK_TAG | + ChunkIdentifier::HIDE_TRACK_TAG + ) : { + TrackFlags flags; + u8 unknown[8]; + Keys keys; + } + + ( + ChunkIdentifier::INSTANCE_NAME | + ChunkIdentifier::BIT_MAP | + ChunkIdentifier::DL_SPOT_PROJECTOR | + ChunkIdentifier::MAT_NAME | + ChunkIdentifier::MAT_MAPNAME + ) : { + char name[]; + } + + ( + ChunkIdentifier::MAT_MAP_TILING + ) : { + u16 tiling; + } + + ( + ChunkIdentifier::WORLD_VIEWPORT_SIZE + ) : { + u16 x, y, w, h; + } + + ( + ChunkIdentifier::N_DIRECT_LIGHT + ) : { + Vector3f position; + Chunk chunks[while($ < chunkEnd)]; + } + + ( + ChunkIdentifier::DL_SPOTLIGHT + ) : { + Vector3f target; + float hotspot, falloff; + Chunk chunks[while($ < chunkEnd)]; + } + + ( + ChunkIdentifier::N_CAMERA + ) : { + Vector3f position, target; + float roll, fov; + } + + + + (_) : { + std::warning(std::format("Unhandled Chunk ID: {}, Skipping 0x{:04X} bytes", identifier, dataLength)); + $ += dataLength; + } + } + } +}; + +Chunk chunk @ 0x00; \ No newline at end of file diff --git a/tests/patterns/test_data/3ds.hexpat.3ds b/tests/patterns/test_data/3ds.hexpat.3ds new file mode 100644 index 0000000000000000000000000000000000000000..9406ee687cfab45802232a8927cfee0a3e7fc0fa GIT binary patch literal 32485 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 literal 0 HcmV?d00001