0025133: TKOpenGl - Crash on closing a view containing presentations with capping
[occt.git] / src / VrmlData / VrmlData_Node.cxx
1 // Created on: 2006-05-25
2 // Created by: Alexander GRIGORIEV
3 // Copyright (c) 2006-2014 OPEN CASCADE SAS
4 //
5 // This file is part of Open CASCADE Technology software library.
6 //
7 // This library is free software; you can redistribute it and/or modify it under
8 // the terms of the GNU Lesser General Public License version 2.1 as published
9 // by the Free Software Foundation, with special exception defined in the file
10 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11 // distribution for complete text of the license and disclaimer of any warranty.
12 //
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
15
16 #include <Precision.hxx>
17 #include <VrmlData_Appearance.hxx>
18 #include <VrmlData_ImageTexture.hxx>
19 #include <VrmlData_Material.hxx>
20 #include <VrmlData_ShapeNode.hxx>
21 #include <VrmlData_UnknownNode.hxx>
22 #include <VrmlData_Scene.hxx>
23 #include <VrmlData_InBuffer.hxx>
24 #include <gp_XY.hxx>
25 #include <gp_XYZ.hxx>
26
27 #ifdef WNT
28 #define _CRT_SECURE_NO_DEPRECATE
29 #pragma warning (disable:4996)
30 #endif
31
32 IMPLEMENT_STANDARD_HANDLE  (VrmlData_Node, Standard_Transient)
33 IMPLEMENT_STANDARD_RTTIEXT (VrmlData_Node, Standard_Transient)
34 IMPLEMENT_STANDARD_HANDLE  (VrmlData_ShapeNode, VrmlData_Node)
35 IMPLEMENT_STANDARD_RTTIEXT (VrmlData_ShapeNode, VrmlData_Node)
36 IMPLEMENT_STANDARD_HANDLE  (VrmlData_Texture, VrmlData_Node)
37 IMPLEMENT_STANDARD_RTTIEXT (VrmlData_Texture, VrmlData_Node)
38 IMPLEMENT_STANDARD_HANDLE  (VrmlData_TextureTransform, VrmlData_Node)
39 IMPLEMENT_STANDARD_RTTIEXT (VrmlData_TextureTransform, VrmlData_Node)
40 IMPLEMENT_STANDARD_HANDLE  (VrmlData_ImageTexture, VrmlData_Texture)
41 IMPLEMENT_STANDARD_RTTIEXT (VrmlData_ImageTexture, VrmlData_Texture)
42 IMPLEMENT_STANDARD_HANDLE  (VrmlData_Appearance, VrmlData_Node)
43 IMPLEMENT_STANDARD_RTTIEXT (VrmlData_Appearance, VrmlData_Node)
44 IMPLEMENT_STANDARD_HANDLE  (VrmlData_UnknownNode, VrmlData_Node)
45 IMPLEMENT_STANDARD_RTTIEXT (VrmlData_UnknownNode, VrmlData_Node)
46
47 static VrmlData_Scene MyDefaultScene;
48
49 //=======================================================================
50 //function : IsEqual
51 //purpose  : Global method
52 //=======================================================================
53
54 Standard_Boolean IsEqual (const Handle(VrmlData_Node)& theOne,
55                           const Handle(VrmlData_Node)& theTwo)
56 {
57   Standard_Boolean aResult (Standard_False);
58   if (theOne->Name() != 0L && theTwo->Name() != 0L)
59     aResult = (strcmp (theOne->Name(), theTwo->Name()) == 0);
60   return aResult;
61 }
62
63 //=======================================================================
64 //function : HashCode
65 //purpose  : Global method
66 //=======================================================================
67
68 Standard_Integer HashCode(const Handle(VrmlData_Node)& theNode,
69                           const Standard_Integer       theUpper)
70 {
71   return (theNode->Name() == 0L ? 0
72           : HashCode((Standard_CString)theNode->Name(), theUpper));
73 }
74
75 //=======================================================================
76 //function : VrmlData_Node
77 //purpose  : 
78 //=======================================================================
79
80 VrmlData_Node::VrmlData_Node ()
81   : myScene (&MyDefaultScene),
82     myName  (0L) {}
83
84 //=======================================================================
85 //function : VrmlData_Node
86 //purpose  : Constructor
87 //=======================================================================
88
89 VrmlData_Node::VrmlData_Node (const VrmlData_Scene& theScene,
90                               const char            * theName)
91   : myScene   (&theScene)
92 {
93   if (theName == 0L)
94     theName = "";
95   setName (theName);
96 }
97
98 //=======================================================================
99 //function : Clone
100 //purpose  : Create a copy of this node.
101 //=======================================================================
102
103 Handle(VrmlData_Node) VrmlData_Node::Clone
104                                 (const Handle(VrmlData_Node)& theOther) const
105 {
106   if (theOther.IsNull() == Standard_False) {
107     if (theOther->IsKind (DynamicType()) == Standard_False)
108       return NULL;
109     if (&theOther->Scene() == myScene)
110       theOther->myName = myName;
111     else
112       theOther->setName (myName);
113   }
114   return theOther;
115 }
116
117 //=======================================================================
118 //function : setName
119 //purpose  : 
120 //=======================================================================
121
122 void VrmlData_Node::setName (const char * theName, const char * theSuffix)
123 {
124   size_t len[2] = {
125     strlen(theName) + 1,
126     0
127   };
128   if (theSuffix)
129     len[1] = strlen (theSuffix);
130   char * aName = (char *)Scene().Allocator()->Allocate(len[0]+len[1]);
131   myName = aName;
132   memcpy (aName, theName, len[0]);
133   if (len[1])
134     memcpy (&aName[len[0] - 1], theSuffix, len[1]+1);
135 }
136
137 //=======================================================================
138 //function : IsDefault
139 //purpose  : 
140 //=======================================================================
141
142 Standard_Boolean VrmlData_Node::IsDefault () const
143 {
144   return Standard_False;
145 }
146
147
148 //=======================================================================
149 //function : Write
150 //purpose  : 
151 //=======================================================================
152
153 VrmlData_ErrorStatus VrmlData_Node::Write (const char *) const
154 {
155   return VrmlData_NotImplemented;
156 }
157
158 //=======================================================================
159 //function : WriteClosing
160 //purpose  : 
161 //=======================================================================
162
163 VrmlData_ErrorStatus VrmlData_Node::WriteClosing () const
164 {
165   VrmlData_ErrorStatus aResult = Scene().Status();
166   if (aResult == VrmlData_StatusOK || aResult == VrmlData_NotImplemented)
167     aResult = Scene().WriteLine ("}", 0L, -GlobalIndent());
168   return aResult;
169 }
170
171 //=======================================================================
172 //function : readBrace
173 //purpose  : 
174 //=======================================================================
175
176 VrmlData_ErrorStatus VrmlData_Node::readBrace (VrmlData_InBuffer& theBuffer)
177 {
178   VrmlData_ErrorStatus aStatus;
179   if (OK(aStatus, VrmlData_Scene::ReadLine(theBuffer))) {
180     if (theBuffer.LinePtr[0] == '}')
181       theBuffer.LinePtr++;
182     else
183       aStatus = VrmlData_VrmlFormatError;
184   }
185   return aStatus;
186 }
187
188 //=======================================================================
189 //function : ReadBoolean
190 //purpose  : 
191 //=======================================================================
192
193 VrmlData_ErrorStatus VrmlData_Node::ReadBoolean (VrmlData_InBuffer& theBuffer,
194                                                  Standard_Boolean&  theResult)
195 {
196   VrmlData_ErrorStatus aStatus;
197   if (OK(aStatus, VrmlData_Scene::ReadLine(theBuffer))) {
198     if (VRMLDATA_LCOMPARE (theBuffer.LinePtr, "TRUE"))
199       theResult = Standard_True;
200     else if (VRMLDATA_LCOMPARE (theBuffer.LinePtr, "FALSE"))
201       theResult = Standard_False;
202     else
203       aStatus = VrmlData_BooleanInputError;
204   }
205   return aStatus;
206 }
207
208 //=======================================================================
209 //function : ReadInteger
210 //purpose  : 
211 //=======================================================================
212
213 VrmlData_ErrorStatus VrmlData_Node::ReadInteger (VrmlData_InBuffer& theBuffer,
214                                                  long&              theResult)
215 {
216   VrmlData_ErrorStatus aStatus;
217   if (OK(aStatus, VrmlData_Scene::ReadLine(theBuffer))) {
218     char * endptr;
219     long aResult;
220     aResult = strtol (theBuffer.LinePtr, &endptr, 10);
221     if (endptr == theBuffer.LinePtr)
222       aStatus = VrmlData_NumericInputError;
223     else {
224       theResult = aResult;
225       theBuffer.LinePtr = endptr;
226     }
227   }
228   return aStatus;
229 }
230
231 //=======================================================================
232 //function : ReadString
233 //purpose  : 
234 //=======================================================================
235
236 VrmlData_ErrorStatus VrmlData_Node::ReadString
237                                 (VrmlData_InBuffer& theBuffer,
238                                  TCollection_AsciiString&  theResult)
239 {
240   VrmlData_ErrorStatus aStatus;
241   if (OK(aStatus, VrmlData_Scene::ReadLine(theBuffer))) {
242     if (theBuffer.LinePtr[0] != '\"')
243       aStatus = VrmlData_StringInputError;
244     else {
245       char * ptr = &theBuffer.LinePtr[1];
246       while (*ptr != '\0' && *ptr != '\"')
247         ptr++;
248       if (*ptr == '\0')
249         aStatus = VrmlData_StringInputError;
250       else {
251         *ptr = '\0';
252         theResult = (Standard_CString) &theBuffer.LinePtr[1];
253         theBuffer.LinePtr = ptr+1;
254       }
255     }
256   }
257   return aStatus;
258 }
259
260 //=======================================================================
261 //function : ReadMultiString
262 //purpose  : 
263 //=======================================================================
264
265 VrmlData_ErrorStatus VrmlData_Node::ReadMultiString
266                         (VrmlData_InBuffer&                         theBuffer,
267                          NCollection_List<TCollection_AsciiString>& theResult)
268 {
269   VrmlData_ErrorStatus aStatus;
270   Standard_Boolean isBracketed (Standard_False);
271   // Read the list of URL
272   if (OK(aStatus, VrmlData_Scene::ReadLine(theBuffer))) {
273     if (theBuffer.LinePtr[0] == '[') {
274       theBuffer.LinePtr++;
275       isBracketed = Standard_True;
276     }
277     while (OK(aStatus, VrmlData_Scene::ReadLine(theBuffer))) {
278       if (isBracketed && theBuffer.LinePtr[0] == ']') { // closing bracket
279         theBuffer.LinePtr++;
280         break;
281       }
282       TCollection_AsciiString aString;
283       if (!OK(aStatus, ReadString(theBuffer, aString)))
284         break;
285       theResult.Append(aString);
286       if (isBracketed == Standard_False ||
287           !OK(aStatus, VrmlData_Scene::ReadLine(theBuffer)))
288         break;
289       if (theBuffer.LinePtr[0] == ',') {
290         theBuffer.LinePtr++;
291         continue;
292       } else if (theBuffer.LinePtr[0] == ']') // closing bracket
293         theBuffer.LinePtr++;
294       else
295         aStatus = VrmlData_VrmlFormatError;
296       break;
297     }
298   }
299   return aStatus;
300 }
301
302 //=======================================================================
303 //function : ReadNode
304 //purpose  : 
305 //=======================================================================
306
307 VrmlData_ErrorStatus VrmlData_Node::ReadNode
308                                 (VrmlData_InBuffer&             theBuffer,
309                                  Handle(VrmlData_Node)&         theNode,
310                                  const Handle(Standard_Type)&   theType)
311 {
312   Handle(VrmlData_Node) aNode;
313   VrmlData_ErrorStatus  aStatus;
314   // First line of a new node should identify this node type
315   if (OK(aStatus, VrmlData_Scene::ReadLine(theBuffer))) {
316     if (VRMLDATA_LCOMPARE(theBuffer.LinePtr, "USE")) {
317       TCollection_AsciiString aName;
318       aStatus = VrmlData_Scene::ReadWord (theBuffer, aName);
319       if (aStatus == VrmlData_StatusOK) {
320         aNode = myScene->FindNode (aName.ToCString(), theType);
321         if (aNode.IsNull())
322           aStatus = VrmlData_NodeNameUnknown;
323 //         else
324 //           aNode = aNode->Clone(0L);
325       }
326     }
327
328     // We create a relevant node using the line with the type ID
329     else if (OK(aStatus,
330                 const_cast<VrmlData_Scene *>(myScene)->createNode (theBuffer,
331                                                                    aNode,
332                                                                    theType)))
333       if (aNode.IsNull() == Standard_False)
334         // The node data are read here, including the final closing brace
335         aStatus = aNode->Read(theBuffer);
336
337     if (aStatus == VrmlData_StatusOK)
338       theNode = aNode;
339   }
340   return aStatus;
341 }
342
343 //=======================================================================
344 //function : VrmlData_ShapeNode::Clone
345 //purpose  : 
346 //=======================================================================
347
348 Handle(VrmlData_Node) VrmlData_ShapeNode::Clone
349                                 (const Handle(VrmlData_Node)& theOther) const
350 {
351   Handle(VrmlData_ShapeNode) aResult =
352     Handle(VrmlData_ShapeNode)::DownCast (VrmlData_Node::Clone(theOther));
353   if (aResult.IsNull())
354     aResult= new VrmlData_ShapeNode(theOther.IsNull()?Scene():theOther->Scene(),
355                                     Name());
356   if (&aResult->Scene() == &Scene()) {
357     aResult->SetAppearance (myAppearance);
358     aResult->SetGeometry   (myGeometry);
359   } else {
360     // Create a dummy node to pass the different Scene instance to methods Clone
361     const Handle(VrmlData_UnknownNode) aDummyNode =
362       new VrmlData_UnknownNode (aResult->Scene());
363     if (myAppearance.IsNull() == Standard_False)
364       aResult->SetAppearance(Handle(VrmlData_Appearance)::DownCast
365                              (myAppearance->Clone (aDummyNode)));
366     if (myGeometry.IsNull() == Standard_False)
367       aResult->SetGeometry (Handle(VrmlData_Geometry)::DownCast
368                             (myGeometry->Clone (aDummyNode)));
369   }
370   return aResult;
371 }
372
373 //=======================================================================
374 //function : VrmlData_ShapeNode::Read
375 //purpose  : 
376 //=======================================================================
377
378 VrmlData_ErrorStatus VrmlData_ShapeNode::Read (VrmlData_InBuffer& theBuffer)
379 {
380   VrmlData_ErrorStatus aStatus;
381   while (OK(aStatus, VrmlData_Scene::ReadLine(theBuffer))) {
382     if (VRMLDATA_LCOMPARE (theBuffer.LinePtr, "appearance"))
383       aStatus = ReadNode (theBuffer, myAppearance,
384                           STANDARD_TYPE(VrmlData_Appearance));
385     else if (VRMLDATA_LCOMPARE (theBuffer.LinePtr, "geometry"))
386       aStatus = ReadNode (theBuffer, myGeometry);
387 // here we do not check for the Geometry type because unknown node types can
388 // occur (IndexedLineSet, etc.)
389 //                          STANDARD_TYPE(VrmlData_Geometry));
390     else
391       break;
392
393     if (!OK(aStatus))
394       break;
395   }
396
397   // Read the terminating (closing) brace
398   if (OK(aStatus))
399     aStatus = readBrace (theBuffer);
400   return aStatus;
401 }
402
403 //=======================================================================
404 //function : VrmlData_ShapeNode::Write
405 //purpose  : 
406 //=======================================================================
407
408 VrmlData_ErrorStatus VrmlData_ShapeNode::Write (const char * thePrefix) const
409 {
410   VrmlData_ErrorStatus aStatus (VrmlData_StatusOK);
411   const VrmlData_Scene& aScene = Scene();
412   static char header[] = "Shape {";
413   if (OK (aStatus, aScene.WriteLine (thePrefix, header, GlobalIndent())))
414   {
415     if (myAppearance.IsNull() == Standard_False)
416       aStatus = aScene.WriteNode ("appearance", myAppearance);
417     if (myGeometry.IsNull() == Standard_False && OK(aStatus))
418       aStatus = aScene.WriteNode ("geometry", myGeometry);
419
420     aStatus = WriteClosing();
421   }
422   return aStatus;
423 }  
424
425 //=======================================================================
426 //function : VrmlData_ShapeNode::IsDefault
427 //purpose  : 
428 //=======================================================================
429
430 Standard_Boolean VrmlData_ShapeNode::IsDefault () const
431 {
432   Standard_Boolean aResult (Standard_True);
433   if (myGeometry.IsNull() == Standard_False)
434     aResult = myGeometry->IsDefault();
435   return aResult;
436 }
437
438 //=======================================================================
439 //function : VrmlData_UnknownNode::Read
440 //purpose  : 
441 //=======================================================================
442
443 VrmlData_ErrorStatus VrmlData_UnknownNode::Read (VrmlData_InBuffer& theBuffer)
444 {
445   VrmlData_ErrorStatus aStatus = VrmlData_StatusOK;
446   Standard_Integer aLevelCounter (0);
447   // This loop searches for any opening brace.
448   // Such brace increments the level counter. A closing brace decrements
449   // the counter. The loop terminates when the counter becomes negative.
450   while (aLevelCounter >= 0 &&
451          OK(aStatus, VrmlData_Scene::ReadLine(theBuffer)))
452   {
453     int aChar;
454     while ((aChar = theBuffer.LinePtr[0]) != '\0') {
455       theBuffer.LinePtr++;
456       if        (aChar == '{') {
457         aLevelCounter++;
458         break;
459       } else if (aChar == '}') {
460         aLevelCounter--;
461         break;
462       }
463     }
464   }
465   return aStatus;
466 }
467
468 //=======================================================================
469 //function : VrmlData_UnknownNode::IsDefault
470 //purpose  : 
471 //=======================================================================
472
473 Standard_Boolean VrmlData_UnknownNode::IsDefault () const
474 {
475   return Standard_True;
476 }
477
478 //=======================================================================
479 //function : VrmlData_Appearance::Clone
480 //purpose  : 
481 //=======================================================================
482
483 Handle(VrmlData_Node) VrmlData_Appearance::Clone
484                                 (const Handle(VrmlData_Node)& theOther) const
485 {
486   Handle(VrmlData_Appearance) aResult =
487     Handle(VrmlData_Appearance)::DownCast (VrmlData_Node::Clone(theOther));
488   if (aResult.IsNull())
489     aResult = new VrmlData_Appearance
490       (theOther.IsNull() ? Scene() : theOther->Scene(), Name());
491   if (&aResult->Scene() == &Scene()) {
492     aResult->SetMaterial          (myMaterial);
493     aResult->SetTexture           (myTexture);
494     aResult->SetTextureTransform  (myTTransform);
495   } else {
496     // Create a dummy node to pass the different Scene instance to methods Clone
497     const Handle(VrmlData_UnknownNode) aDummyNode =
498       new VrmlData_UnknownNode (aResult->Scene());
499     if (myMaterial.IsNull()   == Standard_False)
500       aResult->SetMaterial (Handle(VrmlData_Material)::DownCast
501                             (myMaterial->Clone (aDummyNode)));
502     if (myTexture.IsNull()    == Standard_False)
503       aResult->SetTexture(Handle(VrmlData_Texture)::DownCast
504                           (myTexture->Clone (aDummyNode)));
505     if (myTTransform.IsNull() == Standard_False)
506       aResult->SetTextureTransform(Handle(VrmlData_TextureTransform)::DownCast
507                                    (myTTransform->Clone (aDummyNode)));
508   }
509   return aResult;
510 }
511
512 //=======================================================================
513 //function : VrmlData_Appearance::Read
514 //purpose  : 
515 //=======================================================================
516
517 VrmlData_ErrorStatus VrmlData_Appearance::Read (VrmlData_InBuffer& theBuffer)
518 {
519   VrmlData_ErrorStatus aStatus;
520   while (OK(aStatus, VrmlData_Scene::ReadLine(theBuffer))) {
521     if (VRMLDATA_LCOMPARE (theBuffer.LinePtr, "material"))
522       aStatus = ReadNode (theBuffer, myMaterial,
523                           STANDARD_TYPE(VrmlData_Material));
524     else if (VRMLDATA_LCOMPARE (theBuffer.LinePtr, "textureTransform"))
525       aStatus = ReadNode (theBuffer, myTTransform
526                           /*,STANDARD_TYPE(VrmlData_TextureTransform)*/);
527     else if (VRMLDATA_LCOMPARE (theBuffer.LinePtr, "texture"))
528       aStatus = ReadNode (theBuffer, myTexture,
529                           STANDARD_TYPE(VrmlData_Texture));
530     else
531       break;
532
533     if (!OK(aStatus))
534       break;
535   }
536
537   // Read the terminating (closing) brace
538   if (OK(aStatus))
539     aStatus = readBrace (theBuffer);
540   return aStatus;
541 }
542
543 //=======================================================================
544 //function : VrmlData_Appearance::Write
545 //purpose  : 
546 //=======================================================================
547
548 VrmlData_ErrorStatus VrmlData_Appearance::Write (const char * thePrefix) const
549 {
550   static char header[] = "Appearance {";
551   VrmlData_ErrorStatus aStatus;
552   const VrmlData_Scene& aScene = Scene();
553   if (OK (aStatus, aScene.WriteLine (thePrefix, header, GlobalIndent())))
554   {
555     if (myMaterial.IsNull() == Standard_False)
556       aStatus = aScene.WriteNode ("material", myMaterial);
557     if (myTexture.IsNull() == Standard_False && OK(aStatus))
558       aStatus = aScene.WriteNode ("texture", myTexture);
559     if (myTTransform.IsNull() == Standard_False && OK(aStatus))
560       aStatus = aScene.WriteNode ("textureTransform", myTTransform);
561
562     aStatus = WriteClosing();
563   }
564   return aStatus;
565 }
566
567 //=======================================================================
568 //function : IsDefault
569 //purpose  : 
570 //=======================================================================
571
572 Standard_Boolean VrmlData_Appearance::IsDefault () const
573 {
574   Standard_Boolean aResult (Standard_True);
575   if (myMaterial.IsNull() == Standard_False)
576     aResult = myMaterial->IsDefault();
577   if (aResult == Standard_False)
578     if (myTexture.IsNull() == Standard_False)
579       aResult = myTexture->IsDefault();
580   if (aResult == Standard_False)
581     if (myTTransform.IsNull() == Standard_False)
582       aResult = myTTransform->IsDefault();
583   return aResult;
584 }
585
586 //=======================================================================
587 //function : VrmlData_ImageTexture
588 //purpose  : Constructor
589 //=======================================================================
590
591 VrmlData_ImageTexture::VrmlData_ImageTexture (const VrmlData_Scene&  theScene,
592                                               const char             * theName,
593                                               const char             * theURL,
594                                               const Standard_Boolean theRepS,
595                                               const Standard_Boolean theRepT)
596   : VrmlData_Texture (theScene, theName, theRepS, theRepT),
597     myURL            (theScene.Allocator())
598 {
599   myURL.Append (theURL ? (Standard_CString)theURL : "");
600 }
601
602 //=======================================================================
603 //function : VrmlData_ImageTexture::Clone
604 //purpose  : 
605 //=======================================================================
606
607 Handle(VrmlData_Node) VrmlData_ImageTexture::Clone
608                                 (const Handle(VrmlData_Node)& theOther) const
609 {
610   Handle(VrmlData_ImageTexture) aResult =
611     Handle(VrmlData_ImageTexture)::DownCast (VrmlData_Node::Clone(theOther));
612   if (aResult.IsNull())
613     aResult =
614       new VrmlData_ImageTexture(theOther.IsNull() ? Scene() : theOther->Scene(),
615                                 Name());
616   aResult->myURL = myURL;
617   return aResult;
618 }
619
620 //=======================================================================
621 //function : VrmlData_ImageTexture::Read
622 //purpose  : 
623 //=======================================================================
624
625 VrmlData_ErrorStatus VrmlData_ImageTexture::Read (VrmlData_InBuffer& theBuffer)
626 {
627   VrmlData_ErrorStatus aStatus;
628   Standard_Boolean aRepeatS (Standard_True), aRepeatT (Standard_True);
629   myURL.Clear();
630   while (OK(aStatus, VrmlData_Scene::ReadLine(theBuffer))) {
631     if      (VRMLDATA_LCOMPARE (theBuffer.LinePtr, "url"))
632       aStatus = ReadMultiString (theBuffer, myURL);
633     else if (VRMLDATA_LCOMPARE (theBuffer.LinePtr, "repeatS"))
634       aStatus = ReadBoolean (theBuffer, aRepeatS);
635     else if (VRMLDATA_LCOMPARE (theBuffer.LinePtr, "repeatT"))
636       aStatus = ReadBoolean (theBuffer, aRepeatT);
637     else
638       break;
639
640     if (!OK(aStatus))
641       break;
642   }
643   if (OK(aStatus) && OK(aStatus, readBrace (theBuffer))) {
644     SetRepeatS (aRepeatS);
645     SetRepeatT (aRepeatT);
646   }
647   return aStatus;
648 }
649