// Example C Source code for importing and exporting the Little Stick compact binary v1.0.0 format. // This format is as simple as possible to aid the import of Little Stick trees into other programs. // Shadows, lighting and textures etc. are not included. // Error checking is removed to aid reading. /* The structure of the file is as follows: A 37 byte header. Contains the ascii characters "// Little stick compact format v1.0.0". A 1 byte unsigned char. Contains 1 if the tree has leaves and 0 otherwise. A 1 byte unsigned char. Contains 1 if the tree has fruit and 0 otherwise. For each object, Branches then Leaves (Optional), then Fruit (Optional) { A 4 byte unsigned long integer. Contains the number of vertices and texture co-ordinates used. A 4 byte unsigned long integer. Contains the number of indices used. An array of 4 byte floating point numbers. Contains all of the vertex data. The size of this array is 4 * 3 * (Number of vertices) bytes. Each vertex contains 3 numbers, the x then y then z co-ordinates. Each number is a 4 byte floating point number. An array of 4 byte floating point numbers. Contains all of the texture co-ordinate data. The size if this array is 4 * 2 * (Number of texture co-ordinates) bytes. Each texture co-ordinate contains 2 numbers, the x then y co-ordinates. Each number is a 4 byte floating point number. An array of 4 byte unsigned long integers. Contains all of the indices. There are 3 indices for each triangle. The first 3 indices represent the first triangle. The next 3 indices represent the second triangle, and so on until all indices are used. Only triangles are used. There are no polygons with more vertices than 3. The size of this array is 4 * (Number of indices) bytes. There are (Number of indices) / 3 triangles represented. } */ // An example structure of a tree model made using Little Stick. typedef struct { unsigned char hasLeaves; // Does the tree have leaves (1) or not (0) unsigned char hasFruit; // Does the tree have fruit (1) or not (0) // Branches unsigned long numBranchVertices; // here sizeof(unsigned long) = 4 bytes unsigned long numBranchIndices; // here sizeof(unsigned long) = 4 bytes float *branchVertices; // here sizeof(float) = 4 bytes float *branchTextureCoordinates; // here sizeof(float) = 4 bytes unsigned long *branchIndices; // here sizeof(unsigned long) = 4 bytes // Leaves. All values are zero if there are no leaves. unsigned long numLeafVertices; // here sizeof(unsigned long) = 4 bytes unsigned long numLeafIndices; // here sizeof(unsigned long) = 4 bytes float *leafVertices; // here sizeof(float) = 4 bytes float *leafTextureCoordinates; // here sizeof(float) = 4 bytes unsigned long *leafIndices; // here sizeof(unsigned long) = 4 bytes // Fruit. All values are zero if there is no fruit. unsigned long numFruitVertices; // here sizeof(unsigned long) = 4 bytes unsigned long numFruitIndices; // here sizeof(unsigned long) = 4 bytes float *fruitVertices; // here sizeof(float) = 4 bytes float *fruitTextureCoordinates; // here sizeof(float) = 4 bytes unsigned long *fruitIndices; // here sizeof(unsigned long) = 4 bytes } treeModel; // There are two functions in this file: // 1. An example function that loads a tree model structure. treeModel * importTreeModel( FILE *fp ); // 2. An example function that saves a tree model structure. void exportTreeModel( treeModel *myTree, FILE *fp ); // An example function that loads a tree model structure. // An open standard FILE pointer is given to read from. // A pointer to tree model memory is returned. treeModel * importTreeModel( FILE *fp ) { treeModel *myTree = 0; // The pointer to be returned. char *header = "// Little stick compact format v1.0.0"; // The C string holding the file header. // If an unsigned long is not 4 bytes on your computer you'll have to rewrite this function. if ( sizeof( unsigned long ) != 4 ) { printf( "unsigned long is not 4 bytes\n" ); return 0; } // If a float is not 4 bytes on your computer you'll have to rewrite this function. if ( sizeof( float ) != 4 ) { printf( "float is not 4 bytes\n" ); return 0; } // If an unsigned char is not one byte on your computer you'll have to rewrite this function. if ( sizeof( unsigned char ) != 1 ) { printf( "unsigned char is not 1 byte\n" ); return 0; } // Allocate the memory for the treeModel structure. myTree = ( treeModel * ) malloc( sizeof( treeModel ) ); // Reads past the file header. fread( header, strlen( header ), 1, fp ); // Reads if there are leaves. fread( &myTree->hasLeaves, sizeof( unsigned char ), 1, fp ); // Reads 1 unsigned char // Reads if there is any fruit. fread( &myTree->hasFruit, sizeof( unsigned char ), 1, fp ); // Reads 1 unsigned char // The branches are always there so read them in. // Reads in the number of vertices and texture co-ordinates (numVertices). fread( &myTree->numBranchVertices, sizeof( unsigned long ), 1, fp ); // Reads 1 unsigned long // Reads in the number of indices (numIndices) and allocates memory. fread( &myTree->numBranchIndices, sizeof( unsigned long ), 1, fp ); // Reads 1 unsigned long // Allocates memory for the vertices. There are 3 floats (x,y,z) representing a vertex. myTree->branchVertices = ( float * ) malloc( sizeof( float ) * myTree->numBranchVertices * 3 ); // Allocates memory for the texture co-ordinates. There are 2 floats (x,y) representing a texture co-ordinate. myTree->branchTextureCoordinates = ( float * ) malloc( sizeof( float ) * myTree->numBranchVertices * 2 ); // Allocate memory for the indices. There is 1 unsigned long representing a vertex number. myTree->branchIndices = ( unsigned long * ) malloc( sizeof( unsigned long ) * myTree->numBranchIndices ); // Read in the vertex data. There are 3 floats (x,y,z) representing a vertex. fread( myTree->branchVertices, sizeof( float ), myTree->numBranchVertices * 3, fp ); // Read in the texture co-ordinate data. There are 2 floats (x,y) representing a texture co-ordinate. fread( myTree->branchTextureCoordinates, sizeof( float ), myTree->numBranchVertices * 2, fp ); // Read in all of the indices. There is 1 unsigned long representing a vertex number. fread( myTree->branchIndices, sizeof( unsigned long ), myTree->numBranchIndices, fp ); // If there are any leaves then read them in. if ( myTree->hasLeaves == 1 ) { // Reads in the number of vertices and texture co-ordinates (numVertices). fread( &myTree->numLeafVertices, sizeof( unsigned long ), 1, fp ); // Reads 1 unsigned long // Reads in the number of indices (numIndices) and allocates memory. fread( &myTree->numLeafIndices, sizeof( unsigned long ), 1, fp ); // Reads 1 unsigned long // Allocates memory for the vertices. There are 3 floats (x,y,z) representing a vertex. myTree->leafVertices = ( float * ) malloc( sizeof( float ) * myTree->numLeafVertices * 3 ); // Allocates memory for the texture co-ordinates. There are 2 floats (x,y) representing a texture co-ordinate. myTree->leafTextureCoordinates = ( float * ) malloc( sizeof( float ) * myTree->numLeafVertices * 2 ); // Allocate memory for the indices. There is 1 unsigned long representing a vertex number. myTree->leafIndices = ( unsigned long * ) malloc( sizeof( unsigned long ) * myTree->numLeafIndices ); // Read in the vertex data. There are 3 floats (x,y,z) representing a vertex. fread( myTree->leafVertices, sizeof( float ), myTree->numLeafVertices * 3, fp ); // Read in the texture co-ordinate data. There are 2 floats (x,y) representing a texture co-ordinate. fread( myTree->leafTextureCoordinates, sizeof( float ), myTree->numLeafVertices * 2, fp ); // Read in all of the indices. There is 1 unsigned long representing a vertex number. fread( myTree->leafIndices, sizeof( unsigned long ), myTree->numLeafIndices, fp ); } // If there is any fruit then read it in. if ( myTree->hasFruit == 1 ) { // Reads in the number of vertices and texture co-ordinates (numVertices). fread( &myTree->numFruitVertices, sizeof( unsigned long ), 1, fp ); // Reads 1 unsigned long // Reads in the number of indices (numIndices) and allocates memory. fread( &myTree->numFruitIndices, sizeof( unsigned long ), 1, fp ); // Reads 1 unsigned long // Allocates memory for the vertices. There are 3 floats (x,y,z) representing a vertex. myTree->fruitVertices = ( float * ) malloc( sizeof( float ) * myTree->numFruitVertices * 3 ); // Allocates memory for the texture co-ordinates. There are 2 floats (x,y) representing a texture co-ordinate. myTree->fruitTextureCoordinates = ( float * ) malloc( sizeof( float ) * myTree->numFruitVertices * 2 ); // Allocate memory for the indices. There is 1 unsigned long representing a vertex number. myTree->fruitIndices = ( unsigned long * ) malloc( sizeof( unsigned long ) * myTree->numFruitIndices ); // Read in the vertex data. There are 3 floats (x,y,z) representing a vertex. fread( myTree->fruitVertices, sizeof( float ), myTree->numFruitVertices * 3, fp ); // Read in the texture co-ordinate data. There are 2 floats (x,y) representing a texture co-ordinate. fread( myTree->fruitTextureCoordinates, sizeof( float ), myTree->numFruitVertices * 2, fp ); // Read in all of the indices. There is 1 unsigned long representing a vertex number. fread( myTree->fruitIndices, sizeof( unsigned long ), myTree->numFruitIndices, fp ); } // Return the pointer return myTree; } // This is the function that saves a tree model structure // A valid treeModel pointer and FILE pointer must be arguments. void exportTreeModel( treeModel *myTree, FILE *fp ) { char *header = "// Little stick compact format v1.0.0"; // The C string holding the file header. // If an unsigned long is not 4 bytes on your computer you'll have to rewrite this function. if ( sizeof( unsigned long ) != 4 ) { printf( "unsigned long is not 4 bytes\n" ); return; } // If a float is not 4 bytes on your computer you'll have to rewrite this function. if ( sizeof( float ) != 4 ) { printf( "float is not 4 bytes\n" ); return; } // If an unsigned char is not one byte on your computer you'll have to rewrite this function. if ( sizeof( unsigned char ) != 1 ) { printf( "unsigned char is not 1 byte\n" ); return 0; } // Write the file header. fwrite( header, strlen( header ), 1, fp ); // Write if the tree has leaves or not. fwrite( &myTree->hasLeaves, sizeof( unsigned char ), 1, fp ); // Write if the tree has fruit or not. fwrite( &myTree->hasFruit, sizeof( unsigned char ), 1, fp ); // Write the branch data. // Write the number of vertices. fwrite( &myTree->numBranchVertices, sizeof( unsigned long ), 1, fp ); // Write the number of indices. fwrite( &myTree->numBranchIndices, sizeof( unsigned long ), 1, fp ); // Write the vertices. There are 3 floats (x,y,z) representing a vertex. fwrite( &myTree->branchVertices, sizeof( float ), myTree->numBranchVertices * 3, fp ); // Write the texture co-ordinates. There are 2 floats (x,y) representing a texture co-ordinate. fwrite( &myTree->branchTextrueCoordinates, sizeof( float ), myTree->numBranchVertices * 2, fp ); // Write the indices. There is 1 unsigned long representing a vertex number. fwrite( &myTree->branchIndices, sizeof( unsigned long ), myTree->numBranchIndices, fp ); // If there are any leaves then write the leaf data. if ( myTree->hasLeaves == 1 ) { // Write the number of vertices. fwrite( &myTree->numLeafVertices, sizeof( unsigned long ), 1, fp ); // Write the number of indices. fwrite( &myTree->numLeafIndices, sizeof( unsigned long ), 1, fp ); // Write the vertices. There are 3 floats (x,y,z) representing a vertex. fwrite( &myTree->leafVertices, sizeof( float ), myTree->numLeafVertices * 3, fp ); // Write the texture co-ordinates. There are 2 floats (x,y) representing a texture co-ordinate. fwrite( &myTree->leafTextrueCoordinates, sizeof( float ), myTree->numLeafVertices * 2, fp ); // Write the indices. There is 1 unsigned long representing a vertex number. fwrite( &myTree->leafIndices, sizeof( unsigned long ), myTree->numLeafIndices, fp ); } // If there is any fruit then write the fruit data. if ( myTree->hasFruit == 1 ) { // Write the number of vertices. fwrite( &myTree->numFruitVertices, sizeof( unsigned long ), 1, fp ); // Write the number of indices. fwrite( &myTree->numFruitIndices, sizeof( unsigned long ), 1, fp ); // Write the vertices. There are 3 floats (x,y,z) representing a vertex. fwrite( &myTree->fruitVertices, sizeof( float ), myTree->numFruitVertices * 3, fp ); // Write the texture co-ordinates. There are 2 floats (x,y) representing a texture co-ordinate. fwrite( &myTree->fruitTextrueCoordinates, sizeof( float ), myTree->numFruitVertices * 2, fp ); // Write the indices. There is 1 unsigned long representing a vertex number. fwrite( &myTree->fruitIndices, sizeof( unsigned long ), myTree->numFruitIndices, fp ); } }