The purpose of the data structure classes is to first provides different views of the data for the application itself and OpenGL on the other side. It also provides additional information about the vertex connectivity such as vertex neighbourhood and triangles. The data structure is designed to be accessed one way which means that elements can be added to the structure but not removed. This makes the memory management simpler and the structure faster. The following image tries to give an impression of the data structures and it's application.
Data Classes Overview
mesh
. This is neccessary because the marching cubes algorithm must look up vertices in a special way. The dashed connections between the vertices and the data arrray _data
and between the data array and the index array _indices
shoud be read as is related to.
As told earlier data in the data structure can only be accessed via MCMesh. This class provides all necessary functions to add and access the data. The normal way to add a triangle of vertices to the structure is to first add a new triangle to the structure. The function to accomplish this returns the index of the triangle in an array.
The next step in data creation is to add vertices. In this step the triangle index is needed. Also the position of the corresponding cube and the number of the edge on which the vertex lies are needed to add the vertex to the structure. The structure itself takes care of the connectivity information (see below).
The idea behind all this data classes is to provide the data so that it could be used by glDrawElements. This function uses several data arrays (i.e. vertex data, normal data, ...) and takes a index array that specifies in which order the function should use the vertex in the arrays. In this way all the data can put onto the graphics card at once and OpenGL than accesses these data much faster. This goal is achiefed by splitting the data creation into two phases. The first phase is the above described mesh creation. The second phase compiles the spezial arrays from the mesh.
One kind of connectivity information has to be provided by the user of the data structure: the triangle information. The other kind of connectivity information, the vertex neighbours, will be created by the data structure.
This information can be accomplished trough two facts. First all vertices of a triangle are neighbours and second neighbouring triangles share the same vertices. With these two informations all the vertex neighbours information can be compiled. Imagine the first triangle in the structure. Every vertex added to the triangle is automatically provided with the neighbourhood information in the triangle (i.e. each other vertex in the triangle is added to the vertexe's neighbours list). When all triangles are added the neigbourhood information is complete for this triangle.
The data structure is designed to easily reuse already existing vertices. And this is the point where overall connectivity can be provided. Because a vertex will be used for all neighbouring triangles the triangle connectivitiy information of all triangles will be collected in this single vertex and a complete mesh arrises.
With these connectivity informations also the triangle neighbourhood could be calculated, but this is complecated and not implemented in this first version.
As described below, glDrawElements needs the data array along with a index array. The data array holds all vertices in the mesh, but each vertex is contained only once. This is the reason why an index is needed. In order to make it possible, to color each type of cube different, this index array in turn is split into 255 index arrays, each representing on type of cube.
The vertex and index array is created and filled when needed, i.e. when drawing starts. At that point the mesh tree is walked through and the relevant information is compiled into the arrays.
This step is also split into two phases because of the above described structure of the index array. At the start of compilation, MCMesh does not know, how big each of this index arrays will be, and maybe some will even be empty. Therefor the first step only compiles the data into the vertex array (along with the normals) but also counts the occurence of the different types. This is possible because the algorithm has to walk through the mesh in the same way as it should be drawn because it must calculate the correct normals (this is described below in calcNormals).
The second step than can reserve exactly the necessary memory for each index array and enter the data into it.
An important issues is the fact, that only complete triangles are compiled into the arrays.
glDrawElements uses arrays defined before the function is called. To define an array OpenGL must first be pointed to the array data. For each type of array another function has to be used. Secondly the array has to be activated through the glEnableClientState function with a function parameter also depending on the type of the array. The mapping between array types, functions, and function parameters is shown in th following table.
data type | definition | glEnableClientState | function | parameter -------------------------+-------------------+----------------------- vertex array | glVertexPointer | GL_VERTEX_ARRAY normal array | glNormalPointer | GL_NORMAL_ARRAY color array | glColorPointer | GL_COLOR_ARRAY texture coordinate array | glTexCoordPointer | GL_TEXTURE_COORD_ARRAY
After the declaration and the enabling of the arrays glDrawElements can make use of them. For this reason the function takes an input parameter representing an index array which in turn specifies in which order the data in the arrays should be used.
MCMesh does not take the triangle normals as it would be the easiest way, but calculates the average normal of each neighbouring triangle of a vertex. This is done by adding the normal of the new triangle to the existing one and make the normal a unit vector again afterwards. In this way the survace can be smoothed a little.
As mentioned above the application is able to color the triangles of each cube type differently. This is done by creating 256 index arrays and drawing the mesh 256 times with different arrays. For each drawing step another color can be used.
The actual application supports only one different color because the coloring is connected with the cube browser which by deffinition can show only one type of cube.