00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "geom.h"
00020 #include "config_gobj.h"
00021
00022 #include "graphicsStateGuardianBase.h"
00023 #include "geometricBoundingVolume.h"
00024 #include "datagram.h"
00025 #include "datagramIterator.h"
00026 #include "bamReader.h"
00027 #include "bamWriter.h"
00028 #include "ioPtaDatagramShort.h"
00029 #include "ioPtaDatagramInt.h"
00030 #include "ioPtaDatagramLinMath.h"
00031 #include "indent.h"
00032
00033
00034
00035
00036
00037 TypeHandle Geom::_type_handle;
00038
00039
00040
00041
00042
00043 static const Vertexf &get_vertex_nonindexed(Geom::VertexIterator &vi) {
00044 return *(vi._array++);
00045 }
00046 static const Normalf &get_normal_nonindexed(Geom::NormalIterator &vi) {
00047 return *(vi._array++);
00048 }
00049 static const TexCoordf &get_texcoord_nonindexed(Geom::TexCoordIterator &vi) {
00050 return *(vi._array++);
00051 }
00052 static const Colorf &get_color_nonindexed(Geom::ColorIterator &vi) {
00053 return *(vi._array++);
00054 }
00055
00056
00057
00058
00059
00060 static const Vertexf &get_vertex_indexed(Geom::VertexIterator &vi) {
00061 return vi._array[*(vi._index++)];
00062 }
00063 static const Normalf &get_normal_indexed(Geom::NormalIterator &vi) {
00064 return vi._array[*(vi._index++)];
00065 }
00066 static const TexCoordf &get_texcoord_indexed(Geom::TexCoordIterator &vi) {
00067 return vi._array[*(vi._index++)];
00068 }
00069 static const Colorf &get_color_indexed(Geom::ColorIterator &vi) {
00070 return vi._array[*(vi._index++)];
00071 }
00072
00073
00074
00075
00076
00077 static const Vertexf &get_vertex_noop(Geom::VertexIterator &) {
00078 static Vertexf nothing;
00079 return nothing;
00080 }
00081 static const Normalf &get_normal_noop(Geom::NormalIterator &) {
00082 static Normalf nothing;
00083 return nothing;
00084 }
00085 static const TexCoordf &get_texcoord_noop(Geom::TexCoordIterator &) {
00086 static TexCoordf nothing;
00087 return nothing;
00088 }
00089 static const Colorf &get_color_noop(Geom::ColorIterator &) {
00090 static Colorf nothing;
00091 return nothing;
00092 }
00093
00094
00095
00096
00097
00098
00099 ostream &operator << (ostream &out, GeomBindType t) {
00100 switch (t) {
00101 case G_OFF:
00102 return out << "off";
00103 case G_OVERALL:
00104 return out << "overall";
00105 case G_PER_PRIM:
00106 return out << "per prim";
00107 case G_PER_COMPONENT:
00108 return out << "per component";
00109 case G_PER_VERTEX:
00110 return out << "per vertex";
00111 }
00112 return out << "(**invalid**)";
00113 }
00114
00115
00116
00117
00118
00119
00120 ostream &operator << (ostream &out, GeomAttrType t) {
00121 switch (t) {
00122 case G_COORD:
00123 return out << "coord";
00124 case G_COLOR:
00125 return out << "color";
00126 case G_NORMAL:
00127 return out << "normal";
00128 case G_TEXCOORD:
00129 return out << "texcoord";
00130 }
00131 return out << "(**invalid**)";
00132 }
00133
00134
00135
00136
00137
00138
00139 Geom::
00140 Geom(void) : dDrawable() {
00141 _prepared_gsg = (GraphicsStateGuardianBase *)NULL;
00142 _prepared_context = (GeomContext *)NULL;
00143 init();
00144 }
00145
00146
00147
00148
00149
00150
00151 Geom::
00152 Geom(const Geom& copy) : dDrawable() {
00153 _prepared_gsg = (GraphicsStateGuardianBase *)NULL;
00154 _prepared_context = (GeomContext *)NULL;
00155 *this = copy;
00156 }
00157
00158
00159
00160
00161
00162
00163 Geom::
00164 ~Geom() {
00165 unprepare();
00166 }
00167
00168
00169
00170
00171
00172
00173 void Geom::
00174 operator = (const Geom ©) {
00175 _coords = copy._coords;
00176 _norms = copy._norms;
00177 _colors = copy._colors;
00178 _texcoords = copy._texcoords;
00179
00180 _vindex = copy._vindex;
00181 _nindex = copy._nindex;
00182 _cindex = copy._cindex;
00183 _tindex = copy._tindex;
00184
00185 _numprims = copy._numprims;
00186 _num_vertices = copy._num_vertices;
00187 _primlengths = copy._primlengths;
00188 for (int i = 0; i < num_GeomAttrTypes; i++) {
00189 _bind[i] = copy._bind[i];
00190 }
00191
00192 _get_vertex = copy._get_vertex;
00193 _get_normal = copy._get_normal;
00194 _get_color = copy._get_color;
00195 _get_texcoord = copy._get_texcoord;
00196
00197 mark_bound_stale();
00198 make_dirty();
00199 }
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210 void Geom::
00211 calc_tight_bounds(LPoint3f &min_point, LPoint3f &max_point,
00212 bool &found_any) const {
00213 Geom::VertexIterator vi = make_vertex_iterator();
00214 int num_prims = get_num_prims();
00215
00216 for (int p = 0; p < num_prims; p++) {
00217 int length = get_length(p);
00218 for (int v = 0; v < length; v++) {
00219 Vertexf vertex = get_next_vertex(vi);
00220
00221 if (found_any) {
00222 min_point.set(min(min_point[0], vertex[0]),
00223 min(min_point[1], vertex[1]),
00224 min(min_point[2], vertex[2]));
00225 max_point.set(max(max_point[0], vertex[0]),
00226 max(max_point[1], vertex[1]),
00227 max(max_point[2], vertex[2]));
00228 } else {
00229 min_point = vertex;
00230 max_point = vertex;
00231 found_any = true;
00232 }
00233 }
00234 }
00235 }
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250 void Geom::
00251 transform_vertices(const LMatrix4f &mat) {
00252 PTA_Vertexf coords;
00253 PTA_ushort index;
00254 get_coords(coords, index);
00255 PTA_Vertexf new_coords;
00256 new_coords.reserve(coords.size());
00257 PTA_Vertexf::const_iterator vi;
00258 for (vi = coords.begin(); vi != coords.end(); ++vi) {
00259 new_coords.push_back((*vi) * mat);
00260 }
00261 nassertv(new_coords.size() == coords.size());
00262 set_coords(new_coords, index);
00263 }
00264
00265
00266
00267
00268
00269
00270 void Geom::
00271 set_coords(const PTA_Vertexf &coords,
00272 const PTA_ushort &vindex) {
00273 _coords = coords;
00274 _bind[G_COORD] = G_PER_VERTEX;
00275 _vindex = vindex;
00276
00277 mark_bound_stale();
00278 make_dirty();
00279 }
00280
00281
00282
00283
00284
00285
00286 void Geom::
00287 set_coords(const PTA_Vertexf &coords, GeomBindType bind,
00288 const PTA_ushort &vindex) {
00289 nassertv(bind==G_PER_VERTEX);
00290 set_coords(coords, vindex);
00291 }
00292
00293
00294
00295
00296
00297
00298 void Geom::
00299 set_normals(const PTA_Normalf &norms, GeomBindType bind,
00300 const PTA_ushort &nindex) {
00301 _norms = norms;
00302 _bind[G_NORMAL] = bind;
00303 _nindex = nindex;
00304
00305 make_dirty();
00306 }
00307
00308
00309
00310
00311
00312
00313 void Geom::
00314 set_colors(const PTA_Colorf &colors, GeomBindType bind,
00315 const PTA_ushort &cindex) {
00316 _colors = colors;
00317 _bind[G_COLOR] = bind;
00318 _cindex = cindex;
00319
00320 make_dirty();
00321 }
00322
00323
00324
00325
00326
00327
00328 void Geom::
00329 set_texcoords(const PTA_TexCoordf &texcoords, GeomBindType bind,
00330 const PTA_ushort &tindex) {
00331 _texcoords = texcoords;
00332 assert(bind == G_PER_VERTEX || bind == G_OFF);
00333 _bind[G_TEXCOORD] = bind;
00334 _tindex = tindex;
00335
00336 make_dirty();
00337 }
00338
00339
00340
00341
00342
00343
00344 void Geom::
00345 get_coords(PTA_Vertexf &coords,
00346 PTA_ushort &vindex) const {
00347 coords = _coords;
00348 vindex = _vindex;
00349
00350
00351 }
00352
00353
00354
00355
00356
00357
00358 void Geom::
00359 get_coords(PTA_Vertexf &coords, GeomBindType &bind,
00360 PTA_ushort &vindex) const {
00361 coords = _coords;
00362 bind = _bind[G_COORD];
00363 vindex = _vindex;
00364 }
00365
00366
00367
00368
00369
00370
00371 void Geom::
00372 get_normals(PTA_Normalf &norms, GeomBindType &bind,
00373 PTA_ushort &nindex) const {
00374 norms = _norms;
00375 bind = _bind[G_NORMAL];
00376 nindex = _nindex;
00377 }
00378
00379
00380
00381
00382
00383
00384 void Geom::
00385 get_colors(PTA_Colorf &colors, GeomBindType &bind,
00386 PTA_ushort &cindex) const {
00387 colors = _colors;
00388 bind = _bind[G_COLOR];
00389 cindex = _cindex;
00390 }
00391
00392
00393
00394
00395
00396
00397 void Geom::
00398 get_texcoords(PTA_TexCoordf &texcoords, GeomBindType &bind,
00399 PTA_ushort &tindex) const {
00400 texcoords = _texcoords;
00401 bind = _bind[G_TEXCOORD];
00402 tindex = _tindex;
00403 }
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414 bool Geom::
00415 is_dynamic() const {
00416 return (_vindex != (ushort*)0L);
00417 }
00418
00419
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429
00430
00431 Geom *Geom::
00432 explode() const {
00433 return make_copy();
00434 }
00435
00436
00437
00438
00439
00440
00441
00442
00443
00444
00445
00446
00447
00448
00449
00450
00451 PTA_ushort Geom::
00452 get_tris() const {
00453 return PTA_ushort();
00454 }
00455
00456
00457
00458
00459
00460
00461 void Geom::
00462 draw(GraphicsStateGuardianBase *gsg) {
00463 if (is_dirty()) {
00464 config();
00465 }
00466 if (_prepared_gsg == gsg) {
00467 draw_immediate(gsg, _prepared_context);
00468 } else {
00469 draw_immediate(gsg, (GeomContext *)NULL);
00470 }
00471 }
00472
00473
00474
00475
00476
00477
00478 void Geom::
00479 config() {
00480 WritableConfigurable::config();
00481
00482
00483 if (_coords != (Vertexf*)0L && _bind[G_COORD] != G_OFF) {
00484 _get_vertex =
00485 (_vindex == (ushort*)0L) ? get_vertex_nonindexed : get_vertex_indexed;
00486 } else {
00487 gobj_cat.error()
00488 << "Geom::Config() - no vertex array!" << endl;
00489 }
00490
00491
00492 if (_norms != (Normalf*)0L && _bind[G_NORMAL] != G_OFF) {
00493 _get_normal =
00494 (_nindex == (ushort*)0L) ? get_normal_nonindexed : get_normal_indexed;
00495 } else {
00496 _get_normal = get_normal_noop;
00497 }
00498
00499
00500 if (_texcoords != (TexCoordf*)0L && _bind[G_TEXCOORD] != G_OFF) {
00501 _get_texcoord =
00502 (_tindex == (ushort*)0L) ? get_texcoord_nonindexed : get_texcoord_indexed;
00503 } else {
00504 _get_texcoord = get_texcoord_noop;
00505 }
00506
00507
00508 if (_colors != (Colorf*)0L && _bind[G_COLOR] != G_OFF) {
00509 _get_color =
00510 (_cindex == (ushort*)0L) ? get_color_nonindexed : get_color_indexed;
00511 } else {
00512 _get_color = get_color_noop;
00513 }
00514
00515
00516 unprepare();
00517 }
00518
00519
00520
00521
00522
00523
00524 void Geom::
00525 write(ostream &out, int indent_level) const {
00526 indent(out, indent_level) << *this << endl;
00527 }
00528
00529
00530
00531
00532
00533
00534 void Geom::
00535 output(ostream &out) const {
00536 out << get_type() << " (" << _numprims << ")";
00537
00538
00539
00540
00541
00542
00543
00544
00545
00546
00547
00548 }
00549
00550
00551
00552
00553
00554
00555
00556
00557
00558
00559
00560
00561
00562 GeomContext *Geom::
00563 prepare(GraphicsStateGuardianBase *gsg) {
00564 if (gsg != _prepared_gsg) {
00565 GeomContext *gc = gsg->prepare_geom(this);
00566 if (gc != (GeomContext *)NULL) {
00567 unprepare();
00568 _prepared_context = gc;
00569 _prepared_gsg = gsg;
00570 }
00571 return gc;
00572 }
00573
00574 return _prepared_context;
00575 }
00576
00577
00578
00579
00580
00581
00582
00583 void Geom::
00584 unprepare() {
00585 if (_prepared_gsg != (GraphicsStateGuardianBase *)NULL) {
00586 _prepared_gsg->release_geom(_prepared_context);
00587 _prepared_gsg = (GraphicsStateGuardianBase *)NULL;
00588 _prepared_context = (GeomContext *)NULL;
00589 }
00590 }
00591
00592
00593
00594
00595
00596
00597
00598 void Geom::
00599 unprepare(GraphicsStateGuardianBase *gsg) {
00600 if (_prepared_gsg == gsg) {
00601 _prepared_gsg->release_geom(_prepared_context);
00602 _prepared_gsg = (GraphicsStateGuardianBase *)NULL;
00603 _prepared_context = (GeomContext *)NULL;
00604 }
00605 }
00606
00607
00608
00609
00610
00611
00612
00613
00614
00615
00616 void Geom::
00617 clear_gsg(GraphicsStateGuardianBase *gsg) {
00618 if (_prepared_gsg == gsg) {
00619 _prepared_gsg = (GraphicsStateGuardianBase *)NULL;
00620 _prepared_context = (GeomContext *)NULL;
00621 }
00622 }
00623
00624
00625
00626
00627
00628
00629 void Geom::
00630 init() {
00631 int i;
00632
00633 _coords.clear();
00634 _norms.clear();
00635 _colors.clear();
00636 _texcoords.clear();
00637 _vindex.clear();
00638 _nindex.clear();
00639 _cindex.clear();
00640 _tindex.clear();
00641 _primlengths.clear();
00642
00643 for ( i = 0; i < num_GeomAttrTypes; i++ )
00644 _bind[i] = G_OFF;
00645
00646 _get_vertex = get_vertex_noop;
00647 _get_normal = get_normal_noop;
00648 _get_texcoord = get_texcoord_noop;
00649 _get_color = get_color_noop;
00650
00651 WritableConfigurable::config();
00652 }
00653
00654
00655
00656
00657
00658
00659
00660 BoundingVolume *Geom::
00661 recompute_bound() {
00662
00663 BoundingVolume *bound = BoundedObject::recompute_bound();
00664 nassertr(bound != (BoundingVolume*)0L, bound);
00665
00666 GeometricBoundingVolume *gbv = DCAST(GeometricBoundingVolume, bound);
00667
00668
00669
00670 pvector<LPoint3f> vertices;
00671 VertexIterator vi = make_vertex_iterator();
00672
00673 for (int p = 0; p < get_num_prims(); p++) {
00674 for (int v = 0; v < get_length(p); v++) {
00675 vertices.push_back(get_next_vertex(vi));
00676 }
00677 }
00678
00679 const LPoint3f *vertices_begin = &vertices[0];
00680 const LPoint3f *vertices_end = vertices_begin + vertices.size();
00681
00682 gbv->around(vertices_begin, vertices_end);
00683
00684 return bound;
00685 }
00686
00687
00688
00689
00690
00691
00692
00693 void Geom::
00694 write_datagram(BamWriter *manager, Datagram &me) {
00695 int i;
00696
00697
00698 WRITE_PTA(manager, me, IPD_Vertexf::write_datagram, _coords)
00699
00700 WRITE_PTA(manager, me, IPD_Normalf::write_datagram, _norms)
00701
00702 WRITE_PTA(manager, me, IPD_Colorf::write_datagram, _colors)
00703
00704 WRITE_PTA(manager, me, IPD_TexCoordf::write_datagram, _texcoords)
00705
00706
00707 WRITE_PTA(manager, me, IPD_ushort::write_datagram, _vindex)
00708 WRITE_PTA(manager, me, IPD_ushort::write_datagram, _nindex)
00709 WRITE_PTA(manager, me, IPD_ushort::write_datagram, _cindex)
00710 WRITE_PTA(manager, me, IPD_ushort::write_datagram, _tindex)
00711
00712 me.add_uint16(_numprims);
00713 WRITE_PTA(manager, me, IPD_int::write_datagram, _primlengths)
00714
00715
00716
00717 for(i = 0; i < num_GeomAttrTypes; i++) {
00718 me.add_uint8(_bind[i]);
00719 }
00720 }
00721
00722
00723
00724
00725
00726
00727
00728
00729
00730
00731 void Geom::
00732 fillin(DatagramIterator& scan, BamReader* manager) {
00733 int i;
00734
00735
00736 READ_PTA(manager, scan, IPD_Vertexf::read_datagram, _coords)
00737
00738 READ_PTA(manager, scan, IPD_Normalf::read_datagram, _norms)
00739
00740 READ_PTA(manager, scan, IPD_Colorf::read_datagram, _colors)
00741
00742 READ_PTA(manager, scan, IPD_TexCoordf::read_datagram, _texcoords)
00743
00744
00745 READ_PTA(manager, scan, IPD_ushort::read_datagram, _vindex)
00746 READ_PTA(manager, scan, IPD_ushort::read_datagram, _nindex)
00747 READ_PTA(manager, scan, IPD_ushort::read_datagram, _cindex)
00748 READ_PTA(manager, scan, IPD_ushort::read_datagram, _tindex)
00749
00750 _numprims = scan.get_uint16();
00751
00752
00753 READ_PTA(manager, scan, IPD_int::read_datagram, _primlengths)
00754
00755 if (uses_components()) {
00756 _num_vertices = PTA_int_arraysum(_primlengths);
00757 } else {
00758
00759 _num_vertices = _numprims*get_num_vertices_per_prim();
00760 }
00761
00762
00763
00764 for(i = 0; i < num_GeomAttrTypes; i++) {
00765 _bind[i] = (enum GeomBindType) scan.get_uint8();
00766 }
00767 }
00768
00769
00770
00771
00772
00773
00774 template <class VecType>
00775 static void
00776 describe_attr(ostream &out, const Geom *geom,
00777 GeomBindType bind, const PTA(VecType) &array,
00778 bool newline, int indent_level) {
00779 PTA_int lengths = geom->get_lengths();
00780 int num_prims = geom->get_num_prims();
00781 bool components = geom->uses_components();
00782
00783 int i, j, vi;
00784 switch (bind) {
00785 case G_PER_VERTEX:
00786 indent(out, indent_level)
00787 << "Per vertex:";
00788 vi = 0;
00789 int num_verts;
00790 num_verts = geom->get_num_vertices_per_prim();
00791 for (i = 0; i < num_prims; i++) {
00792 if (components) {
00793 num_verts = lengths[i];
00794 }
00795 out << "\n";
00796 indent(out, indent_level) << "[ ";
00797 if (num_verts > 0) {
00798 out << array[vi++];
00799 for (j = 1; j < num_verts; j++) {
00800 if (newline) {
00801 out << "\n";
00802 indent(out, indent_level + 2);
00803 } else {
00804 out << " ";
00805 }
00806 out << array[vi++];
00807 }
00808 }
00809 out << " ]";
00810 }
00811 break;
00812
00813 case G_PER_COMPONENT:
00814 if (!components) {
00815 indent(out, indent_level)
00816 << "Invalid per-component attribute specified!";
00817 } else {
00818 indent(out, indent_level)
00819 << "Per component:";
00820 vi = 0;
00821 for (i = 0; i < num_prims; i++) {
00822 num_verts = lengths[i] - geom->get_num_more_vertices_than_components();
00823 out << "\n";
00824 indent(out, indent_level) << "[ ";
00825 if (num_verts > 0) {
00826 out << array[vi++];
00827 for (j = 1; j < num_verts; j++) {
00828 if (newline) {
00829 out << "\n";
00830 indent(out, indent_level + 2);
00831 } else {
00832 out << " ";
00833 }
00834 out << array[vi++];
00835 }
00836 out << " ]";
00837 }
00838 }
00839 }
00840 break;
00841
00842 case G_PER_PRIM:
00843 indent(out, indent_level)
00844 << "Per prim:";
00845 for (i = 0; i < num_prims; i++) {
00846 if (newline) {
00847 out << "\n";
00848 indent(out, indent_level + 2);
00849 } else {
00850 out << " ";
00851 }
00852 out << array[i];
00853 }
00854 break;
00855
00856 case G_OVERALL:
00857 indent(out, indent_level)
00858 << "Overall:";
00859 if (newline) {
00860 out << "\n";
00861 indent(out, indent_level + 2);
00862 } else {
00863 out << " ";
00864 }
00865 out << array[0];
00866
00867 case G_OFF:
00868 break;
00869 }
00870 out << "\n";
00871 }
00872
00873
00874
00875
00876
00877
00878
00879
00880 void Geom::
00881 write_verbose(ostream &out, int indent_level) const {
00882 GeomBindType bind_normals;
00883 GeomBindType bind_tcoords;
00884 GeomBindType bind_colors;
00885
00886 PTA_Vertexf g_coords;
00887 PTA_Normalf g_normals;
00888 PTA_TexCoordf g_tcoords;
00889 PTA_Colorf g_colors;
00890
00891 PTA_ushort i_coords;
00892 PTA_ushort i_normals;
00893 PTA_ushort i_tcoords;
00894 PTA_ushort i_colors;
00895
00896 get_coords(g_coords, i_coords);
00897 get_normals(g_normals, bind_normals, i_normals);
00898 get_texcoords(g_tcoords, bind_tcoords, i_tcoords);
00899 get_colors(g_colors, bind_colors, i_colors);
00900
00901 out << "\n";
00902 indent(out, indent_level)
00903 << get_type() << " contains "
00904 << get_num_prims() << " primitives:\n";
00905
00906 if ((i_coords == (ushort *)NULL) && (g_coords == (Vertexf *)NULL)) {
00907 indent(out, indent_level)
00908 << "No coords\n";
00909 } else if (i_coords!=(ushort*)0L) {
00910 indent(out, indent_level)
00911 << "Indexed coords = " << (void *)g_coords << ", length = "
00912 << g_coords.size() << ":\n";
00913 describe_attr(out, this, G_PER_VERTEX, i_coords, false, indent_level + 2);
00914 } else {
00915 indent(out, indent_level)
00916 << "Nonindexed coords:\n";
00917 describe_attr(out, this, G_PER_VERTEX, g_coords, true, indent_level + 2);
00918 }
00919
00920 if (bind_colors == G_OFF) {
00921 indent(out, indent_level)
00922 << "No colors\n";
00923 } else if (i_colors!=(ushort*)0L) {
00924 indent(out, indent_level)
00925 << "Indexed colors = " << (void *)g_colors << ", length = "
00926 << g_colors.size() << "\n";
00927 describe_attr(out, this, bind_colors, i_colors, false, indent_level + 2);
00928 } else {
00929 indent(out, indent_level)
00930 << "Nonindexed colors:\n";
00931 describe_attr(out, this, bind_colors, g_colors, true, indent_level + 2);
00932 }
00933
00934 if (bind_tcoords == G_OFF) {
00935 indent(out, indent_level)
00936 << "No tcoords\n";
00937 } else if (i_tcoords!=(ushort*)0L) {
00938 indent(out, indent_level)
00939 << "Indexed tcoords = " << (void *)g_tcoords << ", length = "
00940 << g_tcoords.size() << "\n";
00941 describe_attr(out, this, bind_tcoords, i_tcoords, false, indent_level + 2);
00942 } else {
00943 indent(out, indent_level)
00944 << "Nonindexed tcoords:\n";
00945 describe_attr(out, this, bind_tcoords, g_tcoords, true, indent_level + 2);
00946 }
00947
00948 if (bind_normals == G_OFF) {
00949 indent(out, indent_level)
00950 << "No normals\n";
00951 } else if (i_normals!=(ushort*)0L) {
00952 indent(out, indent_level)
00953 << "Indexed normals = " << (void *)g_normals << ", length = "
00954 << g_normals.size() << "\n";
00955 describe_attr(out, this, bind_normals, i_normals, false, indent_level + 2);
00956 } else {
00957 indent(out, indent_level)
00958 << "Nonindexed normals:\n";
00959 describe_attr(out, this, bind_normals, g_normals, true, indent_level + 2);
00960 }
00961 }