Qubicle Constructor 1:Data Exchange With Qubicle Binary

From Minddesk Wiki
Jump to: navigation, search

Qubicle Binary is an exchange format that stores voxel data in binary form. It supports storage of multiple separate voxel matrices in a single file, as well as optional compression (RLE).


Contents

Supported Software

Qubicle Binary can be read by:

  • Qubicle Constructor Home/Master
  • Qubicle Unite


Qubicle Binary can be written by:

  • Qubicle Constructor Home/Master
  • Qubicle Voxelizer


Data Structure

Header

The first 24 bytes are used for the header including following information:

  • Version (4 bytes): stores the version of the Qubicle Binary file format as major, minor, release, build. Current version is 1.1.0.0
  • Color Format (4): Can be either 0 or 1. If 0 voxel data is encoded as RGBA, if 1 as BGRA
  • Z-Axis Orientation (4): Can either be 0=left handed or 1=right handed
  • Compression (4): If set to 1 data is compressed using run length encoding (RLE). If set to 0 data is uncompressed.
  • Visibility-Mask encoded (4): If set to 0 the A value of RGBA or BGRA is either 0 (invisble voxel) or 255 (visible voxel). If set to 1 the visibility mask of each voxel is encoded into the A value telling your software which sides of the voxel are visible. You can save a lot of render time using this option. More info about this in the section visibility-mask encoding
  • Matrix count: tells you how many matrices are stored in this file.


Matrix data

All following data is matrix data. For each matrix the size and position is stored and afterwards the voxel data. How that data looks like depends on the settings in the file header.


Parsing Qubicle Binary in pseudocode

The following source code is written in pseudo code and hopefully understandable by any coder no matter the programming language he uses. How you store the data found in the file is up to you. In this example the raw data is stored in a simple one dimensional array. Be careful with the variable types. All of them are unsigned 32bit long integers, except for the position vars.


 function loadQubicleBinary(filename:string) 
 {
   var version:uint32;
   var colorFormat:uint32;
   var zAxisOrientation:uint32;
   var compressed:uint32;
   var visibilityMaskEncoded:uint32;
   var numMatrices:uint32;
   var f:file;
   var i:uint32;
   var j:uint32;
   var x:uint32;
   var y:uint32;
   var z:uint32;
   var sizeX:uint32;
   var sizeY:uint32;
   var sizeZ:uint32;
   var posX:int32;
   var posY:int32;
   var posZ:int32;
   var matrix:array;
   var matrixList:array;
   var index:uint32;
   var data:uint32;
   var count:uint32;
   const CODEFLAG = 2;
   const NEXTSLICEFLAG = 6;
 
   f = fopen(filename);
   version = fread_uint32(f);
   colorFormat = fread_uint32(f);
   zAxisOrientation = fread_uint32(f);
   compressed = fread_uint32(f);
   visibilityMaskEncoded = fread_uint32(f);
   numMatrices = fread_uint32(f);
   matrixList = new array();
 
   for (var i:unit32 = 0; i < numMatrices; i++) // for each matrix stored in file
   {
     // read matrix name
     nameLength = fread_byte(file);
     name = fread_string(file,nameLength);
 	
     // read matrix size 
     sizeX = fread_uint32(file);
     sizeY = fread_uint32(file);
     sizeZ = fread_uint32(file);
   
     // read matrix position (in this example the position is irrelevant)
     posX = fread_int32(file);
     posY = fread_int32(file);
     posZ = fread_int32(file);
   
     // create matrix and add to matrix list
     matrix = new array(sizeX*sizeY*sizeZ);
     matrixList.push(matrix);
   
     if (compressed == 0) // if uncompressd
     {
       for(z = 0; z < sizeZ; z++)
         for(y = 0; y < sizeY; y++)
           for(x = 0; x < sizeX; x++)
             matrix[x + y*sizeX + z*sizeX*sizeY] = fread_uint32(file);
     }
     else // if compressed
     { 
       z = 0;
     
       while (z < sizeZ) 
       {
         z++;
         index = 0;
       
         while (true) 
         {
           data = fread_uint32(file);
         
           if (data == NEXTSLICEFLAG)
             break;
           else if (data == CODEFLAG) 
           {
             count = fread_uint32(file);
             data = fread_uint32(file);
           
             for(j = 0; j < count; j++) 
             {
               x = index mod sizeX + 1; // mod = modulo e.g. 12 mod 8 = 4
               y = index div sizeX + 1; // div = integer division e.g. 12 div 8 = 1
               index++;
               matrix[x + y*sizeX + z*sizeX*sizeY] = data;
             }
           }
           else 
           {
             x = index mod sizex + 1;
             y = index div sizex + 1;
             index++;
             matrix[x + y*sizeX + z*sizeX*sizeY] = data;
           }
         }
       }
     }
   }
 }


Visibility mask encoding

To increase render speed Qubicle internally uses a visibility mask telling the engine which of the voxel's sides to render. The mask is optionally encoded in the A value of the RGBA/BGRA voxel data and uses a single byte. To test whether a side should be rendered use this pseudo code:


  • if (mask == 0) // voxel invisble
  • if (mask && 2 == 2) // left side visible
  • if (mask && 4 == 4) // right side visible
  • if (mask && 8 == 8) // top side visible
  • if (mask && 16 == 16) // bottom side visible
  • if (mask && 32 == 32) // front side visible
  • if (mask && 64 == 64) // back side visible