Dash Model Format >> Name List

File Declaration

0x00 0x04 0x08 0x0c
0x0000 DMF offset rev 1 num props
0x0010  
0x0020 ATTR offset id 0 num attr
0x0030 NAME offset id 0 num tex
0x0040 BONE offset id 0 num bone
0x0050 VERT offset id 0 num vert
0x0060 TEX offset id 0 num props
0x0070 TEX offset id 1 num props
0x0080 MAT offset id 0 num props
0x0090 MAT offset id 1 num props
0x00a0 FACE offset mat id num tri
0x00b0 FACE offset mat id num tri
0x00c0 FACE offset mat id num tri
0x00d0 ANIM offset id 0 num frames
0x00e0 ANIM offset id 1 num frames
0x00f0 ANIM offset id 2 num frames
0x0100  

DMF

The above table displays a sample header for the Dash Model Format. The first row of the file is standard. The first four bytes will always be the magic number DMF. The next four bytes is the offset to the start of the header list. Most often this will be 0x20, as there is a line of padding between the file declaration and the header list in case properties are added later on. It also allows for the option for multiple DMF models to be packed into a single file.

The next four bytes of the file delcaration is the file version. Right now the DMF version is 1, and if things go well, this will be the maintained version. However if changes are made such that compatibility becomes impossible is implausible, this version will be incremented to 2. The last four bytes in the file declaration are the number of properties in the header list.

The header list defines a list of blocks that define the model. Each block header has a length of 16 bytes starting with a magic number to describe the type of the block, followed by the offset inside the file to where the block is defined. The next four bytes is an id or reference. In most cases it defines an id for the block, in the face of face groups, it defines the material index being used for the group of faces. And the last byte bytes contains the number of elements defined inside the block.

A short description of the header list definitions of each blocks will follow below. The definitions for the layout of each block is defined on their respective pages accessible from the left hand side bar.

ATTR

The magic number ATTR defines a list of attributes to be used globally inside the model. Specifically these are vertex weights, number of uv entries, existence of vertex colors and vertex normals. These are defined in a key-value list such that more properties can be defined later if needed as to not break compatibility. If no ATTR block is defined in the file, all default values will be assumed.

NAME

The magic number NAME defines a list of names. Specifically for the texture and animation lists. The list is packed such that the end of each name string is terminated with '\0`. A list of empty names maybe in a file as a sequence of empty zero's. This block is not required and the exporter will check if names are set and omit if not pressent.

BONE

The magic number BONE defines the bone list. Only one bone list can be defined per file. If no bones are present this block is not needed.

VERT

The magic number VERT defines a vertex list. Only one vertex list can be defined per file. The DMF can be used to store a material list where only materials and textures are present. If no VERT block is found, the loader will assume a material list.

TEX

The magic number TEX defines a texture. A block will be defined for the number of textures that exist inside the model. Each texture comes with generally a set number of properties before the image is defined.

MAT

The magic number MAT defines a material. A block will be defined for the number of materials the exist inside the model. The id defines the material id, which is later references by a face group. Any textures referenced by the material will be defined in the key-value block.

FACE

The magic number FACE defines a face group. A block is defined for each 'group' within the model. Specifically a 'group' is a sequence of continuous triangles with the same material index. For instance if a motorcycle is defined with two wheels using the same material and the body using a different material, and the draw order is front wheel, body, back wheel. Then the model would be expressed as three 'groups', each existing as a FACE block.

ANIM

The magic number ANIM defines an skeletal animation. Each animation contains a list of key frames with the transformation matrix for each bone in the frame. An ANIM block for each individual animation.

Header Definitions

0x00 0x04 0x08 0x0c
0x0000 ATTR offset id 0 num attr 4

