Skip to content
Open
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
201 changes: 196 additions & 5 deletions patterns/gltf.hexpat
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,16 @@
* 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 hex.type.json;
import std.core;

/**
* @brief The glTF magic section.
Expand All @@ -53,7 +56,10 @@ 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. */
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is one way you could pass unit tests.

#ifndef __IMHEX__ 
   u8 data[length];
#endif
#ifdef __IMHEX__
    match (type) {
        (gltf_chunk_type_t::JSON): hex::type::Json<length> json;
        (gltf_chunk_type_t::BIN): u8 data[length];
    }      /**< The chunk data. */
 #endif

You would need to also do all other parts that fail the unit tests.

match (type) {
(gltf_chunk_type_t::JSON): hex::type::Json<length> json;
(gltf_chunk_type_t::BIN): u8 data[length];
} /**< The chunk data. */
};

fn gltf_format(gltf_chunk_type_t x)
Expand All @@ -64,7 +70,192 @@ fn gltf_format(gltf_chunk_type_t x)
return "";
};

gltf_magic_t magic @ 0x00;
gltf_chunk_t chunks[while(!std::mem::eof())] @ $;
u64 json_offset = 0;
u64 json_length = 0;

std::assert_warn(std::mem::size() == magic.length, "file size mismatch");
struct StrideType<InnerType, auto Stride> {
InnerType value [[inline]];
if (Stride > 0) {
padding[Stride - sizeof(value)];
}
};

struct Scalar<ComponentType> {
ComponentType scalar;
} [[static, sealed]];

struct Vec2<ComponentType> {
ComponentType x;
ComponentType y;
} [[static]];

struct Vec3<ComponentType> {
ComponentType x;
ComponentType y;
ComponentType z;
} [[static]];

struct Vec4<ComponentType> {
ComponentType x;
ComponentType y;
ComponentType z;
ComponentType w;
} [[static]];

struct Mat2<ComponentType> {
ComponentType a11;
ComponentType a21;
ComponentType a12;
ComponentType a22;
} [[static]];

struct Mat3<ComponentType> {
ComponentType a11;
ComponentType a21;
ComponentType a31;
ComponentType a12;
ComponentType a22;
ComponentType a32;
ComponentType a13;
ComponentType a23;
ComponentType a33;
} [[static]];

struct Mat4<ComponentType> {
ComponentType a11;
ComponentType a21;
ComponentType a31;
ComponentType a41;
ComponentType a12;
ComponentType a22;
ComponentType a32;
ComponentType a42;
ComponentType a13;
ComponentType a23;
ComponentType a33;
ComponentType a43;
ComponentType a14;
ComponentType a24;
ComponentType a34;
ComponentType a44;
} [[static]];

enum ComponentType : u64 {
BYTE = 5120,
UNSIGNED_BYTE = 5121,
SHORT = 5122,
UNSIGNED_SHORT = 5123,
UNSIGNED_INT = 5125,
FLOAT = 5126,
};

