Changeset 718

Show
Ignore:
Timestamp:
01/15/08 18:50:52 (4 months ago)
Author:
leo
Message:

Added VRML export.

Location:
trunk
Files:
11 modified

Legend:

Unmodified
Added
Removed
  • trunk/common/keyboard.cpp

    r679 r718  
    2525    { LC_FILE_POVRAY, "Export POV-Ray", 0, 0, 0 }, 
    2626    { LC_FILE_WAVEFRONT, "Export Wavefront", 0, 0, 0 }, 
     27    { LC_FILE_VRML, "Export VRML", 0, 0, 0 }, 
     28    { LC_FILE_X3DV, "Export X3DV", 0, 0, 0 }, 
    2729//  { LC_FILE_TERRAIN, "Terrain Editor", 0, 0, 0 }, 
    2830    { LC_FILE_LIBRARY, "Piece Library Manager", 0, 0, 0 }, 
  • trunk/common/lc_application.cpp

    r717 r718  
    411411        project->HandleNotify(LC_ACTIVATE, 0); 
    412412        delete project; 
     413        project = NULL; 
    413414    } 
    414415 
  • trunk/common/project.cpp

    r717 r718  
    42834283        } break; 
    42844284 
     4285        case LC_FILE_VRML: 
     4286        { 
     4287            char filename[LC_MAXPATH]; 
     4288            if (!SystemDoDialog(LC_DLG_VRML97, filename)) 
     4289                break; 
     4290 
     4291//          exportVRML97File(filename); 
     4292        } break; 
     4293 
     4294        case LC_FILE_X3DV: 
     4295        { 
     4296            char filename[LC_MAXPATH]; 
     4297            if (!SystemDoDialog(LC_DLG_X3DV, filename)) 
     4298                break; 
     4299 
     4300//          exportX3DVFile(filename); 
     4301        } break; 
     4302 
    42854303        case LC_MODEL_NEW: 
    42864304        { 
     
    86268644    } 
    86278645} 
     8646 
     8647/* 
     8648// FIXME: VRML 
     8649// VRML export written by Joerg Scheurich aka MUFTI <rusmufti@helpdesk.bera.rus.uni-stuttgart.de>   
     8650 
     8651// VRML97 and X3DV export is very similar, cause X3D is the successor of VRML97 
     8652// therefore a lot of the export routines can be reused 
     8653// the member variable VRMLdialect used with the following enum has this information 
     8654 
     8655class Project 
     8656{ 
     8657    // VRML export 
     8658    void exportVRML97File(char *filename); 
     8659    void exportX3DVFile(char *filename); 
     8660    void exportVRMLFile(char *filename, int dialect); 
     8661    template<class type> void writeVRMLShapes(type color, FILE *stream, int coordinateCounter, Piece* pPiece, unsigned short group, float *pos, bool beginAndEnd); 
     8662    void writeVRMLShapeBegin(FILE *stream, unsigned long currentColor, bool blackLines); 
     8663    void writeVRMLShapeMeshBegin(FILE *stream); 
     8664    void writeVRMLShapeMeshData(FILE *stream); 
     8665    void writeVRMLShapeMeshEnd(FILE *stream); 
     8666    void writeVRMLShapeEnd(FILE *stream); 
     8667    void writeIndent(FILE *stream); 
     8668    int indent; 
     8669    int numDEF; 
     8670    bool VRMLdialect; 
     8671    bool firstData; 
     8672    int searchForVertex(float *vertex); 
     8673    template<class type> void generateMeshData(type* info, float *pos, Piece* pPiece, int numVertices, int currentColor); 
     8674    template<class type> void getMinMaxData(type* info, Piece* pPiece, int numVertices, GroupInfo* groupInfo); 
     8675    template<class type> void getMinMax(type col, Piece* pPiece, unsigned short group, GroupInfo* groupInfo); 
     8676    bool handleAsGroup(Piece* piece, GroupInfo groupInfo); 
     8677    int numCoords; 
     8678    float *coords; 
     8679    int numCoordIndices; 
     8680    int *coordIndices; 
     8681    float centerOfMass[3]; 
     8682    int numFaceColors; 
     8683    int *faceColors; 
     8684}; 
     8685 
     8686enum  
     8687{ 
     8688    VRML97, 
     8689    X3DV_WITH_RIGID_BODY_PHYSICS 
     8690}; 
     8691 
     8692void Project::exportVRML97File(char *filename) 
     8693{ 
     8694    exportVRMLFile(filename, VRML97); 
     8695} 
     8696 
     8697void Project::exportX3DVFile(char *filename) 
     8698{ 
     8699    exportVRMLFile(filename, X3DV_WITH_RIGID_BODY_PHYSICS); 
     8700} 
     8701 
     8702void Project::writeIndent(FILE* stream) 
     8703{ 
     8704    for (int i = 0; i < indent; i++) 
     8705        fprintf(stream, " "); 
     8706} 
     8707 
     8708#define INDENT_INC 2 
     8709 
     8710// routines to write VRML/X3DV shape related commands 
     8711// for details see  
     8712// http://www.web3d.org/x3d/specifications/vrml/ISO-IEC-14772-VRML97/part1/ 
     8713// http://www.web3d.org/x3d/specifications/ISO-IEC-19775-X3DAbstractSpecification/Part01/Architecture.html 
     8714 
     8715void Project::writeVRMLShapeBegin(FILE *stream, unsigned long currentColor, bool blackLines) 
     8716{ 
     8717    // http://www.web3d.org/x3d/specifications/ISO-IEC-19775-X3DAbstractSpecification_Revision1_to_Part1/Part01/components/rigid_physics.html#CollidableShape 
     8718 
     8719    if (VRMLdialect == X3DV_WITH_RIGID_BODY_PHYSICS) 
     8720    { 
     8721        numFaceColors = 0; 
     8722        faceColors = (int *) malloc(1); 
     8723 
     8724        writeIndent(stream); 
     8725        fprintf(stream, "DEF CollidableShape%d CollidableShape {\n", numDEF++); 
     8726        indent += INDENT_INC; 
     8727        writeIndent(stream); 
     8728        fprintf(stream, "shape "); 
     8729    } 
     8730    else 
     8731        writeIndent(stream); 
     8732 
     8733    // http://www.web3d.org/x3d/specifications/vrml/ISO-IEC-14772-VRML97/part1/nodesRef.html#Shape 
     8734 
     8735    fprintf(stream, "Shape {\n"); 
     8736    indent += INDENT_INC; 
     8737 
     8738    // http://www.web3d.org/x3d/specifications/vrml/ISO-IEC-14772-VRML97/part1/nodesRef.html#Appearance 
     8739    // http://www.web3d.org/x3d/specifications/vrml/ISO-IEC-14772-VRML97/part1/nodesRef.html#Material 
     8740    writeIndent(stream); 
     8741    fprintf(stream, "appearance Appearance {\n"); 
     8742    indent += INDENT_INC; 
     8743    writeIndent(stream); 
     8744    fprintf(stream, "material Material {\n"); 
     8745    indent += INDENT_INC; 
     8746    if (blackLines) 
     8747    { 
     8748        writeIndent(stream); 
     8749        fprintf(stream, "diffuseColor 0 0 0\n"); 
     8750        writeIndent(stream); 
     8751        fprintf(stream, "emissiveColor 0 0 0\n"); 
     8752    } 
     8753    else 
     8754    { 
     8755        writeIndent(stream); 
     8756        fprintf(stream, "diffuseColor %g %g %g\n", (float)(FlatColorArray[currentColor][0]) / 256.0, (float)(FlatColorArray[currentColor][1]) / 256.0, (float)(FlatColorArray[currentColor][2]) / 256.0); 
     8757        if (currentColor > 13 && currentColor < 22)  
     8758        { 
     8759            writeIndent(stream); 
     8760            fprintf(stream, "transparency 0.5\n"); 
     8761        } 
     8762    } 
     8763    indent -= INDENT_INC; 
     8764    writeIndent(stream); 
     8765    fprintf(stream, "}\n");                                 
     8766    indent -= INDENT_INC; 
     8767    writeIndent(stream); 
     8768    fprintf(stream, "}\n");                                 
     8769     
     8770    if (blackLines) 
     8771    { 
     8772        // http://www.web3d.org/x3d/specifications/vrml/ISO-IEC-14772-VRML97/part1/nodesRef.html#IndexedLineSet 
     8773        writeIndent(stream); 
     8774        fprintf(stream, "geometry IndexedLineSet {\n"); 
     8775        indent += INDENT_INC; 
     8776    } 
     8777    else 
     8778    { 
     8779        // http://www.web3d.org/x3d/specifications/ISO-IEC-19775-X3DAbstractSpecification/Part01/components/rendering.html#TriangleSet 
     8780        // http://www.web3d.org/x3d/specifications/vrml/ISO-IEC-14772-VRML97/part1/nodesRef.html#IndexedFaceSet 
     8781        writeIndent(stream); 
     8782        if (VRMLdialect == X3DV_WITH_RIGID_BODY_PHYSICS) 
     8783            fprintf(stream, "geometry TriangleSet {\n"); 
     8784        else 
     8785            fprintf(stream, "geometry IndexedFaceSet {\n"); 
     8786        indent += INDENT_INC; 
     8787        writeIndent(stream); 
     8788        fprintf(stream, "solid FALSE\n"); 
     8789        if (VRMLdialect != X3DV_WITH_RIGID_BODY_PHYSICS) 
     8790        { 
     8791            writeIndent(stream); 
     8792            fprintf(stream, "creaseAngle 0.79\n"); 
     8793        } 
     8794    } 
     8795} 
     8796 
     8797void Project::writeVRMLShapeEnd(FILE *stream) 
     8798{ 
     8799    indent -= INDENT_INC; 
     8800    writeIndent(stream); 
     8801    fprintf(stream, "}\n"); 
     8802    indent -= INDENT_INC; 
     8803    writeIndent(stream); 
     8804    fprintf(stream, "}\n"); 
     8805} 
     8806 
     8807// search for vertex (vertex[0], vertex[1], vertex[2]) in coords and give 
     8808// back index (-1 if not found) 
     8809 
     8810int Project::searchForVertex(float* vertex)  
     8811{ 
     8812    for (int i = 0; i < numCoords; i++) 
     8813        if (coords[i * 3] == vertex[0]) 
     8814            if (coords[i * 3 + 1] == vertex[1]) 
     8815                if (coords[i * 3 + 2] == vertex[2]) 
     8816                    return i; 
     8817    return -1; 
     8818} 
     8819 
     8820// routines to collect VRML indexed polygon mesh data or X3DV triangle mesh data 
     8821 
     8822template<class type> void Project::generateMeshData(type* info, float *pos, Piece* pPiece, int numVertices, int currentColor) 
     8823{ 
     8824    float rot[4]; 
     8825    Vector3 Pos = pPiece->GetPosition(); 
     8826    pPiece->GetRotation(rot); 
     8827    Matrix matrix(rot, Pos); 
     8828 
     8829    bool rigidBody = (VRMLdialect == X3DV_WITH_RIGID_BODY_PHYSICS); 
     8830 
     8831    PieceInfo* pInfo = pPiece->GetPieceInfo(); 
     8832    if (rigidBody) 
     8833    { 
     8834        // IndexedLineSet not supported by xj3d RigidBody node 
     8835        if (numVertices == 2) 
     8836            return; 
     8837 
     8838        int maxJ = 1; 
     8839        // write 2 triangles instead of 1 quad 
     8840        if (numVertices == 4) 
     8841            maxJ = 2; 
     8842        for (int j = 0; j < maxJ; j++)  
     8843        { 
     8844            for (int i = 0; i < 3; i++) 
     8845            { 
     8846                int index = i; 
     8847                if (j == 1) 
     8848                { 
     8849                    switch (i) { 
     8850                        case 0: 
     8851                            index = 2; 
     8852                            break; 
     8853                        case 1: 
     8854                            index = 0; 
     8855                            break; 
     8856                        case 2: 
     8857                            index = 3; 
     8858                            break; 
     8859                    } 
     8860                } 
     8861                float *localVertex = &pInfo->m_fVertexArray[info[index] * 3]; 
     8862                float vertex[3]; 
     8863                matrix.TransformPoint(vertex, localVertex); 
     8864                coords = (float *) realloc(coords, (numCoords + 1) * 3 * sizeof(float)); 
     8865                coords[numCoords * 3 + 0] = vertex[1] - pos[1]; 
     8866                coords[numCoords * 3 + 1] = vertex[2] - pos[2]; 
     8867                coords[numCoords * 3 + 2] = vertex[0] - pos[0]; 
     8868                numCoords++; 
     8869            } 
     8870            faceColors = (int *) realloc(faceColors, (numFaceColors + 1) * sizeof(int)); 
     8871            faceColors[numFaceColors] = currentColor; 
     8872            numFaceColors++; 
     8873        } 
     8874        return; 
     8875    }            
     8876    for (int i = 0; i < numVertices; i++) 
     8877    { 
     8878        float *localVertex = &pInfo->m_fVertexArray[info[i] * 3]; 
     8879        int index = searchForVertex(localVertex); 
     8880        if (index == -1) 
     8881        { 
     8882            float vertex[3]; 
     8883            if (rigidBody) 
     8884                matrix.TransformPoint(vertex, localVertex); 
     8885            else 
     8886            { 
     8887                vertex[0] = localVertex[0]; 
     8888                vertex[1] = localVertex[1]; 
     8889                vertex[2] = localVertex[2]; 
     8890            } 
     8891            coords = (float *) realloc(coords, (numCoords + 1) * 3 * sizeof(float)); 
     8892            coords[numCoords * 3 + 0] = vertex[1] - (rigidBody ? pos[1] : 0); 
     8893            coords[numCoords * 3 + 1] = vertex[2] - (rigidBody ? pos[2] : 0); 
     8894            coords[numCoords * 3 + 2] = vertex[0] - (rigidBody ? pos[0] : 0); 
     8895            index = numCoords; 
     8896            numCoords++; 
     8897        } 
     8898        coordIndices = (int *) realloc(coordIndices, (numCoordIndices + 1) * sizeof(int)); 
     8899        coordIndices[numCoordIndices] = index; 
     8900        numCoordIndices++; 
     8901    } 
     8902    coordIndices = (int *) realloc(coordIndices, (numCoordIndices + 1) * sizeof(int)); 
     8903    coordIndices[numCoordIndices] = -1; 
     8904    numCoordIndices++; 
     8905    faceColors = (int *) realloc(faceColors, (numFaceColors + 1) * sizeof(int)); 
     8906    faceColors[numFaceColors] = currentColor; 
     8907    numFaceColors++; 
     8908} 
     8909 
     8910// write collected mesh data 
     8911 
     8912void Project::writeVRMLShapeMeshBegin(FILE *stream) 
     8913{ 
     8914    writeIndent(stream); 
     8915 
     8916    fprintf(stream, "coord Coordinate {\n"); 
     8917    indent += INDENT_INC; 
     8918    writeIndent(stream); 
     8919    fprintf(stream, "point [\n"); 
     8920    indent += INDENT_INC; 
     8921} 
     8922 
     8923void Project::writeVRMLShapeMeshData(FILE *stream) 
     8924{ 
     8925    for (int i = 0; i < numCoords; i++)  
     8926    { 
     8927        writeIndent(stream); 
     8928        fprintf(stream, "%f %f %f\n", coords[i * 3], coords[i * 3 + 1], coords[i * 3 + 2]); 
     8929    } 
     8930} 
     8931 
     8932void Project::writeVRMLShapeMeshEnd(FILE *stream) 
     8933{ 
     8934    indent -= INDENT_INC; 
     8935    writeIndent(stream); 
     8936    fprintf(stream, "]\n"); 
     8937    indent -= INDENT_INC; 
     8938    writeIndent(stream); 
     8939    fprintf(stream, "}\n"); 
     8940 
     8941     
     8942    if (VRMLdialect == X3DV_WITH_RIGID_BODY_PHYSICS) 
     8943    { 
     8944        writeIndent(stream); 
     8945        fprintf(stream, "colorPerVertex FALSE\n");  
     8946 
     8947        writeIndent(stream); 
     8948        fprintf(stream, "color ColorRGBA {\n");  
     8949        indent += INDENT_INC;        
     8950        writeIndent(stream); 
     8951        fprintf(stream, "color [\n");  
     8952        indent += INDENT_INC;        
     8953 
     8954        for (int i = 0; i < numFaceColors; i++) 
     8955        { 
     8956            int currentColor = faceColors[i]; 
     8957            writeIndent(stream); 
     8958            fprintf(stream, "%g %g %g %g\n", (float)(FlatColorArray[currentColor][0]) / 256.0, (float)(FlatColorArray[currentColor][1]) / 256.0, (float)(FlatColorArray[currentColor][2]) / 256.0, (currentColor > 13 && currentColor < 22) ? 0.5 : 1); 
     8959        } 
     8960 
     8961        indent -= INDENT_INC;        
     8962        writeIndent(stream); 
     8963        fprintf(stream, "]\n");  
     8964 
     8965        indent -= INDENT_INC; 
     8966        writeIndent(stream); 
     8967        fprintf(stream, "}\n"); 
     8968    } 
     8969    else 
     8970    { 
     8971        writeIndent(stream); 
     8972        fprintf(stream, "coordIndex [\n");  
     8973        indent += INDENT_INC; 
     8974 
     8975        for (int i = 0; i < numCoordIndices; i ++)  
     8976        { 
     8977            writeIndent(stream); 
     8978            fprintf(stream, "%d\n", coordIndices[i]); 
     8979        } 
     8980 
     8981        indent -= INDENT_INC; 
     8982        writeIndent(stream); 
     8983        fprintf(stream, "]\n"); 
     8984    } 
     8985} 
     8986 
     8987// routine to run through leoCADs internal data space, collect and write data 
     8988 
     8989template<class type> void Project::writeVRMLShapes(type color, FILE *stream, int coordinateCounter, Piece* pPiece, unsigned short group, float *pos, bool beginAndEnd) 
     8990{  
     8991    PieceInfo* pInfo = pPiece->GetPieceInfo(); 
     8992    const char* colname; 
     8993    type* info = (type*)(pInfo->m_pGroups[group].drawinfo); 
     8994    type currentColor = color; 
     8995    type count, colors = *info; 
     8996    type maxColors = colors; 
     8997    info++; 
     8998 
     8999    while (colors--) 
     9000    { 
     9001        numCoords = 0; 
     9002        coords = (float *) malloc(1); 
     9003        numCoordIndices = 0; 
     9004        coordIndices = (int *) malloc(1); 
     9005 
     9006        if ((*info == LC_COL_DEFAULT) || (*info == LC_COL_EDGES)) 
     9007        { 
     9008            colname = altcolornames[color]; 
     9009            currentColor = color; 
     9010        } 
     9011        else 
     9012        { 
     9013            if ((*info >= LC_MAXCOLORS)) 
     9014            { 
     9015                info++; 
     9016                info += *info + 1; 
     9017                info += *info + 1; 
     9018                info += *info + 1; 
     9019 
     9020                continue; 
     9021            } 
     9022            colname = altcolornames[*info]; 
     9023            currentColor = *info; 
     9024        } 
     9025        info++; 
     9026         
     9027        bool skipNext = (info[0] < 1); 
     9028        if (skipNext) 
     9029            skipNext = (info[1] < 1); 
     9030        if (skipNext) 
     9031            info += 2;                 
     9032        else 
     9033        { 
     9034            for (count = *info, info++; count; count -= 4) 
     9035            { 
     9036                generateMeshData(info, pos, pPiece, 4, currentColor); 
     9037                info += 4; 
     9038            } 
     9039     
     9040            for (count = *info, info++; count; count -= 3) 
     9041            { 
     9042                generateMeshData(info, pos, pPiece, 3, currentColor); 
     9043                info += 3; 
     9044            } 
     9045            writeIndent(stream); 
     9046            fprintf(stream, "# %s\n", colname); 
     9047 
     9048            bool rigidBody = (VRMLdialect == X3DV_WITH_RIGID_BODY_PHYSICS); 
     9049 
     9050            bool writeBegin = ((!rigidBody) || (beginAndEnd && (colors == (maxColors - 1))));  
     9051            bool writeEnd = ((!rigidBody) || (beginAndEnd && (colors == 0))); 
     9052 
     9053            if (writeBegin)  
     9054            { 
     9055                writeVRMLShapeBegin(stream, currentColor, false); 
     9056                writeVRMLShapeMeshBegin(stream); 
     9057            } 
     9058 
     9059            writeVRMLShapeMeshData(stream); 
     9060 
     9061            if (writeEnd) 
     9062            { 
     9063                writeVRMLShapeMeshEnd(stream); 
     9064                writeVRMLShapeEnd(stream); 
     9065            } 
     9066        } 
     9067 
     9068        if (*info > 0) 
     9069        { 
     9070            // IndexedLineSet not supported in RigidBody node for the xj3d browser 8-( 
     9071            if (VRMLdialect != X3DV_WITH_RIGID_BODY_PHYSICS)  
     9072            { 
     9073                writeIndent(stream); 
     9074                fprintf(stream, "# lines of color %s\n", colname); 
     9075            } 
     9076 
     9077            for (count = *info, info++; count; count -= 2) 
     9078            { 
     9079                generateMeshData(info, pos, pPiece, 2, currentColor); 
     9080                info += 2; 
     9081            } 
     9082 
     9083            // IndexedLineSet not supported in RigidBody node for the xj3d browser 8-( 
     9084            if (VRMLdialect != X3DV_WITH_RIGID_BODY_PHYSICS)  
     9085            { 
     9086                writeVRMLShapeBegin(stream, currentColor, true); 
     9087                writeVRMLShapeMeshBegin(stream); 
     9088                writeVRMLShapeMeshData(stream); 
     9089                writeVRMLShapeMeshEnd(stream); 
     9090                writeVRMLShapeEnd(stream); 
     9091            } 
     9092        } else 
     9093            info++; 
     9094        free(coords); 
     9095        free(coordIndices); 
     9096    } 
     9097} 
     9098 
     9099// The X3DV export need to "melt together" faces of different pieces into one triangleSet 
     9100// based on the leocad "piece -> group" menupoint, otherwise the rigid body simulation would simulate all pieces seperatly 
     9101// Additionally a center of mass is required for the X3DV export  
     9102// Unfortunalty, the origin of a piece in leocad is not usefull for use as center of mass 
     9103// So the exporter use the mid of the boundingbox of all pieces in a group as center of mass 
     9104// the needed information is stored in the following compound datatype 
     9105 
     9106class GroupInfo { 
     9107public: 
     9108    Group *group; 
     9109    float minBoundingBox[3]; 
     9110    float maxBoundingBox[3]; 
     9111    char  groupname[65]; 
     9112    bool  firstData; 
     9113    Piece *firstPiece;  
     9114    Piece *lastPiece;  
     9115}; 
     9116 
     9117// routines to account a boundingbox  
     9118 
     9119template<class type> void Project::getMinMaxData(type* info, Piece* pPiece, int numVertices, GroupInfo* groupInfo) 
     9120{ 
     9121    float rot[4]; 
     9122    Vector3 Pos = pPiece->GetPosition(); 
     9123    pPiece->GetRotation(rot); 
     9124    Matrix matrix(rot, Pos); 
     9125 
     9126    PieceInfo* pInfo = pPiece->GetPieceInfo(); 
     9127 
     9128    for (int i = 0; i < numVertices; i++) 
     9129    { 
     9130        float vertex[3]; 
     9131        float *localVertex = &pInfo->m_fVertexArray[info[i] * 3]; 
     9132        matrix.TransformPoint(vertex, localVertex); 
     9133 
     9134        for (int j = 0; j < 3; j++) 
     9135        { 
     9136            if (groupInfo->firstData) 
     9137            { 
     9138                groupInfo->minBoundingBox[j] = vertex[j]; 
     9139                groupInfo->maxBoundingBox[j] = vertex[j]; 
     9140            } 
     9141            if (vertex[j] < groupInfo->minBoundingBox[j]) 
     9142                groupInfo->minBoundingBox[j] = vertex[j]; 
     9143            if (vertex[j] > groupInfo->maxBoundingBox[j]) 
     9144                groupInfo->maxBoundingBox[j] = vertex[j]; 
     9145        } 
     9146        groupInfo->firstData = false; 
     9147    } 
     9148} 
     9149 
     9150template<class type> void Project::getMinMax(type col, Piece* piece, unsigned short group, GroupInfo* groupInfo) 
     9151{  
     9152    PieceInfo *pInfo = piece->GetPieceInfo(); 
     9153    type* info = (type*)(pInfo->m_pGroups[group].drawinfo); 
     9154    type colors = *info; 
     9155    info++; 
     9156 
     9157    type count; 
     9158 
     9159    while (colors--) 
     9160    { 
     9161        if ((*info == LC_COL_DEFAULT) || (*info == LC_COL_EDGES)) 
     9162        { 
     9163        } 
     9164        else 
     9165        { 
     9166            if ((*info >= LC_MAXCOLORS)) 
     9167            { 
     9168                info++; 
     9169                info += *info + 1; 
     9170                info += *info + 1; 
     9171                info += *info + 1; 
     9172 
     9173                continue; 
     9174            } 
     9175        } 
     9176        info++; 
     9177         
     9178        bool skipNext = (info[0] < 1); 
     9179        if (skipNext) 
     9180            skipNext = (info[1] < 1); 
     9181        if (skipNext) 
     9182            info += 2;                 
     9183        else 
     9184        { 
     9185            for (count = *info, info++; count; count -= 4) 
     9186            { 
     9187                getMinMaxData(info, piece, 4, groupInfo); 
     9188                info += 4; 
     9189            } 
     9190     
     9191            for (count = *info, info++; count; count -= 3) 
     9192            { 
     9193                getMinMaxData(info, piece, 3, groupInfo); 
     9194                info += 3; 
     9195            } 
     9196        } 
     9197 
     9198        if (*info > 0) 
     9199        { 
     9200            // skip lines 
     9201            for (count = *info, info++; count; count -= 2) 
     9202            { 
     9203                info += 2; 
     9204            } 
     9205        } else 
     9206            info++; 
     9207    } 
     9208} 
     9209 
     9210// Pieces without TopGroup represent Pieces without "Piece->Group" in LeoCAD 
     9211// The handleAsGroup function is used with "if" in loops over pieces,  
     9212// to run the if/loop content for either only single pieces or all pieces part 
     9213// of a LeoCAD "Piece->Group" 
     9214 
     9215bool Project::handleAsGroup(Piece* pPiece, GroupInfo groupInfo) 
     9216{ 
     9217    if (pPiece->GetTopGroup() == NULL) 
     9218    { 
     9219        if (groupInfo.firstPiece == pPiece) 
     9220            return true; 
     9221    } 
     9222    else 
     9223    { 
     9224        if (pPiece->GetTopGroup() == groupInfo.group) 
     9225            return true; 
     9226    } 
     9227    return false; 
     9228} 
     9229 
     9230// main routine to export VRML97 or X3DV files 
     9231 
     9232void Project::exportVRMLFile(char *filename, int dialect) 
     9233{ 
     9234    numDEF = 0; 
     9235    indent = 0; 
     9236    int coordinateCounter = 1; 
     9237    char buf[LC_MAXPATH], *ptr; 
     9238    FILE* stream = fopen(filename, "wt"); 
     9239    Piece* pPiece; 
     9240    bool rigidBody = (dialect == X3DV_WITH_RIGID_BODY_PHYSICS); 
     9241    VRMLdialect = dialect;   
     9242    strcpy(buf, m_strPathName); 
     9243    ptr = strrchr(buf, '\\'); 
     9244    if (ptr) 
     9245        ptr++; 
     9246    else 
     9247    { 
     9248        ptr = strrchr(buf, '/'); 
     9249        if (ptr) 
     9250            ptr++; 
     9251        else 
     9252            ptr = buf; 
     9253    } 
     9254 
     9255    // write header 
     9256    switch (VRMLdialect) 
     9257    { 
     9258    case VRML97: 
     9259        fputs("#VRML V2.0 utf8\n", stream); 
     9260        break; 
     9261    case X3DV_WITH_RIGID_BODY_PHYSICS: 
     9262        fputs("#X3D V3.0 utf8\n", stream); 
     9263        fputs("PROFILE Immersive\n", stream); 
     9264        fputs("COMPONENT xj3d_RigidBodyPhysics:2\n", stream); 
     9265        // if xj3d is ready use: fputs("COMPONENT RigidBodyPhysics:2\n", stream); 
     9266        break; 
     9267    } 
     9268 
     9269    // write leading comments 
     9270    fputs("# Model exported from LeoCAD\n", stream); 
     9271    if (strlen(buf) != 0) 
     9272        fprintf(stream,"# Original name: %s\n", ptr); 
     9273    if (strlen(m_strAuthor)) 
     9274        fprintf(stream, "# Author: %s\n", m_strAuthor); 
     9275 
     9276    // write leading once needed X3DV commands 
     9277    if (rigidBody) 
     9278    { 
     9279        fputs("\n", stream); 
     9280        writeIndent(stream); 
     9281        fputs("Group {\n", stream); 
     9282        indent += INDENT_INC; 
     9283        writeIndent(stream); 
     9284        fputs("children [\n", stream); 
     9285        indent += INDENT_INC; 
     9286    } 
     9287 
     9288    // initalise "melt together" group information 
     9289    ObjArray<GroupInfo> allGroups; 
     9290    GroupInfo groupObject; 
     9291    for (pPiece = m_pPieces; pPiece; pPiece = pPiece->m_pNext) 
     9292    { 
     9293        Group *topGroup = pPiece->GetTopGroup(); 
     9294        int foundGroup = false;; 
     9295        if (topGroup != NULL) 
     9296        { 
     9297            for (int i = 0; i < allGroups.GetSize(); i++) 
     9298                if (allGroups[i].group == topGroup) 
     9299                { 
     9300                    allGroups[i].lastPiece = pPiece; 
     9301                    foundGroup = true; 
     9302                }  
     9303        } 
     9304        if (!foundGroup) 
     9305        { 
     9306            groupObject.group = topGroup; 
     9307            groupObject.firstPiece = pPiece; 
     9308            groupObject.lastPiece = pPiece; 
     9309            groupObject.firstData = true; 
     9310            if (topGroup != NULL) 
     9311                snprintf(groupObject.groupname, 64, "%s", topGroup->m_strName); 
     9312            else 
     9313                snprintf(groupObject.groupname, 64, "%s", pPiece->GetName()); 
     9314            allGroups.Add(groupObject); 
     9315        } 
     9316    } 
     9317 
     9318    // account bounding box information 
     9319    for (pPiece = m_pPieces; pPiece; pPiece = pPiece->m_pNext) 
     9320    { 
     9321        unsigned char color = pPiece->GetColor(); 
     9322        PieceInfo *pInfo = pPiece->GetPieceInfo(); 
     9323        for (int j = 0; j < allGroups.GetSize(); j++) 
     9324        { 
     9325            if (handleAsGroup(pPiece, allGroups[j])) 
     9326            { 
     9327                unsigned short group; 
     9328 
     9329                for (group = 0; group < pInfo->m_nGroupCount; group++) 
     9330                { 
     9331                    if (pInfo->m_nFlags & LC_PIECE_LONGDATA) 
     9332                    { 
     9333 
     9334                        unsigned long col = color; 
     9335                        getMinMax(col, pPiece, group, &(allGroups[j])); 
     9336                    } 
     9337                    else 
     9338                    { 
     9339                        unsigned short col = color; 
     9340                        getMinMax(col, pPiece, group, &(allGroups[j])); 
     9341