1 /* ************************
2    Copyright Terrain Experts Inc.
3    Terrain Experts Inc (TERREX) reserves all rights to this source code
4    unless otherwise specified in writing by the President of TERREX.
5    This copyright may be updated in the future, in which case that version
6    supercedes this one.
7    -------------------
8    Terrex Experts Inc.
9    4400 East Broadway #314
10    Tucson, AZ  85711
11    info@terrex.com
12    Tel: (520) 323-7990
13    ************************
14    */
15 
16 #include <stdlib.h>
17 #include <stdio.h>
18 #include <string.h>
19 
20 /* trpage_nodes.cpp
21    The methods for all the hierarchy nodes (e.g. groups, transforms, etc...)
22    is here.
23    You should only need to modify this if you want to add something to one
24    of these classes.
25 */
26 
27 #include <trpage_geom.h>
28 #include <trpage_read.h>
29 
30 /* Write Group
31    Basic group.
32 */
33 
34 // Constructor
trpgGroup()35 trpgGroup::trpgGroup()
36 {
37     name = 0;
38     Reset();
39 
40 }
~trpgGroup()41 trpgGroup::~trpgGroup()
42 {
43     Reset();
44 }
45 
46 // Reset
Reset()47 void trpgGroup::Reset()
48 {
49     numChild = 0;
50     id = -1;
51     if ( name ) {
52         delete [] name;
53         name = 0;
54     }
55 }
56 
57 // Set functions
SetNumChild(int no)58 void trpgGroup::SetNumChild(int no)
59 {
60     numChild = no;
61 }
AddChild()62 int trpgGroup::AddChild()
63 {
64     numChild++;
65     return numChild-1;
66 }
SetID(int inID)67 void trpgGroup::SetID(int inID)
68 {
69     id = inID;
70 }
71 
SetName(const char * newname)72 void trpgGroup::SetName(const char* newname )
73 {
74     if ( name )
75     {
76         delete [] name;
77         name = 0;
78     }
79     if (newname)
80     {
81         if ( strlen(newname) )
82         {
83             name = new char[strlen(newname)+1];
84             strcpy(name,newname);
85         }
86     }
87 }
88 
89 // Get methods
GetName(void) const90 const char* trpgGroup::GetName(void) const
91 {
92     return name;
93 }
94 
GetNumChild(int & n) const95 bool trpgGroup::GetNumChild(int &n) const
96 {
97     if (!isValid())  return false;
98     n = numChild;
99     return true;
100 }
GetID(int & inID) const101 bool trpgGroup::GetID(int &inID) const
102 {
103     if (!isValid()) return false;
104     inID = id;
105     return true;
106 }
107 
108 // Validity check
isValid() const109 bool trpgGroup::isValid() const
110 {
111     if (numChild <= 0)  return false;
112     if (id < 0)  return false;
113 
114     return true;
115 }
116 
117 // Write group
Write(trpgWriteBuffer & buf)118 bool trpgGroup::Write(trpgWriteBuffer &buf)
119 {
120     if (!isValid())
121         return false;
122 
123     buf.Begin(TRPG_GROUP);
124     buf.Add(numChild);
125     buf.Add(id);
126 
127     if ( name && strlen(name) ) {
128         buf.Add(name);
129     }
130 
131     buf.End();
132 
133     return true;
134 }
135 
136 // Read group
Read(trpgReadBuffer & buf)137 bool trpgGroup::Read(trpgReadBuffer &buf)
138 {
139     try {
140         buf.Get(numChild);
141         if (numChild < 0) throw 1;
142         buf.Get(id);
143         if (id < 0) throw 1;
144         if ( !buf.isEmpty() ) {
145             char nm[1024] = {0};
146             buf.Get(nm,1024);
147             SetName(nm);
148         }
149     }
150     catch (...) {
151         return false;
152     }
153 
154     return isValid();
155 }
156 
157 /* Write Billboard
158    Represents rotational billboarded geometry.
159 */
160 
161 // Constructor
trpgBillboard()162 trpgBillboard::trpgBillboard()
163 {
164     name = 0;
165     Reset();
166 }
~trpgBillboard()167 trpgBillboard::~trpgBillboard()
168 {
169     Reset();
170 }
171 
172 // Reset function
Reset()173 void trpgBillboard::Reset()
174 {
175     id = -1;
176     mode = Axial;
177     type = Group;
178     axis = trpg3dPoint(0,0,1);
179     center = trpg3dPoint(0,0,0);
180     numChild = 0;
181     if ( name )
182     {
183         delete [] name;
184         name = 0;
185     }
186 }
187 
188 // Set functions
SetCenter(const trpg3dPoint & pt)189 void trpgBillboard::SetCenter(const trpg3dPoint &pt)
190 {
191     center = pt;
192     valid = true;
193 }
SetMode(int m)194 void trpgBillboard::SetMode(int m)
195 {
196     mode = m;
197 }
SetAxis(const trpg3dPoint & pt)198 void trpgBillboard::SetAxis(const trpg3dPoint &pt)
199 {
200     axis = pt;
201 }
SetType(int t)202 void trpgBillboard::SetType(int t)
203 {
204     type = t;
205 }
206 
207 // Get methods
GetCenter(trpg3dPoint & pt) const208 bool trpgBillboard::GetCenter(trpg3dPoint &pt) const
209 {
210     if (!isValid()) return false;
211     pt = center;
212     return true;
213 }
GetMode(int & m) const214 bool trpgBillboard::GetMode(int &m) const
215 {
216     if (!isValid()) return false;
217     m = mode;
218     return true;
219 }
GetAxis(trpg3dPoint & pt) const220 bool trpgBillboard::GetAxis(trpg3dPoint &pt) const
221 {
222     if (!isValid()) return false;
223     pt = axis;
224     return true;
225 }
GetType(int & t) const226 bool trpgBillboard::GetType(int &t) const
227 {
228     if (!isValid()) return false;
229     t = type;
230     return true;
231 }
232 
233 // Write billboard
Write(trpgWriteBuffer & buf)234 bool trpgBillboard::Write(trpgWriteBuffer &buf)
235 {
236     if (!isValid())
237         return false;
238 
239     buf.Begin(TRPG_BILLBOARD);
240     buf.Add(numChild);
241     buf.Add(id);
242     buf.Add((uint8)type);
243     buf.Add((uint8)mode);
244     buf.Add(center);
245     buf.Add(axis);
246 
247     if ( name && strlen(name) ) {
248         buf.Add(name);
249     }
250     buf.End();
251 
252     return true;
253 }
254 
255 // Read billboard
Read(trpgReadBuffer & buf)256 bool trpgBillboard::Read(trpgReadBuffer &buf)
257 {
258     uint8 uChar;
259 
260     try {
261         buf.Get(numChild);
262         buf.Get(id);
263         buf.Get(uChar);  type = uChar;
264         buf.Get(uChar);  mode = uChar;
265         buf.Get(center);
266         buf.Get(axis);
267         if ( !buf.isEmpty() ) {
268             char nm[1024] = {0};
269             buf.Get(nm,1024);
270             SetName(nm);
271         }
272     }
273     catch (...) {
274         return false;
275     }
276 
277     return isValid();
278 }
279 
280 /* Write Level of Detail
281    Represents LOD information.
282 */
283 
284 // Constructor
trpgLod()285 trpgLod::trpgLod()
286 {
287     name = 0;
288     Reset();
289 }
~trpgLod()290 trpgLod::~trpgLod()
291 {
292     Reset();
293 }
294 
295 // Reset function
Reset()296 void trpgLod::Reset()
297 {
298     id = -1;
299     numRange = 0;
300     center = trpg3dPoint(0,0,0);
301     switchIn = switchOut = width = 0;
302     rangeIndex = -1;
303     valid = true;
304     if ( name ) {
305         delete [] name;
306         name = 0;
307     }
308 }
309 
310 // Set functions
SetCenter(const trpg3dPoint & pt)311 void trpgLod::SetCenter(const trpg3dPoint &pt)
312 {
313     center = pt;
314     valid = true;
315 }
SetNumChild(int no)316 void trpgLod::SetNumChild(int no)
317 {
318     if (no < 0)
319         return;
320 
321     numRange = no;
322 }
SetLOD(double in,double out,double wid)323 void trpgLod::SetLOD(double in,double out,double wid)
324 {
325     switchIn = in;
326     switchOut = out;
327     width = wid;
328 }
SetID(int inID)329 void trpgLod::SetID(int inID)
330 {
331     id = inID;
332 }
333 
SetName(const char * newname)334 void trpgLod::SetName(const char* newname )
335 {
336     if ( name ) {
337         delete [] name;
338         name = 0;
339     }
340     if (newname) {
341         if ( strlen(newname) ) {
342             name = new char[strlen(newname)+1];
343             strcpy(name,newname);
344         }
345     }
346 }
347 
SetRangeIndex(int ri)348 void trpgLod::SetRangeIndex(int ri)
349 {
350     rangeIndex = ri;
351 }
352 
353 // Get methods
GetName(void) const354 const char* trpgLod::GetName(void) const
355 {
356     return name;
357 }
358 
359 // Get functions
GetCenter(trpg3dPoint & pt) const360 bool trpgLod::GetCenter(trpg3dPoint &pt) const
361 {
362     if (!isValid()) return false;
363     pt = center;
364     return true;
365 }
GetNumChild(int & n) const366 bool trpgLod::GetNumChild(int &n) const
367 {
368     if (!isValid()) return false;
369     n = numRange;
370     return true;
371 }
GetLOD(double & in,double & out,double & wid) const372 bool trpgLod::GetLOD(double &in,double &out,double &wid) const
373 {
374     if (!isValid()) return false;
375     in = switchIn;
376     out = switchOut;
377     wid = width;
378     return true;
379 }
GetID(int & outID) const380 bool trpgLod::GetID(int &outID) const
381 {
382     if (!isValid()) return false;
383     outID = id;
384     return true;
385 }
GetRangeIndex(int & ri) const386 bool trpgLod::GetRangeIndex(int &ri) const
387 {
388     if (!isValid()) return false;
389 
390     ri = rangeIndex;
391 
392     return true;
393 }
394 
395 // Write out LOD
Write(trpgWriteBuffer & buf)396 bool trpgLod::Write(trpgWriteBuffer &buf)
397 {
398     if (!isValid())
399         return false;
400 
401     buf.Begin(TRPG_LOD);
402     buf.Add(id);
403     buf.Add(numRange);
404     buf.Add(center);
405     buf.Add(switchIn);
406     buf.Add(switchOut);
407     buf.Add(width);
408 
409     if ( name && strlen(name) ) {
410         buf.Add(name);
411     } else
412         buf.Add("");
413 
414 
415     buf.End();
416 
417     return true;
418 }
419 
420 // Read in LOD
Read(trpgReadBuffer & buf)421 bool trpgLod::Read(trpgReadBuffer &buf)
422 {
423     try {
424         buf.Get(id);
425         buf.Get(numRange);
426         if (numRange < 0) throw 1;
427         buf.Get(center);
428         buf.Get(switchIn);
429         buf.Get(switchOut);
430         buf.Get(width);
431         if ( !buf.isEmpty() ) {
432             char nm[1024] = {0};
433             buf.Get(nm,1024);
434             if (*nm)
435                 SetName(nm);
436             // Look for a range index
437             if (!buf.isEmpty())
438                 buf.Get(rangeIndex);
439         }
440     }
441     catch (...) {
442         return false;
443     }
444 
445     return isValid();
446 }
447 
448 /* Write Layer
449    A layer is just a group with a different opcode.
450 */
451 
452 // Constructor
trpgLayer()453 trpgLayer::trpgLayer()
454 {
455     name = 0;
456 }
457 
~trpgLayer()458 trpgLayer::~trpgLayer()
459 {
460     Reset();
461 }
462 
463 // Write it
Write(trpgWriteBuffer & buf)464 bool trpgLayer::Write(trpgWriteBuffer &buf)
465 {
466     if (!isValid())
467         return false;
468 
469     buf.Begin(TRPG_LAYER);
470     buf.Add(numChild);
471     buf.Add(id);
472 
473     if ( name && strlen(name) ) {
474         buf.Add(name);
475     }
476 
477     buf.End();
478 
479     return true;
480 }
481 
482 // Read layer
Read(trpgReadBuffer & buf)483 bool trpgLayer::Read(trpgReadBuffer &buf)
484 {
485     try {
486         buf.Get(numChild);
487         if (numChild < 0) throw 1;
488         buf.Get(id);
489         if (id < 0) throw 1;
490         if ( !buf.isEmpty() ) {
491             char nm[1024] = {0};
492             buf.Get(nm,1024);
493             SetName(nm);
494         }
495     }
496     catch (...) {
497         return false;
498     }
499 
500     return isValid();
501 }
502 
503 // Reset function
Reset()504 void trpgLayer::Reset()
505 {
506     numChild = 0;
507     if ( name ) {
508         delete [] name;
509         name = 0;
510     }
511 }
512 
513 /* Write Transform
514    Matrix defining the transform with children.
515 */
516 
517 // Constructor
trpgTransform()518 trpgTransform::trpgTransform()
519 {
520     name = 0;
521     Reset();
522 }
~trpgTransform()523 trpgTransform::~trpgTransform()
524 {
525     Reset();
526 }
527 
528 // Reset function
Reset()529 void trpgTransform::Reset()
530 {
531     id = -1;
532     // Note: Is this row major or column major?
533     m[0][0] = 1; m[0][1] = 0; m[0][2] = 0; m[0][3] = 0;
534     m[1][0] = 0; m[1][1] = 1; m[1][2] = 0; m[1][3] = 0;
535     m[2][0] = 0; m[2][1] = 0; m[2][2] = 1; m[2][3] = 0;
536     m[3][0] = 0; m[3][1] = 0; m[3][2] = 0; m[3][3] = 1;
537 
538     if ( name ) {
539         delete [] name;
540         name = 0;
541     }
542 }
543 
544 // Set functions
SetMatrix(const float64 * im)545 void trpgTransform::SetMatrix(const float64 *im)
546 {
547     m[0][0] = im[4*0+0]; m[0][1] = im[4*0+1]; m[0][2] = im[4*0+2]; m[0][3] = im[4*0+3];
548     m[1][0] = im[4*1+0]; m[1][1] = im[4*1+1]; m[1][2] = im[4*1+2]; m[1][3] = im[4*1+3];
549     m[2][0] = im[4*2+0]; m[2][1] = im[4*2+1]; m[2][2] = im[4*2+2]; m[2][3] = im[4*2+3];
550     m[3][0] = im[4*3+0]; m[3][1] = im[4*3+1]; m[3][2] = im[4*3+2]; m[3][3] = im[4*3+3];
551 }
552 
553 // Get methods
GetMatrix(float64 * rm) const554 bool trpgTransform::GetMatrix(float64 *rm) const
555 {
556     if (!isValid()) return false;
557     for (int i=0;i<4;i++)
558         for (int j=0;j<4;j++)
559             // Note: is this right?
560             rm[i*4+j] = m[i][j];
561     return true;
562 }
563 
564 // Write transform
Write(trpgWriteBuffer & buf)565 bool trpgTransform::Write(trpgWriteBuffer &buf)
566 {
567     if (!isValid())
568         return false;
569 
570     buf.Begin(TRPG_TRANSFORM);
571     buf.Add(numChild);
572     buf.Add(id);
573     for (int i=0;i<4;i++)
574         for (int j=0;j<4;j++)
575             buf.Add(m[i][j]);
576 
577     if ( name && strlen(name) ) {
578         buf.Add(name);
579     }
580     buf.End();
581 
582     return true;
583 }
584 
585 // Read transform
Read(trpgReadBuffer & buf)586 bool trpgTransform::Read(trpgReadBuffer &buf)
587 {
588     try {
589         buf.Get(numChild);
590         buf.Get(id);
591         if (numChild < 0) throw 1;
592         for (int i=0;i<4;i++)
593             for (int j=0;j<4;j++)
594             buf.Get(m[i][j]);
595         if ( !buf.isEmpty() ) {
596             char nm[1024] = {0};
597             buf.Get(nm,1024);
598             SetName(nm);
599         }
600     }
601     catch (...) {
602         return false;
603     }
604 
605     return isValid();
606 }
607 
608 /* Model Reference
609    This is just a matrix transform and a model ID.
610 */
611 
612 // Constructor
trpgModelRef()613 trpgModelRef::trpgModelRef()
614 {
615     Reset();
616 }
617 
~trpgModelRef()618 trpgModelRef::~trpgModelRef()
619 {
620 }
621 
622 // Reset function
Reset()623 void trpgModelRef::Reset()
624 {
625     m[0][0] = 1; m[0][1] = 0; m[0][2] = 0; m[0][3] = 0;
626     m[1][0] = 0; m[1][1] = 1; m[1][2] = 0; m[1][3] = 0;
627     m[2][0] = 0; m[2][1] = 0; m[2][2] = 1; m[2][3] = 0;
628     m[3][0] = 0; m[3][1] = 0; m[3][2] = 0; m[3][3] = 1;
629     modelRef = -1;
630 }
631 
632 // Set functions
SetModel(int id)633 void trpgModelRef::SetModel(int id)
634 {
635     modelRef = id;
636     valid = true;
637 }
SetMatrix(const float64 * im)638 void trpgModelRef::SetMatrix(const float64 *im)
639 {
640     m[0][0] = im[4*0+0]; m[0][1] = im[4*0+1]; m[0][2] = im[4*0+2]; m[0][3] = im[4*0+3];
641     m[1][0] = im[4*1+0]; m[1][1] = im[4*1+1]; m[1][2] = im[4*1+2]; m[1][3] = im[4*1+3];
642     m[2][0] = im[4*2+0]; m[2][1] = im[4*2+1]; m[2][2] = im[4*2+2]; m[2][3] = im[4*2+3];
643     m[3][0] = im[4*3+0]; m[3][1] = im[4*3+1]; m[3][2] = im[4*3+2]; m[3][3] = im[4*3+3];
644 }
645 
646 // Get methods
GetModel(int32 & mod) const647 bool trpgModelRef::GetModel(int32 &mod) const
648 {
649     if (!isValid()) return false;
650     mod = modelRef;
651     return true;
652 }
GetMatrix(float64 * rm) const653 bool trpgModelRef::GetMatrix(float64 *rm) const
654 {
655     if (!isValid()) return false;
656     for (int i=0;i<4;i++)
657         for (int j=0;j<4;j++)
658             // Note: is this right?
659             rm[i*4+j] = m[i][j];
660     return true;
661 }
662 
663 // Write model reference
Write(trpgWriteBuffer & buf)664 bool trpgModelRef::Write(trpgWriteBuffer &buf)
665 {
666     if (!isValid())
667         return false;
668 
669     buf.Begin(TRPG_MODELREF);
670     buf.Add(modelRef);
671     for (int i=0;i<4;i++)
672         for (int j=0;j<4;j++)
673             buf.Add(m[i][j]);
674     buf.End();
675 
676     return true;
677 }
678 
679 // Read model reference
Read(trpgReadBuffer & buf)680 bool trpgModelRef::Read(trpgReadBuffer &buf)
681 {
682     try {
683         buf.Get(modelRef);
684         if (modelRef < 0)
685             throw 1;
686         for (int i=0;i<4;i++)
687             for (int j=0;j<4;j++)
688                 buf.Get(m[i][j]);
689     }
690     catch (...) {
691         return false;
692     }
693 
694     valid = true;
695     return isValid();
696 }
697 
698 /* Attach Node
699    You'll find one of these in each tile, except for the lowest LOD.
700    It's basically a group with some extra info that tells you where to attach it.
701    The ID corresponds to the one in Group and LOD.
702 */
703 
704 // Constructor
trpgAttach()705 trpgAttach::trpgAttach()
706 {
707     name = 0;
708     Reset();
709 }
~trpgAttach()710 trpgAttach::~trpgAttach()
711 {
712     Reset();
713 }
714 
715 // Reset
Reset()716 void trpgAttach::Reset()
717 {
718     parentID = -1;
719     childPos = -1;
720     if ( name ) {
721         delete [] name;
722         name = 0;
723     }
724 }
725 
726 // Parent ID is the node this one gets attached to
SetParentID(int pid)727 void trpgAttach::SetParentID(int pid)
728 {
729     parentID = pid;
730 }
GetParentID(int & pid) const731 bool trpgAttach::GetParentID(int &pid) const
732 {
733     if (!isValid()) return false;
734     pid = parentID;
735     return true;
736 }
737 
738 // Child Position is a unique number of parent
739 // It could be used as an array index, for example
SetChildPos(int cid)740 void trpgAttach::SetChildPos(int cid)
741 {
742     childPos = cid;
743 }
GetChildPos(int & cid) const744 bool trpgAttach::GetChildPos(int &cid) const
745 {
746     if (!isValid()) return false;
747     cid = childPos;
748     return true;
749 }
750 
751 // Validity check
isValid() const752 bool trpgAttach::isValid() const
753 {
754     if (parentID < 0 || childPos < 0) return false;
755     return true;
756 }
757 
758 // Write Attach node
Write(trpgWriteBuffer & buf)759 bool trpgAttach::Write(trpgWriteBuffer &buf)
760 {
761     if (!isValid()) return false;
762 
763     buf.Begin(TRPG_ATTACH);
764     buf.Add(numChild);
765     buf.Add(id);
766     buf.Add(parentID);
767     buf.Add(childPos);
768 
769     if ( name && strlen(name) ) {
770         buf.Add(name);
771     }
772 
773     buf.End();
774 
775     return true;
776 }
777 
778 // Read Attach node
Read(trpgReadBuffer & buf)779 bool trpgAttach::Read(trpgReadBuffer &buf)
780 {
781     try {
782         buf.Get(numChild);
783         buf.Get(id);
784         if (id < 0)  throw 1;
785         buf.Get(parentID);
786         if (parentID < 0) throw 1;
787         buf.Get(childPos);
788         if (childPos < 0) throw 1;
789         if ( !buf.isEmpty() ) {
790             char nm[1024] = {0};
791             buf.Get(nm,1024);
792             SetName(nm);
793         }
794     }
795     catch (...) {
796         return false;
797     }
798 
799     return true;
800 }
801 
802 /* ChildRef Node
803    You'll find in the parent tile one of these for each tile children.
804    It gives the children grid location and file address.
805 */
806 
807 // Constructor
trpgChildRef()808 trpgChildRef::trpgChildRef()
809 {
810     Reset();
811 }
~trpgChildRef()812 trpgChildRef::~trpgChildRef()
813 {
814     Reset();
815 }
816 
817 // Reset
Reset()818 void trpgChildRef::Reset()
819 {
820     zmin = 0.0f;
821     zmax = 0.0f;
822     x = -1;
823     y = -1;
824     lod = -1;
825     addr.file = -1;
826     addr.offset = -1;
827 }
828 
SetTileLoc(int gx,int gy,int glod)829 void trpgChildRef::SetTileLoc(int gx,int gy,int glod)
830 {
831     x = gx;
832     y = gy;
833     lod = glod;
834 }
835 
GetTileLoc(int & gx,int & gy,int & glod) const836 bool trpgChildRef::GetTileLoc(int &gx,int &gy,int &glod) const
837 {
838     if (!isValid()) return false;
839 
840     gx = x;
841     gy = y;
842     glod = lod;
843 
844     return true;
845 }
846 
SetTileAddress(const trpgwAppAddress & gAddr)847 void trpgChildRef::SetTileAddress(const trpgwAppAddress& gAddr)
848 {
849     addr = gAddr;
850 }
SetTileAddress(int32 file,int32 offset)851 void trpgChildRef::SetTileAddress(int32 file, int32 offset)
852 {
853     addr.file = file;
854     addr.offset = offset;
855 }
GetTileAddress(int32 & file,int32 & offset) const856 bool trpgChildRef::GetTileAddress(int32& file, int32& offset) const
857 {
858     if (!isValid()) return false;
859 
860     file = addr.file;
861     offset = addr.offset;
862 
863     return true;
864 
865 }
866 
GetTileAddress(trpgwAppAddress & gAddr) const867 bool trpgChildRef::GetTileAddress(trpgwAppAddress& gAddr) const
868 {
869     if (!isValid()) return false;
870 
871     gAddr = addr;
872 
873     return true;
874 }
875 
SetTileZValue(float gZmin,float gZmax)876 void trpgChildRef::SetTileZValue( float gZmin, float gZmax)
877 {
878     zmin = gZmin;
879     zmax = gZmax;
880 }
881 
GetTileZValue(float & gZmin,float & gZmax) const882 bool trpgChildRef::GetTileZValue( float& gZmin, float& gZmax) const
883 {
884     if (!isValid()) return false;
885 
886     gZmin = zmin;
887     gZmax = zmax;
888 
889     return true;
890 }
891 
892 
893 // Validity check
isValid() const894 bool trpgChildRef::isValid() const
895 {
896     if (lod < 0)
897     return false;
898     return true;
899 }
900 
901 
902 // Write Attach node
Write(trpgWriteBuffer & buf)903 bool trpgChildRef::Write(trpgWriteBuffer &buf)
904 {
905     if (!isValid()) return false;
906 
907     buf.Begin(TRPG_CHILDREF);
908 
909     buf.Add(lod);
910     buf.Add(x);
911     buf.Add(y);
912     buf.Add(addr.file);
913     buf.Add(addr.offset);
914     buf.Add(zmin);
915     buf.Add(zmax);
916 
917     buf.End();
918 
919     return true;
920 }
921 
922 // Read Attach node
Read(trpgReadBuffer & buf)923 bool trpgChildRef::Read(trpgReadBuffer &buf)
924 {
925     try
926     {
927 
928         buf.Get(lod);
929         if (lod <  0) throw 1;
930         buf.Get(x);
931         buf.Get(y);
932         buf.Get(addr.file);
933         buf.Get(addr.offset);
934         buf.Get(zmin);
935         buf.Get(zmax);
936 
937     }
938     catch (...)
939     {
940         return false;
941     }
942 
943     return true;
944 }
945 
946