Both loaders and writers convert between ssg's internal geometry representation and that of the file format. One of the main differences is that when loading, you have to support all possibile geometry-representations of the file-format, when writing only one. OTOH, during load you have to support just one possibile geometry-representations of plib, during writing all.
Regarding plib's geometry-representations, there are only two on the highest
level: ssgVtxTable
and ssgVtxArray
. Actually, there is also
ssgVTable, but that is deprecated.
ssgVtxArray
is newer, is derived
from ssgVtxTable and uses a index-list. Apart from that they are quite
similar, and both have an interface getNumTriangles () ;
and
getTriangle ( i, ...);
For these reasons, it is easier to write a writer than a loader.
For both ssgVtxTable and ssgVtxArray you need to choose a
GL-type. I have to admit I was lazy and used GL_TRIANGLES
.
void ssgLoaderWriterMesh::AddFaceFromCArray(int nNoOfVerticesForThisFace, int *aiVertices);With this, you can add several n-sided polys to one mesh ("one node"). When you are done constructing the mesh from the file, you call
void ssgLoaderWriterMesh::add2SSG( class ssgSimpleState *currentState, class ssgLoaderOptions* current_options, class ssgBranch *curr_branch_)and the class adds the information into the scene graph. It handles ssg's restrictions, so, for example, if the polys of the mesh use 5 textures then at least 5 nodes will be added to the scene graph. Unfortunately the class isn't completely implemented yet, I (Wolfram Kuss, w_kuss@rz-online.de) have just implemented those parts I needed for the ."my" loaders. But I urge everyone and am willing to help everyone writing a new loader for a file format that doesnt hold all ssg-restrictions to use this class. Then the loaders will become more consistent and therefore easier to maintain and read. Also, there are a lot of optimizations that can be done (for example, if the state is different, but not the texture, do we need several nodes? When we have multitexturing, can we use that? Is there an optimal strip length? How do I subdivide polys into triangles so that the stripifier will work well? etc). It will be easier to do them once in the ssgLoaderWriterMesh than in all the loaders seperately. BTW, most loaders written before ssgLoaderWriterMesh have some sort of intermediatory mesh structure.
In the future, ssgLoaderWriterMesh should also be used for writers, doing the opposite job: It takes the information from ssg with the restrictions and then looks whether it can optimise (for example merging nodes) by relaxing the restrictions.
ssgLoaderWriterMesh
or do a ReInit()
. To insert the data into the ssgLoaderWriterMesh
,
you have to add vertices, faces, materials, materialindexes (saying what face uses what material)
and, if applicable texture coordinates. For all of these, you can say in advance how many you have.
If you know that you have 3712 vertices, call ThereAreNVertices(3712)
and everything is allocated
at once and the addVertex
works very fast. Vertices are simply sgVec3s. Faces are simply
lists/arrays of vertex indexes.
For adding faces, use addFace
if you already have a ssgIndexArray
or use
AddFaceFromCArray
if you have the vertex indexes in a C(++) array.
You need to add at least one material (ssgSimpleState
). For each face, you tell
ssg which material to use via addMaterialIndex
. Here is code from ssgLoadOFF, which tells
ssg to use the ssgSimpleState
ss for all faces:
theMesh.ThereAreNMaterials( 1 );
theMesh.addMaterial( &ss );
theMesh.ThereAreNMaterialIndexes( _ssgNoFacesToRead ) ;
for(i=0;i<_ssgNoFacesToRead ;i++)
theMesh.addMaterialIndex ( 0 ) ;
void openFile( const char* fname, const _ssgParserSpec* spec = 0 );Here you give the parser the specification of the format, for example you say what characters start a comment and what are used for braces etc. Most important are the delimiters. These determine where one token ends and the next one begins. For example, the first token of the line
1234,567is
1234
if ","
is a delimiter and 1234,567
else.
The parser differentiates between skipable delimiters that
are "swallowed" by the parser and non-skipable ones that are
passed to the loader. So, regarding the example-line there
are three possibilities:
","
is not a delimiter => The line contains one token, namely
"1234,567"
","
is a skipable delimiter => The line contains two tokens, namely
"1234"
and "567"
","
is a non-skipable delimiter => The line contains three tokens,
namely "1234"
, ","
and "567"
ssgSaveDXF
or ssgSaveTRI
.
The function
int ssgSaveXYZ ( const char *filename, ssgEntity *ent )normally calls a function
static void save_entities ( ssgEntity *e )which just recursively walks the scene graph. You should be able to use this function and just write a
static void save_vtx_table ( ssgVtxTable *vt )which writes a
ssgVtxTable
.
<= previous = | Return to SSG Index |