struct Accessor<auto Offset> {
hex::type::Json<json_length> Json @ json_offset;
hex::type::Json<json_length> Json2 @ json_offset;
hex::type::Json<json_length> Json3 @ json_offset;
u64 accessor_index = std::core::array_index();
u64 view_index = Json.accessors[accessor_index].bufferView [[export]];
u64 view_offset = Json.bufferViews[view_index].byteOffset [[export]];
if (std::core::has_member(Json2.bufferViews[view_index], "byteStride")) {
u64 byte_stride = Json.bufferViews[view_index].byteStride [[export]];
} else {
u64 byte_stride = 0 [[export]];
}
if (std::core::has_member(Json3.accessors[accessor_index], "byteOffset")) {
u64 accessor_offset = Json.accessors[accessor_index].byteOffset [[export]];
} else {
u64 accessor_offset = 0 [[export]];
}
view_offset = view_offset + accessor_offset;
u64 count_elements = Json.accessors[accessor_index].count;
ComponentType component_type = Json.accessors[accessor_index].componentType [[export]];

match (Json.accessors[accessor_index].type, component_type) {
("SCALAR", ComponentType::BYTE): StrideType<Scalar<s8>, byte_stride> content[count_elements] @ view_offset + Offset;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You want to avoid having to list all cases for each data type and each component type. There should be one case for SCALAR, one for VEC2, and so one with no sub-matches or nothing, just one line per type. Instead of using the type asargument pass the enumeration so you can match the built in types at the lowest level possible. That way you only have to match them once instead of having to match them once for scalar, one for vec2 ,.... Note that you don't need to change the StrideType struct templates, only the ones for scalar, vec2,...
Start by creating a new templated type for ComponentType (I would rename ComponentType enum to ComponentTypes.) that does the matching on the template argument. Then use the newly created type to populate scalar, vec2,vec3,...
I think the code will become cleaner and easier to read and work with.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mean with that something like this in the different types?

struct Scalar<auto ComponentType, auto Stride> {
    match (ComponentType) {
        (ComponentTypes::BYTE): StrideType<s8, Stride> scalar;
        (ComponentTypes::UNSIGNED_BYTE): StrideType<u8, Stride> scalar;
        (ComponentTypes::SHORT): StrideType<s16, Stride> scalar;
        (ComponentTypes::UNSIGNED_SHORT): StrideType<u16, Stride> scalar;
        (ComponentTypes::UNSIGNED_INT): StrideType<u32, Stride> scalar;
        (ComponentTypes::FLOAT): StrideType<float, Stride> scalar;
    }
};

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That would also not be optimal including matches for each type. Ypu can create only one match to test for content_type enum value

struct ComponentType<auto component_type> {
    match (component_type) {
        (ComponentTypes::BYTE)                        :  s8 value;
        (ComponentTypes::UNSIGNED_BYTE)   :  u8 value;
        (ComponentTypes::SHORT)                      : s16 value;
        (ComponentTypes::UNSIGNED_SHORT) : u16 value;
        (ComponentTypes::UNSIGNED_INT)       :  u32 value ;
        (ComponentTypes::FLOAT)                       : float value;
    }
};

Then you can define Scalar and the rest like this

struct Scalar<auto component_type> {
    ComponentType<component_type> x;
} [[static, sealed]];

with formaters to avoid the extra layers added. This creates the same data types but using only one match for the value types (int ,short,...) and one match for the data types (scalar, vector2,...).

("SCALAR", ComponentType::UNSIGNED_BYTE): StrideType<Scalar<u8>, byte_stride> content[count_elements] @ view_offset + Offset;
("SCALAR", ComponentType::SHORT): StrideType<Scalar<s16>, byte_stride> content[count_elements] @ view_offset + Offset;
("SCALAR", ComponentType::UNSIGNED_SHORT): StrideType<Scalar<u16>, byte_stride> content[count_elements] @ view_offset + Offset;
("SCALAR", ComponentType::UNSIGNED_INT): StrideType<Scalar<u32>, byte_stride> content[count_elements] @ view_offset + Offset;
("SCALAR", ComponentType::FLOAT): StrideType<Scalar<float>, byte_stride> content[count_elements] @ view_offset + Offset;
("VEC2", ComponentType::FLOAT): StrideType<Vec2<s8>, byte_stride> content[count_elements] @ view_offset + Offset;
("VEC2", ComponentType::UNSIGNED_INT): StrideType<Vec2<u8>, byte_stride> content[count_elements] @ view_offset + Offset;
("VEC2", ComponentType::UNSIGNED_SHORT): StrideType<Vec2<s16>, byte_stride> content[count_elements] @ view_offset + Offset;
("VEC2", ComponentType::SHORT): StrideType<Vec2<u16>, byte_stride> content[count_elements] @ view_offset + Offset;
("VEC2", ComponentType::UNSIGNED_BYTE): StrideType<Vec2<u32>, byte_stride> content[count_elements] @ view_offset + Offset;
("VEC2", ComponentType::BYTE): StrideType<Vec2<float>, byte_stride> content[count_elements] @ view_offset + Offset;
("VEC3", ComponentType::FLOAT): StrideType<Vec3<float>, byte_stride> content[count_elements] @ view_offset + Offset;
("VEC3", ComponentType::UNSIGNED_INT): StrideType<Vec3<u32>, byte_stride> content[count_elements] @ view_offset + Offset;
("VEC3", ComponentType::UNSIGNED_SHORT): StrideType<Vec3<u16>, byte_stride> content[count_elements] @ view_offset + Offset;
("VEC3", ComponentType::SHORT): StrideType<Vec3<s16>, byte_stride> content[count_elements] @ view_offset + Offset;
("VEC3", ComponentType::UNSIGNED_BYTE): StrideType<Vec3<u8>, byte_stride> content[count_elements] @ view_offset + Offset;
("VEC3", ComponentType::BYTE): StrideType<Vec3<s8>, byte_stride> content[count_elements] @ view_offset + Offset;
("VEC4", ComponentType::FLOAT): StrideType<Vec4<float>, byte_stride> content[count_elements] @ view_offset + Offset;
("VEC4", ComponentType::UNSIGNED_INT): StrideType<Vec4<u32>, byte_stride> content[count_elements] @ view_offset + Offset;
("VEC4", ComponentType::UNSIGNED_SHORT): StrideType<Vec4<u16>, byte_stride> content[count_elements] @ view_offset + Offset;
("VEC4", ComponentType::SHORT): StrideType<Vec4<s16>, byte_stride> content[count_elements] @ view_offset + Offset;
("VEC4", ComponentType::UNSIGNED_BYTE): StrideType<Vec4<u8>, byte_stride> content[count_elements] @ view_offset + Offset;
("VEC4", ComponentType::BYTE): StrideType<Vec4<s8>, byte_stride> content[count_elements] @ view_offset + Offset;
("MAT2", ComponentType::FLOAT): StrideType<Mat2<float>, byte_stride> content[count_elements] @ view_offset + Offset;
("MAT2", ComponentType::UNSIGNED_INT): StrideType<Mat2<u32>, byte_stride> content[count_elements] @ view_offset + Offset;
("MAT2", ComponentType::UNSIGNED_SHORT): StrideType<Mat2<u16>, byte_stride> content[count_elements] @ view_offset + Offset;
("MAT2", ComponentType::SHORT): StrideType<Mat2<s16>, byte_stride> content[count_elements] @ view_offset + Offset;
("MAT2", ComponentType::UNSIGNED_BYTE): StrideType<Mat2<u8>, byte_stride> content[count_elements] @ view_offset + Offset;
("MAT2", ComponentType::BYTE): StrideType<Mat2<s8>, byte_stride> content[count_elements] @ view_offset + Offset;
("MAT3", ComponentType::FLOAT): StrideType<Mat3<float>, byte_stride> content[count_elements] @ view_offset + Offset;
("MAT3", ComponentType::UNSIGNED_INT): StrideType<Mat3<u32>, byte_stride> content[count_elements] @ view_offset + Offset;
("MAT3", ComponentType::UNSIGNED_SHORT): StrideType<Mat3<u16>, byte_stride> content[count_elements] @ view_offset + Offset;
("MAT3", ComponentType::SHORT): StrideType<Mat3<s16>, byte_stride> content[count_elements] @ view_offset + Offset;
("MAT3", ComponentType::UNSIGNED_BYTE): StrideType<Mat3<u8>, byte_stride> content[count_elements] @ view_offset + Offset;
("MAT3", ComponentType::BYTE): StrideType<Mat3<s8>, byte_stride> content[count_elements] @ view_offset + Offset;
("MAT4", ComponentType::FLOAT): StrideType<Mat4<float>, byte_stride> content[count_elements] @ view_offset + Offset;
("MAT4", ComponentType::UNSIGNED_INT): StrideType<Mat4<u32>, byte_stride> content[count_elements] @ view_offset + Offset;
("MAT4", ComponentType::UNSIGNED_SHORT): StrideType<Mat4<u16>, byte_stride> content[count_elements] @ view_offset + Offset;
("MAT4", ComponentType::SHORT): StrideType<Mat4<s16>, byte_stride> content[count_elements] @ view_offset + Offset;
("MAT4", ComponentType::UNSIGNED_BYTE): StrideType<Mat4<u8>, byte_stride> content[count_elements] @ view_offset + Offset;
("MAT4", ComponentType::BYTE): StrideType<Mat4<s8>, byte_stride> content[count_elements] @ view_offset + Offset;
}
};

