summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xcommon/library.cpp2
-rw-r--r--common/project.cpp922
-rw-r--r--common/project.h29
-rw-r--r--common/typedefs.h25
-rw-r--r--linux/dialogs.cpp134
-rw-r--r--linux/libdlg.cpp432
-rw-r--r--linux/libdlg.h14
-rw-r--r--linux/menu.cpp4
-rw-r--r--linux/module.mk2
-rw-r--r--linux/system.cpp62
10 files changed, 1519 insertions, 107 deletions
diff --git a/common/library.cpp b/common/library.cpp
index f1f06cf..0df8c51 100755
--- a/common/library.cpp
+++ b/common/library.cpp
@@ -114,7 +114,7 @@ bool PiecesLibrary::Load (const char *libpath)
// Load moved files reference.
if (m_pMovedReference != NULL)
free(m_pMovedReference);
- m_pMovedReference = (char*)malloc(18*movedcount);
+ m_pMovedReference = (char*)malloc(18*(movedcount+1));
memset (m_pMovedReference, 0, 18*movedcount);
m_nMovedCount = movedcount;
diff --git a/common/project.cpp b/common/project.cpp
index bf303cc..f9903e6 100644
--- a/common/project.cpp
+++ b/common/project.cpp
@@ -3897,6 +3897,11 @@ void Project::HandleCommand(LC_COMMANDS id, unsigned long nParam)
strcat (fn, m_strTitle);
strcat (fn, htmlext);
f = fopen (fn, "wt");
+ if (f == NULL)
+ {
+ perror(fn);
+ return;
+ }
fprintf (f, "<HTML>\n<HEAD>\n<TITLE>Instructions for %s</TITLE>\n</HEAD>\n<BR>\n<CENTER>\n", m_strTitle);
for (i = 1; i <= last; i++)
@@ -3923,7 +3928,11 @@ void Project::HandleCommand(LC_COMMANDS id, unsigned long nParam)
strcat (fn, "-index");
strcat (fn, htmlext);
f = fopen (fn, "wt");
-
+ if (f == NULL)
+ {
+ perror(fn);
+ return;
+ }
fprintf(f, "<HTML>\n<HEAD>\n<TITLE>Instructions for %s</TITLE>\n</HEAD>\n<BR>\n<CENTER>\n", m_strTitle);
for (i = 1; i <= last; i++)
@@ -3941,7 +3950,11 @@ void Project::HandleCommand(LC_COMMANDS id, unsigned long nParam)
{
sprintf(fn, "%s%s-%02d%s", opts.path, m_strTitle, i, htmlext);
f = fopen(fn, "wt");
-
+ if (f == NULL)
+ {
+ perror(fn);
+ return;
+ }
fprintf(f, "<HTML>\n<HEAD>\n<TITLE>%s - Step %02d</TITLE>\n</HEAD>\n<BR>\n<CENTER>\n", m_strTitle, i);
fprintf(f, "<IMG SRC=\"%s-%02d%s\" ALT=\"Step %02d\" WIDTH=%d HEIGHT=%d><BR><BR>\n",
m_strTitle, i, ext, i, opts.imdlg.width, opts.imdlg.height);
@@ -3973,6 +3986,11 @@ void Project::HandleCommand(LC_COMMANDS id, unsigned long nParam)
strcat (fn, "-pieces");
strcat (fn, htmlext);
f = fopen (fn, "wt");
+ if (f == NULL)
+ {
+ perror(fn);
+ return;
+ }
fprintf (f, "<HTML>\n<HEAD>\n<TITLE>Pieces used by %s</TITLE>\n</HEAD>\n<BR>\n<CENTER>\n", m_strTitle);
CreateHTMLPieceList(f, 0, opts.images, ext);
@@ -4439,6 +4457,27 @@ void Project::HandleCommand(LC_COMMANDS id, unsigned long nParam)
}
} break;
+ // Export to VRML97, exchange x -> z, z -> y, y -> x,
+ case LC_FILE_VRML97:
+ {
+ char filename[LC_MAXPATH];
+ if (!SystemDoDialog(LC_DLG_VRML97, filename))
+ break;
+
+ exportVRML97File(filename);
+ } break;
+
+ // Export to X3DV for rigid body component
+ // exchange x -> z, z -> y, y -> x,
+ case LC_FILE_X3DV:
+ {
+ char filename[LC_MAXPATH];
+ if (!SystemDoDialog(LC_DLG_X3DV, filename))
+ break;
+
+ exportX3DVFile(filename);
+ } break;
+
case LC_FILE_WAVEFRONT:
{
char filename[LC_MAXPATH];
@@ -9337,3 +9376,882 @@ void Project::UpdateOverlayScale()
}
}
}
+
+// VRML97 and X3DV export is very similar, cause X3D is the successor of VRML97
+// therefore a lot of the export routines can be reused
+// the member variable VRMLdialect used with the following enum has this information
+
+enum
+{
+ VRML97,
+ X3DV_WITH_RIGID_BODY_PHYSICS
+};
+
+void Project::exportVRML97File(char *filename)
+{
+ exportVRMLFile(filename, VRML97);
+}
+
+void Project::exportX3DVFile(char *filename)
+{
+ exportVRMLFile(filename, X3DV_WITH_RIGID_BODY_PHYSICS);
+}
+
+void Project::writeIndent(FILE* stream)
+{
+ for (int i = 0; i < indent; i++)
+ fprintf(stream, " ");
+}
+
+#define INDENT_INC 2
+
+// routines to write VRML/X3DV shape related commands
+// for details see
+// http://www.web3d.org/x3d/specifications/vrml/ISO-IEC-14772-VRML97/part1/
+// http://www.web3d.org/x3d/specifications/ISO-IEC-19775-X3DAbstractSpecification/Part01/Architecture.html
+
+void Project::writeVRMLShapeBegin(FILE *stream, unsigned long currentColor, bool blackLines)
+{
+ // http://www.web3d.org/x3d/specifications/ISO-IEC-19775-X3DAbstractSpecification_Revision1_to_Part1/Part01/components/rigid_physics.html#CollidableShape
+
+ if (VRMLdialect == X3DV_WITH_RIGID_BODY_PHYSICS)
+ {
+ numFaceColors = 0;
+ faceColors = (int *) malloc(1);
+
+ writeIndent(stream);
+ fprintf(stream, "DEF CollidableShape%d CollidableShape {\n", numDEF++);
+ indent += INDENT_INC;
+ writeIndent(stream);
+ fprintf(stream, "shape ");
+ }
+ else
+ writeIndent(stream);
+
+ // http://www.web3d.org/x3d/specifications/vrml/ISO-IEC-14772-VRML97/part1/nodesRef.html#Shape
+
+ fprintf(stream, "Shape {\n");
+ indent += INDENT_INC;
+
+ // http://www.web3d.org/x3d/specifications/vrml/ISO-IEC-14772-VRML97/part1/nodesRef.html#Appearance
+ // http://www.web3d.org/x3d/specifications/vrml/ISO-IEC-14772-VRML97/part1/nodesRef.html#Material
+ writeIndent(stream);
+ fprintf(stream, "appearance Appearance {\n");
+ indent += INDENT_INC;
+ writeIndent(stream);
+ fprintf(stream, "material Material {\n");
+ indent += INDENT_INC;
+ if (blackLines)
+ {
+ writeIndent(stream);
+ fprintf(stream, "diffuseColor 0 0 0\n");
+ writeIndent(stream);
+ fprintf(stream, "emissiveColor 0 0 0\n");
+ }
+ else
+ {
+ writeIndent(stream);
+ 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);
+ if (currentColor > 13 && currentColor < 22)
+ {
+ writeIndent(stream);
+ fprintf(stream, "transparency 0.5\n");
+ }
+ }
+ indent -= INDENT_INC;
+ writeIndent(stream);
+ fprintf(stream, "}\n");
+ indent -= INDENT_INC;
+ writeIndent(stream);
+ fprintf(stream, "}\n");
+
+ if (blackLines)
+ {
+ // http://www.web3d.org/x3d/specifications/vrml/ISO-IEC-14772-VRML97/part1/nodesRef.html#IndexedLineSet
+ writeIndent(stream);
+ fprintf(stream, "geometry IndexedLineSet {\n");
+ indent += INDENT_INC;
+ }
+ else
+ {
+ // http://www.web3d.org/x3d/specifications/ISO-IEC-19775-X3DAbstractSpecification/Part01/components/rendering.html#TriangleSet
+ // http://www.web3d.org/x3d/specifications/vrml/ISO-IEC-14772-VRML97/part1/nodesRef.html#IndexedFaceSet
+ writeIndent(stream);
+ if (VRMLdialect == X3DV_WITH_RIGID_BODY_PHYSICS)
+ fprintf(stream, "geometry TriangleSet {\n");
+ else
+ fprintf(stream, "geometry IndexedFaceSet {\n");
+ indent += INDENT_INC;
+ writeIndent(stream);
+ fprintf(stream, "solid FALSE\n");
+ if (VRMLdialect != X3DV_WITH_RIGID_BODY_PHYSICS)
+ {
+ writeIndent(stream);
+ fprintf(stream, "creaseAngle 0.79\n");
+ }
+ }
+}
+
+void Project::writeVRMLShapeEnd(FILE *stream)
+{
+ indent -= INDENT_INC;
+ writeIndent(stream);
+ fprintf(stream, "}\n");
+ indent -= INDENT_INC;
+ writeIndent(stream);
+ fprintf(stream, "}\n");
+}
+
+// search for vertex (vertex[0], vertex[1], vertex[2]) in coords and give
+// back index (-1 if not found)
+
+int Project::searchForVertex(float* vertex)
+{
+ for (int i = 0; i < numCoords; i++)
+ if (coords[i * 3] == vertex[0])
+ if (coords[i * 3 + 1] == vertex[1])
+ if (coords[i * 3 + 2] == vertex[2])
+ return i;
+ return -1;
+}
+
+// routines to collect VRML indexed polygon mesh data or X3DV triangle mesh data
+
+template<class type> void Project::generateMeshData(type* info, float *pos, Piece* pPiece, int numVertices, int currentColor)
+{
+ float rot[4];
+ Vector3 Pos = pPiece->GetPosition();
+ pPiece->GetRotation(rot);
+ Matrix matrix(rot, Pos);
+
+ bool rigidBody = (VRMLdialect == X3DV_WITH_RIGID_BODY_PHYSICS);
+
+ PieceInfo* pInfo = pPiece->GetPieceInfo();
+ if (rigidBody)
+ {
+ // IndexedLineSet not supported by xj3d RigidBody node
+ if (numVertices == 2)
+ return;
+
+ int maxJ = 1;
+ // write 2 triangles instead of 1 quad
+ if (numVertices == 4)
+ maxJ = 2;
+ for (int j = 0; j < maxJ; j++)
+ {
+ for (int i = 0; i < 3; i++)
+ {
+ int index = i;
+ if (j == 1)
+ {
+ switch (i) {
+ case 0:
+ index = 2;
+ break;
+ case 1:
+ index = 0;
+ break;
+ case 2:
+ index = 3;
+ break;
+ }
+ }
+ float *localVertex = &pInfo->m_fVertexArray[info[index] * 3];
+ float vertex[3];
+ matrix.TransformPoint(vertex, localVertex);
+ coords = (float *) realloc(coords, (numCoords + 1) * 3 * sizeof(float));
+ coords[numCoords * 3 + 0] = vertex[1] - pos[1];
+ coords[numCoords * 3 + 1] = vertex[2] - pos[2];
+ coords[numCoords * 3 + 2] = vertex[0] - pos[0];
+ numCoords++;
+ }
+ faceColors = (int *) realloc(faceColors, (numFaceColors + 1) * sizeof(int));
+ faceColors[numFaceColors] = currentColor;
+ numFaceColors++;
+ }
+ return;
+ }
+ for (int i = 0; i < numVertices; i++)
+ {
+ float *localVertex = &pInfo->m_fVertexArray[info[i] * 3];
+ int index = searchForVertex(localVertex);
+ if (index == -1)
+ {
+ float vertex[3];
+ if (rigidBody)
+ matrix.TransformPoint(vertex, localVertex);
+ else
+ {
+ vertex[0] = localVertex[0];
+ vertex[1] = localVertex[1];
+ vertex[2] = localVertex[2];
+ }
+ coords = (float *) realloc(coords, (numCoords + 1) * 3 * sizeof(float));
+ coords[numCoords * 3 + 0] = vertex[1] - (rigidBody ? pos[1] : 0);
+ coords[numCoords * 3 + 1] = vertex[2] - (rigidBody ? pos[2] : 0);
+ coords[numCoords * 3 + 2] = vertex[0] - (rigidBody ? pos[0] : 0);
+ index = numCoords;
+ numCoords++;
+ }
+ coordIndices = (int *) realloc(coordIndices, (numCoordIndices + 1) * sizeof(int));
+ coordIndices[numCoordIndices] = index;
+ numCoordIndices++;
+ }
+ coordIndices = (int *) realloc(coordIndices, (numCoordIndices + 1) * sizeof(int));
+ coordIndices[numCoordIndices] = -1;
+ numCoordIndices++;
+ faceColors = (int *) realloc(faceColors, (numFaceColors + 1) * sizeof(int));
+ faceColors[numFaceColors] = currentColor;
+ numFaceColors++;
+}
+
+// write collected mesh data
+
+void Project::writeVRMLShapeMeshBegin(FILE *stream)
+{
+ writeIndent(stream);
+
+ fprintf(stream, "coord Coordinate {\n");
+ indent += INDENT_INC;
+ writeIndent(stream);
+ fprintf(stream, "point [\n");
+ indent += INDENT_INC;
+}
+
+void Project::writeVRMLShapeMeshData(FILE *stream)
+{
+ for (int i = 0; i < numCoords; i++)
+ {
+ writeIndent(stream);
+ fprintf(stream, "%f %f %f\n", coords[i * 3], coords[i * 3 + 1], coords[i * 3 + 2]);
+ }
+}
+
+void Project::writeVRMLShapeMeshEnd(FILE *stream)
+{
+ indent -= INDENT_INC;
+ writeIndent(stream);
+ fprintf(stream, "]\n");
+ indent -= INDENT_INC;
+ writeIndent(stream);
+ fprintf(stream, "}\n");
+
+
+ if (VRMLdialect == X3DV_WITH_RIGID_BODY_PHYSICS)
+ {
+ writeIndent(stream);
+ fprintf(stream, "color ColorRGBA {\n");
+ indent += INDENT_INC;
+ writeIndent(stream);
+ fprintf(stream, "color [\n");
+ indent += INDENT_INC;
+
+ for (int i = 0; i < numFaceColors; i++)
+ {
+ int currentColor = faceColors[i];
+ writeIndent(stream);
+ 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);
+ writeIndent(stream);
+ 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);
+ writeIndent(stream);
+ 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);
+
+ fprintf(stderr, "{ %d, %g, %g, %g, %g },\n", currentColor, (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);
+ }
+
+ indent -= INDENT_INC;
+ writeIndent(stream);
+ fprintf(stream, "]\n");
+
+ indent -= INDENT_INC;
+ writeIndent(stream);
+ fprintf(stream, "}\n");
+ }
+ else
+ {
+ writeIndent(stream);
+ fprintf(stream, "coordIndex [\n");
+ indent += INDENT_INC;
+
+ for (int i = 0; i < numCoordIndices; i ++)
+ {
+ writeIndent(stream);
+ fprintf(stream, "%d\n", coordIndices[i]);
+ }
+
+ indent -= INDENT_INC;
+ writeIndent(stream);
+ fprintf(stream, "]\n");
+ }
+}
+
+// routine to run through leoCADs internal data space, collect and write data
+
+template<class type> void Project::writeVRMLShapes(type color, FILE *stream, int coordinateCounter, Piece* pPiece, unsigned short group, float *pos, bool beginAndEnd)
+{
+ PieceInfo* pInfo = pPiece->GetPieceInfo();
+ const char* colname;
+ type* info = (type*)(pInfo->m_pGroups[group].drawinfo);
+ type currentColor = color;
+ type count, colors = *info;
+ type maxColors = colors;
+ info++;
+
+ while (colors--)
+ {
+ numCoords = 0;
+ coords = (float *) malloc(1);
+ numCoordIndices = 0;
+ coordIndices = (int *) malloc(1);
+
+ if ((*info == LC_COL_DEFAULT) || (*info == LC_COL_EDGES))
+ {
+ colname = altcolornames[color];
+ currentColor = color;
+ }
+ else
+ {
+ if ((*info >= LC_MAXCOLORS))
+ {
+ info++;
+ info += *info + 1;
+ info += *info + 1;
+ info += *info + 1;
+
+ continue;
+ }
+ colname = altcolornames[*info];
+ currentColor = *info;
+ }
+ info++;
+
+ bool skipNext = (info[0] < 1);
+ if (skipNext)
+ skipNext = (info[1] < 1);
+ if (skipNext)
+ info += 2;
+ else
+ {
+ for (count = *info, info++; count; count -= 4)
+ {
+ generateMeshData(info, pos, pPiece, 4, currentColor);
+ info += 4;
+ }
+
+ for (count = *info, info++; count; count -= 3)
+ {
+ generateMeshData(info, pos, pPiece, 3, currentColor);
+ info += 3;
+ }
+ writeIndent(stream);
+ fprintf(stream, "# %s\n", colname);
+
+ bool rigidBody = (VRMLdialect == X3DV_WITH_RIGID_BODY_PHYSICS);
+
+ bool writeBegin = ((!rigidBody) || (beginAndEnd && (colors == (maxColors - 1))));
+ bool writeEnd = ((!rigidBody) || (beginAndEnd && (colors == 0)));
+
+ if (writeBegin)
+ {
+ writeVRMLShapeBegin(stream, currentColor, false);
+ writeVRMLShapeMeshBegin(stream);
+ }
+
+ writeVRMLShapeMeshData(stream);
+
+ if (writeEnd)
+ {
+ writeVRMLShapeMeshEnd(stream);
+ writeVRMLShapeEnd(stream);
+ }
+ }
+
+ if (*info > 0)
+ {
+ // IndexedLineSet not supported in RigidBody node for the xj3d browser 8-(
+ if (VRMLdialect != X3DV_WITH_RIGID_BODY_PHYSICS)
+ {
+ writeIndent(stream);
+ fprintf(stream, "# lines of color %s\n", colname);
+ }
+
+ for (count = *info, info++; count; count -= 2)
+ {
+ generateMeshData(info, pos, pPiece, 2, currentColor);
+ info += 2;
+ }
+
+ // IndexedLineSet not supported in RigidBody node for the xj3d browser 8-(
+ if (VRMLdialect != X3DV_WITH_RIGID_BODY_PHYSICS)
+ {
+ writeVRMLShapeBegin(stream, currentColor, true);
+ writeVRMLShapeMeshBegin(stream);
+ writeVRMLShapeMeshData(stream);
+ writeVRMLShapeMeshEnd(stream);
+ writeVRMLShapeEnd(stream);
+ }
+ } else
+ info++;
+ free(coords);
+ free(coordIndices);
+ }
+}
+
+// The X3DV export need to "melt together" faces of different pieces into one triangleSet
+// based on the leocad "piece -> group" menupoint, otherwise the rigid body simulation would simulate all pieces seperatly
+// Additionally a center of mass is required for the X3DV export
+// Unfortunalty, the origin of a piece in leocad is not usefull for use as center of mass
+// So the exporter use the mid of the boundingbox of all pieces in a group as center of mass
+// the needed information is stored in the following compound datatype
+
+class GroupInfo {
+public:
+ Group *group;
+ float minBoundingBox[3];
+ float maxBoundingBox[3];
+ char groupname[65];
+ bool firstData;
+ Piece *firstPiece;
+ Piece *lastPiece;
+};
+
+// routines to account a boundingbox
+
+template<class type> void Project::getMinMaxData(type* info, Piece* pPiece, int numVertices, GroupInfo* groupInfo)
+{
+ float rot[4];
+ Vector3 Pos = pPiece->GetPosition();
+ pPiece->GetRotation(rot);
+ Matrix matrix(rot, Pos);
+
+ PieceInfo* pInfo = pPiece->GetPieceInfo();
+
+ for (int i = 0; i < numVertices; i++)
+ {
+ float vertex[3];
+ float *localVertex = &pInfo->m_fVertexArray[info[i] * 3];
+ matrix.TransformPoint(vertex, localVertex);
+
+ for (int j = 0; j < 3; j++)
+ {
+ if (groupInfo->firstData)
+ {
+ groupInfo->minBoundingBox[j] = vertex[j];
+ groupInfo->maxBoundingBox[j] = vertex[j];
+ }
+ if (vertex[j] < groupInfo->minBoundingBox[j])
+ groupInfo->minBoundingBox[j] = vertex[j];
+ if (vertex[j] > groupInfo->maxBoundingBox[j])
+ groupInfo->maxBoundingBox[j] = vertex[j];
+ }
+ groupInfo->firstData = false;
+ }
+}
+
+template<class type> void Project::getMinMax(type col, Piece* piece, unsigned short group, GroupInfo* groupInfo)
+{
+ PieceInfo *pInfo = piece->GetPieceInfo();
+ type* info = (type*)(pInfo->m_pGroups[group].drawinfo);
+ type colors = *info;
+ info++;
+
+ type count;
+
+ while (colors--)
+ {
+ if ((*info == LC_COL_DEFAULT) || (*info == LC_COL_EDGES))
+ {
+ }
+ else
+ {
+ if ((*info >= LC_MAXCOLORS))
+ {
+ info++;
+ info += *info + 1;
+ info += *info + 1;
+ info += *info + 1;
+
+ continue;
+ }
+ }
+ info++;
+
+ bool skipNext = (info[0] < 1);
+ if (skipNext)
+ skipNext = (info[1] < 1);
+ if (skipNext)
+ info += 2;
+ else
+ {
+ for (count = *info, info++; count; count -= 4)
+ {
+ getMinMaxData(info, piece, 4, groupInfo);
+ info += 4;
+ }
+
+ for (count = *info, info++; count; count -= 3)
+ {
+ getMinMaxData(info, piece, 3, groupInfo);
+ info += 3;
+ }
+ }
+
+ if (*info > 0)
+ {
+ // skip lines
+ for (count = *info, info++; count; count -= 2)
+ {
+ info += 2;
+ }
+ } else
+ info++;
+ }
+}
+
+// Pieces without TopGroup represent Pieces without "Piece->Group" in LeoCAD
+// The handleAsGroup function is used with "if" in loops over pieces,
+// to run the if/loop content for either only single pieces or all pieces part
+// of a LeoCAD "Piece->Group"
+
+bool Project::handleAsGroup(Piece* pPiece, GroupInfo groupInfo)
+{
+ if (pPiece->GetTopGroup() == NULL)
+ {
+ if (groupInfo.firstPiece == pPiece)
+ return true;
+ }
+ else
+ {
+ if (pPiece->GetTopGroup() == groupInfo.group)
+ return true;
+ }
+ return false;
+}
+
+// main routine to export VRML97 or X3DV files
+
+void Project::exportVRMLFile(char *filename, int dialect)
+{
+ numDEF = 0;
+ indent = 0;
+ int coordinateCounter = 1;
+ char buf[LC_MAXPATH], *ptr;
+ FILE* stream = fopen(filename, "wt");
+ Piece* pPiece;
+ bool rigidBody = (dialect == X3DV_WITH_RIGID_BODY_PHYSICS);
+ VRMLdialect = dialect;
+ strcpy(buf, m_strPathName);
+ ptr = strrchr(buf, '\\');
+ if (ptr)
+ ptr++;
+ else
+ {
+ ptr = strrchr(buf, '/');
+ if (ptr)
+ ptr++;
+ else
+ ptr = buf;
+ }
+
+ // write header
+ switch (VRMLdialect)
+ {
+ case VRML97:
+ fputs("#VRML V2.0 utf8\n", stream);
+ break;
+ case X3DV_WITH_RIGID_BODY_PHYSICS:
+ fputs("#X3D V3.0 utf8\n", stream);
+ fputs("PROFILE Immersive\n", stream);
+ fputs("COMPONENT xj3d_RigidBodyPhysics:2\n", stream);
+ // if xj3d is ready use: fputs("COMPONENT RigidBodyPhysics:2\n", stream);
+ break;
+ }
+
+ // write leading comments
+ fputs("# Model exported from LeoCAD\n", stream);
+ if (strlen(buf) != 0)
+ fprintf(stream,"# Original name: %s\n", ptr);
+ if (strlen(m_strAuthor))
+ fprintf(stream, "# Author: %s\n", m_strAuthor);
+
+ // write leading once needed X3DV commands
+ if (rigidBody)
+ {
+ fputs("\n", stream);
+ writeIndent(stream);
+ fputs("Group {\n", stream);
+ indent += INDENT_INC;
+ writeIndent(stream);
+ fputs("children [\n", stream);
+ indent += INDENT_INC;
+ }
+
+ // initalise "melt together" group information
+ ObjArray<GroupInfo> allGroups;
+ GroupInfo groupObject;
+ for (pPiece = m_pPieces; pPiece; pPiece = pPiece->m_pNext)
+ {
+ Group *topGroup = pPiece->GetTopGroup();
+ int foundGroup = false;;
+ if (topGroup != NULL)
+ {
+ for (int i = 0; i < allGroups.GetSize(); i++)
+ if (allGroups[i].group == topGroup)
+ {
+ allGroups[i].lastPiece = pPiece;
+ foundGroup = true;
+ }
+ }
+ if (!foundGroup)
+ {
+ groupObject.group = topGroup;
+ groupObject.firstPiece = pPiece;
+ groupObject.lastPiece = pPiece;
+ groupObject.firstData = true;
+ if (topGroup != NULL)
+ snprintf(groupObject.groupname, 64, "%s", topGroup->m_strName);
+ else
+ snprintf(groupObject.groupname, 64, "%s", pPiece->GetName());
+ allGroups.Add(groupObject);
+ }
+ }
+
+ // account bounding box information
+ for (pPiece = m_pPieces; pPiece; pPiece = pPiece->m_pNext)
+ {
+ unsigned char color = pPiece->GetColor();
+ PieceInfo *pInfo = pPiece->GetPieceInfo();
+ for (int j = 0; j < allGroups.GetSize(); j++)
+ {
+ if (handleAsGroup(pPiece, allGroups[j]))
+ {
+ unsigned short group;
+
+ for (group = 0; group < pInfo->m_nGroupCount; group++)
+ {
+ if (pInfo->m_nFlags & LC_PIECE_LONGDATA)
+ {
+ unsigned long col = color;
+ getMinMax(col, pPiece, group, &(allGroups[j]));
+ }
+ else
+ {
+ unsigned short col = color;
+ getMinMax(col, pPiece, group, &(allGroups[j]));
+ }
+ }
+ }
+ }
+ }
+
+ // write main VRML97/X3DV data
+ for (int j = 0; j < allGroups.GetSize(); j++)
+ {
+ for (pPiece = m_pPieces; pPiece; pPiece = pPiece->m_pNext)
+ {
+ bool beginGroup = ((allGroups[j].group == NULL) || (allGroups[j].firstPiece == pPiece));
+ bool endGroup = ((allGroups[j].group == NULL) || (allGroups[j].lastPiece == pPiece));
+
+ if (handleAsGroup(pPiece, allGroups[j]))
+ {
+ PieceInfo* pInfo = pPiece->GetPieceInfo();
+ unsigned char color = pPiece->GetColor();
+
+ strcpy(buf, pPiece->GetName());
+ for (unsigned int i = 0; i < strlen(buf); i++)
+ if ((buf[i] == '#') || (buf[i] == ' '))
+ buf[i] = '_';
+
+ writeIndent(stream);
+ fprintf(stream, "# %s\n", buf);
+
+ float pos[3];
+ float rot[4];
+
+ switch (VRMLdialect)
+ {
+ case VRML97:
+ pPiece->GetPosition(pos);
+ pPiece->GetRotation(rot);
+ writeIndent(stream);
+ fprintf(stream, "Transform {\n");
+ indent += INDENT_INC;
+ writeIndent(stream);
+ fprintf(stream, "translation %g %g %g\n", pos[1], pos[2], pos[0]);
+ writeIndent(stream);
+ fprintf(stream, "rotation %g %g %g %g\n", rot[1], rot[2], rot[0], rot[3] * M_PI / 180.0);
+ writeIndent(stream);
+ fprintf(stream, "children [\n");
+ indent += INDENT_INC;
+ break;
+ case X3DV_WITH_RIGID_BODY_PHYSICS:
+ for (int k = 0; k < 3; k++)
+ pos[k] = allGroups[j].minBoundingBox[k] + (allGroups[j].maxBoundingBox[k] - allGroups[j].minBoundingBox[k]) / 2.0f;
+ }
+
+ unsigned short group;
+
+ if (pInfo->m_nGroupCount > 0)
+ {
+
+ if (beginGroup && rigidBody)
+ {
+ if (pInfo->m_nFlags & LC_PIECE_LONGDATA)
+ {
+ unsigned long col = color;
+ writeVRMLShapeBegin(stream, col, false);
+ writeVRMLShapeMeshBegin(stream);
+ }
+ else
+ {
+ unsigned short col = color;
+ writeVRMLShapeBegin(stream, col, false);
+ writeVRMLShapeMeshBegin(stream);
+ }
+ }
+
+ for (group = 0; group < pInfo->m_nGroupCount; group++)
+ {
+ writeIndent(stream);
+ fprintf(stream, "# group %d\n",(int)group);
+ if (pInfo->m_nFlags & LC_PIECE_LONGDATA)
+ {
+ unsigned long col = color;
+ writeVRMLShapes(col, stream, coordinateCounter, pPiece, group, pos, !rigidBody);
+ }
+ else
+ {
+ unsigned short col = color;
+ writeVRMLShapes(col, stream, coordinateCounter, pPiece, group, pos, !rigidBody);
+ }
+ }
+
+ if (endGroup && rigidBody)
+ {
+ writeVRMLShapeMeshEnd(stream);
+ writeVRMLShapeEnd(stream);
+ }
+ }
+
+ if (!rigidBody)
+ {
+ indent -= INDENT_INC;
+ writeIndent(stream);
+ fprintf(stream, "]\n");
+ }
+
+ if (endGroup || (!rigidBody))
+ {
+ indent -= INDENT_INC;
+ writeIndent(stream);
+ fprintf(stream, "} # endShape\n");
+ }
+
+ coordinateCounter++;
+ }
+
+ }
+ }
+
+ if (rigidBody)
+ {
+ // write trailing once needed X3DV commands
+ // http://www.xj3d.org/extensions/rigid_physics.html
+ // http://www.web3d.org/x3d/specifications/ISO-IEC-19775-X3DAbstractSpecification_Revision1_to_Part1/Part01/components/rigid_physics.html
+ indent -= INDENT_INC;
+ writeIndent(stream);
+ fputs("]\n", stream);
+ indent -= INDENT_INC;
+ writeIndent(stream);
+ fputs("}\n", stream);
+
+ writeIndent(stream);
+ fputs("DEF RigidBodyCollection1 RigidBodyCollection {\n", stream);
+ indent += INDENT_INC;
+ writeIndent(stream);
+ fputs("bodies [\n", stream);
+ indent += INDENT_INC;
+ coordinateCounter = 0;
+ for (int j = 0; j < allGroups.GetSize(); j++)
+ {
+ for (pPiece = m_pPieces; pPiece; pPiece = pPiece->m_pNext)
+ {
+ bool beginGroup = ((allGroups[j].group == NULL) || (allGroups[j].firstPiece == pPiece));
+ bool endGroup = ((allGroups[j].group == NULL) || (allGroups[j].lastPiece == pPiece));
+
+ if (handleAsGroup(pPiece, allGroups[j]))
+ {
+ float pos[3];
+
+ if (VRMLdialect == X3DV_WITH_RIGID_BODY_PHYSICS)
+ {
+ if (beginGroup)
+ {
+ for (int k = 0; k < 3; k++)
+ pos[k] = allGroups[j].minBoundingBox[k] + (allGroups[j].maxBoundingBox[k] - allGroups[j].minBoundingBox[k]) / 2.0f;
+ writeIndent(stream);
+ fprintf(stream, "# %s\n", allGroups[j].groupname);
+ writeIndent(stream);
+ fprintf(stream, "RigidBody {\n");
+ indent += INDENT_INC;
+ writeIndent(stream);
+ fprintf(stream, "position %g %g %g\n", pos[1], pos[2], pos[0]);
+ writeIndent(stream);
+ fprintf(stream, "geometry USE CollidableShape%d\n", coordinateCounter);
+ }
+ if (endGroup)
+ {
+ indent -= INDENT_INC;
+ writeIndent(stream);
+ fprintf(stream, "}\n");
+ }
+ }
+ }
+
+ }
+ coordinateCounter++;
+ }
+ indent -= INDENT_INC;
+ writeIndent(stream);
+ fputs("]\n", stream);
+
+ writeIndent(stream);
+ fputs("collider DEF CollisionCollection1 CollisionCollection", stream);
+ fputs(" {\n", stream);
+ indent += INDENT_INC;
+ writeIndent(stream);
+ fputs("collidables [\n", stream);
+ indent += INDENT_INC;
+ for (int i = 0; i < numDEF; i++)
+ {
+ writeIndent(stream);
+ fprintf(stream, "USE CollidableShape%d\n", i);
+ }
+ indent -= INDENT_INC;
+ writeIndent(stream);
+ fputs("]\n", stream);
+ indent -= INDENT_INC;
+ writeIndent(stream);
+ fputs("}\n", stream);
+ indent -= INDENT_INC;
+ writeIndent(stream);
+ fputs("}\n", stream);
+
+ writeIndent(stream);
+ fputs("DEF CollisionSensor1 CollisionSensor {\n", stream);
+ indent += INDENT_INC;
+ writeIndent(stream);
+ fputs("collidables USE CollisionCollection1\n", stream);
+ indent -= INDENT_INC;
+ writeIndent(stream);
+ fputs("}\n", stream);
+ fputs("\n", stream);
+ fputs("ROUTE CollisionSensor1.contacts TO RigidBodyCollection1.set_contacts\n", stream);
+ }
+
+ if (indent != 0)
+ fprintf(stderr, "internal error: indent %d\n", indent);
+ fclose(stream);
+}
+
+
diff --git a/common/project.h b/common/project.h
index f4bb61c..38ebc57 100644
--- a/common/project.h
+++ b/common/project.h
@@ -30,6 +30,7 @@ class Piece;
class Camera;
class Light;
class Group;
+class GroupInfo;
class Texture;
class Terrain;
class PieceInfo;
@@ -308,6 +309,34 @@ protected:
friend class CCADView;
friend void PrintPiecesThread(void* pv);
friend void Export3DStudio();
+
+ // VRML export
+ void exportVRML97File(char *filename);
+ void exportX3DVFile(char *filename);
+ void exportVRMLFile(char *filename, int dialect);
+ template<class type> void writeVRMLShapes(type color, FILE *stream, int coordinateCounter, Piece* pPiece, unsigned short group, float *pos, bool beginAndEnd);
+ void writeVRMLShapeBegin(FILE *stream, unsigned long currentColor, bool blackLines);
+ void writeVRMLShapeMeshBegin(FILE *stream);
+ void writeVRMLShapeMeshData(FILE *stream);
+ void writeVRMLShapeMeshEnd(FILE *stream);
+ void writeVRMLShapeEnd(FILE *stream);
+ void writeIndent(FILE *stream);
+ int indent;
+ int numDEF;
+ bool VRMLdialect;
+ bool firstData;
+ int searchForVertex(float *vertex);
+ template<class type> void generateMeshData(type* info, float *pos, Piece* pPiece, int numVertices, int currentColor);
+ template<class type> void getMinMaxData(type* info, Piece* pPiece, int numVertices, GroupInfo* groupInfo);
+ template<class type> void getMinMax(type col, Piece* pPiece, unsigned short group, GroupInfo* groupInfo);
+ bool handleAsGroup(Piece* piece, GroupInfo groupInfo);
+ int numCoords;
+ float *coords;
+ int numCoordIndices;
+ int *coordIndices;
+ float centerOfMass[3];
+ int numFaceColors;
+ int *faceColors;
};
#endif // _PROJECT_H_
diff --git a/common/typedefs.h b/common/typedefs.h
index ce68b1f..10953ea 100644
--- a/common/typedefs.h
+++ b/common/typedefs.h
@@ -35,6 +35,8 @@ typedef enum
LC_FILE_HTML,
LC_FILE_POVRAY,
LC_FILE_WAVEFRONT,
+ LC_FILE_VRML97,
+ LC_FILE_X3DV,
LC_FILE_PROPERTIES,
LC_FILE_TERRAIN,
LC_FILE_LIBRARY,
@@ -139,6 +141,27 @@ typedef enum
LC_EDIT_ACTION_PAN,
LC_EDIT_ACTION_ROTATE_VIEW,
LC_EDIT_ACTION_ROLL,
+ LC_LIBDLG_FILE_RESET,
+ LC_LIBDLG_FILE_OPEN,
+ LC_LIBDLG_FILE_SAVE,
+ LC_LIBDLG_FILE_SAVEAS,
+ LC_LIBDLG_FILE_PRINTCATALOG,
+ LC_LIBDLG_FILE_MERGEUPDATE,
+ LC_LIBDLG_FILE_IMPORTPIECE,
+ LC_LIBDLG_FILE_RETURN,
+ LC_LIBDLG_FILE_CANCEL,
+ LC_LIBDLG_CATEGORY_NEW,
+ LC_LIBDLG_CATEGORY_REMOVE,
+ LC_LIBDLG_CATEGORY_EDIT,
+ LC_LIBDLG_CATEGORY_RESET,
+ LC_LIBDLG_GROUP_INSERT,
+ LC_LIBDLG_GROUP_DELETE,
+ LC_LIBDLG_GROUP_EDIT,
+ LC_LIBDLG_GROUP_MOVEUP,
+ LC_LIBDLG_GROUP_MOVEDOWN,
+ LC_LIBDLG_PIECE_NEW,
+ LC_LIBDLG_PIECE_EDIT,
+ LC_LIBDLG_PIECE_DELETE,
} LC_COMMANDS;
typedef enum
@@ -293,6 +316,8 @@ typedef enum {
LC_DLG_HTML,
LC_DLG_POVRAY,
LC_DLG_WAVEFRONT,
+ LC_DLG_VRML97,
+ LC_DLG_X3DV,
LC_DLG_MINIFIG,
LC_DLG_ARRAY,
LC_DLG_PREFERENCES,
diff --git a/linux/dialogs.cpp b/linux/dialogs.cpp
index 5318caf..f58d60a 100644
--- a/linux/dialogs.cpp
+++ b/linux/dialogs.cpp
@@ -23,6 +23,7 @@
#include "config.h"
#include "message.h"
#include "project.h"
+#include "libdlg.h"
// =============================================================================
// Modal dialog helper functions
@@ -2161,11 +2162,14 @@ static void propertiesdlg_ok(GtkWidget *widget, gpointer data)
LC_PROPERTIESDLG_STRUCT* s = (LC_PROPERTIESDLG_STRUCT*)data;
LC_PROPERTIESDLG_OPTS* opts = (LC_PROPERTIESDLG_OPTS*)s->data;
- strcpy(opts->strAuthor, gtk_entry_get_text (GTK_ENTRY (s->sum_author)));
- strcpy(opts->strDescription, gtk_entry_get_text (GTK_ENTRY (s->sum_description)));
+ strcpy(opts->strAuthor, gtk_entry_get_text(GTK_ENTRY(s->sum_author)));
+ strcpy(opts->strDescription, gtk_entry_get_text(GTK_ENTRY(s->sum_description)));
char* comments = gtk_editable_get_chars(GTK_EDITABLE(s->sum_comments), 0, -1);
- strcpy(opts->strComments, comments);
- g_free(comments);
+ if (comments != NULL)
+ {
+ strcpy(opts->strComments, comments);
+ g_free(comments);
+ }
*cur_ret = LC_OK;
}
@@ -2743,13 +2747,13 @@ int groupdlg_execute(void* param)
// =============================================================================
// Piece Library Dialog
-#if 0
#include "library.h"
#include "pieceinf.h"
+#include "lc_application.h"
static void librarydlg_update_list (GtkWidget *dlg)
{
- PiecesLibrary *lib = project->GetPiecesLibrary();
+ PiecesLibrary *lib = g_App->GetPiecesLibrary();
GtkCTree *ctree = GTK_CTREE (gtk_object_get_data (GTK_OBJECT (dlg), "tree"));
GtkCList *clist = GTK_CLIST (gtk_object_get_data (GTK_OBJECT (dlg), "list"));
int row, sel = GTK_CLIST (ctree)->focus_row;
@@ -2776,7 +2780,7 @@ static void librarydlg_update_list (GtkWidget *dlg)
static void librarydlg_update_tree (GtkWidget *dlg)
{
- PiecesLibrary *lib = project->GetPiecesLibrary();
+ PiecesLibrary *lib = g_App->GetPiecesLibrary();
GtkCTree *ctree = GTK_CTREE (gtk_object_get_data (GTK_OBJECT (dlg), "tree"));
GtkCTreeNode *parent;
char *text = "Groups";
@@ -2800,24 +2804,25 @@ static void librarydlg_treefocus (GtkCTree *ctree, GtkCTreeNode *row, gint colum
librarydlg_update_list (GTK_WIDGET (data));
}
+static GtkWidget *last_dlg = NULL;
+
static void librarydlg_command (GtkWidget *widget, gpointer data)
{
- /*
GtkWidget *parent = gtk_widget_get_toplevel (widget);
- LibraryDialog *dlg = (LibraryDialog*) gtk_object_get_data (GTK_OBJECT (parent), "lib");
+ LibraryDialog *dlg = (LibraryDialog*) gtk_object_get_data (GTK_OBJECT (parent), "menu_file_import_piece");
int id = GPOINTER_TO_INT (data);
+ dlg = (LibraryDialog *)last_dlg;
+
dlg->HandleCommand (id);
- */
}
int librarydlg_execute (void *param)
{
-#if 0
GtkWidget *dlg, *vbox, *clist, *scr, *ctree, *hsplit, *item, *menu, *menubar, *handle;
- GtkAccelGroup *accel, *menu_accel;
+ GtkAccelGroup *accel;
int loop = 1, ret = LC_CANCEL;
- LibraryManager lib;
+ PiecesLibrary *lib = g_App->GetPiecesLibrary();
dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_transient_for (GTK_WINDOW (dlg), GTK_WINDOW (((GtkWidget*)(*main_window))));
@@ -2829,7 +2834,10 @@ int librarydlg_execute (void *param)
gtk_object_set_data (GTK_OBJECT (dlg), "loop", &loop);
gtk_object_set_data (GTK_OBJECT (dlg), "ret", &ret);
gtk_window_set_default_size (GTK_WINDOW (dlg), 500, 250);
- accel = gtk_accel_group_get_default ();
+
+ accel = gtk_accel_group_new();
+ gtk_window_add_accel_group(GTK_WINDOW(dlg), accel);
+// accel = gtk_accel_group_get_default ();
vbox = gtk_vbox_new (FALSE, 5);
gtk_widget_show (vbox);
@@ -2844,60 +2852,58 @@ int librarydlg_execute (void *param)
gtk_widget_show (menubar);
// File menu
- menu = create_sub_menu (menubar, "_File", accel, &menu_accel);
+ menu = create_sub_menu (menubar, "_File", accel);
menu_tearoff (menu);
- /*
- create_menu_item (menu, "_Reset", menu_accel,
- GTK_SIGNAL_FUNC (librarydlg_command), LC_LIBDLG_FILE_RESET);
- create_menu_item (menu, "_Open...", menu_accel,
- GTK_SIGNAL_FUNC (librarydlg_command), LC_LIBDLG_FILE_OPEN);
- create_menu_item (menu, "_Save", menu_accel,
- GTK_SIGNAL_FUNC (librarydlg_command), LC_LIBDLG_FILE_SAVE);
- create_menu_item (menu, "Save _As...", menu_accel,
- GTK_SIGNAL_FUNC (librarydlg_command), LC_LIBDLG_FILE_SAVEAS);
+/*
+ create_menu_item (menu, "_Reset", accel,
+ GTK_SIGNAL_FUNC (librarydlg_command), GTK_OBJECT (dlg), LC_LIBDLG_FILE_RESET, "menu_file_reset");
+ create_menu_item (menu, "_Open...", accel,
+ GTK_SIGNAL_FUNC (librarydlg_command), GTK_OBJECT (dlg), LC_LIBDLG_FILE_OPEN, "menu_file_open");
+ create_menu_item (menu, "_Save", accel,
+ GTK_SIGNAL_FUNC (librarydlg_command), GTK_OBJECT (dlg), LC_LIBDLG_FILE_SAVE, "menu_file_save");
+ create_menu_item (menu, "Save _As...", accel,
+ GTK_SIGNAL_FUNC (librarydlg_command), GTK_OBJECT (dlg), LC_LIBDLG_FILE_SAVEAS, "menu_file_save_as");
menu_separator (menu);
- item = create_menu_item (menu, "_Print Catalog...", menu_accel,
- GTK_SIGNAL_FUNC (librarydlg_command), LC_LIBDLG_FILE_PRINTCATALOG);
+ item = create_menu_item (menu, "_Print Catalog...", accel,
+ GTK_SIGNAL_FUNC (librarydlg_command), GTK_OBJECT (dlg), LC_LIBDLG_FILE_PRINTCATALOG, "menu_print_catalog");
gtk_widget_set_sensitive (item, FALSE);
- item = create_menu_item (menu, "Load _Update...", menu_accel,
- GTK_SIGNAL_FUNC (librarydlg_command), LC_LIBDLG_FILE_MERGEUPDATE);
- item = create_menu_item (menu, "_Import Piece...", menu_accel,
- GTK_SIGNAL_FUNC (librarydlg_command), LC_LIBDLG_FILE_IMPORTPIECE);
+*/
+ item = create_menu_item (menu, "Load _Update...", accel,
+ GTK_SIGNAL_FUNC (librarydlg_command), GTK_OBJECT (dlg), LC_LIBDLG_FILE_MERGEUPDATE, "menu_file_merge_update");
+ item = create_menu_item (menu, "_Import Piece...", accel,
+ GTK_SIGNAL_FUNC (librarydlg_command), GTK_OBJECT (dlg), LC_LIBDLG_FILE_IMPORTPIECE, "menu_file_import_piece");
+/*
menu_separator (menu);
- item = create_menu_item (menu, "Re_turn", menu_accel,
- GTK_SIGNAL_FUNC (librarydlg_command), LC_LIBDLG_FILE_RETURN);
- item = create_menu_item (menu, "_Cancel", menu_accel,
- GTK_SIGNAL_FUNC (librarydlg_command), LC_LIBDLG_FILE_CANCEL);
- */
+ item = create_menu_item (menu, "Re_turn", accel,
+ GTK_SIGNAL_FUNC (librarydlg_command), GTK_OBJECT (dlg), LC_LIBDLG_FILE_RETURN, "menu_file_return");
+ item = create_menu_item (menu, "_Cancel", accel,
+ GTK_SIGNAL_FUNC (librarydlg_command), GTK_OBJECT (dlg), LC_LIBDLG_FILE_CANCEL, "menu_file_cancel");
// Group menu
- menu = create_sub_menu (menubar, "_Group", accel, &menu_accel);
+ menu = create_sub_menu (menubar, "_Group", accel);
menu_tearoff (menu);
- /*
- create_menu_item (menu, "Insert...", menu_accel,
- GTK_SIGNAL_FUNC (librarydlg_command), LC_LIBDLG_GROUP_INSERT);
- create_menu_item (menu, "Delete", menu_accel,
- GTK_SIGNAL_FUNC (librarydlg_command), LC_LIBDLG_GROUP_DELETE);
- create_menu_item (menu, "Edit...", menu_accel,
- GTK_SIGNAL_FUNC (librarydlg_command), LC_LIBDLG_GROUP_EDIT);
+ create_menu_item (menu, "Insert...", accel,
+ GTK_SIGNAL_FUNC (librarydlg_command), GTK_OBJECT (dlg), LC_LIBDLG_GROUP_INSERT, "menu_group_insert");
+ create_menu_item (menu, "Delete", accel,
+ GTK_SIGNAL_FUNC (librarydlg_command), GTK_OBJECT (dlg), LC_LIBDLG_GROUP_DELETE, "menu_group_delete");
+ create_menu_item (menu, "Edit...", accel,
+ GTK_SIGNAL_FUNC (librarydlg_command), GTK_OBJECT (dlg), LC_LIBDLG_GROUP_EDIT, "menu_group_edit");
menu_separator (menu);
- create_menu_item (menu, "Move Up", menu_accel,
- GTK_SIGNAL_FUNC (librarydlg_command), LC_LIBDLG_GROUP_MOVEUP);
- create_menu_item (menu, "Move Down", menu_accel,
- GTK_SIGNAL_FUNC (librarydlg_command), LC_LIBDLG_GROUP_MOVEDOWN);
- */
+ create_menu_item (menu, "Move Up", accel,
+ GTK_SIGNAL_FUNC (librarydlg_command), GTK_OBJECT (dlg), LC_LIBDLG_GROUP_MOVEUP, "menu_group_moveup");
+ create_menu_item (menu, "Move Down", accel,
+ GTK_SIGNAL_FUNC (librarydlg_command), GTK_OBJECT (dlg), LC_LIBDLG_GROUP_MOVEDOWN, "menu_group_down");
// Piece menu
- menu = create_sub_menu (menubar, "_Piece", accel, &menu_accel);
+ menu = create_sub_menu (menubar, "_Piece", accel);
menu_tearoff (menu);
- /*
- item = create_menu_item (menu, "_New", menu_accel,
- GTK_SIGNAL_FUNC (librarydlg_command), LC_LIBDLG_PIECE_NEW);
+ item = create_menu_item (menu, "_New", accel,
+ GTK_SIGNAL_FUNC (librarydlg_command), GTK_OBJECT (dlg), LC_LIBDLG_PIECE_NEW, "menu_piece_new");
gtk_widget_set_sensitive (item, FALSE);
- item = create_menu_item (menu, "_Edit", menu_accel,
- GTK_SIGNAL_FUNC (librarydlg_command), LC_LIBDLG_PIECE_EDIT);
+ item = create_menu_item (menu, "_Edit", accel,
+ GTK_SIGNAL_FUNC (librarydlg_command), GTK_OBJECT (dlg), LC_LIBDLG_PIECE_EDIT, "menu_piece_edit");
gtk_widget_set_sensitive (item, FALSE);
- create_menu_item (menu, "_Delete", menu_accel,
- GTK_SIGNAL_FUNC (librarydlg_command), LC_LIBDLG_PIECE_DELETE);
- */
+ create_menu_item (menu, "_Delete", accel,
+ GTK_SIGNAL_FUNC (librarydlg_command), GTK_OBJECT (dlg), LC_LIBDLG_PIECE_DELETE, "menu_piece_delete");
+*/
hsplit = gtk_hpaned_new ();
gtk_paned_set_gutter_size (GTK_PANED (hsplit), 12);
gtk_box_pack_start (GTK_BOX (vbox), hsplit, TRUE, TRUE, 0);
@@ -2937,6 +2943,8 @@ int librarydlg_execute (void *param)
gtk_grab_add (dlg);
gtk_widget_show (dlg);
+ last_dlg = dlg;
+
while (loop)
gtk_main_iteration ();
@@ -2949,20 +2957,8 @@ int librarydlg_execute (void *param)
gtk_widget_destroy (dlg);
return ret;
-#endif
- return LC_OK;
}
-#else
-
-int librarydlg_execute (void *param)
-{
- // TODO: FIXME !
- return 0;
-}
-
-#endif
-
// =============================================================================
// Modify Dialog
diff --git a/linux/libdlg.cpp b/linux/libdlg.cpp
new file mode 100644
index 0000000..ad741e3
--- /dev/null
+++ b/linux/libdlg.cpp
@@ -0,0 +1,432 @@
+// LibDlg.cpp : implementation file
+//
+
+#include <limits.h>
+//#include "leocad.h"
+#include "libdlg.h"
+//#include "GroupDlg.h"
+//#include "Print.h"
+//#include "Tools.h"
+#include "project.h"
+#include "pieceinf.h"
+#include "globals.h"
+#include "system.h"
+#include "library.h"
+#include "lc_application.h"
+
+bool LibraryDialog::HandleCommand(int id)
+{
+ switch (id)
+ {
+ case LC_LIBDLG_FILE_OPEN:
+ {
+ lcGetPiecesLibrary()->LoadCategories(NULL);
+// UpdateTree();
+ return true;
+ }
+
+ case LC_LIBDLG_FILE_SAVE:
+ {
+ lcGetPiecesLibrary()->DoSaveCategories(false);
+ return true;
+ }
+
+ case LC_LIBDLG_FILE_SAVEAS:
+ {
+ lcGetPiecesLibrary()->DoSaveCategories(true);
+ return true;
+ }
+
+/*
+ case LC_LIBDLG_FILE_PRINTCATALOG:
+ {
+ PRINT_PARAMS* param = (PRINT_PARAMS*)malloc(sizeof(PRINT_PARAMS));
+ param->pParent = this;
+ param->pMainFrame = (CFrameWnd*)AfxGetMainWnd();
+ AfxBeginThread(PrintCatalogFunction, param);
+
+ return true;
+ }
+*/
+
+ case LC_LIBDLG_FILE_MERGEUPDATE:
+ {
+ char filename[PATH_MAX];
+ LC_FILEOPENDLG_OPTS opts;
+
+ strcpy(opts.path, "");
+ opts.type = LC_FILEOPENDLG_LUP;
+
+ if (SystemDoDialog(LC_DLG_FILE_OPEN, filename))
+ {
+ lcGetPiecesLibrary()->LoadUpdate(filename);
+// UpdateTree();
+ }
+
+ return true;
+ }
+
+ case LC_LIBDLG_FILE_IMPORTPIECE:
+ {
+ char filename[PATH_MAX];
+ LC_FILEOPENDLG_OPTS opts;
+
+ strcpy(opts.path, Sys_ProfileLoadString ("Default", "LDraw Pieces Path", ""));
+ opts.type = LC_FILEOPENDLG_DAT;
+
+ if (SystemDoDialog (LC_DLG_FILE_OPEN, filename))
+ {
+/*
+ for (int i = 0; i < opts.numfiles; i++)
+ {
+ lcGetPiecesLibrary ()->ImportLDrawPiece (opts.filenames[i]);
+ free (opts.filenames[i]);
+ }
+ free (opts.filenames);
+*/
+ lcGetPiecesLibrary ()->ImportLDrawPiece (filename);
+ Sys_ProfileSaveString ("Default", "LDraw Pieces Path", filename);
+
+// UpdateList();
+ }
+
+ return true;
+ }
+
+/*
+ case LC_LIBDLG_FILE_TEXTURES:
+ {
+ CTexturesDlg dlg;
+ dlg.DoModal();
+ } break;
+*/
+
+ case LC_LIBDLG_CATEGORY_RESET:
+ {
+ if (SystemDoMessageBox("Are you sure you want to reset the categories?", LC_MB_YESNO | LC_MB_ICONQUESTION) == LC_YES)
+ {
+ lcGetPiecesLibrary()->ResetCategories();
+
+// UpdateList();
+// UpdateTree();
+ }
+
+ return true;
+ }
+
+ case LC_LIBDLG_CATEGORY_NEW:
+ {
+ LC_CATEGORYDLG_OPTS Opts;
+ Opts.Name = "New Category";
+ Opts.Keywords = "";
+
+ if (SystemDoDialog(LC_DLG_EDITCATEGORY, &Opts))
+ {
+ lcGetPiecesLibrary()->AddCategory(Opts.Name, Opts.Keywords);
+ }
+
+// UpdateTree();
+
+ return true;
+ }
+
+ case LC_LIBDLG_CATEGORY_REMOVE:
+ {
+/*
+ HTREEITEM Item = m_Tree.GetSelectedItem();
+
+ if (Item == NULL)
+ break;
+
+ PiecesLibrary* Lib = lcGetPiecesLibrary();
+ CString CategoryName = m_Tree.GetItemText(Item);
+ int Index = Lib->FindCategoryIndex((const char*)CategoryName);
+
+ if (Index == -1)
+ break;
+
+ char Msg[1024];
+ String Name = Lib->GetCategoryName(Index);
+ sprintf(Msg, "Are you sure you want to remove the %s category?", Name);
+
+ if (SystemDoMessageBox(Msg, LC_MB_YESNO | LC_MB_ICONQUESTION) == LC_YES)
+ {
+ Lib->RemoveCategory(Index);
+ }
+
+ UpdateTree();
+*/
+ return true;
+ }
+
+ case LC_LIBDLG_CATEGORY_EDIT:
+ {
+/*
+ HTREEITEM Item = m_Tree.GetSelectedItem();
+
+ if (Item == NULL)
+ break;
+
+ PiecesLibrary* Lib = lcGetPiecesLibrary();
+ CString CategoryName = m_Tree.GetItemText(Item);
+ int Index = Lib->FindCategoryIndex((const char*)CategoryName);
+
+ if (Index == -1)
+ break;
+
+ LC_CATEGORYDLG_OPTS Opts;
+ Opts.Name = Lib->GetCategoryName(Index);
+ Opts.Keywords = Lib->GetCategoryKeywords(Index);
+
+ if (SystemDoDialog(LC_DLG_EDITCATEGORY, &Opts))
+ {
+ String OldName = Lib->GetCategoryName(Index);
+ Lib->SetCategory(Index, Opts.Name, Opts.Keywords);
+ }
+
+ UpdateTree();
+
+*/
+ return true;
+ }
+
+ case LC_LIBDLG_PIECE_NEW:
+ {
+ return true;
+ }
+
+ case LC_LIBDLG_PIECE_EDIT:
+ {
+ return true;
+ }
+
+ case LC_LIBDLG_PIECE_DELETE:
+ {
+/*
+ PtrArray<PieceInfo> Pieces;
+
+ for (int i = 0; i < m_List.GetItemCount(); i++)
+ {
+ if (m_List.GetItemState(i, LVIS_SELECTED))
+ Pieces.Add((PieceInfo*)m_List.GetItemData(i));
+ }
+
+ if (Pieces.GetSize() == 0)
+ return true;
+
+ if (SystemDoMessageBox ("Are you sure you want to permanently delete the selected pieces?", LC_MB_YESNO|LC_MB_ICONQUESTION) != LC_YES)
+ return true;
+
+ lcGetPiecesLibrary()->DeletePieces(Pieces);
+
+ UpdateList();
+*/
+ return true;
+ }
+ }
+
+// return CDialog::OnCommand(wParam, lParam);
+ return true;
+}
+
+/*
+void CLibraryDlg::UpdateList()
+{
+ m_List.DeleteAllItems();
+ m_List.SetRedraw(false);
+
+ PiecesLibrary *Lib = lcGetPiecesLibrary();
+
+ HTREEITEM CategoryItem = m_Tree.GetSelectedItem();
+ CString CategoryName = m_Tree.GetItemText(CategoryItem);
+ int CategoryIndex = Lib->FindCategoryIndex((const char*)CategoryName);
+
+ if (CategoryIndex != -1)
+ {
+ PtrArray<PieceInfo> SinglePieces, GroupedPieces;
+
+ Lib->GetCategoryEntries(CategoryIndex, false, SinglePieces, GroupedPieces);
+
+ for (int i = 0; i < SinglePieces.GetSize(); i++)
+ {
+ PieceInfo* Info = SinglePieces[i];
+
+ LVITEM lvi;
+ lvi.mask = LVIF_TEXT | LVIF_PARAM;
+ lvi.iItem = 0;
+ lvi.iSubItem = 0;
+ lvi.lParam = (LPARAM)Info;
+ lvi.pszText = Info->m_strDescription;
+ int idx = m_List.InsertItem(&lvi);
+
+ m_List.SetItemText(idx, 1, Info->m_strName);
+ }
+ }
+ else
+ {
+ if (CategoryName == "Unassigned")
+ {
+ // Test each piece against all categories.
+ for (int i = 0; i < Lib->GetPieceCount(); i++)
+ {
+ PieceInfo* Info = Lib->GetPieceInfo(i);
+
+ for (int j = 0; j < Lib->GetNumCategories(); j++)
+ {
+ if (Lib->PieceInCategory(Info, Lib->GetCategoryKeywords(j)))
+ break;
+ }
+
+ if (j == Lib->GetNumCategories())
+ {
+ LVITEM lvi;
+ lvi.mask = LVIF_TEXT | LVIF_PARAM;
+ lvi.iItem = 0;
+ lvi.iSubItem = 0;
+ lvi.lParam = (LPARAM)Info;
+ lvi.pszText = Info->m_strDescription;
+ int idx = m_List.InsertItem(&lvi);
+
+ m_List.SetItemText(idx, 1, Info->m_strName);
+ }
+ }
+ }
+ else if (CategoryName == "Pieces")
+ {
+ for (int i = 0; i < Lib->GetPieceCount(); i++)
+ {
+ PieceInfo* Info = Lib->GetPieceInfo(i);
+
+ LVITEM lvi;
+ lvi.mask = LVIF_TEXT | LVIF_PARAM;
+ lvi.iItem = 0;
+ lvi.iSubItem = 0;
+ lvi.lParam = (LPARAM)Info;
+ lvi.pszText = Info->m_strDescription;
+ int idx = m_List.InsertItem(&lvi);
+
+ m_List.SetItemText(idx, 1, Info->m_strName);
+ }
+ }
+ }
+
+ m_List.SortItems((PFNLVCOMPARE)ListCompare, m_SortColumn);
+ m_List.SetRedraw(true);
+}
+
+void CLibraryDlg::UpdateTree()
+{
+ m_Tree.SetRedraw(false);
+ m_Tree.DeleteAllItems();
+
+ HTREEITEM Root = m_Tree.InsertItem(TVIF_IMAGE|TVIF_SELECTEDIMAGE|TVIF_TEXT, "Pieces", 0, 1, 0, 0, 0, TVI_ROOT, TVI_SORT);
+
+ PiecesLibrary *Lib = lcGetPiecesLibrary();
+ for (int i = 0; i < Lib->GetNumCategories(); i++)
+ m_Tree.InsertItem(TVIF_IMAGE|TVIF_SELECTEDIMAGE|TVIF_PARAM|TVIF_TEXT, Lib->GetCategoryName(i), 0, 1, 0, 0, 0, Root, TVI_SORT);
+
+ m_Tree.InsertItem(TVIF_IMAGE|TVIF_SELECTEDIMAGE|TVIF_PARAM|TVIF_TEXT, "Unassigned", 0, 1, 0, 0, 0, Root, TVI_LAST);
+
+ m_Tree.Expand(Root, TVE_EXPAND);
+ m_Tree.SetRedraw(true);
+ m_Tree.Invalidate();
+}
+
+void CLibraryDlg::OnSelChangedTree(NMHDR* pNMHDR, LRESULT* pResult)
+{
+ NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
+ UpdateList();
+ *pResult = 0;
+}
+
+void CLibraryDlg::OnCancel()
+{
+ // Check if it's ok to close the dialog
+ if (!lcGetPiecesLibrary()->SaveCategories())
+ return;
+
+ CDialog::OnCancel();
+}
+
+void CLibraryDlg::OnOK()
+{
+ // Check if it's ok to close the dialog
+ if (!lcGetPiecesLibrary()->SaveCategories())
+ return;
+
+ CDialog::OnOK();
+}
+
+BOOL CLibraryDlg::ContinueModal()
+{
+ HTREEITEM h = m_Tree.GetSelectedItem();
+ BOOL bValid = (h != m_Tree.GetRootItem()) && (h != NULL);
+
+ EnableControl(LC_LIBDLG_GROUP_RENAME, bValid);
+ EnableControl(LC_LIBDLG_GROUP_DELETE, bValid);
+
+ return CDialog::ContinueModal();
+}
+
+void CLibraryDlg::EnableControl(UINT nID, BOOL bEnable)
+{
+ GetMenu()->GetSubMenu(1)->EnableMenuItem(nID, MF_BYCOMMAND | (bEnable ? MF_ENABLED : (MF_DISABLED | MF_GRAYED)));
+ int state = m_wndToolBar.GetToolBarCtrl().GetState(nID) & ~TBSTATE_ENABLED;
+ if (bEnable)
+ state |= TBSTATE_ENABLED;
+ m_wndToolBar.GetToolBarCtrl().SetState(nID, state);
+}
+
+BOOL CLibraryDlg::OnToolTipText(UINT, NMHDR* pNMHDR, LRESULT* pResult)
+{
+ ASSERT(pNMHDR->code == TTN_NEEDTEXTA || pNMHDR->code == TTN_NEEDTEXTW);
+
+ // allow top level routing frame to handle the message
+ if (GetRoutingFrame() != NULL)
+ return false;
+
+ // need to handle both ANSI and UNICODE versions of the message
+ TOOLTIPTEXTA* pTTTA = (TOOLTIPTEXTA*)pNMHDR;
+ TOOLTIPTEXTW* pTTTW = (TOOLTIPTEXTW*)pNMHDR;
+ CString cstTipText;
+ UINT nID = pNMHDR->idFrom;
+
+ if (pNMHDR->code == TTN_NEEDTEXTA && (pTTTA->uFlags & TTF_IDISHWND) ||
+ pNMHDR->code == TTN_NEEDTEXTW && (pTTTW->uFlags & TTF_IDISHWND))
+ {
+ // idFrom is actually the HWND of the tool
+ nID = ((UINT)(WORD)::GetDlgCtrlID((HWND)nID));
+ }
+
+ if (nID != 0) // will be zero on a separator
+ {
+ cstTipText.LoadString(nID);
+ }
+
+ // Non-UNICODE Strings only are shown in the tooltip window...
+ if (pNMHDR->code == TTN_NEEDTEXTA)
+ lstrcpyn(pTTTA->szText, cstTipText, (sizeof(pTTTA->szText)/sizeof(pTTTA->szText[0])));
+ else
+ _mbstowcsz(pTTTW->szText, cstTipText, (sizeof(pTTTW->szText)/sizeof(pTTTW->szText[0])));
+
+ *pResult = 0;
+
+ // bring the tooltip window above other popup windows
+ ::SetWindowPos(pNMHDR->hwndFrom, HWND_TOP, 0, 0, 0, 0,
+ SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE);
+
+ return true; // message was handled
+}
+
+void CLibraryDlg::OnListColumnClick(NMHDR* pNMHDR, LRESULT* pResult)
+{
+ NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
+
+ // Save the column index.
+ m_SortColumn = pNMListView->iSubItem;
+
+ m_List.SortItems((PFNLVCOMPARE)ListCompare, m_SortColumn);
+
+ *pResult = 0;
+}
+*/
diff --git a/linux/libdlg.h b/linux/libdlg.h
new file mode 100644
index 0000000..f4a762b
--- /dev/null
+++ b/linux/libdlg.h
@@ -0,0 +1,14 @@
+#ifndef _LIBDLG_H_
+#define _LIBDLG_H_
+
+class PieceInfo;
+
+// =============================================================================
+// LibraryDialog class
+
+class LibraryDialog {
+public:
+ bool HandleCommand(int id);
+};
+
+#endif // _LIBDLG_H_
diff --git a/linux/menu.cpp b/linux/menu.cpp
index 8d48354..6b3db7b 100644
--- a/linux/menu.cpp
+++ b/linux/menu.cpp
@@ -59,6 +59,10 @@ void create_main_menu (GtkObject *window, GtkWidget *vbox)
window, LC_FILE_HTML, "menu_file_html");
create_menu_item (menu_in_menu, "_POV-Ray...", accel, GTK_SIGNAL_FUNC (OnCommandDirect),
window, LC_FILE_POVRAY, "menu_file_povray");
+ create_menu_item (menu_in_menu, "_VRML97...", accel, GTK_SIGNAL_FUNC (OnCommandDirect),
+ window, LC_FILE_VRML97, "menu_file_vrml97");
+ create_menu_item (menu_in_menu, "_Rigid Body Physics X3DV Draft...", accel, GTK_SIGNAL_FUNC (OnCommandDirect),
+ window, LC_FILE_X3DV, "menu_file_x3dv");
create_menu_item (menu_in_menu, "_Wavefront...", accel, GTK_SIGNAL_FUNC (OnCommandDirect),
window, LC_FILE_WAVEFRONT, "menu_file_wavefront");
menu_separator (menu);
diff --git a/linux/module.mk b/linux/module.mk
index 853b7e7..fe45824 100644
--- a/linux/module.mk
+++ b/linux/module.mk
@@ -2,4 +2,4 @@ SRC += linux/profile.cpp \
linux/dialogs.cpp linux/dlgpiece.cpp linux/dlgfile.cpp \
linux/gtktools.cpp linux/main.cpp linux/menu.cpp \
linux/system.cpp linux/toolbar.cpp linux/gtkmisc.cpp \
- linux/linux_gl.cpp linux/basewnd.cpp linux/glwindow.cpp
+ linux/linux_gl.cpp linux/basewnd.cpp linux/glwindow.cpp linux/libdlg.cpp
diff --git a/linux/system.cpp b/linux/system.cpp
index cdf9921..6568ad3 100644
--- a/linux/system.cpp
+++ b/linux/system.cpp
@@ -618,71 +618,65 @@ bool SystemDoDialog(int mode, void* param)
{
switch (mode)
{
- case LC_DLG_FILE_OPEN_PROJECT: {
+ case LC_DLG_FILE_OPEN_PROJECT:
return openprojectdlg_execute ((char*)param) == LC_OK;
- } break;
- case LC_DLG_FILE_SAVE_PROJECT: {
+ case LC_DLG_FILE_SAVE_PROJECT:
return saveprojectdlg_execute ((char*)param) == LC_OK;
- } break;
- case LC_DLG_FILE_MERGE_PROJECT: {
+ case LC_DLG_FILE_MERGE_PROJECT:
return openprojectdlg_execute ((char*)param) == LC_OK;
- } break;
- case LC_DLG_ABOUT: {
+ case LC_DLG_FILE_OPEN:
+ return openprojectdlg_execute ((char*)param) == LC_OK;
+
+ case LC_DLG_ABOUT:
return aboutdlg_execute(param) == LC_OK;
- } break;
- case LC_DLG_ARRAY: {
+ case LC_DLG_ARRAY:
return arraydlg_execute(param) == LC_OK;
- } break;
- case LC_DLG_HTML: {
+ case LC_DLG_HTML:
return htmldlg_execute(param) == LC_OK;
- } break;
- case LC_DLG_POVRAY: {
+ case LC_DLG_POVRAY:
return povraydlg_execute(param) == LC_OK;
- } break;
- case LC_DLG_WAVEFRONT: {
+ case LC_DLG_VRML97:
+ return filedlg_execute("Save File", (char*)param) == LC_OK;
+
+ case LC_DLG_X3DV:
return filedlg_execute("Save File", (char*)param) == LC_OK;
- } break;
- case LC_DLG_PREFERENCES: {
+ case LC_DLG_WAVEFRONT:
+ return filedlg_execute("Save File", (char*)param) == LC_OK;
+
+ case LC_DLG_PREFERENCES:
return preferencesdlg_execute(param) == LC_OK;
- } break;
- case LC_DLG_PICTURE_SAVE: {
+ case LC_DLG_PICTURE_SAVE:
return savepicturedlg_execute (param) == LC_OK;
- } break;
- case LC_DLG_MINIFIG: {
+ case LC_DLG_MINIFIG:
return minifigdlg_execute(param) == LC_OK;
- } break;
- case LC_DLG_PROPERTIES: {
+ case LC_DLG_PROPERTIES:
return propertiesdlg_execute(param) == LC_OK;
- } break;
- case LC_DLG_LIBRARY: {
+ case LC_DLG_LIBRARY:
return librarydlg_execute(param) == LC_OK;
- } break;
- case LC_DLG_SELECTBYNAME: {
- } break;
+ case LC_DLG_SELECTBYNAME:
+ break;
- case LC_DLG_STEPCHOOSE: {
- } break;
+ case LC_DLG_STEPCHOOSE:
+ break;
- case LC_DLG_EDITGROUPS: {
+ case LC_DLG_EDITGROUPS:
return groupeditdlg_execute(param) == LC_OK;
- } break;
- case LC_DLG_GROUP: {
+ case LC_DLG_GROUP:
return groupdlg_execute(param) == LC_OK;
- } break;
}
return false;