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