fn mem_cnt(auto value) {
return std::core::member_count(value);
};

struct ImageBuffer<auto Offset> {
hex::type::Json<json_length> Json @ json_offset;
u64 image_index = std::core::array_index();
u64 buffer_view_index = Json.images[image_index].bufferView;
u64 byte_offset = Json.bufferViews[buffer_view_index].byteOffset;
u64 byte_length = Json.bufferViews[buffer_view_index].byteLength;
u8 image[byte_length] @ Offset + byte_offset;
} [[hex::visualize("image", image)]];

struct BufferView<auto Offset> {
hex::type::Json<json_length> Json @ json_offset;
u64 buffer_view_index = std::core::array_index();
u64 byte_offset = Json.bufferViews[buffer_view_index].byteOffset;
u64 byte_length = Json.bufferViews[buffer_view_index].byteLength;
u8 data[byte_length] @ Offset + byte_offset;
};

struct Glb {
gltf_magic_t magic;
gltf_chunk_t json_chunk;
gltf_chunk_t chunks[while(!std::mem::eof())];

json_offset = addressof(json_chunk.json);
json_length = json_chunk.length;

std::assert_warn(std::mem::size() == magic.length, "file size mismatch");

if (std::core::member_count(chunks) == 1) {
u128 bin_chunk = addressof(chunks[0].data);
hex::type::Json<json_length> Json @ json_offset;
if (std::core::has_member(Json, "images")) {
ImageBuffer<bin_chunk> images[mem_cnt(json_chunk.json.images)];
}
BufferView<bin_chunk> buffer_views[mem_cnt(json_chunk.json.bufferViews)];
Accessor<bin_chunk> accessors[mem_cnt(json_chunk.json.accessors)];
}
};

Glb glb @ 0x00;
Loading