| | 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 | |
| | 8655 | class 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 | |
| | 8686 | enum |
| | 8687 | { |
| | 8688 | VRML97, |
| | 8689 | X3DV_WITH_RIGID_BODY_PHYSICS |
| | 8690 | }; |
| | 8691 | |
| | 8692 | void Project::exportVRML97File(char *filename) |
| | 8693 | { |
| | 8694 | exportVRMLFile(filename, VRML97); |
| | 8695 | } |
| | 8696 | |
| | 8697 | void Project::exportX3DVFile(char *filename) |
| | 8698 | { |
| | 8699 | exportVRMLFile(filename, X3DV_WITH_RIGID_BODY_PHYSICS); |
| | 8700 | } |
| | 8701 | |
| | 8702 | void 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 | |
| | 8715 | void 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 | |
| | 8797 | void 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 | |
| | 8810 | int 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 | |
| | 8822 | template<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 | |
| | 8912 | void 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 | |
| | 8923 | void 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 | |
| | 8932 | void 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 | |
| | 8989 | template<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 | |
| | 9106 | class GroupInfo { |
| | 9107 | public: |
| | 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 | |
| | 9119 | template<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 | |
| | 9150 | template<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 | |
| | 9215 | bool 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 | |
| | 9232 | void 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 |   |