Source code: com/trapezium/vrmlspace/SpaceStructureLoader.java
1 /*
2 * @(#)SpaceStructureLoader.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.vrmlspace;
12
13 import com.trapezium.space.*;
14 import com.trapezium.vrmlspace.*;
15 import com.trapezium.parse.TokenTypes;
16 import com.trapezium.vrml.VrmlElement;
17 import com.trapezium.vrml.Scene;
18 import com.trapezium.vrml.node.Node;
19 import com.trapezium.vrml.fields.*;
20 import com.trapezium.parse.TokenEnumerator;
21
22 import java.util.Vector;
23 import java.util.Hashtable;
24
25 /** The SpaceStructureLoader manages a set of SpaceStructures associated
26 * with IndexedFaceSets in a file. Two sets of SpaceStructures are kept --
27 * one for each IFS in the file, accessed by index, and one for each
28 * Coordinate node in the file, accessed by coord node. These lists will
29 * be different if the file uses DEF/USE of Coordinate nodes.
30 *
31 * @author Johannes N. Johannsen
32 * @version 1.0, 8 Oct 1998
33 *
34 * @since 1.0
35 */
36
37 public class SpaceStructureLoader {
38
39 Vector independentStructures;
40 Hashtable completeStructures; // key coord node, value SpaceStructure
41 TokenEnumerator dataSource;
42
43 /** Class constructor */
44 public SpaceStructureLoader() {
45 dataSource = null;
46 independentStructures = new Vector();
47 completeStructures = new Hashtable();
48 }
49
50 // set dataSource if it isn't set
51 void setDataSource( Node n ) {
52 if ( dataSource == null ) {
53 Scene s = (Scene)n.getRoot();
54 dataSource = s.getTokenEnumerator();
55 }
56 }
57
58 /** Access space structure by offset.
59 *
60 * @param offset the offset of the SpaceStructure
61 * @return the SpaceStructure at that offset, null if offset invalid
62 */
63 public SpaceStructure getSpaceStructure( int offset ) {
64 if (( offset < 0 ) || ( offset >= independentStructures.size() )) {
65 return( null );
66 } else {
67 return( (SpaceStructure)independentStructures.elementAt( offset ));
68 }
69 }
70
71 /** Access space structure by coord node.
72 *
73 * @param coordNode the Coordinate Node associated with a SpaceStructure,
74 * in this case, the SpaceStructure represents the union of all
75 * IndexedFaceSets sharing that Coordinate Node.
76 * @return the SpaceStructure associated with the coordNode, null if none
77 */
78 public SpaceStructure getSpaceStructure( Node coordNode ) {
79 return( (SpaceStructure)completeStructures.get( coordNode ));
80 }
81
82 /** Load a SpaceStructuare, save it in the independentStructures and
83 * completeStructures list. If the Coordinate node is used, then the
84 * existing entry from the completeStructures list is used, and the
85 * faces for the current SpaceStructure are appended onto that entry,
86 * resulting in that entry being a union of all SpaceStructures associated
87 * with a particular coordinate node.
88 *
89 * @param n the IndexedFaceSet node to be loaded
90 * @return a SpaceStructure containing the faces for the Node n (i.e.
91 * the independentStructures entry, not the completeStructures entry)
92 */
93 public SpaceStructure loadSpaceStructure( Node n ) {
94 setDataSource( n );
95 Node coord = n.getNodeValue( "coord" );
96 if ( coord == null ) {
97 return( null );
98 }
99 Field coordIndex = n.getField( "coordIndex" );
100 Field texCoord = n.getField( "texCoord" );
101 Field texCoordIndex = n.getField( "texCoordIndex" );
102 Field color = n.getField( "color" );
103 Field colorIndex = n.getField( "colorIndex" );
104 Field normal = n.getField( "normal" );
105 Field normalIndex = n.getField( "normalIndex" );
106
107 SpaceStructure s = (SpaceStructure)completeStructures.get( coord );
108 boolean coordNodeSSfound = !( s == null );
109 if ( !coordNodeSSfound ) {
110 s = new SpaceStructure();
111 }
112 SpaceStructure loaded = null;
113 if ( anyDEFUSE( coord, texCoord, color, normal )) {
114 loaded = new SpaceStructure();
115 loaded.setVertices( s.getVertices() );
116 } else {
117 loaded = s;
118 }
119 load3f( coord, loaded.getVertices() );
120
121 if ( coordIndex != null ) {
122 loadIlist( coordIndex, loaded.getFaces(), s.getFaces() );
123 }
124 if ( !coordNodeSSfound ) {
125 completeStructures.put( coord, s );
126 }
127 independentStructures.addElement( s );
128 s.createTextures( texCoord, texCoordIndex );
129 load2f( texCoord, s.getTexCoord() );
130 loadIlist( texCoordIndex, s.getTexCoordIndex(),
131 loaded.getTexCoordIndex() );
132 if ( loaded != s ) {
133 loaded.createTextures( texCoord, texCoordIndex );
134 load2f( texCoord, loaded.getTexCoord() );
135 }
136 s.createColors( color, colorIndex, n.getBoolValue( "colorPerVertex" ));
137 load3f( color, s.getColor() );
138 if ( loaded != s ) {
139 loaded.createColors( color, colorIndex, n.getBoolValue( "colorPerVertex" ));
140 load3f( color, loaded.getColor() );
141 }
142 loadIlist( colorIndex, s.getColorIndex(), loaded.getColorIndex() );
143 s.createNormals( normal, normalIndex, n.getBoolValue( "normalPerVertex" ));
144 load3f( normal, s.getNormal() );
145 if ( loaded != s ) {
146 loaded.createNormals( normal, normalIndex, n.getBoolValue( "normalPerVertex" ));
147 load3f( normal, loaded.getNormal() );
148 }
149 loadIlist( normalIndex, s.getNormalIndex(), loaded.getNormalIndex() );
150 return( loaded );
151 }
152
153 /** Check if any of the fields refer to a DEFUSEnode */
154 boolean anyDEFUSE( Field f1, Field f2, Field f3, Field f4 ) {
155 if ( hasDEFUSE( f1 )) {
156 return( true );
157 }
158 if ( hasDEFUSE( f2 )) {
159 return( true );
160 }
161 if ( hasDEFUSE( f3 )) {
162 return( true );
163 }
164 return( hasDEFUSE( f4 ));
165 }
166
167 /** Check if field refers to a DEFUSENode */
168 boolean hasDEFUSE( Field f ) {
169 if ( f != null ) {
170 FieldValue fv = f.getFieldValue();
171 if ( fv instanceof SFNodeValue ) {
172 SFNodeValue sfnv = (SFNodeValue)fv;
173 Node n = sfnv.getNode();
174 if ( n != null ) {
175 return( n.isDEForUSE() );
176 }
177 }
178 }
179 return( false );
180 }
181
182 /** Load the vertices into a SpaceStructure.
183 *
184 * @param valueNode source of vertex data
185 * @param target where to load the data
186 */
187 void load3f( VrmlElement valueNode, SpaceEntitySet target ) {
188 if ( valueNode != null ) {
189 float[] loc = new float[3];
190 dataSource.setState( valueNode.getFirstTokenOffset() );
191 int last = valueNode.getLastTokenOffset();
192 while ( dataSource.copy3f( loc, last )) {
193 target.add3f( loc );
194 }
195 }
196 }
197
198 /** Load the texCoords into a SpaceStructure.
199 *
200 * @param valueNode source of vertex data
201 * @param target where to load the data
202 */
203 void load2f( VrmlElement valueNode, SpaceEntitySet target ) {
204 if ( valueNode != null ) {
205 float[] loc = new float[2];
206 dataSource.setState( valueNode.getFirstTokenOffset() );
207 int last = valueNode.getLastTokenOffset();
208 while ( dataSource.copy2f( loc, last )) {
209 target.add2f( loc );
210 }
211 }
212 }
213
214 /** Load the index array into a SpaceStructure.
215 *
216 * @param ilist source of face data
217 * @param target1 first of two destinations of face data, this is the
218 * one that only contains the single set of face data
219 * @param target2 second of two destinations of face data, this is the
220 * one that contains the union of all faces with the same coord node
221 */
222 void loadIlist( VrmlElement ilist, SpaceEntitySet target1, SpaceEntitySet target2 ) {
223 if ( target1 == target2 ) {
224 target2 = null;
225 }
226 int scanner = ilist.getFirstTokenOffset();
227 dataSource.setState( scanner );
228 int last = ilist.getLastTokenOffset();
229 int val = -1;
230 while ( scanner < last ) {
231 dataSource.skipTo( TokenTypes.NumberToken );
232 scanner = dataSource.getState();
233 if (( scanner == -1 ) || ( scanner > last )) {
234 break;
235 }
236 val = dataSource.getIntValue( scanner );
237 target1.add( val );
238 if ( target2 != null ) {
239 target2.add( val );
240 }
241 scanner = dataSource.getNextToken();
242 }
243 if ( val != -1 ) {
244 target1.add( -1 );
245 if ( target2 != null ) {
246 target2.add( -1 );
247 }
248 }
249 }
250 }