Source code: com/trapezium/chisel/mutators/IFS_Converter.java
1 /*
2 * @(#)IFS_Converter.java
3 *
4 * Copyright (c) 1998 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.mutators;
12
13 import com.trapezium.chisel.*;
14
15 import com.trapezium.vrml.node.Node;
16 import com.trapezium.vrml.VrmlElement;
17 import com.trapezium.vrml.fields.Field;
18 import com.trapezium.vrml.fields.FieldValue;
19 import com.trapezium.vrml.fields.MFFieldValue;
20 import com.trapezium.vrml.node.DEFUSENode;
21
22
23 /**
24 * This base class chisel turns IndexedFaceSets into IndexedLineSets or PointSet
25 */
26 abstract public class IFS_Converter extends Optimizer {
27 /** single option, sets emissiveColor because otherwise ILS might
28 * be invisible.
29 */
30 boolean setEmissiveColor;
31
32 /** Preserve original as first in a LOD */
33 boolean preserveOriginalInLOD;
34
35 /** range for level 0 */
36 int level0range;
37
38 /** The Node type we are converting to -- either IndexedLineSet or PointSEt */
39 String convertTo;
40
41 /** Constructor, only notify on IndexedFaceSets */
42 public IFS_Converter( String convertTo ) {
43 super( "IndexedFaceSet", "Converting IndexedFaceSet to " + convertTo );
44 setEmissiveColor = true;
45 this.convertTo = convertTo;
46 preserveOriginalInLOD = false;
47 level0range = 10;
48 }
49
50 /** Always replace the entire containing Shape node */
51 public void attemptOptimization( Node n ) {
52 Node ifs = n;
53 n = n.getNodeParent();
54 if ( n instanceof DEFUSENode ) {
55 n = n.getNodeParent();
56 }
57 if ( n != null ) {
58 replaceRange( n.getFirstTokenOffset(), n.getLastTokenOffset(), n );
59 }
60 }
61
62
63 void preserveField( TokenPrinter tp, Node n, String fieldName ) {
64 Field f = n.getField( fieldName );
65 if ( f != null ) {
66 tp.printRange( f.getFirstTokenOffset(), f.getLastTokenOffset(), false );
67 }
68 }
69
70 // RangeReplacer calls this when it has a range of tokens to replace
71 public void optimize( TokenPrinter tp, Object param, int startTokenOffset, int endTokenOffset ) {
72 if ( param instanceof Node ) {
73 Node shape = (Node)param;
74
75 // if preserving original Shape in LOD 0, we rewrite it here
76 if ( preserveOriginalInLOD ) {
77 tp.print( "LOD { range [" );
78 tp.print( level0range );
79 tp.print( "]" );
80 tp.print( "level [" );
81 tp.flush();
82 tp.printRange( shape.getFirstTokenOffset(), shape.getLastTokenOffset(), false );
83 }
84
85 Field f = shape.getField( "geometry" );
86 Node ifs = f.getNodeValue();
87 Field fa = shape.getField( "appearance" );
88 Node appearanceNode = null;
89 String appearanceDEFName = null;
90 Node materialNode = null;
91 String materialDEFName = null;
92 boolean preserveMaterial = false;
93
94 // if we are preserving original in LOD, DEFs are preserved there
95 if (( fa != null ) && !preserveOriginalInLOD ) {
96 appearanceNode = fa.getNodeValue();
97 if ( appearanceNode != null ) {
98 if ( appearanceNode.getParent() instanceof DEFUSENode ) {
99 DEFUSENode appearanceDEF = (DEFUSENode)(appearanceNode.getParent());
100 if ( appearanceDEF.isUsed() ) {
101 appearanceDEFName = appearanceDEF.getDEFName();
102 preserveMaterial = true;
103 }
104 }
105 Field fm = appearanceNode.getField( "material" );
106 if ( fm != null ) {
107 materialNode = fm.getNodeValue();
108 if ( materialNode != null ) {
109 if ( materialNode.getParent() instanceof DEFUSENode ) {
110 DEFUSENode materialDEF = (DEFUSENode)(materialNode.getParent());
111 if ( materialDEF.isUsed() ) {
112 materialDEFName = materialDEF.getDEFName();
113 preserveMaterial = true;
114 }
115 }
116 }
117 }
118 }
119 }
120
121 tp.print( "Shape {" );
122 // if there is an appearance node DEFfed, preserve the DEF
123 tp.print( "appearance" );
124 if ( appearanceDEFName != null ) {
125 tp.print( "DEF" );
126 tp.print( appearanceDEFName );
127 }
128 tp.print( "Appearance {" );
129 if ( appearanceDEFName != null ) {
130 // if its DEFfed, preserve its texture & textureTransform fields
131 // since they may be used
132 preserveField( tp, appearanceNode, "texture" );
133 preserveField( tp, appearanceNode, "textureTransform" );
134 }
135 // now print the matierial field
136 tp.print( "material" );
137 if ( materialDEFName != null ) {
138 tp.print( "DEF" );
139 tp.print( materialDEFName );
140 }
141 tp.print( "Material {" );
142 if ( preserveMaterial ) {
143 // if its DEFfed, preserve its fields
144 preserveField( tp, materialNode, "ambientIntensity" );
145 preserveField( tp, materialNode, "diffuseColor" );
146 preserveField( tp, materialNode, "shininess" );
147 preserveField( tp, materialNode, "specularColor" );
148 preserveField( tp, materialNode, "transparency" );
149 }
150 tp.print( "emissiveColor" );
151
152 boolean printedColor = false;
153 if ( setEmissiveColor ) {
154 Field appearance = shape.getField( "appearance" );
155 if ( appearance != null ) {
156 appearanceNode = appearance.getNodeValue();
157 if ( appearanceNode != null ) {
158 Field material = appearanceNode.getField( "material" );
159 if ( material != null ) {
160 materialNode = material.getNodeValue();
161 if ( materialNode != null ) {
162 Field diffuseColor = materialNode.getField( "diffuseColor" );
163 if ( diffuseColor != null ) {
164 tp.printRange( diffuseColor.getFirstTokenOffset() + 1, diffuseColor.getLastTokenOffset(), false );
165 printedColor = true;
166 }
167 }
168 }
169 }
170 }
171 }
172 if ( !printedColor ) {
173 tp.print( "1 1 1" );
174 }
175 tp.print( "} }" );
176 tp.flush();
177 tp.print( "geometry" );
178
179 Field coord = ifs.getField( "coord" );
180 startTokenOffset = ifs.getFirstTokenOffset();
181 int coordStart = -1;
182 if ( coord != null ) {
183 coordStart = coord.getFirstTokenOffset();
184 }
185 Node coordNode = coord.getNodeValue();
186 boolean coordNodeIsUSE = false;
187 String coordDEFname = null;
188 if ( coordNode != null ) {
189 VrmlElement vn = coordNode.getParent();
190 if ( vn instanceof DEFUSENode ) {
191 DEFUSENode dun = (DEFUSENode)vn;
192 if ( !dun.isDEF() ) {
193 coordDEFname = dun.getDEFName();
194 coordNodeIsUSE = true;
195 }
196 }
197 }
198 Field coordIndex = ifs.getField( "coordIndex" );
199 int coordIndexStart = -1;
200 if ( coordIndex != null ) {
201 coordIndexStart = coordIndex.getFirstTokenOffset();
202 }
203 Field color = ifs.getField( "color" );
204 int colorStart = -1;
205 if ( color != null ) {
206 colorStart = color.getFirstTokenOffset();
207 }
208 Field colorIndex = ifs.getField( "colorIndex" );
209 int colorIndexStart = -1;
210 if ( colorIndex != null ) {
211 colorIndexStart = colorIndex.getFirstTokenOffset();
212 }
213 Field colorPerVertex = ifs.getField( "colorPerVertex" );
214 int colorPerVertexStart = -1;
215 if ( colorPerVertex != null ) {
216 colorPerVertexStart = colorPerVertex.getFirstTokenOffset();
217 }
218 Field normal = ifs.getField( "normal" );
219 int normalStart = -1;
220 if ( normal != null ) {
221 normalStart = normal.getFirstTokenOffset();
222 }
223 Field normalIndex = ifs.getField( "normalIndex" );
224 int normalIndexStart = -1;
225 if ( normalIndex != null ) {
226 normalIndexStart = normalIndex.getFirstTokenOffset();
227 }
228 Field normalPerVertex = ifs.getField( "normalPerVertex" );
229 int normalPerVertexStart = -1;
230 if ( normalPerVertex != null ) {
231 normalPerVertexStart = normalPerVertex.getFirstTokenOffset();
232 }
233 int breakOffset = getBreakOffset( coordStart, coordIndexStart );
234 breakOffset = getBreakOffset( breakOffset, colorStart );
235 breakOffset = getBreakOffset( breakOffset, colorIndexStart );
236 breakOffset = getBreakOffset( breakOffset, normalStart );
237 breakOffset = getBreakOffset( breakOffset, normalIndexStart );
238 breakOffset = getBreakOffset( breakOffset, colorPerVertexStart );
239 breakOffset = getBreakOffset( breakOffset, normalPerVertexStart );
240 breakOffset--;
241 tp.print( convertTo );
242 printIFSrange( tp, startTokenOffset + 1, breakOffset, ifs );
243 if ( coordStart != -1 ) {
244 if ( coordNodeIsUSE ) {
245 tp.print( "coord USE" );
246 tp.print( coordDEFname );
247 } else {
248 printIFSrange( tp, coordStart, coord.getLastTokenOffset(), ifs );
249 }
250 }
251 if ( coordIndexStart != -1 ) {
252 printCoordIndex( tp, coordIndex );
253 }
254 convertColorInfo( ifs, tp, colorStart, color, colorPerVertexStart, colorPerVertex, colorIndexStart, colorIndex );
255 // end braces for PointSet/ILS and Shape
256 tp.print( "} }" );
257 if ( preserveOriginalInLOD ) {
258 tp.print( "] }" );
259 }
260 }
261 }
262
263 /** Print a range of tokens from an IFS, but skip ccw, convex, creaseAngle and solid
264 * fields.
265 */
266 int[] skipStart;
267 int[] skipEnd;
268 void printIFSrange( TokenPrinter tp, int start, int end, Node ifs ) {
269 Field ccw = ifs.getField( "ccw" );
270 Field convex = ifs.getField( "convex" );
271 Field creaseAngle = ifs.getField( "creaseAngle" );
272 Field solid = ifs.getField( "solid" );
273 if ( skipStart == null ) {
274 skipStart = new int[4];
275 skipEnd = new int[4];
276 }
277 for ( int i = 0; i < 4; i++ ) {
278 skipStart[i] = skipEnd[i] = -1;
279 }
280 if ( ccw != null ) {
281 skipStart[0] = ccw.getFirstTokenOffset();
282 skipEnd[0] = ccw.getLastTokenOffset();
283 }
284 if ( convex != null ) {
285 skipStart[1] = convex.getFirstTokenOffset();
286 skipEnd[1] = convex.getLastTokenOffset();
287 }
288 if ( creaseAngle != null ) {
289 skipStart[2] = creaseAngle.getFirstTokenOffset();
290 skipEnd[2] = creaseAngle.getLastTokenOffset();
291 }
292 if ( solid != null ) {
293 skipStart[3] = solid.getFirstTokenOffset();
294 skipEnd[3] = solid.getLastTokenOffset();
295 }
296 for ( int scanner = start; scanner <= end; scanner++ ) {
297 if ( okToPrint( scanner )) {
298 tp.print( dataSource, scanner );
299 }
300 }
301 }
302
303 /** Check if the token is within the skipping range */
304 boolean okToPrint( int offset ) {
305 for ( int i = 0; i < 4; i++ ) {
306 if (( offset >= skipStart[i] ) && ( offset <= skipEnd[i] )) {
307 return( false );
308 }
309 }
310 return( true );
311 }
312
313
314 int getBreakOffset( int a, int b ) {
315 if ( a == -1 ) {
316 return( b );
317 } else if ( b == -1 ) {
318 return( a );
319 } else if ( a < b ) {
320 return( a );
321 } else {
322 return( b );
323 }
324 }
325
326 abstract void printCoordIndex( TokenPrinter tp, Field coordIndex );
327 abstract void convertColorInfo( Node n, TokenPrinter tp,
328 int colorStart, VrmlElement color,
329 int colorPerVertexStart, VrmlElement colorPerVertex,
330 int colorIndexStart, VrmlElement colorIndex );
331
332 /** Option interface, allow set emissiveColor to diffuseColor option */
333 public int getNumberOptions() {
334 return( 3 );
335 }
336
337 /** Get the class for an option */
338 public Class getOptionClass( int offset ) {
339 if ( offset < 2 ) {
340 return( Boolean.TYPE );
341 } else {
342 return( Integer.TYPE );
343 }
344 }
345
346 public String getOptionLabel( int offset ) {
347 if ( offset == 0 ) {
348 return( "set emissiveColor to diffuseColor" );
349 } else if ( offset == 1 ) {
350 return( "preserve original IFS in LOD level 0" );
351 } else if ( offset == 2 ) {
352 return( "level 0 range" );
353 } else {
354 return( null );
355 }
356 }
357
358 public Object getOptionValue( int offset ) {
359 if ( offset == 0 ) {
360 return( booleanToOptionValue( setEmissiveColor ));
361 } else if ( offset == 1 ) {
362 return( booleanToOptionValue( preserveOriginalInLOD ));
363 } else {
364 return( intToOptionValue( level0range ));
365 }
366 }
367
368 public void setOptionValue( int offset, Object value ) {
369 if ( offset == 0 ) {
370 setEmissiveColor = optionValueToBoolean(value);
371 } else if ( offset == 1 ) {
372 preserveOriginalInLOD = optionValueToBoolean(value);
373 } else {
374 level0range = optionValueToInt(value);
375 }
376 }
377 }
378
379