Source code: org/pqt/autorib/instr/InstrWReader.java
1 //AutoRIB
2 // Copyright © 1998 - 2002, P W Quint
3 //
4 // Contact: autorib00@aol.com
5 //
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU General Public
8 // License as published by the Free Software Foundation; either
9 // version 2 of the License, or (at your option) any later version.
10 //
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 // General Public License for more details.
15 //
16 // You should have received a copy of the GNU General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
20 package org.pqt.autorib.instr;
21 import java.util.*;
22 import java.io.*;
23
24 import org.pqt.autorib.tokenizer.*;
25 import org.pqt.autorib.globals.*;
26 import org.pqt.autorib.util.*;
27 import org.pqt.autorib.rib.*;
28
29
30 /**
31 * This class provides routines for reading and writing
32 * Instr (instrutions) files, for storing their contents,
33 * and for applying them to RIB.
34 * <p> The writing routines are used for debugging only.
35 *
36 */
37
38 public class InstrWReader {
39 /** used for saving and restoring the state within blocks */
40 private Stack stateStack = new Stack();
41 /** the current state, by which we mean map dimensions,
42 * filtering etc.
43 */
44 public InstrState state = new InstrState();
45 /** a tokenizer for the instructions file */
46 public InstrTokenizer tokenizer;
47 /** used to hold the current instruction being read in */
48 private InstrRequest rq = null;
49 /** the number of requests read in this and archived files*/
50 public int requestsRead = 0;
51 /** true if rq holds a token that has been pushed back*/
52 private boolean pushedBack = false;
53 /** this holds the contents of the instructions file */
54 private Vector content = new Vector(50,25);
55 /** true if we are currently reading instructions from within a lights block*/
56 public boolean inLightBlock = false;
57 /** true if we are reading instructions from within a for block*/
58 public boolean inForBlock = false;
59 /** true if we are reading instructions inside an Objects block*/
60 public boolean inObjectBlock = false;
61 /** used to hold the rib stream being processed */
62 public RIBWReader rib = null;
63 /** this records whether we need to process any RIB added by GlobalRIB or
64 * FrameRIB */
65 public boolean globalOrFrameRIB = false;
66 /** this stores any lights added by FrameRIB (or, indeed, globalRIB) */
67 public Vector addedLights = new Vector(5,5);
68 /** this is used to manage the numbering of groups of individual primitives by name*/
69 public NameGroupManager nameGroupManager = new NameGroupManager();
70 /** this manages name / number lookups */
71 public NameNumberManager nameNumberManager = null;
72 /** this stores saved Pref values from objects */
73 public Hashtable storedPrefs = new Hashtable(50);
74
75 /** Open the named Instr file
76 * @param name the name of the file to open
77 * @throws FormatException A syntax error
78 * @throws FileNotFoundException The file is not found
79 */
80 public InstrWReader(String name) throws FormatException,
81 FileNotFoundException {
82 tokenizer = new InstrTokenizer(name);
83 }
84
85 /** Read in a single request
86 * @throws FormatException thrown if a syntax error is found
87 * @throws IOException an io error
88 * @return the instruction read in, or null if the
89 * end of file has been reached
90 */
91 public InstrRequest readRequest() throws FormatException, IOException {
92 if (!pushedBack) {
93 tokenizer.getToken();
94 if (tokenizer.token.tokenType == Token.EOF)
95 rq = null; //rq is a class wide variable
96 else if ((tokenizer.token.tokenType == Token.OPENBRACE) ||
97 (tokenizer.token.tokenType == Token.CLOSEBRACE))
98 rq = new InstrBrace(tokenizer.token.tokenType);
99 else if (tokenizer.token.tokenType != Token.REQUEST)
100 throw new FormatException("Instruction expected",tokenizer);
101 else {
102 tokenizer.token.requestID = findID(tokenizer.token.requestVal);
103 tokenizer.pushBack(); //make sure token available to be read later
104 switch (tokenizer.token.requestID) //read in this particular call
105 {
106 case InstrGlobals.LIGHTS:
107 rq = new InstrLights(this);
108 break;
109 case InstrGlobals.FORHANDLES:
110 rq = new InstrForHandles(this);
111 break;
112 case InstrGlobals.MAPFORMAT:
113 rq = new InstrMapFormat(this);
114 break;
115 case InstrGlobals.MAPFORMATMULT:
116 rq = new InstrMapFormatMult(this);
117 break;
118 case InstrGlobals.DEFAULTCONEANGLE:
119 rq = new InstrDefaultConeAngle(this);
120 break;
121 case InstrGlobals.APPENDPARAM:
122 case InstrGlobals.REPLACEPARAM:
123 rq = new InstrAppendParam(this);
124 break;
125 case InstrGlobals.FORSHADERS:
126 rq = new InstrForShaders(this);
127 break;
128 case InstrGlobals.SHADOWSPOT:
129 rq = new InstrShadowSpot(this);
130 break;
131 case InstrGlobals.RENAMESHADER:
132 rq = new InstrRenameShader(this);
133 break;
134 case InstrGlobals.SOFTSHADOWSPOT:
135 rq = new InstrSoftShadowSpot(this);
136 break;
137 case InstrGlobals.FORCOLORS:
138 rq = new InstrForColors(this);
139 break;
140 case InstrGlobals.REMOVEPARAM:
141 rq = new InstrRemoveParam(this);
142 break;
143 case InstrGlobals.RENAMEPARAM:
144 rq = new InstrRenameParam(this);
145 break;
146 case InstrGlobals.SHADOWPOINT:
147 rq = new InstrShadowPoint(this);
148 break;
149 case InstrGlobals.SHADOWDIST:
150 rq = new InstrShadowDist(this);
151 break;
152 case InstrGlobals.ADDRIB:
153 rq = new InstrAddRIB(this);
154 break;
155 case InstrGlobals.OMIT:
156 rq = new InstrOmit(this);
157 break;
158 case InstrGlobals.OBJECTS:
159 rq = new InstrObjects(this);
160 break;
161 case InstrGlobals.ENVMAP:
162 rq = new InstrEnvMap(this);
163 break;
164 case InstrGlobals.FORNAMES:
165 rq = new InstrForNames(this);
166 break;
167 case InstrGlobals.MAPSAMPLES:
168 rq = new InstrMapSamples(this);
169 break;
170 case InstrGlobals.MAPFILTER:
171 rq = new InstrMapFilter(this);
172 break;
173 case InstrGlobals.MAPDISPLAY:
174 rq = new InstrMapDisplay(this);
175 break;
176 case InstrGlobals.REFLMAP:
177 rq = new InstrReflMap(this);
178 break;
179 case InstrGlobals.GLOBALRIB:
180 case InstrGlobals.FRAMERIB:
181 globalOrFrameRIB = true;
182 rq = new InstrRIB(this);
183 break;
184 case InstrGlobals.INSTROPTION:
185 rq = new InstrOption(this);
186 break;
187 case InstrGlobals.DELETEPRIMS:
188 rq = new InstrDeletePrims(this);
189 break;
190 case InstrGlobals.APPENDNUMBER:
191 rq = new InstrAppendNumber(this);
192 break;
193 case InstrGlobals.NUMBERGROUP:
194 rq = new InstrNumberGroup(this);
195 break;
196 case InstrGlobals.SURFACE:
197 case InstrGlobals.DISPLACEMENT:
198 case InstrGlobals.INTERIOR:
199 case InstrGlobals.EXTERIOR:
200 case InstrGlobals.ATMOSPHERE:
201 rq = new InstrShader(this);
202 break;
203 case InstrGlobals.TOSUBDIVISION:
204 rq = new InstrToSubdivision(this);
205 break;
206 case InstrGlobals.ENVMAPAUTO:
207 rq = new InstrEnvMapAuto(this);
208 break;
209 case InstrGlobals.REFLMAPAUTO:
210 rq = new InstrReflMapAuto(this);
211 break;
212 case InstrGlobals.SHADOWDISTAUTO:
213 rq = new InstrShadowDistAuto(this);
214 break;
215 case InstrGlobals.TIGHTCLIPPING:
216 rq = new InstrTightClipping(this);
217 break;
218 case InstrGlobals.LIGHTDOME:
219 rq = new InstrLightDome(this);
220 break;
221 case InstrGlobals.PERSPMAP:
222 rq = new InstrPerspMap(this);
223 break;
224 case InstrGlobals.ORTHOMAP:
225 rq = new InstrOrthoMap(this);
226 break;
227 case InstrGlobals.SIXSNAPS:
228 rq = new InstrSixSnaps(this);
229 break;
230 case InstrGlobals.APPENDPRIMPARAM:
231 rq = new InstrAppendPrimParam(this);
232 break;
233 case InstrGlobals.SAVEPREF:
234 rq = new InstrSavePref(this);
235 break;
236 case InstrGlobals.CLEANPOLY:
237 rq = new InstrCleanPoly(this);
238 break;
239 case InstrGlobals.COMBINEPOLYS:
240 rq = new InstrCombinePolys(this);
241 break;
242 case InstrGlobals.GROUPENVMAP:
243 rq = new InstrGroupEnvMap(this);
244 break;
245 default:
246 throw new FormatException("Unrecognised request",
247 tokenizer);
248 }
249 requestsRead++;
250 }
251 }
252 else
253 pushedBack = false;
254 return rq;
255 }
256
257
258 /**
259 * read a block assuming the opening brace '{' has already been read
260 * @param content instructions read will be added to this Vector
261 * @param valid - an array of instructions that are valid in the block being read
262 * @throws FormatException a syntax error
263 * @throws IOException an io exception
264 */
265 public void readToEndBlock(Vector content, int[] valid) throws FormatException,
266 IOException {
267 InstrRequest ir;
268 while (true) {
269 ir = readRequest();
270 if ((ir == null) || (ir.requestID == Token.OPENBRACE))
271 throw new FormatException("} expected",tokenizer);
272 else if (ir.requestID == Token.CLOSEBRACE)
273 break;
274 else {
275 int i;
276 for (i = 0; i < valid.length; i++)
277 if (ir.requestID == valid[i]) break;
278 if (i < valid.length)
279 content.addElement(ir);
280 else
281 throw new FormatException("Instruction " +
282 InstrGlobals.requests[ir.requestID - InstrGlobals.BASE] +
283 " is not allowed here",
284 tokenizer);
285 }
286 }
287 }
288
289 /** Read in the whole instuctions file
290 * @throws FormatException if a syntax error is found
291 * @throws IOException an io error
292 */
293 public void read() throws FormatException,
294 IOException {
295 InstrRequest ir;
296 while (true) {
297 ir = readRequest();
298 if (ir == null)
299 break;
300 else
301 content.addElement(ir);
302 }
303 //set up the object number handling mechanism now all the groups are read in
304 nameNumberManager = new NameNumberManager(nameGroupManager);
305 }
306
307 /** write out the entire contents of the stored
308 * instructions file
309 * @param outStream - the stream to write it to
310 * @throws IOException an io error
311 */
312 public void write(Writer outStream) throws IOException {
313 Enumeration i = content.elements();
314 while (i.hasMoreElements())
315 ((InstrRequest)i.nextElement()).write(outStream);
316 }
317
318
319 /** Push back the most recently read instruction, so
320 * that it will be returned in response to the next
321 * read
322 */
323 public void pushBack() {
324 if ((requestsRead > 0) && !pushedBack) {
325 pushedBack = true;
326 requestsRead--;
327 }
328 }
329
330 /** push the current state onto a stack to be retrieved later */
331 public void saveState() {
332 stateStack.push(state.clone());
333 }
334
335 /** restore the state from the top of the stack */
336 public void restoreState() {
337 if (!stateStack.empty())
338 state = (InstrState) stateStack.pop();
339 }
340
341 /** process an individual light - go through the instructions file calling
342 * the process functions of all instuctions
343 * @param ribp a RIBWReader linked to the rib file being processed - used mainly to
344 * get line number information for reporting errors
345 * @param light the light to be processed
346 * @throws IOException an io error
347 * @throws FormatException a syntax error
348 */
349 public void process(RIBWReader ribp, RIBLight light) throws IOException,
350 FormatException {
351 rib = ribp;
352 Enumeration i =content.elements();
353 while (i.hasMoreElements())
354 ((InstrRequest)i.nextElement()).process(this, light);
355 }
356
357 /** Process an object,
358 * @param ribp the rib file from which the object
359 * @param object the object to process
360 * @throws IOException an io error
361 * @throws FormatException a syntax error
362 */
363 public void process(RIBWReader ribp, RIBObjectGroup object) throws IOException,
364 FormatException {
365 rib = ribp;
366 Enumeration i =content.elements();
367 while (i.hasMoreElements())
368 ((InstrRequest)i.nextElement()).process(this, object);
369 }
370
371 /** process the rib file and add rib. This function is used to add the rib
372 * specified in the GlobalRIB and FrameRIB instructions cf the AddRIB instruction
373 * which works on a per object/light basis
374 * @param ribp the rib stream being processed
375 * @param header the vector to which new rib will be added if it is not an option
376 * - this will either be the GlobalHeader or FrameHeader
377 * @param option the appropriate set of global or frame options - is the RIB to be
378 * added is an option then the contents of this class will be changed, else the
379 * rib will be added to the header
380 * @param instr the instruction request ID appropriate to the type of additions
381 * to be added - in practice either GLOBALRIB or FRAMERIB
382 * @throws IOException an io error
383 * @throws FormatException a syntax error
384 */
385 //this is a dreadful hack - sort it out some time
386 public void process(RIBWReader ribp, Vector header, RIBOptionRec option,
387 int instr) throws IOException, FormatException {
388 rib = ribp;
389 Enumeration i = content.elements();
390 //Add general RIB
391 while (i.hasMoreElements()) {
392 InstrRequest is = (InstrRequest) i.nextElement();
393 if (is.requestID == instr)
394 ((InstrRIB) is).process(header, option);
395 }
396 }
397
398 public void processMisc(RIBWReader ribp, RIBOptionRec option) throws IOException, FormatException {
399 rib = ribp;
400 Enumeration i = content.elements();
401 //Add general RIB
402 while (i.hasMoreElements()) {
403 InstrRequest is = (InstrRequest) i.nextElement();
404 if (is.requestID == InstrGlobals.TIGHTCLIPPING)
405 ((InstrTightClipping) is).process(ribp, option);
406 else if (is.requestID == InstrGlobals.LIGHTDOME)
407 ((InstrLightDome) is).process(this, ribp);
408 else if (is.requestID == InstrGlobals.SIXSNAPS)
409 ((InstrSixSnaps) is).process(ribp);
410 }
411 }
412
413
414 /** find the id of a given instruction request
415 * @param name the name of the request
416 * @return the ID of the request, or throw exception if not found */
417
418 private int findID(String name) throws FormatException {
419 Integer i = (Integer) InstrGlobals.map.get(name);
420 if (i != null)
421 return i.intValue();
422 else
423 throw new FormatException("Unrecognized request",tokenizer);
424 }
425
426
427
428 }//class