The table above shows the header entry for the attribute block. The first four bytes are the magic number. The second four bytes are the offset to the block. The third offset is the id of the attribute block, which should always be zero. And the last four bytes of the header definition should be the int 4, until new attributes are added into the definition. The attrbute block defines optional attributes than are used global across the model. If this block is not defined, then no optional values will be read, specifically meaning that vertices will not include weights, and triangles will only consist of indices without any uv, vertex normals or vertex colors.

Block Definition

0x00 0x04 0x08 0x0c
0x0000 ATTR len VWGT bool
0x0010 UVCT int VNRM bool
0x0020 VCLR bool

The table above gives the layout for the body of the attribute block. The block starts with the magic number of the block, which is ATTR, followed by the length of the data defined in the block.

Currently the attributes defined in this block are as follows.

  • VWGT - "Vertex Weights" defines if skin indices and skin weights are included in the vertex list or not. 0 for no, 1 for yes.
  • UVCT - "UV Count" defines the number of uv's defined in each face triangle. Currently the only values recognized by the importer and exporter are 0 and 1, but more uv values maybe added in the future, though they might be defined as "MAP" definitions. More research needs to be done in this area. Though if map is used this property will be switched from a UV to a boolean and defined as MAPT.
  • VNRM - "Vertex Normals" definses if normals are attached to the face definition or not. Normals are defined as x, y, z float values between 0.0 and 1.0.
  • VCLR - "Vertex Colors" defines if colors are attached to the face definition or not. Colors are defines as r, b, g, float values between 0.0 and 1.0.
  • Open Issues

    Right now I'm debating the following issues for this section.

  • Do I need to define vertex weights in this section, or can i assume that vertex weights must be pressent in the vertex list. Or do I require the attribute to be set as a form of possitive confirmation?
  • What properties do I need to define for uv's? Do i simply define a list of uv's to be stored for the user? Or do I create properties for the specific purposes of uv's?
  • Is defining attributes globally for the entire model a good approach? Or should I allow face attributes to be set by group? One of the design goals of this file format is to allow models to be easily converted to buffer geometry. And that means keeping the interface consistent across all faces.
  • So for now defining an attribute block means that I can add attributes into the header as needed, and keep them global across the model. And allow for the possibility of declaring multiple attribute blocks to change attributes if needed in the future. Right now only the first attribute block declared will be reconigized, and must come before any vertex or face lists.
  • Header Definitions

    0x00 0x04 0x08 0x0c
    0x0000 NAME offset id 0 bone name 13
    0x0000 NAME offset id 1 tex name 2
    0x0000 NAME offset id 2 anim name 3

    The table above shows the header entry for the name block. The first four bytes are the NAME magic number, followed by its offset in the file. The third set is the block id. And the last four bytes is the number of the property being defined.

    Block Definition

    0x00 0x04 0x08 0x0c
    0x0000 NAME len TEX moto
    0x0000 rcyl e_wh eel. png
    0x0000 \0mot orcy le_b ody.
    0x0000 png\0

    The table above shows the structure of the name block. The block starts with the NAME magic number and the length of the content of the block. Following the magic and the length, the first data is a maguc number defining the name of the property being defined.

    Following the example of the motorcycle defined in the header, we have "motorcycle_wheel.png" and "motorcycle_body.png" for texture names. And "drive", "park", and "crash" for animation names.

    If no NAME block is defined, then no names will be asigned to the attributes being parsed in the file. The exporter will look at the names of the attributes being exported, and if all are null or empty strings, the NAME block will not be generated for that attribute.

    Since names will have to be defined before their respective blocks, it's recomended to have them defined at the begining of the file. Names will not be retroactively applied.

    Strings will be parsed one at a time until a null byte is encountered. In this way a series of null characters can be represent emtpy strings. So in the case that only the second texture had a name, this block would be represented as "\0motorcycle_body.png\0".

    Header Definitions

    0x00 0x04 0x08 0x0c
    0x0000 BONE offset id 0 num bone 3

    The table above shows the format for the header entry of the BONE block. Only one bone block is allowed per DMF file. If a bone entry exists, the model will be parsed as a skinned mesh, otherwise the model will be parsed as a standard mesh. The first four bytes are the magic number BONE, the second four bytes are the pointer to the block location in the file. The third four bytes is the id 0. And last is the number of bones declared in the block.

    Block Definition

    0x00 0x04 0x08 0x0c
    0x0000 BONE len id | parent id elem 0
    0x0000 elem 1 elem 2 elem 3 elem 4
    0x0000 elem 5 elem 6 elem 7 elem 8
    0x0000 elem 9 elem 10 elem 11 elem 12
    0x0000 elem 13 elem 14 elem 15 id | parent id
    0x0000 elem 0 elem 1 elem 2 elem 3
    0x0000 elem 4 elem 5 elem 6 elem 7
    0x0000 elem 8 elem 9 elem 10 elem 11
    0x0000 elem 12 elem 13 elem 14 elem 15
    0x0000 id | parent id elem 0 elem 1 elem 2
    0x0000 elem 3 elem 4 elem 5 elem 6
    0x0000 elem 7 elem 8 elem 9 elem 10
    0x0000 elem 11 elem 12 elem 13 elem 14
    0x0000 elem 15

    The table above shows the block definition of the bone list. The block starts out with the magic number BONE and the length of the content defined within the bone. The first data is a signed short for the id, and a signed short for the parent id. In the case of the first bone, this will always be 0 and -1. The short is signed in order to express the negaive number to express the lack of a parent bone for the root bone.

    From there, there are 16 floats that make up a 4x4 transformation matrix that makes up the bone. The elements are stored in column-major order. After the end of the 16 elements have been declared, the next bone starts with signed shorts for the id and parent id, followed by 16 elements for the bone. This pattern continues for number of bones defined in the header.

    struct DashBone {
    	short id;
    	short parent_id;
    	float elements[16];
    };
    

    Open Issues

    Another option would be to include the position, rotation and scale for each bone. But that would require rebuilding the bone from the elements, so simply having the elements seems like the most standard way to manage this information.

    Header Definitions

    0x00 0x04 0x08 0x0c
    0x0000 VERT offset id 0 num vertex 64

    The table above shows the header defition of the VERT block. The first four bytes are the magic number VERT, the second four bytes is the offset inside the file. The third four bytes is the id of 0. And the last four bytes are the number of vertices defined in the file.

    0x00 0x04 0x08 0x0c
    0x0000 VERT len x y
    0x0000 z indice 0 | 1 indice 2 | 3 weight 0
    0x0000 weight 1 weight 2 weight 3 x
    0x0000 y z indice 0 | 1 indice 2 | 3
    0x0000 weight 0 weight 1 weight 2 ...

    The table above shows a sample of the VERT block. The block starts with the VERT magic number, and is followed by the length of the data declared within the block. The vertex list then has two possible formats depending on if the VWGT or "vertex weight" flag is set in the ATTR block inside the file.

    In the case that there is either no ATTR block, or an ATTR block has been defined and the VWGT flags is not set, then the vertex list will simply be a list of x, y, z vertices defined as a list of 32 bit floats.

    In the case that the ATTR block exists and the VWGT flags is set then the vertex list has the structure of x, y, z 32 bit floats for each vertex followed by four unsigned short indices, followed by four 32 bit floats for vertex weights.

    Note that the number of weights is always 4 and there is no flag to set the number of weights. If no weights exist for a given vertex, or there are less than four weights are required, simply enter 0 for the indice and 0 for the weight.

    struct DashVertex {
    	float x,y,z
    }
    
    struct DashVertexWeight {
    	unsigned short indices[4];
    	float weights[4];
    }
    					

    Open Issues

    Originally I was going to include a number of weights per vertex option. But threejs and gltf have weights defined as vec4 data types. So to keep consistency and reduce potential confusion I decided to force four weights even if it means a slightly longer file. Though in addition to the VWGT "vertex weights" yes or no flag, another flag can be introduced for the number of weights, with the default of four set, without breaking backwards compatibility.

    Header Definitions

    0x00 0x04 0x08 0x0c
    0x0000 TEX offset id 0 num props
    0x0000 TEX offset id 1 num props

    The table above shows the header format of the TEX block. A TEX block defines a texture, and properties associated with it. The first four bytes is the magic number TEX, the second four bytes are the pointer to the location of the offset. The third four bytes is a unique integer id for the texture. Not that the number displayed is not the one actually used. The texture id is forced by the order in which the textures are listed in the file. Materials refer to textures by these numbers for mapping. As such these numbers are to be used as a reference while viewing the file.

    The last four bytes are the number of properties defined in the file. The number of properties will always be at least three, as the extension, the length of the image and the actual image data always need to be defined. Other properties like flipy and properties for texture repeat can be set here too.

    0x00 0x04 0x08 0x0c
    0x0000 TEX len TYPE png
    0x0000 LEN unsigned int FLPY bool
    0x0000 WID unsgined int HGT unsigned int
    0x0000 WRPS unsigned int WRPT unsigned int
    0x0000 IMG img data -

    The table above shows the block definition of the TEX block. The first four bytes are the magic number TEX followed by the length of data defined inside the block. Following the block label is a list of properties that can come in any order with one exception, the IMG property comes last.

    The texture block defines a list of properties that define a texture. These properties include:

  • TYPE (required) - the extension of the image, right now png format is forced in the importer and exporter, but ttf, jpeg, or otherwise could be included later.
  • LEN (required) - the byte length of the IMG defined in this block.
  • FLPY - "flipY" property, follwed by a boolean 1 for yes, 0 for no value.
  • WID - width of the image in pixels.
  • HGT - height of the image in pixels
  • WRPS - wrapS This defines how the texture is wrapped horizontally and corresponds to U in UV mapping. The default is THREE.ClampToEdgeWrapping, where the edge is clamped to the outer edge texels. other two choices are THREE.RepeatWrapping and THREE.MirroredRepeatWrapping.
  • WRPT - wrapT This defines how the texture is wrapped vertically and corresponds to V in UV mapping. The default is THREE.ClampToEdgeWrapping, where the edge is clamped to the outer edge texels. other two choices are THREE.RepeatWrapping and THREE.MirroredRepeatWrapping.
  • IMG - The actual image data. Currently a base64 data url string. Could be switched to binary later.
  • Open Issues

    Originally I had just wanted to declare the image directly without any properties but I realized that wrapping, filtering, and sampling it would be better to have a list of properties to preceed the image to be on the safe side.

    I am tempted to make the option of adding in global properties into the ATTR block to set default texture properties so they don't have to be defined everytime. Though that would make the parses and exporter code comre complicated. And in general use, not a lot can be assumed about which options are global, so setting them for each image seems to be the safe bet.

    Right now I'm forcing png with a limited number of properties. Allowing for more image types and defining more properties like filtering, maybe something I have to implement later. But for testing I'll keep it simple. Also, not sure about introducing mipmaps or not.

    Header Definitions

    0x00 0x04 0x08 0x0c
    0x0000 MAT offset id 0 num props
    0x0000 MAT offset id 1 num props

    The table above shows the header definition for the MAT block. The first four bytes is the magic number MAT. The second four bytes is the offset inside the file. The third four bytes is the material id. This will be a sequential number of integers starting from 0. Face groups will refer to this number. And the last four bytes is the number of properties.

    Block Definitions

    0x00 0x04 0x08 0x0c
    0x0000 MAT len DIFF r
    0x0000 g b MAP0 tex id
    0x0000 TYPE basi c\0
    0x0000 OPAC float ALPT float
    0x0000 VCLR int PREC enum
    0x0000 DITH bool SIDE int
    0x0000 TRNS bool VSBL bool

    The table above shows the definition of the MAT block. The block starts off with the magic number MAT and is followed by the length of the data defined in the block. The block itself is made of key value pairs. Properties of the material are defined with magic numbers follows by the value data that defines it.

    In most cases the values will be defined as four byte ints. However depending on the property, they can be longer. Such as the DIFF or "diffuse" property which is followed by three 32 bit floats, one for red, green and blue respectively. The properties as as defined below.

  • DIFF - "diffuse" diffuse color of the material, followed by three floats for r, g, b/
  • MAP0 - The texture id which is used with the uv0 coords.
  • TYPE - the type of the material, defined as a 12 byte string. Possible values are "basic", "phong", "lambert".
  • OPAC - The opacity of the material defined as a 32 bit float between 0.0 and 1.0.
  • ALPT - Alphatest, defined as a 32 bit float bewteen 0.0 and 1.0.
  • VCLR - Vertex color default is THREE.NoColors otherwise THREE.VertexColors
  • PREC - Float precision values are "low", "med" or "high"
  • DITH - Dithering, true defined as 1, false defined as 0
  • SIDE -Defines which side of faces will be rendered - front, back or both. Default is THREE.FrontSide. Other options are THREE.BackSide and THREE.DoubleSide.
  • TRNS - Transparent, true is defined as 1, false defined as 0
  • VSBL - Visible, true is defined as 1, false defined as 0
  • Open Issues

    Materials are a rabbit hole, so right now I only have a few properties defined for basic use. More properties will need to be defined with a magic number for each one and a definition. There's also more material types, but I'll keep it simple and slowly expand out.

    The other issue is how to handle texture mapping. Right now I have the number of uv's defined on each face as an int. That gives me a couple of options to define how textures. Do i defined them as MAP0, MAP1, MAP2 for which texture to use a specific UV array. Or do I make it more specific, MAPT, MAPE, MAPN for "map texture", "map environment", "map normals". I could do this and also define a number after each ne for the uv reference and then another one for the texture id reference.

    Header Definitions

    0x00 0x04 0x08 0x0c
    0x0000 FACE offset mat id 0 num indices 21
    0x0000 FACE offset mat id 1 num indices 66
    0x0000 FACE offset mat id 0 num indices 21

    The table above shows the header entry for the FACE block. The first four bytes are the magic number FACE, the second four bytes are the offset inside the file. The third four bytes is the material index id for the face group. And the last our bytes is the number of indices defined inside the block. Indices represent points on a triangle, so the number should always be divisble by three.

    Header Definitions

    0x00 0x04 0x08 0x0c
    0x0000 FACE len a indice u0
    0x0000 v0 normal x normal y normal z
    0x0000 vcolor r vcolor b vcolor g b indice
    0x0000 u0 v0 normal x normal y
    0x0000 normal z vcolor r vcolor b vcolor g
    0x0000 c indice u0 v0 normal x
    0x0000 normal y normal z vcolor r vcolor b
    0x0000 vcolor g ...

    The table above shows the structure of the FACE block. The first four bytes are the bagic number FACE, followed by the length of the data defined inside block. The block data starts with the a indice, which is actually a two byte unsigned short. It it displayed in the table above as a 4 byte value for the sake of formatting.

    What information follows deoends on the flags declared in the ATTR block. If no flags are set, then this list will simply be a list of indices. The three attributes that affect this block are UVCT "uv count", VNRM "vertex normal" and VCLR "vertex color".

    [ unsigned short Indice ] 
    ( UVCT [ float U0 ] [float V0] ) 
    (VNRM [float x] [float y][float z] )  
    (VCLR [float r] [float g][float b] )

    The text above shows what the above table looks like. Following the indices, if the UVCT attribute is above 1, then that number of uv pairs will follow the indice. In this case there is only one UV declared in the uv count, but if two were declared, they would follow in the order of u0, v0, u1, v1.

    If set, the next value will be the vertex normals. The vertex normals are a float for x, y, and z respectively. Note that face normals are not included in this definition as they are not attached to the vertex, and can be calculated with "calculateFaceNormals".

    If set, the next value will be vertex colors. The vertex colors are a float for r, g, and b between 0 and 1. This pattern is then repeated for each indice with every three indices forming a triangle. So the order is a0, b0, c0, a1, b1, c1, with the properties for each indice following each indice.

    Open Issues

    When creating this format, I went for indice specific to create a repeating pattern. But after writing this I'm tempted to change the definition to a triangle centric representation. Of a0, b0, c0, followed by a list of uv'v, followed by the normals, followed by the colors. That would be a lot easier to export and parse. And it would make the number of triangles easier to use in the header. This could also be done with minimal changes to the code. Though it actually works pretty well now, and changes to how parsing is done could be added to the ATTR block later.

    Header Definitions

    0x00 0x04 0x08 0x0c
    0x0000 ANIM offset anim id 0 num frames 21
    0x0000 ANIM offset anim id 1 num frames 43
    0x0000 ANIM offset anim id 2 num frames 32

    The table above shows the format for the animation header entry. The first four bytes are the magic number ANIM. The second four bytes are the offset inside the file. The third four bytes show the animation id number, which should be a sequential list of integers. Note that the order of animations defines the animation id, and these numbers are here for display purposes. If the animation names are set in a NAME block, then names will be added according to the order they appear in. And the last four bytes are the total number of keyframes in the file. Which is not used, but available for verfication purposes.

    Block Definition

    0x00 0x04 0x08 0x0c
    0x0000 ANIM len duration float parent -1
    0x0000 num key frames 2 time 0 'prs" pos0
    0x0000 pos1 pos2 rot0 rot1
    0x0000 rot2 rot3 scl0 scl1
    0x0000 scl2 time 1 'pr" pos0
    0x0000 pos1 pos2 rot0 rot1
    0x0000 rot2 rot3 parent 0 num key frames
    0x0000 'prs' pos0 pos1 ...

    The table above shows the description of the animation block. It starts with the magic number ANIM, followed by the length of the data defined inside the block.

    The first value defined inside the block is the duration, defined as a float value. Following that will be a list of key frames for each bone starting with bone 0. So while not actually needed, for confirmation, the following value is a signed int for the bone parent number. After the parent number is the number of key frames given for that bone. In this example we'll go with two.

    Following the definition is a float value given for the time, followed by the key frame format, which will consist of the characters 'prs'. The 'prs' characters define which transformations are being defined for the frame. If 'p' exists, that means position is defined, and three float for the postion will be included. If 'r' exists it means that four floats for the rotation quarternion will be defined. If 's' exists, it means that three floats for scale will be defined.

    Any combination of 'prs' is possible. 'p' only, 'r' only, 's' only, 'prs', 'pr' and 'rs'. But a character will not be repeated and will always be declared in the order of p first, then r, then s in the case they exist.

    So the 'prs' format is read. Which means 12 bytes for position, 16 bytes for rotation, and 12 bytes for scale. Following the keyframe will be the time index for the next keyframe, followed by the next 'prs' format, which will give the format for the next key frame. This loop for the number of keyframes defined after the parent bone number.

    This will repeat for each parent bone for the number of bones in the bone list. So starting with -1, 0, and up until the number of bones has been reached. First the bone number is declared, followed by the number of frames. Each frame is given a time index, followed by the 'prs' format, followed by the data defined.

    Open Issues

    Originally I had wanted to use transformation matrices, but didn't get good results with the matrix decope method to get the individual transformations back, and ended up going with the separated elements to begin with. The difference in size for each entry isn't hard to deal with, using the 'prs' definition header.

    Blender

  • Import Plugin
  • Load from server
  • Load from file
  • Load from indexeddb
  • Export Plugin
  • Example Page
  • Blender

    Copyright © 2018 DashGL Project