Source code: com/trapezium/chisel/condensers/PROTOMaker.java
1 /*
2 * @(#)PROTOMaker.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.condensers;
12
13 import com.trapezium.pattern.Visitor;
14 import com.trapezium.vrml.grammar.VRML97;
15 import com.trapezium.vrml.VrmlElement;
16 import com.trapezium.vrml.Value;
17 import com.trapezium.vrml.node.Node;
18 import com.trapezium.vrml.node.DEFUSENode;
19 import com.trapezium.vrml.node.PROTOInstance;
20 import com.trapezium.vrml.fields.Field;
21 import com.trapezium.vrml.fields.FieldValue;
22 import com.trapezium.vrml.fields.MFFieldValue;
23 import com.trapezium.vrml.fields.SFNodeValue;
24 import com.trapezium.vrml.Scene;
25 import com.trapezium.vrml.ROUTE;
26 import com.trapezium.util.NameGenerator;
27 import com.trapezium.util.ReturnInteger;
28 import com.trapezium.chisel.*;
29
30 import java.util.Vector;
31 import java.util.Hashtable;
32 import java.util.Enumeration;
33
34 /**
35 * Creates PROTOs for interpolators if they have the same keys
36 */
37 public class PROTOMaker extends Optimizer {
38
39 class ROUTEReplacer {
40 boolean srcIsInterpolator;
41 boolean destIsInterpolator;
42 ROUTE route;
43
44 ROUTEReplacer( ROUTE route, boolean srcIsInterpolator, boolean destIsInterpolator ) {
45 this.route = route;
46 this.srcIsInterpolator = srcIsInterpolator;
47 this.destIsInterpolator = destIsInterpolator;
48 }
49
50 ROUTE getRoute() {
51 return( route );
52 }
53
54 boolean isSrcInterpolator() {
55 return( srcIsInterpolator );
56 }
57
58 boolean isDestInterpolator() {
59 return( destIsInterpolator );
60 }
61 }
62
63 boolean attemptedFirstNode;
64 Hashtable interpolatorLists;
65 Scene theScene;
66 NameGenerator nameGenerator;
67 boolean printedPROTOs;
68
69 public PROTOMaker() {
70 super( "Interpolator", "Creating PROTOs for interpolators..." );
71 reset();
72 }
73
74 public void reset() {
75 interpolatorLists = new Hashtable();
76 theScene = null;
77 nameGenerator = new NameGenerator();
78 attemptedFirstNode = false;
79 printedPROTOs = false;
80 }
81
82 public boolean isROUTElistener() {
83 return( true );
84 }
85
86 /** Add an interpolator node to the corresponding list */
87 void addInterpolator( String interpolatorType, Node n ) {
88 InterpolatorEntry ie = (InterpolatorEntry)interpolatorLists.get( interpolatorType );
89 if ( ie == null ) {
90 ie = new InterpolatorEntry( interpolatorType, nameGenerator );
91 interpolatorLists.put( interpolatorType, ie );
92 }
93 ie.add( n );
94 }
95
96 /** Is a specific node in the replacement interpolator lists? */
97 boolean isInterpolatorReplaced( String interpolatorType, Node n ) {
98 InterpolatorEntry ie = (InterpolatorEntry)interpolatorLists.get( interpolatorType );
99 if ( ie == null ) {
100 return( false );
101 } else {
102 return( ie.find( n ));
103 }
104 }
105
106 /** Check if a node name is an interpolator */
107 boolean isInterpolator( String nodeName ) {
108 if ( nodeName.compareTo( "ColorInterpolator" ) == 0 ) {
109 return( true );
110 } else if ( nodeName.compareTo( "CoordinateInterpolator" ) == 0 ) {
111 return( true );
112 } else if ( nodeName.compareTo( "NormalInterpolator" ) == 0 ) {
113 return( true );
114 } else if ( nodeName.compareTo( "OrientationInterpolator" ) == 0 ) {
115 return( true );
116 } else if ( nodeName.compareTo( "PositionInterpolator" ) == 0 ) {
117 return( true );
118 } else if ( nodeName.compareTo( "ScalarInterpolator" ) == 0 ) {
119 return( true );
120 } else {
121 return( false );
122 }
123 }
124
125 public void attemptOptimization( Node n ) {
126 // don't mess with interpolators that are inside PROTOs
127 Scene s = (Scene)n.getScene();
128 if ( s.getPROTOparent() != null ) {
129 return;
130 }
131 // don't mess with interpolators that may have been copied due
132 // to being inside a PROTO
133 if ( n.getParent() instanceof PROTOInstance ) {
134 return;
135 }
136 if ( !attemptedFirstNode ) {
137 attemptedFirstNode = true;
138 replaceRange( 1, 1, null );
139 }
140 boolean foundInterpolator = false;
141 if ( theScene == null ) {
142 theScene = (Scene)n.getScene();
143 }
144 String nodeName = n.getBaseName();
145 if ( !VRML97.isValidFieldId( nodeName, "key" )) {
146 return;
147 }
148 if ( n.getField( "key" ) == null ) {
149 return;
150 }
151 if ( isInterpolator( nodeName )) {
152 foundInterpolator = true;
153 addInterpolator( nodeName, n );
154 }
155 if ( foundInterpolator ) {
156 replaceRange( n.getFirstTokenOffset(), n.getLastTokenOffset(), n );
157 }
158 }
159
160 public void attemptOptimization( ROUTE route ) {
161 String sourceObject = route.getSourceDEFname();
162 String destObject = route.getDestDEFname();
163 Scene s = (Scene)route.getScene();
164 if (( sourceObject != null ) && ( destObject != null ) && ( s != null )) {
165 DEFUSENode src = s.getDEF( sourceObject );
166 DEFUSENode dest = s.getDEF( destObject );
167 Node srcNode = src.getNode();
168 Node destNode = dest.getNode();
169 if (( srcNode != null ) && ( destNode != null )) {
170 String srcName = srcNode.getBaseName();
171 String destName = destNode.getBaseName();
172 boolean srcIsInterpolator = isInterpolator( srcName );
173 boolean destIsInterpolator = isInterpolator( destName );
174 if ( srcIsInterpolator && !isInterpolatorReplaced( srcName, srcNode )) {
175 return;
176 }
177 if ( destIsInterpolator && !isInterpolatorReplaced( destName, destNode )) {
178 return;
179 }
180 if ( srcIsInterpolator || destIsInterpolator ) {
181 replaceRange( route.getFirstTokenOffset(), route.getLastTokenOffset(), new ROUTEReplacer( route, srcIsInterpolator, destIsInterpolator ));
182 }
183 }
184 }
185 }
186
187 void printPROTOs( TokenPrinter tp ) {
188 Enumeration keys = interpolatorLists.keys();
189 while ( keys.hasMoreElements() ) {
190 InterpolatorEntry ie = (InterpolatorEntry)interpolatorLists.get( keys.nextElement() );
191 ie.printPROTO( tp );
192 }
193 }
194
195 public void optimize( TokenPrinter tp, Object param, int startTokenOffset, int endTokenOffset ) {
196 if (( param == null ) && !printedPROTOs ) {
197 printPROTOs( tp );
198 printedPROTOs = true;
199 tp.print( dataSource, startTokenOffset );
200 } else if ( param instanceof Node ) {
201 // in case interpolator was first node
202 if ( !printedPROTOs ) {
203 printPROTOs( tp );
204 printedPROTOs = true;
205 }
206 String nodeName = ((Node)param).getBaseName();
207 InterpolatorEntry ie = (InterpolatorEntry)interpolatorLists.get( nodeName );
208 if ( ie != null ) {
209 ie.print( tp, (Node)param );
210 }
211 } else if ( param instanceof ROUTEReplacer ) {
212 ROUTEReplacer rr = (ROUTEReplacer)param;
213 ROUTE route = rr.getRoute();
214 boolean replaceSource = rr.isSrcInterpolator();
215 boolean replaceDest = rr.isDestInterpolator();
216 tp.flush();
217 tp.print( "ROUTE" );
218 String src = route.getSourceDEFname();
219 String srcField = route.getSourceFieldName();
220 String s = src + "." + remap( srcField, replaceSource );
221 tp.print( s );
222 tp.print( "TO" );
223 String dest = route.getDestDEFname();
224 String destField = route.getDestFieldName();
225 s = dest + "." + remap( destField, replaceDest );
226 tp.print( s );
227 tp.flush();
228 }
229 }
230
231 String remap( String interpolatorField, boolean replaceit ) {
232 if ( replaceit ) {
233 if ( interpolatorField.compareTo( "set_fraction" ) == 0 ) {
234 return( "i" );
235 } else if ( interpolatorField.compareTo( "value_changed" ) == 0 ) {
236 return( "o" );
237 } else if ( interpolatorField.compareTo( "key" ) == 0 ) {
238 return( "k" );
239 } else if ( interpolatorField.compareTo( "keyValue" ) == 0 ) {
240 return( "v" );
241 } else {
242 return( "??" );
243 }
244 } else {
245 return( interpolatorField );
246 }
247 }
248
249 class KeyFieldEntry {
250 Field keyField;
251 ReturnInteger count;
252
253 KeyFieldEntry( Field keyField ) {
254 this.keyField = keyField;
255 count = new ReturnInteger( 1 );
256 }
257
258 public Field getKeyField() {
259 return( keyField );
260 }
261
262 public int getCount() {
263 return( count.getValue() );
264 }
265
266 public void incCount() {
267 count.incValue();
268 }
269 }
270
271 class InterpolatorEntry {
272 // name of VRML interpolator
273 String interpolatorType;
274
275 // generated PROTO name
276 String PROTOname;
277
278 // vector of KeyFieldEntry, which just contain "key" field and
279 // a count of how many identical "key" fields found
280 Vector keyFields;
281
282 // mapping from a Node to an offset in the "keyFields" vector
283 Hashtable nodeToKeyEntry;
284
285 NameGenerator nameGenerator;
286
287 // offset of the most popular "key" field, which gets used
288 // as the default
289 int mostPopularKeyOffset;
290
291 InterpolatorEntry( String interpolatorType, NameGenerator nameGenerator ) {
292 this.interpolatorType = interpolatorType;
293 this.nameGenerator = nameGenerator;
294 keyFields = new Vector();
295 nodeToKeyEntry = new Hashtable();
296 PROTOname = null;
297 }
298
299 /** Keep count of most popular key fields, put in mapping node to key entry */
300 void add( Node n ) {
301 Field key = n.getField( "key" );
302 int keyStart = key.getFirstTokenOffset();
303 int keyEnd = key.getLastTokenOffset();
304 int keyFieldsSize = keyFields.size();
305 for ( int i = 0; i < keyFieldsSize; i++ ) {
306 KeyFieldEntry kfe = (KeyFieldEntry)keyFields.elementAt( i );
307 Field testField = kfe.getKeyField();
308 if ( fieldsIdentical( keyStart, keyEnd, testField.getFirstTokenOffset(), testField.getLastTokenOffset() )) {
309 kfe.incCount();
310 nodeToKeyEntry.put( n, new Integer( i ));
311 return;
312 }
313 }
314 KeyFieldEntry kfe = new KeyFieldEntry( key );
315 keyFields.addElement( kfe );
316 nodeToKeyEntry.put( n, new Integer( keyFieldsSize ));
317 }
318
319 /** Check if a node is registered in the list */
320 boolean find( Node n ) {
321 return( nodeToKeyEntry.get( n ) != null );
322 }
323
324 void calculateMostPopularKeyOffset() {
325 int keyFieldsSize = keyFields.size();
326 int winner = 0;
327 int winnerCount = -1;
328 for ( int i = 0; i < keyFieldsSize; i++ ) {
329 KeyFieldEntry kfe = (KeyFieldEntry)keyFields.elementAt( i );
330 if ( kfe.getCount() > winnerCount ) {
331 winner = i;
332 winnerCount = kfe.getCount();
333 }
334 }
335 mostPopularKeyOffset = winner;
336 }
337
338 boolean fieldsIdentical( int f1start, int f1end, int f2start, int f2end ) {
339 int f1size = f1end - f1start + 1;
340 int f2size = f2end - f2start + 1;
341 if ( f1size != f2size ) {
342 return( false );
343 }
344 for ( int i = f1start; i <= f1end; i++, f2start++ ) {
345 if ( !dataSource.sameAs( i, f2start )) {
346 return( false );
347 }
348 }
349 return( true );
350 }
351
352 void printKeyField( TokenPrinter tp ) {
353 calculateMostPopularKeyOffset();
354 KeyFieldEntry kfe = (KeyFieldEntry)keyFields.elementAt( mostPopularKeyOffset );
355 tp.print( "exposedField MFFloat k" );
356 printField( tp, kfe.getKeyField(), true );
357 }
358
359 void printField( TokenPrinter tp, Field f ) {
360 printField( tp, f, false );
361 }
362
363 void printField( TokenPrinter tp, Field f, String nm ) {
364 tp.print( nm );
365 printField( tp, f, true );
366 }
367
368 void printField( TokenPrinter tp, Field f, boolean skipFirst ) {
369 if ( f != null ) {
370 int fStart = f.getFirstTokenOffset();
371 if ( skipFirst ) {
372 fStart++;
373 }
374 int fEnd = f.getLastTokenOffset();
375 for ( int i = fStart; i <= fEnd; i++ ) {
376 tp.print( dataSource, i );
377 }
378 }
379 }
380
381 /** Get the key entry offset for a node */
382 int getKeyEntryOffset( Node n ) {
383 Integer offset = (Integer)nodeToKeyEntry.get( n );
384 return( offset.intValue() );
385 }
386
387 /** Print a node, but as a PROTO */
388 void print( TokenPrinter tp, Node n ) {
389 tp.print( PROTOname );
390 tp.print( "{" );
391 int keyEntryOffset = getKeyEntryOffset( n );
392 KeyFieldEntry kfe = (KeyFieldEntry)keyFields.elementAt( keyEntryOffset );
393 if ( keyEntryOffset != mostPopularKeyOffset ) {
394 printField( tp, n.getField( "key" ), "k" );
395 }
396 printField( tp, n.getField( "keyValue" ), "v" );
397 tp.print( "}" );
398 }
399
400 void createPROTOname() {
401 while ( true ) {
402 String testName = nameGenerator.generateName();
403 if ( theScene.getPROTO( testName ) == null ) {
404 PROTOname = testName;
405 return;
406 }
407 }
408 }
409
410 void printEventIn( TokenPrinter tp ) {
411 tp.flush();
412 tp.print( "eventIn SFFloat i" );
413 tp.flush();
414 }
415
416 void printEventOut( TokenPrinter tp ) {
417 tp.flush();
418 tp.print( "eventOut" );
419 tp.print( VRML97.getFieldTypeString( interpolatorType, "value_changed" ));
420 tp.print( "o" );
421 tp.flush();
422 }
423
424 void printPROTO( TokenPrinter tp ) {
425 createPROTOname();
426 tp.flush();
427 tp.print( "PROTO" );
428 tp.print( PROTOname );
429 tp.print( "[" );
430 printEventIn( tp );
431 printKeyField( tp );
432 tp.print( "exposedField" );
433 tp.print( VRML97.getFieldTypeString( interpolatorType, "keyValue" ));
434 tp.print( "v" );
435 tp.print( "[]" );
436 printEventOut( tp );
437 tp.print( "] {" );
438 tp.flush();
439 tp.print( interpolatorType );
440 tp.print( "{" );
441 tp.flush();
442 tp.print( "set_fraction IS i" );
443 tp.flush();
444 tp.print( "key IS k" );
445 tp.flush();
446 tp.print( "keyValue IS v" );
447 tp.flush();
448 tp.print( "value_changed IS o" );
449 tp.print( "} }" );
450 }
451 }
452 }