Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: com/trapezium/chisel/cleaners/IFS_CoordRemover.java


1   /*
2    * @(#)IFS_CoordRemover.java
3    *
4    * Copyright (c) 1998-1999 by Trapezium Development LLC.  All Rights Reserved.
5    *
6    * The information in this file is the property of Trapezium Development LLC
7    * and may be used only in accordance with the terms of the license granted
8    * by Trapezium.
9    *
10   */
11  package com.trapezium.chisel.cleaners;
12  
13  import com.trapezium.parse.TokenTypes;
14  import com.trapezium.vrml.VrmlElement;
15  import com.trapezium.vrml.Value;
16  import com.trapezium.vrml.Scene;
17  import com.trapezium.vrml.node.Node;
18  import com.trapezium.vrml.node.UsageInfo;
19  import com.trapezium.vrml.node.IndexInfo;
20  import com.trapezium.vrml.node.DEFUSENode;
21  import com.trapezium.vrml.fields.Field;
22  import com.trapezium.vrml.fields.FieldValue;
23  import com.trapezium.vrml.fields.MFFieldValue;
24  import com.trapezium.vrml.node.generated.IndexedFaceSet;
25  import com.trapezium.chisel.*;
26  
27  import java.util.BitSet;
28  import java.util.Hashtable;
29  import java.io.PrintStream;
30  
31  //
32  //  Base class for any optimizer that removes "coord" entries from an IndexedFaceSet
33  //  or IndexedLineSet.
34  //
35  //  Collects "coord", "coordIndex" ranges to optimize.  Looks up any dependencies with
36  //  normal/normalIndex, color/colorIndex, or texCoord/texCoordIndex.  Replace range
37  //  handles all these.
38  //
39  public class IFS_CoordRemover extends Optimizer {
40      static public int Coord = 0;
41      static public int CoordIndex = 1;
42      static public int TexCoord = 2;
43      static public int TexCoordIndex = 3;
44      static public int Color = 4;
45      static public int ColorIndex = 5;
46      static public int Normal = 6;
47      static public int NormalIndex = 7;
48  
49    protected int numberCoordsRemoved = 0;
50    protected int numberTexCoordsRemoved = 0;
51    protected int numberNormalsRemoved = 0;
52    protected int numberColorsRemoved = 0;
53  
54    public IFS_CoordRemover() {
55      super( "CoordinateOwner", "Removing unused values..." );
56    }
57  
58      //
59      // Just records optimization for coord/coordIndex, plus any dependent nodes based
60      // on the IndexInfo associated with the node.
61      //
62    public void attemptOptimization( Node n ) {
63      Field coord = n.getField( "coord" );
64      Field coordIndex = n.getField( "coordIndex" );
65      if (( coord != null ) && ( coordIndex != null )) {
66          MFFieldValue mfv2 = (MFFieldValue)coordIndex.getFieldValue();
67          int coordIndexCount = 0;
68          if ( mfv2 != null ) {
69              coordIndexCount = mfv2.getRawValueCount();
70              if ( coordIndexCount == 0 ) {
71                  return;
72              }
73          } else {
74              return;
75          }
76  
77        FieldValue fv = coord.getFieldValue();
78        Node coordNode = (Node)fv.getChildAt( 0 );
79        if ( coordNode instanceof DEFUSENode ) {
80          DEFUSENode dun = (DEFUSENode)coordNode;
81          coordNode = dun.getNode();
82        }
83        if ( coordNode != null ) {
84            BitSet coordBits = null;
85          Scene s = (Scene)n.getScene();
86          if ( s != null ) {
87              Hashtable usageTable = s.getUsageTable();
88                  UsageInfo ui = (UsageInfo)usageTable.get( coordNode );
89                  if ( ui != null ) {
90                      coordBits = ui.getUsageBits();
91                  }
92                  if ( coordBits == null ) {
93                      return;
94                  }
95                  int numberFaces = 0;
96                  if ( n instanceof IndexedFaceSet ) {
97                      numberFaces = ((IndexedFaceSet)n).getNumberFaces();
98                  } 
99  
100                 Hashtable texCoordTable = s.getTexCoordTable();
101                 IndexInfo texInfo = (IndexInfo)texCoordTable.get( n );
102                 synchWithCoord( texInfo, TexCoord, coordBits, coordIndexCount, numberFaces );
103 
104                 Hashtable colorTable = s.getColorTable();
105                 IndexInfo colorInfo = (IndexInfo)colorTable.get( n );
106                 synchWithCoord( colorInfo, Color, coordBits, coordIndexCount, numberFaces );
107 
108                 Hashtable normalTable = s.getNormalTable();
109                 IndexInfo normalInfo = (IndexInfo)normalTable.get( n );
110                 synchWithCoord( normalInfo, Normal, coordBits, coordIndexCount, numberFaces );
111               }
112 
113         Field coords = coordNode.getField( "point" );
114         FieldValue coordFieldValue = coords.getFieldValue();
115         int valcount = 0;
116         if ( coordFieldValue instanceof MFFieldValue ) {
117             MFFieldValue mfv = (MFFieldValue)coordFieldValue;
118             valcount = mfv.getRawValueCount();
119         }
120          
121         if ( valcount > 0 ) {
122             replaceRange( coords.getFirstTokenOffset(), 
123                 coords.getLastTokenOffset(), 
124                 new CoordRemoveData( Coord, null, coordBits, coordIndexCount, 0 ));
125             replaceRange( coordIndex.getFirstTokenOffset(), 
126                 coordIndex.getLastTokenOffset(), 
127                 new CoordRemoveData( CoordIndex, null, coordBits, coordIndexCount, 0 ));
128           }
129       }
130     }
131   }
132 
133     /** Synchronize IndexInfo with coord info.
134      *
135      *  There are three types of synchronization:
136      *  1.  values are synched with coord values.  This means the "perVertex"
137      *      setting is true, and there is no "..Index" field.
138      *  2.  values are synched with index.  This means there is an "..Index" field,
139      *      with values in synch with the corresponding value node.  There are two
140      *      mutually exclusive further restrictions on the "..Index" field:
141      *      a) the "..Index" field must be in synch with with the coord index,
142      *         which happens when the "perVertex" setting is true.
143      *      b) the "..Index" field must be in synch with the coord faces, which
144      *         happens when the "perVertex" setting is false.
145      *
146      *  @param ii  IndexInfo contains relationship between value and index fields
147      *     generic for texture, color, normal.  The corresponding fields are:
148      *     texCoord/texCoordIndex, color/colorIndex/colorPerVertex,
149      *     normal/normalIndex/normalPerVertex.
150      *  @param dataType the type of field being removed:  Coord, CoordIndex,
151      *     TexCoord, TexCoordIndex, Color, ColorIndex, Normal, NormalIndex.  
152      *     These constants follow the convention that the "Index" constant
153      *     is one greater than the "Value" constant.
154      *  @param coordBits BitSet indicating which coordinates are in use
155      *  @param coordIndexCount count of the number of index values, needed for
156      *     truncating index lists that are too long.  This occurs if texCoordIndex
157      *     has more values, or if colorIndex/normalIndex have more values and
158      *     the colorPerVertex/normalPerVertex is true.
159      *  @param numberFaces number of faces, which must match colorIndex/normalIndex
160      *     if colorPerVertex/normalPerVertex is false.
161      */
162     void synchWithCoord( IndexInfo ii, int dataType, BitSet coordBits, int coordIndexCount, int numberFaces ) {
163         if ( ii == null ) {
164             return;
165         }
166         if ( coordBits == null ) {
167             return;
168         }
169       if ( ii.isValueSynchedWithCoord() ) {
170           Node valueNode = ii.getValueNode();
171           replaceRange( valueNode.getFirstTokenOffset(), 
172               valueNode.getLastTokenOffset(), 
173               new CoordRemoveData( dataType, ii, coordBits, coordIndexCount, 0 ));
174       } else if ( ii.isValueSynchedWithIndex() ) {
175           Node valueNode = ii.getValueNode();
176           MFFieldValue index = ii.getIndexValue();
177           coordBits = ii.getUsageBits();
178           if ( coordBits != null ) {
179               replaceRange( valueNode.getFirstTokenOffset(), 
180                   valueNode.getLastTokenOffset(), 
181                   new CoordRemoveData( dataType, ii, coordBits, coordIndexCount, 0 ));
182               if ( ii.isPerVertex() ) {
183                   numberFaces = 0;
184               }
185               replaceRange( index.getFirstTokenOffset(), index.getLastTokenOffset(), 
186                   new CoordRemoveData( dataType+1, ii, coordBits, coordIndexCount, numberFaces ));
187           }
188       }
189   }
190 
191   // RangeReplacer calls this when it has a range of tokens to replace
192   public void optimize( TokenPrinter tp, Object param, int startTokenOffset, int endTokenOffset ) {
193     CoordRemoveData cmd = (CoordRemoveData)param;
194     if ( cmd.isCoord() ) {
195         removeCoord( tp, cmd, startTokenOffset, endTokenOffset );
196     } else {
197         removeIndex( tp, cmd, startTokenOffset, endTokenOffset );
198     }
199   }
200 
201   /** remove coord, texCoord, color, or normal entries based on the usage bitset */
202   void removeCoord( TokenPrinter tp, CoordRemoveData cmd, int startTokenOffset, int endTokenOffset ) {
203       BitSet keep = cmd.getCoordsToKeep();
204       int unitCount = cmd.getUnitCount();
205       int scannerOffset = startTokenOffset;
206     int idx = 0;
207     boolean hitEnd = false;  // only useful in degenerate cases
208     while ( scannerOffset != -1 ) {
209       if ( dataSource.isNumber( scannerOffset )) {
210         if ( keep.get( idx )) {
211             for ( int i = 0; i < unitCount; i++ ) {
212             tp.print( dataSource, scannerOffset );
213             scannerOffset = dataSource.getNextToken( scannerOffset );
214             if ( scannerOffset == endTokenOffset ) hitEnd = true;
215           }
216         } else {
217             for ( int i = 0; i < unitCount; i++ ) {
218                 scannerOffset = dataSource.getNextToken( scannerOffset );
219                 if ( scannerOffset == endTokenOffset ) hitEnd = true;
220             }
221             numberCoordsRemoved++;
222         }
223         idx++;
224       } else {
225         tp.print( dataSource, scannerOffset );
226         if ( scannerOffset == endTokenOffset ) {
227           break;
228         }
229         scannerOffset = dataSource.getNextToken( scannerOffset );
230       }
231       if ( hitEnd ) {
232           tp.print( dataSource, scannerOffset );
233           break;
234       }
235     }
236   }
237 
238     /** Remove index values based on CoordRemoveData parameter.
239      *
240      *  There are three ways index values get removed.  For coord/coordIndex, 
241      *  texCoord/texCoordIndex, color/colorIndex, normal/normalIndex, any removed
242      *  coord affects the index.  In this case we create an array to adjust all the
243      *  offsets.
244      *
245      *  The second way index values may be affected is in the case of color/colorIndex
246      *  and normal/normalIndex when perVertex is true.  In this case, there is a one
247      *  to one correspondence between the index and the coord.  
248      *
249      *  The third way is when perVertex is false, and there are faces involved.  In this
250      *  case, the number of index values must match the number of faces.  If there are
251      *  more index values than faces, we remove the additional index values.
252      */
253   void removeIndex( TokenPrinter tp, CoordRemoveData cmd, int startTokenOffset, int endTokenOffset ) {
254       BitSet keep = cmd.getCoordsToKeep();
255       int keepSize = keep.size();
256       int[] offsets = new int[ keepSize ];
257       int idx = 0;
258       for ( int i = 0; i < keepSize; i++ ) {
259           offsets[i] = idx;
260           if ( keep.get( i )) {
261               idx++;
262           }
263       }
264          adjustIndex( tp, offsets, startTokenOffset, endTokenOffset, keepSize, cmd.getIndexLimit() );
265   }
266   
267   /** Rewrite the index field, performing value adjustment along the way.
268    *  Also limits the index field size to the maximum allowed by coordIndex
269    */
270   void adjustIndex( TokenPrinter tp, int[] offsets, int scannerOffset, int endTokenOffset, int keepSize, int indexLimit ) {
271         int indexCount = 0;
272     while ( scannerOffset != -1 ) {
273         int type = dataSource.getType( scannerOffset );
274       if ( type == TokenTypes.NumberToken ) {
275           // indexLimit of 0, temporary until face count limit implemented
276           if (( indexLimit == 0 ) || ( indexCount < indexLimit )) {
277             int ival = dataSource.getIntValue( scannerOffset );
278             if ( ival == -1 ) {
279               tp.print( dataSource, scannerOffset, TokenTypes.NumberToken );
280             } else {
281                 if ( ival >= keepSize ) {
282                     // out of range value, print it
283                     tp.print( dataSource, scannerOffset );
284                     System.out.println( "Index value at " + scannerOffset + " value is " + ival + " out of range, max value is " + keepSize );
285                 } else {
286                   tp.print( offsets[ ival ] );
287                 }
288             }
289             indexCount++;
290           }
291       } else {
292         tp.print( dataSource, scannerOffset, type );
293       }
294       if ( scannerOffset == endTokenOffset ) {
295         break;
296       }
297       scannerOffset = dataSource.getNextToken( scannerOffset );
298     }
299   }
300 
301   public void summarize( PrintStream ps ) {
302     if ( numberCoordsRemoved == 0 ) {
303       ps.println( "Did not remove any coordinates." );
304     } else if ( numberCoordsRemoved == 1 ) {
305       ps.println( "Removed 1 coordinate." );
306     } else {
307       ps.println( "Removed " + numberCoordsRemoved + " coordinates." );
308     }
309   }
310 }
311 
312