diff --git a/patterns/gltf.hexpat b/patterns/gltf.hexpat index 85d94b8f..a208b965 100644 --- a/patterns/gltf.hexpat +++ b/patterns/gltf.hexpat @@ -22,13 +22,18 @@ * SOFTWARE. */ -#pragma author H. Utku Maden +#pragma author H. Utku Maden, xZise #pragma description GL Transmission Format binary 3D model (.glb) #pragma MIME model/gltf-binary +#pragma magic [67 6C 54 46] @ 0x00 import std.mem; import std.io; import type.magic; +import std.core; +#ifdef __IMHEX__ +import hex.type.json; +#endif /** * @brief The glTF magic section. @@ -53,7 +58,15 @@ enum gltf_chunk_type_t : u32 { struct gltf_chunk_t { u32 length; /**< Length of this chunk. */ gltf_chunk_type_t type [[format("gltf_format")]]; /**< Type of the chunk. JSON or BIN expected. */ - u8 string[length]; /**< The chunk data. */ +#ifndef __IMHEX__ + u8 data[length]; /**< The chunk data. */ +#endif +#ifdef __IMHEX__ + match (type) { + (gltf_chunk_type_t::JSON): hex::type::Json json; + (gltf_chunk_type_t::BIN): u8 data[length]; + } /**< The chunk data. */ +#endif }; fn gltf_format(gltf_chunk_type_t x) @@ -64,7 +77,162 @@ fn gltf_format(gltf_chunk_type_t x) return ""; }; -gltf_magic_t magic @ 0x00; -gltf_chunk_t chunks[while(!std::mem::eof())] @ $; +struct stride_type_t { + InnerType value [[inline]]; + if (Stride > 0) { + padding[Stride - sizeof(value)]; + } +}; + +enum component_types_t : u64 { + BYTE = 5120, + UNSIGNED_BYTE = 5121, + SHORT = 5122, + UNSIGNED_SHORT = 5123, + UNSIGNED_INT = 5125, + FLOAT = 5126, +}; + +fn component_type_format(component_types_t component_type) +{ + if (component_type == component_types_t::BYTE) return "s8"; +else if (component_type == component_types_t::UNSIGNED_BYTE) return "u8"; +else if (component_type == component_types_t::SHORT) return "s16"; +else if (component_type == component_types_t::UNSIGNED_SHORT) return "u16"; +else if (component_type == component_types_t::UNSIGNED_INT) return "u32"; +else if (component_type == component_types_t::FLOAT) return "float"; + + return std::format("{}", component_type); +}; + +struct component_type_t { + match (component_type) { + (component_types_t::BYTE): s8 value; + (component_types_t::UNSIGNED_BYTE): u8 value; + (component_types_t::SHORT): s16 value; + (component_types_t::UNSIGNED_SHORT): u16 value; + (component_types_t::UNSIGNED_INT): u32 value; + (component_types_t::FLOAT): float value; + } +}; + +struct scalar_t { + component_type_t scalar [[inline]]; +} [[static]]; + +struct vec2_t { + component_type_t x; + component_type_t y; +} [[static]]; + +struct vec3_t { + component_type_t x; + component_type_t y; + component_type_t z; +} [[static]]; + +struct vec4_t { + component_type_t x; + component_type_t y; + component_type_t z; + component_type_t w; +} [[static]]; + +struct mat2_t { + component_type_t a11, a21; + component_type_t a12, a22; +} [[static]]; + +struct mat3_t { + component_type_t a11, a21, a31; + component_type_t a12, a22, a32; + component_type_t a13, a23, a33; +} [[static]]; + +struct mat4_t { + component_type_t a11, a21, a31, a41; + component_type_t a12, a22, a32, a42; + component_type_t a13, a23, a33, a43; + component_type_t a14, a24, a34, a44; +} [[static]]; + +fn mem_cnt(auto value) { + return std::core::member_count(value); +}; + +fn has_mem(auto value, str member) { + return std::core::has_member(value, member); +}; + +struct accessor_t { + u64 accessor_index = std::core::array_index(); + u64 view_index = glb.json_chunk.json.accessors[accessor_index].bufferView [[export]]; + u64 view_offset = glb.json_chunk.json.bufferViews[view_index].byteOffset [[export]]; + if (has_mem(glb.json_chunk.json.bufferViews[view_index], "byteStride")) { + u64 byte_stride = glb.json_chunk.json.bufferViews[view_index].byteStride [[export]]; + } else { + u64 byte_stride = 0 [[export]]; + } + if (has_mem(glb.json_chunk.json.accessors[accessor_index], "byteOffset")) { + u64 accessor_offset = glb.json_chunk.json.accessors[accessor_index].byteOffset [[export]]; + } else { + u64 accessor_offset = 0 [[export]]; + } + view_offset = view_offset + accessor_offset; + u64 count_elements = glb.json_chunk.json.accessors[accessor_index].count; + component_types_t component_type = glb.json_chunk.json.accessors[accessor_index].componentType [[export]]; + str element_type = glb.json_chunk.json.accessors[accessor_index].type [[export]]; + + match (element_type) { + ("SCALAR"): stride_type_t, byte_stride> content[count_elements] @ view_offset + addressof(glb.chunks[0].data); + ("VEC2"): stride_type_t, byte_stride> content[count_elements] @ view_offset + addressof(glb.chunks[0].data); + ("VEC3"): stride_type_t, byte_stride> content[count_elements] @ view_offset + addressof(glb.chunks[0].data); + ("VEC4"): stride_type_t, byte_stride> content[count_elements] @ view_offset + addressof(glb.chunks[0].data); + ("MAT2"): stride_type_t, byte_stride> content[count_elements] @ view_offset + addressof(glb.chunks[0].data); + ("MAT3"): stride_type_t, byte_stride> content[count_elements] @ view_offset + addressof(glb.chunks[0].data); + ("MAT4"): stride_type_t, byte_stride> content[count_elements] @ view_offset + addressof(glb.chunks[0].data); + } +} [[format("accessor_format")]]; + +fn accessor_format(accessor_t accessor) { + return std::format("{}<{}>[{}]", accessor.element_type, accessor.component_type, accessor.count_elements); +}; + +struct image_buffer_t { + u64 image_index = std::core::array_index(); + u64 buffer_view_index = glb.json_chunk.json.images[image_index].bufferView; + u64 byte_offset = glb.json_chunk.json.bufferViews[buffer_view_index].byteOffset; + u64 byte_length = glb.json_chunk.json.bufferViews[buffer_view_index].byteLength; + u8 image[byte_length] @ addressof(glb.chunks[0].data) + byte_offset; +} [[hex::visualize("image", image)]]; + +struct buffer_view_t { + u64 buffer_view_index = std::core::array_index(); + u64 byte_offset = glb.json_chunk.json.bufferViews[buffer_view_index].byteOffset; + u64 byte_length = glb.json_chunk.json.bufferViews[buffer_view_index].byteLength; + u8 data[byte_length] @ addressof(glb.chunks[0].data) + byte_offset; +}; + +struct glb_file_t { + gltf_magic_t magic; + gltf_chunk_t json_chunk; + gltf_chunk_t chunks[while(!std::mem::eof())]; + + std::assert_warn(std::mem::size() == magic.length, "file size mismatch"); +}; + +glb_file_t glb @ 0x00; + +#ifdef __IMHEX__ +struct glb_objects_t { + if (std::core::member_count(glb.chunks) == 1) { + if (has_mem(glb.json_chunk.json, "images")) { + image_buffer_t images[mem_cnt(glb.json_chunk.json.images)]; + } + buffer_view_t buffer_views[mem_cnt(glb.json_chunk.json.bufferViews)]; + accessor_t accessors[mem_cnt(glb.json_chunk.json.accessors)]; + } +}; -std::assert_warn(std::mem::size() == magic.length, "file size mismatch"); +glb_objects_t objects @ 0x00; +#endif \ No newline at end of file diff --git a/patterns/png.hexpat b/patterns/png.hexpat index ebd7122e..787d058f 100644 --- a/patterns/png.hexpat +++ b/patterns/png.hexpat @@ -214,6 +214,11 @@ struct Chunks { chunk_t iend_chunk [[comment("Image End Chunk")]]; }; -u8 visualizer[std::mem::size()] @ 0x00 [[sealed, hex::visualize("image", this)]]; -header_t header @ 0x00 [[comment("PNG file signature"), name("Signature")]]; -Chunks chunks @ 0x08 [[name("Chunks")]]; \ No newline at end of file +struct Png { + header_t header [[comment("PNG file signature"), name("Signature")]]; + Chunks chunks [[name("Chunks")]]; + u128 length = $ - addressof(this); + u8 visualizer[length] @ addressof(this) [[sealed, hex::visualize("image", this), no_unique_address]]; +}; + +Png png @ 0x00; \ No newline at end of file diff --git a/patterns/png2.hexpat b/patterns/png2.hexpat new file mode 100644 index 00000000..787d058f --- /dev/null +++ b/patterns/png2.hexpat @@ -0,0 +1,224 @@ +#pragma description PNG image + +#pragma MIME image/png +#pragma endian big + +import std.mem; + +struct header_t { + u8 highBitByte; + char signature[3]; + char dosLineEnding[2]; + char dosEOF; + char unixLineEnding; +}; + +struct actl_t { + u32 frames [[comment("Total № of frames in animation")]]; + u32 plays [[comment("№ of times animation will loop")]]; +} [[comment("Animation control chunk"), name("acTL")]]; + +enum ColorType: u8 { + Grayscale = 0x0, + RGBTriple = 0x2, + Palette, + GrayscaleAlpha, + RGBA = 0x6 +}; + +enum Interlacing: u8 { + None, + Adam7 +}; + +struct ihdr_t { + u32 width [[comment("Image width")]]; + u32 height [[comment("Image height")]]; + u8 bit_depth; + ColorType color_type [[comment("PNG Image Type")]]; + u8 compression_method [[comment("Only 0x0 = zlib supported by most")]]; + u8 filter_method [[comment("Only 0x0 = adaptive supported by most")]]; + Interlacing interlacing; +}; + +enum sRGB: u8 { + Perceptual = 0x0, + RelativeColorimetric, + Saturation, + AbsoluteColorimetric +}; + +enum Unit: u8 { + Unknown, + Meter +}; + +struct phys_t { + u32 ppu_x [[comment("Pixels per unit, X axis")]]; + u32 ppu_y [[comment("Pixels per unit, Y axis")]]; + Unit unit; +}; + +enum BlendOp: u8 { + Source = 0x0, + Over +}; + +enum DisposeOp: u8 { + None = 0x0, + Background, + Previous +}; + +struct fctl_t { + u32 sequence_no [[comment("Sequence №")]]; + u32 width [[comment("Frame width")]]; + u32 height; + u32 xoff; + u32 yoff; + u16 delay_num; + u16 delay_den; + DisposeOp dispose_op; + BlendOp blend_op; +}; + +struct fdat_t { + u32 sequence_no; +}; + +fn text_len() { + u64 len = parent.parent.length - ($ - addressof(parent.keyword)); + return len; +}; + +struct itxt_t { + char keyword[]; + u8 compression_flag; + u8 compression_method; + char language_tag[]; + char translated_keyword[]; + char text[text_len()]; +}; + +struct ztxt_t { + char keyword[]; + u8 compression_method; + char text[text_len()]; +}; + +struct text_t { + char keyword[]; + char text[text_len()]; +}; + +struct iccp_t { + char keyword[]; + u8 compression_method; + u8 compressed_profile[text_len()]; +}; + +struct palette_entry_t { + u24 color; +} [[inline]]; + +struct chrm_t { + u32 white_point_x; + u32 white_point_y; + u32 red_x; + u32 red_y; + u32 green_x; + u32 green_y; + u32 blue_x; + u32 blue_y; +}; + +struct time_t { + u16 year; + u8 month; + u8 day; + u8 hour; + u8 minute; + u8 second; +}; + +struct chunk_t { + u32 length [[color("17BECF")]]; + char name[4]; + + #define IHDR_k "IHDR" + #define PLTE_k "PLTE" + #define sRGB_k "sRGB" + #define pHYs_k "pHYs" + #define iTXt_k "iTXt" + #define tEXt_k "tEXt" + #define zTXt_k "zTXt" + #define IDAT_k "IDAT" + #define IEND_k "IEND" + #define gAMA_k "gAMA" + #define iCCP_k "iCCP" + #define acTL_k "acTL" + #define fdAT_k "fdAT" + #define fcTL_k "fcTL" + #define cHRM_k "cHRM" + #define tIME_k "tIME" + + if (name == IHDR_k) { + ihdr_t ihdr [[comment("Image Header chunk"), name("IHDR")]]; + } else if (name == PLTE_k) { + palette_entry_t entries[length / 3]; + } else if (name == sRGB_k) { + sRGB srgb; + } else if (name == pHYs_k) { + phys_t phys; + } else if (name == acTL_k) { + actl_t actl [[comment("Animation control chunk")]]; + } else if (name == fcTL_k) { + fctl_t fctl [[comment("Frame control chunk")]]; + } else if (name == iTXt_k) { + itxt_t text; + } else if (name == gAMA_k) { + u32 gamma [[name("image gamma"), comment("4 byte unsigned integer representing gamma times 100000")]]; + } else if (name == iCCP_k) { + iccp_t iccp; + } else if (name == tEXt_k) { + text_t text; + } else if (name == zTXt_k) { + ztxt_t text; + } else if (name == iCCP_k) { + iccp_t iccp; + } else if (name == fdAT_k) { + fdat_t fdat [[comment("Frame data chunk")]]; + u8 data[length-sizeof(u32)]; + } else if (name == cHRM_k) { + chrm_t chrm; + } else if (name == tIME_k) { + time_t time; + } else { + u8 data[length]; + } + + u32 crc; +} [[name(chunkValueName(this))]]; + +fn chunkValueName(ref chunk_t chunk) { + return chunk.name; +}; + +struct chunk_set { + chunk_t chunks[while(builtin::std::mem::read_string($ + 4, 4) != "IEND")] [[inline]]; +} [[inline]]; + +struct Chunks { + chunk_t ihdr_chunk [[comment("PNG Header chunk")]]; + chunk_set set [[comment("PNG Chunks"), name("Chunks"), inline]]; + chunk_t iend_chunk [[comment("Image End Chunk")]]; +}; + +struct Png { + header_t header [[comment("PNG file signature"), name("Signature")]]; + Chunks chunks [[name("Chunks")]]; + u128 length = $ - addressof(this); + u8 visualizer[length] @ addressof(this) [[sealed, hex::visualize("image", this), no_unique_address]]; +}; + +Png png @ 0x00; \ No newline at end of file