home *** CD-ROM | disk | FTP | other *** search
/ Freelog Special Freeware 25 / FreelogHS25.iso / Dessin / ArtOfIllusion2.2.1 / Scripts / Tools / Text.bsh < prev    next >
Text File  |  2006-02-04  |  16KB  |  350 lines

  1. /*
  2. <?xml version='1.0' standalone='yes' ?>
  3.  
  4. <script>
  5.     <name>Text</name>
  6.     <author>Yokiyoki (Julio Sangrador-Pat∩┐╜n) (yokiyoki@users.sourceforge.net) and Peter Eastman</author>
  7.     <version>2.2.1</version>
  8.     <date>02/04/2006</date>
  9.     <description>
  10. Build the model of a string of text, in the form of simple approximating curves, tubes
  11. which follow these, flat triangle meshes or extruded solid triangle meshes. 
  12.  
  13. Help: 
  14.  
  15. Build the model of a string of text, in the form of simple approximating curves, tubes which follow these,
  16. flat triangle meshes or extruded solid triangle meshes. 
  17. 1. Choose one of the above at the top of the dialog.
  18. 2. Choose a font face from the list. Be aware that (on linux at least) a great deal of them
  19. make the script crash. It seems to have to do with the font being Adobe type, but I'm not
  20. sure yet. 
  21. 3. Mark if you want it bold or italic. 
  22. 4. Write the text you want to be modelled. 
  23. 5. Enter the tolerance value, which grosso modo tells how accurate the outlines will be (the smaller,
  24. the more accurate). 
  25. 6. Enter the thickness of the mesh (for 3D meshes) or of the tube (for tubes). 
  26. 7. Enter the degree of subdivision you want for the meshes, which can be 0 or a positive integer. A value
  27. of at least 1 is recomended to avoid artifacts. You will seldom need more than 2, and might do well
  28. with 0.
  29.     </description>
  30.     <comments>
  31. This is an alpha version, but quite usable especially on windows. 
  32. Written with great aid from Peter Eastman and others
  33.     </comments>
  34. </script>
  35. */
  36.  
  37. import java.awt.font.*;
  38. import java.awt.geom.*;
  39.  
  40. showInfoWindow() {
  41.     warning = new BTextArea("This is an experimental tool. In particular, it doesn't work\n"+
  42.         "well with some fonts."+
  43.         "However, it works often and can be useful, and that is my intention. \n"+
  44.         "But be aware that I can't be held responsible for any damage it does to \n"+
  45.         "your work.\n"+
  46.         "In case of crash, I suggest saving your work if it wasn't and closing Art of "+
  47.         "Illusion and opening it again.\n\n"+
  48.         "Enjoy!", 10, 80);
  49.     warning.setEditable(false);
  50.     wrnDlg = new PanelDialog(window, "Important Information", new BScrollPane(warning));
  51. }
  52.  
  53. showHelpWindow() {
  54.     helpText = new BTextArea("Text tool script.\n\n"+
  55.         "By Yokiyoki (Julio Sangrador-Pat∩┐╜n), with great aid from Peter Eastman and others.\n"+
  56.         "This is a beta version, but quite usable especially on windows.\n\n"+
  57.         "Help:\n\n"+                
  58.         "Tool to build the model of a string of text, in the form of simple approximating curves, tubes which follow these,\n\n"+
  59.         "flat triangle meshes or extruded solid triangle meshes. Steps:\n\n"+
  60.         "1. Choose one of the above at the top of the dialog.\n"+
  61.         "2. Choose a font face from the list. Be aware that (on linux at least) a great deal of them\n"+
  62.         "make the script crash. It seems to have to do with the font being Adobe type, but I'm not\n"+
  63.         "sure yet.\n"+
  64.         "3. Mark if you want it bold and/or italic.\n"+
  65.         "4. Write the text you want to be modelled.\n"+
  66.         "5. Enter the tolerance value, which grosso modo tells how accurate the outlines will be (the smaller\n"+
  67.         "the value, the more accurate).\n"+
  68.         "6. Enter the thickness of the mesh (for 3D meshes) or of the tube (for tubes). Useless for curves and flat surfaces.\n"+
  69.         "7. Enter the degree of subdivision you want for the meshes, which can be 0 or a positive integer. A value\n"+
  70.         "of at least 1 is recomended to avoid artifacts. You will seldom need more than 2, and might do well\n"+
  71.         "with 0.", 10, 80);
  72.     helpText.setEditable(false);
  73.     hlpDlg = new PanelDialog(window, "Help", new BScrollPane(helpText));
  74. }
  75.  
  76. /* Modes */
  77.  
  78. M_TUBE = -1;
  79. M_SPLINE = 0;
  80. M_2D = 1;
  81. M_3D = 2;
  82.  
  83. /* Prepare to remember the user selections */
  84.  
  85. if(global.textToolwantsBold == void) {
  86.     global.textToolwantsBold = false;
  87.     global.textToolwantsItalic = false;
  88.     global.textToolfont = "SurelyThisIsntAFontName";
  89.     global.textTooltheString = "Write some text";
  90.     global.textTooltolerance = 0.1;
  91.     global.textToolmesh = M_2D;
  92.     global.textToolthickness = 0.1;
  93.     global.textToolsubdivideTimes = 1;
  94. }
  95.  
  96. /* error message function */
  97.  
  98. errorMessage(s) {
  99.         return (new MessageDialog(window, s)).getChoice();
  100. }
  101.  
  102. /* Rewrite of the solidify function, using the static methods of the Extrude Dialog Plugin */
  103. /* Copied from a message to the forum by Peter Eastman */
  104.  
  105. solidify2(info, thickness) {
  106.     extrudeDialog = ModellingApp.getClass("artofillusion.tools.ExtrudeDialog");
  107.     extrudeMesh = extrudeDialog.getMethod("extrudeMesh",
  108.         new Class [] {TriangleMesh.class, CoordinateSystem.class, Vec3.class, Integer.TYPE,
  109.         Double.TYPE, Boolean.TYPE});
  110.     extruded = extrudeMesh.invoke(null, new Object[] {info.object, info.coords,
  111.         new Vec3(0,0,thickness), 1, 0.0, true});
  112.     return extruded;
  113. }
  114.  
  115. /* Create the components of the options dialog */
  116.  
  117. meshType = new RadioButtonGroup();
  118. meshSpline = new BRadioButton("Silhouette", global.textToolmesh==M_SPLINE,meshType);
  119. mesh2D = new BRadioButton("2D surface", global.textToolmesh==M_2D,meshType);
  120. mesh3D = new BRadioButton("3D solid", global.textToolmesh==M_3D,meshType);
  121. meshTube = new BRadioButton("Tube", global.textToolmesh==M_TUBE,meshType);
  122.  
  123. kindOfMesh = new GridContainer(2, 2);
  124. kindOfMesh.setDefaultLayout(new LayoutInfo(LayoutInfo.WEST, LayoutInfo.NONE, new Insets(2, 2, 2, 2), null));
  125. kindOfMesh.add(meshSpline, 0, 0);
  126. kindOfMesh.add(mesh2D, 0, 1);
  127. kindOfMesh.add(mesh3D, 1, 0);
  128. kindOfMesh.add(meshTube, 1, 1);
  129.  
  130. fonts = GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames();
  131. fontsList = new BList(fonts);
  132. fontsList.setPreferredVisibleRows(10);
  133. fontsList.setMultipleSelectionEnabled(false);
  134. theSelectedIndex = 0;
  135. for(y=0;y<fonts.length;y++) {
  136.     if(fonts[y].equals(global.textToolfont)) {
  137.         theSelectedIndex = y;
  138.     }
  139. }
  140. fontsList.setSelected(theSelectedIndex, true);
  141. fontsList.scrollToItem(theSelectedIndex);
  142.  
  143. wantsBoldCheck = new BCheckBox("Bold", global.textToolwantsBold);
  144. wantsItalicCheck = new BCheckBox("Italic", global.textToolwantsItalic);
  145. fontStyle = new RowContainer();
  146. fontStyle.add(wantsBoldCheck);
  147. fontStyle.add(wantsItalicCheck);
  148.  
  149. textToShow = new BTextField(global.textTooltheString);
  150. toleranceValue = new ValueField(global.textTooltolerance, ValueField.POSITIVE);
  151. thicknessValue = new ValueField(global.textToolthickness, ValueField.POSITIVE);
  152. degreeOfSubdivision = new ValueField(global.textToolsubdivideTimes, ValueField.INTEGER);
  153.  
  154. infoButton = new BButton("Important Info");
  155. infoButton.addEventLink(CommandEvent.class, new Runnable() {
  156.     void run()
  157.     {
  158.         showInfoWindow();
  159.     }
  160. }, "run");
  161.  
  162. helpButton = new BButton("Help");
  163. helpButton.addEventLink(CommandEvent.class, new Runnable() {
  164.     void run()
  165.     {
  166.         showHelpWindow();
  167.     }
  168. }, "run");
  169.  
  170. /* Create and show the dialog */
  171.  
  172. dlg = new ComponentsDialog(window, "Select Parameters for Text Tool",
  173.     new Widget [] {kindOfMesh, UIUtilities.createScrollingList(fontsList), fontStyle, textToShow, toleranceValue, thicknessValue, degreeOfSubdivision, infoButton, helpButton},
  174.     new String [] {"Type of Object", "Font", "Style", "Text to Render","Tolerance", "Thickness", "Degree of subdivision", null, null});
  175. if (!dlg.clickedOk()) {
  176.     return;
  177. }
  178.  
  179. /* Obtain the user values */
  180.  
  181. global.textToolwantsBold = wantsBold = wantsBoldCheck.getState();
  182. global.textToolwantsItalic = wantsItalic = wantsItalicCheck.getState();
  183. font = new Font(fontsList.getSelectedValue(), Font.PLAIN | (wantsBold?Font.BOLD:0) | (wantsItalic?Font.ITALIC:0), 1);
  184. global.textToolfont =  fontsList.getSelectedValue();
  185. global.textTooltheString = theString = textToShow.getText();
  186. global.textTooltolerance = tolerance = toleranceValue.getValue();
  187. global.textToolmesh = mesh = (meshSpline.getState()?M_SPLINE:mesh2D.getState()?M_2D:mesh3D.getState()?M_3D:M_TUBE);
  188. global.textToolthickness = thickness = thicknessValue.getValue();
  189. global.textToolsubdivideTimes = subdivideTimes = (int)Math.abs(degreeOfSubdivision.getValue());
  190.  
  191. if(font.canDisplayUpTo(theString) != -1) {
  192.     errorMessage("Sorry, you cannot represent that text with that font.");
  193.     return;
  194. }
  195.  
  196. /* Create the text. Here begins everything */
  197.  
  198. sceneDefaultTex = window.getScene().getDefaultTexture(); // so as to make getBounds() work
  199. glyphVector = font.createGlyphVector(new FontRenderContext(null, true, true),theString);
  200. parent = new NullObject();
  201. parentObjectInfo = new ObjectInfo(parent, new CoordinateSystem(), theString);
  202. window.addObject(parentObjectInfo,null);
  203. numGlyphs = glyphVector.getNumGlyphs();
  204.  
  205. for(glyphIndex = 0 ; glyphIndex < numGlyphs ; glyphIndex++) {
  206.     currentOutline = glyphVector.getGlyphOutline(glyphIndex);
  207.     pathIterator = currentOutline.getPathIterator(null);
  208.     segmentCoords = new float[6];
  209.     pointsRuntimeTypeArray = new Vec3[1];
  210.     points = new Vector();
  211.     smoothnesses = new Vector();
  212.     firstCurveOfGlyph = true;
  213.     glyphName = Character.toString(theString.charAt(glyphVector.getGlyphCharIndex(glyphIndex)));
  214.     fullLetterOI = null;
  215.     while(!pathIterator.isDone()){
  216.         switch(pathIterator.currentSegment(segmentCoords)) {
  217.             case PathIterator.SEG_MOVETO:
  218.             case PathIterator.SEG_LINETO:
  219.                 points.add(new Vec3((double)segmentCoords[0],-(double)segmentCoords[1],0));
  220.                 smoothnesses.add(new Float(0.0f));
  221.                 break;
  222.             case PathIterator.SEG_QUADTO:
  223.                 points.add(new Vec3((double)segmentCoords[0],-(double)segmentCoords[1],0));
  224.                 smoothnesses.add(new Float(1.0f));
  225.                 points.add(new Vec3((double)segmentCoords[2],-(double)segmentCoords[3],0));
  226.                 smoothnesses.add(new Float(1.0f));
  227.                 break;
  228.             case PathIterator.SEG_CUBICTO:
  229.                 points.add(new Vec3((double)segmentCoords[0],-(double)segmentCoords[1],0));
  230.                 smoothnesses.add(new Float(1.0f));
  231.                 points.add(new Vec3((double)segmentCoords[2],-(double)segmentCoords[3],0));
  232.                 smoothnesses.add(new Float(1.0f));
  233.                 points.add(new Vec3((double)segmentCoords[4],-(double)segmentCoords[5],0));
  234.                 smoothnesses.add(new Float(1.0f));
  235.                 break;
  236.             case PathIterator.SEG_CLOSE:
  237.                 // Sometimes the initial point is duplicated at the end,
  238.                 // so try to remove the duplicate
  239.                 if(((Vec3)points.elementAt(0)).distance((Vec3)points.elementAt(points.size()-1))<0.0001) {
  240.                     points.removeElementAt(points.size()-1);
  241.                     smoothnesses.removeElementAt(smoothnesses.size()-1);
  242.                 }
  243.                 // Convert the vectors into arrays
  244.                 smoothnessesArray = new float[smoothnesses.size()];
  245.                 for(i=0;i<smoothnesses.size();i++) {
  246.                     smoothnessesArray[i] = smoothnesses.elementAt(i).floatValue();
  247.                 }
  248.                 theCurve = new Curve(points.toArray(pointsRuntimeTypeArray),smoothnessesArray,Mesh.APPROXIMATING,true);
  249.                 currentGlyphOI = new ObjectInfo(theCurve, new CoordinateSystem(), glyphName);
  250.                 currentGlyphOI.setTexture(sceneDefaultTex, sceneDefaultTex.getDefaultMapping());
  251.                 if(mesh>M_SPLINE) { // i.e, Surface or Solid
  252.                     // try to triangulate the curve
  253.                     theMesh = theCurve.subdivideCurve(subdivideTimes).convertToTriangleMesh(tolerance);
  254.                                         if (theMesh == null)
  255.                                                 continue;
  256.                     currentGlyphOI = new ObjectInfo(theMesh, new CoordinateSystem(), glyphName);
  257.                     currentGlyphOI.setTexture(sceneDefaultTex, sceneDefaultTex.getDefaultMapping());
  258.                     if(firstCurveOfGlyph) {
  259.                         fullLetterOI = currentGlyphOI;
  260.                     }
  261.                     else { // More curves, see if they intersect or unite what we already have
  262.                         meshToTestForIntersection = new ObjectInfo(solidify2(currentGlyphOI,0.2), currentGlyphOI.coords.duplicate(), glyphName);
  263.                         meshToTestForIntersection.setTexture(sceneDefaultTex, sceneDefaultTex.getDefaultMapping()); // for getBounds() to work
  264.                         coordsDiff = currentGlyphOI.getBounds().getCenter().minus(meshToTestForIntersection.getBounds().getCenter());
  265.                         meshToTestForIntersection.coords.setOrigin(meshToTestForIntersection.coords.getOrigin().plus(coordsDiff));
  266.                         testCSG = new CSGObject(fullLetterOI,meshToTestForIntersection,CSGObject.INTERSECTION);
  267.                         testCSGMesh = testCSG.convertToTriangleMesh(tolerance);
  268.                         if(testCSGMesh.getEdges().length > 0) { // Intersects
  269.                                                         bounds1 = fullLetterOI.getBounds();
  270.                                                         bounds2 = currentGlyphOI.getBounds();
  271.                                                         firstIsLarger = ((bounds1.maxx-bounds1.minx)*(bounds1.maxy-bounds1.miny) >= (bounds2.maxx-bounds2.minx)*(bounds2.maxy-bounds2.miny));
  272.                                                         firstMesh = (firstIsLarger ? fullLetterOI : currentGlyphOI);
  273.                                                         secondMesh = (firstIsLarger ? currentGlyphOI : fullLetterOI);
  274.                                                         meshToCut = new ObjectInfo(solidify2(secondMesh,0.2), secondMesh.coords.duplicate(), glyphName);
  275.                             meshToCut.setTexture(sceneDefaultTex, sceneDefaultTex.getDefaultMapping());  // for getBounds() to work
  276.                             coordsDiff = secondMesh.getBounds().getCenter().minus(meshToCut.getBounds().getCenter());
  277.                             meshToCut.coords.setOrigin(meshToCut.coords.getOrigin().plus(coordsDiff));
  278.                             aCSG = new CSGObject(firstMesh, meshToCut, CSGObject.DIFFERENCE12);
  279.                             aCSGMesh = aCSG.convertToTriangleMesh(tolerance);
  280.                             fullLetterOI = new ObjectInfo(aCSGMesh,fullLetterOI.coords.duplicate(), glyphName);
  281.                             fullLetterOI.setTexture(sceneDefaultTex, sceneDefaultTex.getDefaultMapping());
  282.                         }
  283.                         else { // Unites
  284.                             aCSG = new CSGObject(fullLetterOI, currentGlyphOI, CSGObject.UNION);
  285.                             aCSGMesh = aCSG.convertToTriangleMesh(tolerance);
  286.                             fullLetterOI = new ObjectInfo(aCSGMesh,fullLetterOI.coords.duplicate(), glyphName);
  287.                             fullLetterOI.setTexture(sceneDefaultTex, sceneDefaultTex.getDefaultMapping());
  288.                         }
  289.                         try { // Optimize the mesh while we are building it
  290.                             fullLetterOI.object = TriangleMesh.optimizeMesh(fullLetterOI.object);
  291.                             fullLetterOI.clearCachedMeshes();
  292.                         } catch (Exception e) {e.printStackTrace();} // Should we act? Not sure...
  293.                     }
  294.                     firstCurveOfGlyph = false;
  295.                 }
  296.                 else if(mesh==M_TUBE) { // User wants tubes
  297.                     nVerts = theCurve.getVertices().length;
  298.                     tubeThickness = new double[nVerts];
  299.                     for(t=0;t<nVerts;t++) {
  300.                         tubeThickness[t]=thickness;
  301.                     }
  302.                     theTube = new Tube(theCurve, tubeThickness, Tube.CLOSED_ENDS);
  303.                     currentTube = new ObjectInfo(theTube, new CoordinateSystem(), glyphName);
  304.                     parentObjectInfo.addChild(currentTube,parentObjectInfo.children.length);
  305.                     window.addObject(currentTube,null);
  306.                 }
  307.                 else { // User wants only the curves
  308.                     parentObjectInfo.addChild(currentGlyphOI,parentObjectInfo.children.length);
  309.                     window.addObject(currentGlyphOI,null);
  310.                 }
  311.                 segmentCoords = new float[6];
  312.                 pointsRuntimeTypeArray = new Vec3[1];
  313.                 points = new Vector();
  314.                 smoothnesses = new Vector();
  315.         } /* Segments loop */
  316.         pathIterator.next();
  317.     } /* Curves loop */
  318.     if (fullLetterOI != null) {
  319.         if((mesh == M_3D) || mesh == (M_2D)) {
  320.             try { // Final optimization of the mesh, maybe it is redundant.
  321.                 fullLetterOI.object.setSmoothingMethod(Mesh.SMOOTH_SHADING);
  322.                 fullLetterOI.object = TriangleMesh.optimizeMesh(fullLetterOI.object);
  323.                 fullLetterOI.clearCachedMeshes();
  324.             }
  325.             catch (Exception e) {e.printStackTrace();} // Again, should we act?
  326.         }
  327.         if(mesh==M_3D) { // Extrude the shape.
  328.             extrudedMeshOI = new ObjectInfo(solidify2(fullLetterOI, thickness), fullLetterOI.coords.duplicate(), glyphName);
  329.             extrudedMeshOI.setTexture(sceneDefaultTex, sceneDefaultTex.getDefaultMapping());  // for getBounds() to work
  330.             coordsDiff = fullLetterOI.getBounds().getCenter().minus(extrudedMeshOI.getBounds().getCenter());
  331.             extrudedMeshOI.coords.setOrigin(extrudedMeshOI.coords.getOrigin().plus(coordsDiff));
  332.             fullLetterOI = extrudedMeshOI;
  333.             selection = new boolean [fullLetterOI.object.getEdges().length];
  334.             Arrays.fill(selection, true);
  335.             new TriMeshSimplifier(fullLetterOI.object, selection, 0.0001, null);
  336.             fullLetterOI.object.autosmoothMeshEdges(1.5);
  337.             fullLetterOI.object.setSmoothingMethod(Mesh.SMOOTH_SHADING);
  338.             fullLetterOI.object = TriangleMesh.optimizeMesh(fullLetterOI.object);
  339.             fullLetterOI.clearCachedMeshes();
  340.         }
  341.         if(!(mesh==M_SPLINE)&& !(mesh==M_TUBE) && !firstCurveOfGlyph){ // We had already added them for these
  342.             parentObjectInfo.addChild(fullLetterOI,parentObjectInfo.children.length);
  343.             window.addObject(fullLetterOI,null);
  344.         }
  345.     }
  346.  
  347. } /* Glyphs loop */
  348.  
  349. window.rebuildItemList();
  350.