header 0x0000 type_float 0x0001 type_ubyte 0x0002 type_short 0x0003 type_int 0x0004 type_uint 0x0005 ... skeleton 0x1000 skeleton_file 0x1100 num_bones 0x1200 joint 0x1300 joint_name 0x1310 joint_data 0x1320 materials 0x2000 material_file 0x2100 material 0x2200 mat_name 0x2210 textures 0x2220 fragshader_file 0x2230 ambient 0x2240 diffuse 0x2250 emission 0x2260 specular 0x2270 shininess 0x2271 mesh 0x3000 num_submeshes 0x3100 submesh 0x3200 submesh_file 0x3210 hook 0x3211 vrt_shader 0x3221 material_used 0x3222 num_vertices 0x3231 num_tc_per_vrt 0x3232 num_indices 0x3233 attribs 0x3241 positions 0x3242 normals 0x3243 texcoords 0x3244 tc_set 0x3245 color_prim 0x3246 color_sec 0x3247 bone_weights 0x3248 tri_list 0x3251 tri_strip 0x3252 Many details are debatable, the focus however is to allow adding new chunk types easily without breaking existing loaders by making it easy to ignore unknown chunk types. Pure string chunks store the string length as chunk size. Chunks containing mixed information store the size in the byte before the string. That should avoid loops to read them, but requires manually adding \0 when using c-strings (maybe additionally store the \0?) Many chunks have a file chunk, storing the name of a file which contains the actual chunk. That should allow sharing skeletons, material libraries or referencing submeshes (like a carried weapon or other equipment). The "hook" chunk simply specifies the bone this submesh should be bound or attached to. Submeshes are defined by their material, so all geometry is automatically sorted by material. For most uses just one submesh should be enough. Intented internal use is storing vertices/indices for the whole mesh and making submeshes offsets into the index array and material properties (to avoid lots of glxxxPointer calls). It's possible to store any number of index-sets for triangle lists and strips to make use of stripified geometry without much hassle (limit tri lists to one? All extra triangles should be collected there anyway) Ugly parts are tex coords and bone weights. To allow any number of any dimensional tex coords the structure is a bit more complex. Tex sets store one byte with the dimension followed by data per vertex. Bones are stored as list of bone/weight per vertex, requiring a bit of nestling some loops. Generic vertex attribute chunks can be used, but to avoid confusion should then be used exclusively (or add index of attribute?) Animations will be stored as keyframes, specifying index of bones different from the bind pose and the difference in rotation/position. With animation blending in mind I feel that might be easier to handle than storing difference to last frame (though most likely results in much more data). The highest used bone index should be indicated for an easy check against the number of joints in the skeleton (mostly when using external animations to ensure at least screwed animation instead of crashing). Big question: allow for a mesh/material to use multiple shaders? No experience how common that might be. Though it only requires to allow multiple x_shader_file chunks. header (used for each chunk): [size(uint), id(ushort)] skeleton file [filename(char[size])] num_joints [num(ushort)] joint* joint_name [name(char[size])] joint_data [parent(1sh), rot(3f), pos(3f)]* materials file [filename(char[size])] material* mat_name [name(char[size])] textures [num(1ubyte)] [length(1ubyte), filename (char[length])]* fragshader_file [name(char[size])] ambient [type(1ubyte), color(4 * sizeof(type)] diffuse [type(1ubyte), color(4 * sizeof(type)] emission [type(1ubyte), color(4 * sizeof(type)] specular [type(1ubyte), color(4 * sizeof(type)] shininess [shiny(1f)] mesh num_submeshes [num(uint)] submesh* file [filename(char[size])] hook [bone_idx(ushort)] vrt_shader [filename(char[size])] material_used [mat_name(char[size])] num_vertices [num(uint)] num_tc_per_vrt [num(uint)] num_indices [num(uint)] positions [position(3float)]* normals [normal(3float)]* texcoords tc_set* [dim(1b)] [dim*tc(1float)]* bone_weights [ [num_bones(1ubyte)] [bone_idx(ushort), weight(float)]* ]* color_prim [type(1ubyte)] [4 * sizeof(type)]* color_sec [type(1ubyte)] [4 * sizeof(type)]* vertex_attrib [dim(1ubyte), type(1ubyte)] [dim * sizeof(type)]* tri_list [idx(1uint)]* tri_strip [idx(1uint)]*