00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052 #include "GLState.hh"
00053
00054
00055
00056
00057
00058 namespace ACG {
00059
00060
00061
00062
00063
00064 const Vec4f GLState::default_clear_color(0.0, 0.0, 0.0, 1.0);
00065 const Vec4f GLState::default_base_color(1.0, 1.0, 1.0, 1.0);
00066 const Vec4f GLState::default_ambient_color(0.2, 0.2, 0.2, 1.0);
00067 const Vec4f GLState::default_diffuse_color(0.50, 0.53, 0.6, 1.0);
00068 const Vec4f GLState::default_specular_color(0.75, 0.8, 0.85, 1.0);
00069 const float GLState::default_shininess(100.0);
00070
00071
00072
00073
00074
00075 GLState::GLState(bool _updateGL)
00076 : multisampling_(false),
00077 allow_multisampling_(true),
00078 updateGL_(_updateGL),
00079 blending_(false),
00080 msSinceLastRedraw_ (1)
00081 {
00082 initialize();
00083 }
00084
00085
00086
00087
00088
00089 void GLState::initialize()
00090 {
00091
00092 while (!stack_projection_.empty())
00093 stack_projection_.pop();
00094 while (!stack_modelview_.empty())
00095 stack_modelview_.pop();
00096 while (!stack_inverse_projection_.empty())
00097 stack_inverse_projection_.pop();
00098 while (!stack_inverse_modelview_.empty())
00099 stack_inverse_modelview_.pop();
00100
00101
00102
00103 reset_projection();
00104 reset_modelview();
00105
00106
00107
00108 set_clear_color(default_clear_color);
00109 set_base_color(default_base_color);
00110 set_ambient_color(default_ambient_color);
00111 set_diffuse_color(default_diffuse_color);
00112 set_specular_color(default_specular_color);
00113 set_shininess(default_shininess);
00114
00115
00116
00117 set_point_size(1.0f);
00118 set_line_width(1.0f);
00119
00120
00121 set_multisampling(true);
00122
00123
00124 set_twosided_lighting(true);
00125 }
00126
00127
00128
00129 void GLState::setState ()
00130 {
00131 makeCurrent();
00132
00133
00134 glMatrixMode(GL_PROJECTION);
00135 glLoadMatrixd(projection_.get_raw_data());
00136 glMatrixMode(GL_MODELVIEW);
00137
00138
00139 glLoadMatrixd(modelview_.get_raw_data());
00140
00141
00142 glClearColor(clear_color_[0], clear_color_[1], clear_color_[2], clear_color_[3]);
00143
00144
00145 glColor4fv(base_color_.data());
00146
00147
00148 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, ambient_color_.data());
00149
00150
00151 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, diffuse_color_.data());
00152
00153
00154 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, specular_color_.data());
00155
00156
00157 glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, shininess_);
00158
00159
00160 glPointSize(point_size_);
00161
00162
00163 glLineWidth(line_width_);
00164
00165
00166 if (twosided_lighting_)
00167 glLightModeli( GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE );
00168 else
00169 glLightModeli( GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE );
00170
00171
00172 glViewport(left_, bottom_, width_, height_);
00173 }
00174
00175
00176
00177
00178 void GLState::clearBuffers ()
00179 {
00180 glPushAttrib (GL_ALL_ATTRIB_BITS);
00181
00182 glDisable(GL_DEPTH_TEST);
00183 glDisable(GL_LIGHTING);
00184 glDisable(GL_DITHER);
00185 glShadeModel( GL_FLAT );
00186
00187 glMatrixMode(GL_PROJECTION);
00188 glPushMatrix();
00189 glLoadIdentity ();
00190
00191 glMatrixMode(GL_MODELVIEW);
00192 glPushMatrix();
00193 glLoadIdentity ();
00194
00195 glColor4fv(clear_color_.data());
00196 glBegin (GL_QUADS);
00197 glVertex3f (-1.0, -1.0, 1.0);
00198 glVertex3f (1.0, -1.0, 1.0);
00199 glVertex3f (1.0, 1.0, 1.0);
00200 glVertex3f (-1.0, 1.0, 1.0);
00201 glEnd ();
00202
00203 glPopMatrix ();
00204 glMatrixMode(GL_PROJECTION);
00205 glPopMatrix();
00206 glMatrixMode(GL_MODELVIEW);
00207 glPopAttrib ();
00208 }
00209
00210
00211
00212 void GLState::reset_projection()
00213 {
00214 projection_.identity();
00215 inverse_projection_.identity();
00216
00217 if (updateGL_)
00218 {
00219 makeCurrent();
00220 glMatrixMode(GL_PROJECTION);
00221 glLoadIdentity();
00222 glMatrixMode(GL_MODELVIEW);
00223 }
00224
00225 update_matrices();
00226 }
00227
00228
00229
00230
00231
00232 void GLState::set_projection(const GLMatrixd& _m, const GLMatrixd& _inv_m)
00233 {
00234 projection_ = _m;
00235 inverse_projection_ = _inv_m;
00236
00237 if (updateGL_)
00238 {
00239 makeCurrent();
00240 glMatrixMode(GL_PROJECTION);
00241 glLoadMatrixd(projection_.get_raw_data());
00242 glMatrixMode(GL_MODELVIEW);
00243 }
00244
00245 update_matrices();
00246 }
00247
00248
00249
00250
00251
00252 void GLState::reset_modelview()
00253 {
00254 modelview_.identity();
00255 inverse_modelview_.identity();
00256
00257 if (updateGL_)
00258 {
00259 makeCurrent();
00260 glLoadIdentity();
00261 }
00262
00263 update_matrices();
00264 }
00265
00266
00267
00268
00269
00270 void GLState::set_modelview(const GLMatrixd& _m, const GLMatrixd& _inv_m)
00271 {
00272 modelview_ = _m;
00273 inverse_modelview_ = _inv_m;
00274
00275 if (updateGL_)
00276 {
00277 makeCurrent();
00278 glLoadMatrixd(modelview_.get_raw_data());
00279 }
00280
00281 update_matrices();
00282 }
00283
00284
00285
00286
00287
00288 void GLState::ortho( double _left, double _right,
00289 double _bottom, double _top,
00290 double _n, double _f )
00291 {
00292 near_plane_ = _n;
00293 far_plane_ = _f;
00294
00295 projection_.ortho(_left, _right, _bottom, _top, _n, _f);
00296 inverse_projection_.inverse_ortho(_left,_right,_bottom,_top,_n,_f);
00297
00298 if (updateGL_)
00299 {
00300 makeCurrent();
00301 glMatrixMode(GL_PROJECTION);
00302 glOrtho(_left, _right, _bottom, _top, _n, _f);
00303 glMatrixMode(GL_MODELVIEW);
00304 }
00305
00306 update_matrices();
00307 }
00308
00309
00310
00311
00312
00313 void GLState::frustum( double _left, double _right,
00314 double _bottom, double _top,
00315 double _n, double _f )
00316 {
00317 near_plane_ = _n;
00318 far_plane_ = _f;
00319
00320 projection_.frustum(_left, _right, _bottom, _top, _n, _f);
00321 inverse_projection_.inverse_frustum(_left,_right,_bottom,_top,_n,_f);
00322
00323 if (updateGL_)
00324 {
00325 makeCurrent();
00326 glMatrixMode(GL_PROJECTION);
00327 glFrustum(_left, _right, _bottom, _top, _n, _f);
00328 glMatrixMode(GL_MODELVIEW);
00329 }
00330
00331 update_matrices();
00332 }
00333
00334
00335
00336
00337
00338 void GLState::perspective( double _fovY, double _aspect,
00339 double _n, double _f )
00340 {
00341 near_plane_ = _n;
00342 far_plane_ = _f;
00343
00344 projection_.perspective(_fovY, _aspect, _n, _f);
00345 inverse_projection_.inverse_perspective(_fovY, _aspect, _n, _f);
00346
00347 if (updateGL_)
00348 {
00349 makeCurrent();
00350 glMatrixMode(GL_PROJECTION);
00351 gluPerspective(_fovY, _aspect, _n, _f);
00352 glMatrixMode(GL_MODELVIEW);
00353 }
00354
00355 update_matrices();
00356 }
00357
00358
00359
00360
00361
00362 void GLState::viewport( int _left, int _bottom,
00363 int _width, int _height,
00364 int _glwidth, int _glheight)
00365 {
00366 left_ = _left;
00367 bottom_ = _bottom;
00368 width_ = _width;
00369 height_ = _height;
00370
00371 if (_glwidth < _width || _glheight < _height)
00372 {
00373 glwidth_ = _width;
00374 glheight_ = _height;
00375 } else {
00376 glwidth_ = _glwidth;
00377 glheight_ = _glheight;
00378 }
00379
00380 window2viewport_.identity();
00381 window2viewport_(0,0) = 0.5f * width_;
00382 window2viewport_(0,3) = 0.5f * width_ + left_;
00383 window2viewport_(1,1) = 0.5f * height_;
00384 window2viewport_(1,3) = 0.5f * height_ + bottom_;
00385 window2viewport_(2,2) = 0.5f;
00386 window2viewport_(2,3) = 0.5f;
00387
00388 inverse_window2viewport_.identity();
00389 inverse_window2viewport_(0,0) = 2.0f / width_;
00390 inverse_window2viewport_(0,3) = -(2.0*left_ + width_) / width_;
00391 inverse_window2viewport_(1,1) = 2.0f / height_;
00392 inverse_window2viewport_(1,3) = -(2.0*bottom_ + height_) / height_;
00393 inverse_window2viewport_(2,2) = 2.0f;
00394 inverse_window2viewport_(2,3) = -1.0f;
00395
00396 if (updateGL_)
00397 {
00398 makeCurrent();
00399 glViewport(_left, _bottom, _width, _height);
00400 }
00401
00402 update_matrices();
00403 }
00404
00405
00406
00407
00408
00409 void GLState::lookAt( const Vec3d& _eye,
00410 const Vec3d& _center,
00411 const Vec3d& _up )
00412 {
00413 modelview_.lookAt(_eye, _center, _up);
00414 inverse_modelview_.inverse_lookAt(_eye, _center, _up);
00415
00416 if (updateGL_)
00417 {
00418 makeCurrent();
00419 gluLookAt(_eye[0],
00420 _eye[1],
00421 _eye[2],
00422 _center[0],
00423 _center[1],
00424 _center[2],
00425 _up[0],
00426 _up[1],
00427 _up[2]);
00428 }
00429
00430 update_matrices();
00431 }
00432
00433
00434
00435
00436
00437 void GLState::translate( double _x, double _y, double _z,
00438 MultiplyFrom _mult_from )
00439 {
00440 if (_mult_from == MULT_FROM_RIGHT)
00441 {
00442 modelview_.translate(_x, _y, _z);
00443 inverse_modelview_.translate(-_x, -_y, -_z, MULT_FROM_LEFT);
00444 }
00445 else
00446 {
00447 modelview_.translate(_x, _y, _z, MULT_FROM_LEFT);
00448 inverse_modelview_.translate(-_x, -_y, -_z);
00449 }
00450
00451 if (updateGL_)
00452 {
00453 makeCurrent();
00454 glLoadMatrixd(modelview_.get_raw_data());
00455 }
00456
00457 update_matrices();
00458 }
00459
00460
00461
00462
00463
00464 void GLState::rotate( double _angle, double _x, double _y, double _z,
00465 MultiplyFrom _mult_from )
00466 {
00467 if (_mult_from == MULT_FROM_RIGHT)
00468 {
00469 modelview_.rotate(_angle, _x, _y, _z);
00470 inverse_modelview_.rotate(-_angle, _x, _y, _z, MULT_FROM_LEFT);
00471 }
00472 else
00473 {
00474 modelview_.rotate(_angle, _x, _y, _z, MULT_FROM_LEFT);
00475 inverse_modelview_.rotate(-_angle, _x, _y, _z);
00476 }
00477
00478 if (updateGL_)
00479 {
00480 makeCurrent();
00481 glLoadMatrixd(modelview_.get_raw_data());
00482 }
00483
00484 update_matrices();
00485 }
00486
00487
00488
00489
00490
00491 void GLState::scale( double _sx, double _sy, double _sz,
00492 MultiplyFrom _mult_from )
00493 {
00494 if (_mult_from == MULT_FROM_RIGHT)
00495 {
00496 modelview_.scale(_sx, _sy, _sz, MULT_FROM_RIGHT);
00497 inverse_modelview_.scale(1.0f/_sx, 1.0f/_sy, 1.0f/_sz, MULT_FROM_LEFT);
00498 }
00499 else
00500 {
00501 modelview_.scale(_sx, _sy, _sz, MULT_FROM_LEFT);
00502 inverse_modelview_.scale(1.0f/_sx, 1.0f/_sy, 1.0f/_sz, MULT_FROM_RIGHT);
00503 }
00504
00505 if (updateGL_)
00506 {
00507 makeCurrent();
00508 glLoadMatrixd(modelview_.get_raw_data());
00509 }
00510
00511 update_matrices();
00512 }
00513
00514
00515
00516
00517
00518 void GLState::mult_matrix( const GLMatrixd& _m, const GLMatrixd& _inv_m,
00519 MultiplyFrom _mult_from )
00520 {
00521 if (_mult_from == MULT_FROM_RIGHT)
00522 {
00523 modelview_ *= _m;
00524 inverse_modelview_.leftMult(_inv_m);
00525 }
00526 else
00527 {
00528 modelview_.leftMult(_m);
00529 inverse_modelview_ *= _inv_m;
00530 }
00531
00532 if (updateGL_)
00533 {
00534 makeCurrent();
00535 glLoadMatrixd(modelview_.get_raw_data());
00536 }
00537
00538 update_matrices();
00539 }
00540
00541
00542
00543
00544
00545 void GLState::update_matrices()
00546 {
00547 forward_projection_ = window2viewport_;
00548 forward_projection_ *= projection_;
00549 forward_projection_ *= modelview_;
00550
00551 backward_projection_ = inverse_modelview_;
00552 backward_projection_ *= inverse_projection_;
00553 backward_projection_ *= inverse_window2viewport_;
00554 }
00555
00556
00557
00558
00559
00560 Vec3d GLState::project(const Vec3d& _point) const
00561 {
00562 return forward_projection_.transform_point(_point);
00563 }
00564
00565
00566
00567
00568
00569 Vec3d GLState::unproject(const Vec3d& _winPoint) const
00570 {
00571 return backward_projection_.transform_point(_winPoint);
00572 }
00573
00574
00575
00576
00577
00578 void GLState::set_clear_color(const Vec4f& _col)
00579 {
00580 clear_color_ = _col;
00581
00582 if (updateGL_)
00583 {
00584 makeCurrent();
00585 glClearColor(_col[0], _col[1], _col[2], _col[3]);
00586 }
00587 }
00588
00589
00590
00591
00592
00593 void GLState::set_base_color(const Vec4f& _col)
00594 {
00595 base_color_ = _col;
00596
00597 if (updateGL_)
00598 {
00599 makeCurrent();
00600 glColor4fv(_col.data());
00601 }
00602 }
00603
00604
00605
00606
00607
00608 void GLState::set_ambient_color(const Vec4f& _col)
00609 {
00610 ambient_color_ = _col;
00611
00612 if (updateGL_)
00613 {
00614 makeCurrent();
00615 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, _col.data());
00616 }
00617 }
00618
00619
00620
00621
00622
00623 void GLState::set_diffuse_color(const Vec4f& _col)
00624 {
00625 diffuse_color_ = _col;
00626
00627 if (updateGL_)
00628 {
00629 makeCurrent();
00630 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, _col.data());
00631 }
00632 }
00633
00634
00635
00636
00637
00638 void GLState::set_specular_color(const Vec4f& _col)
00639 {
00640 specular_color_ = _col;
00641
00642 if (updateGL_)
00643 {
00644 makeCurrent();
00645 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, _col.data());
00646 }
00647 }
00648
00649
00650
00651
00652
00653 void GLState::set_shininess(float _shininess)
00654 {
00655 shininess_ = _shininess;
00656
00657 if (updateGL_)
00658 {
00659 makeCurrent();
00660 glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, _shininess);
00661 }
00662 }
00663
00664
00665
00666
00667
00668 void GLState::set_point_size(float _f)
00669 {
00670 point_size_ = _f;
00671
00672 if (updateGL_)
00673 {
00674 makeCurrent();
00675 glPointSize(point_size_);
00676 }
00677 }
00678
00679
00680
00681
00682
00683 void GLState::set_line_width(float _f)
00684 {
00685 line_width_ = _f;
00686
00687 if (updateGL_)
00688 {
00689 makeCurrent();
00690 glLineWidth(line_width_);
00691 }
00692 }
00693
00694
00695
00696
00697
00698 void GLState::set_twosided_lighting(bool _b)
00699 {
00700 twosided_lighting_ = _b;
00701
00702 if (updateGL_)
00703 {
00704 makeCurrent();
00705 if (twosided_lighting_)
00706 glLightModeli( GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE );
00707 else
00708 glLightModeli( GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE );
00709 }
00710 }
00711
00712
00713
00714
00715 void GLState::set_multisampling(bool _b)
00716 {
00717
00718 multisampling_ = _b;
00719
00720 if (updateGL_)
00721 {
00722 makeCurrent();
00723 if ( allow_multisampling_ ) {
00724
00725 if ( _b )
00726 glEnable( GL_MULTISAMPLE );
00727 else
00728 glDisable( GL_MULTISAMPLE );
00729
00730 } else {
00731
00732 multisampling_ = false;
00733
00734 if ( glIsEnabled( GL_MULTISAMPLE ) )
00735 glDisable( GL_MULTISAMPLE );
00736
00737 }
00738 }
00739
00740 }
00741
00742
00743
00744 double GLState::fovy() const
00745 {
00746 assert(projection_(0,0) != 0.0);
00747
00748 return atan(1.0/projection_(0,0))*2.0;
00749 }
00750
00751
00752
00753 double GLState::aspect() const
00754 {
00755 assert(projection_(1,1) != 0.0);
00756
00757 return projection_(0,0) / projection_(1,1);
00758 }
00759
00760
00761
00762 Vec3d GLState::eye() const
00763 {
00764 return inverse_modelview_.transform_point(Vec3d(0.0, 0.0, 0.0));
00765 }
00766
00767
00768
00769
00770 Vec3d GLState::viewing_direction(int _x, int _y) const
00771 {
00772 Vec3d dir = ( unproject(Vec3d(_x, _y, 1.0)) -
00773 unproject(Vec3d(_x, _y, 0.0)) );
00774 dir.normalize();
00775 return dir;
00776 }
00777
00778
00779
00780
00781
00782 Vec3d GLState::up() const
00783 {
00784 Vec3d dir( unproject(Vec3d(0.5*width_, height_-1, 0.0)) -
00785 unproject(Vec3d(0.5*width_, 0.5*height_, 0.0)) );
00786 dir.normalize();
00787 return dir;
00788 }
00789
00790
00791
00792
00793
00794 Vec3d GLState::right() const
00795 {
00796 Vec3d dir( unproject(Vec3d(width_-1, 0.5*height_, 0.0)) -
00797 unproject(Vec3d(0.5*width_, 0.5*height_, 0.0)) );
00798 dir.normalize();
00799 return dir;
00800 }
00801
00802
00803
00804
00805
00806 void GLState::viewing_ray( int _x, int _y,
00807 Vec3d& _origin, Vec3d& _direction) const
00808 {
00809 _origin = unproject(Vec3d(_x, _y, 0.0));
00810 _direction = unproject(Vec3d(_x, _y, 1.0)) - _origin;
00811 _direction.normalize();
00812 }
00813
00814
00815
00816
00817
00818 void GLState::push_projection_matrix()
00819 {
00820 stack_projection_.push(projection_);
00821 stack_inverse_projection_.push(inverse_projection_);
00822
00823 if (updateGL_)
00824 {
00825 makeCurrent();
00826 glMatrixMode(GL_PROJECTION);
00827 glPushMatrix();
00828 glMatrixMode(GL_MODELVIEW);
00829 }
00830 }
00831
00832
00833
00834
00835
00836 void GLState::pop_projection_matrix()
00837 {
00838 projection_ = stack_projection_.top();
00839 inverse_projection_ = stack_inverse_projection_.top();
00840
00841 stack_projection_.pop();
00842 stack_inverse_projection_.pop();
00843
00844 update_matrices();
00845
00846 if (updateGL_)
00847 {
00848 makeCurrent();
00849 glMatrixMode(GL_PROJECTION);
00850 glPopMatrix();
00851 glMatrixMode(GL_MODELVIEW);
00852 }
00853 }
00854
00855
00856
00857
00858
00859 void GLState::push_modelview_matrix()
00860 {
00861 stack_modelview_.push(modelview_);
00862 stack_inverse_modelview_.push(inverse_modelview_);
00863
00864 update_matrices();
00865
00866 if (updateGL_)
00867 {
00868 makeCurrent();
00869 glPushMatrix();
00870 }
00871 }
00872
00873
00874
00875
00876
00877 void GLState::pop_modelview_matrix()
00878 {
00879 modelview_ = stack_modelview_.top();
00880 inverse_modelview_ = stack_inverse_modelview_.top();
00881
00882 stack_modelview_.pop();
00883 stack_inverse_modelview_.pop();
00884
00885 update_matrices();
00886
00887 if (updateGL_)
00888 {
00889 makeCurrent();
00890 glPopMatrix();
00891 }
00892 }
00893
00894
00895
00896 void GLState::pick_init (bool _color)
00897 {
00898 colorPicking_ = _color;
00899 colorStack_.initialize ();
00900 glInitNames();
00901 glPushName((GLuint) 0);
00902 }
00903
00904
00905
00906 bool GLState::pick_set_maximum (unsigned int _idx)
00907 {
00908 bool rv = colorStack_.setMaximumIndex (_idx);
00909 if (colorPicking_)
00910 return rv;
00911 return true;
00912 }
00913
00914
00915
00916 void GLState::pick_set_name (unsigned int _idx)
00917 {
00918 colorStack_.setIndex (_idx);
00919 glLoadName (_idx);
00920 }
00921
00922
00923
00924 Vec4uc GLState::pick_get_name_color (unsigned int _idx)
00925 {
00926 if (colorPicking_)
00927 return colorStack_.getIndexColor (_idx);
00928 return Vec4uc (0, 0, 0, 0);
00929 }
00930
00931
00932
00933 void GLState::pick_push_name (unsigned int _idx)
00934 {
00935 colorStack_.pushIndex (_idx);
00936 glLoadName (_idx);
00937 glPushName (0);
00938 }
00939
00940
00941
00942 void GLState::pick_pop_name ()
00943 {
00944 colorStack_.popIndex ();
00945 glPopName ();
00946 }
00947
00948
00949
00950 std::vector<unsigned int> GLState::pick_color_to_stack (Vec4uc _rgba) const
00951 {
00952 if (colorPicking_ && colorStack_.initialized ())
00953 return colorStack_.colorToStack (_rgba);
00954 return std::vector<unsigned int> ();
00955 }
00956
00957
00958
00959 unsigned int GLState::pick_free_indicies () const
00960 {
00961 if (colorPicking_ && colorStack_.initialized ())
00962 return colorStack_.freeIndicies ();
00963 return -1;
00964 }
00965
00966
00967
00968 bool GLState::pick_error () const
00969 {
00970 if (colorPicking_)
00971 return colorStack_.error ();
00972 return false;
00973 }
00974
00975
00976
00977 unsigned int GLState::pick_current_index () const
00978 {
00979 if (colorPicking_)
00980 return colorStack_.currentIndex ();
00981 else
00982 return 0;
00983 }
00984
00985
00986
00987 bool GLState::color_picking () const
00988 {
00989 return colorPicking_;
00990 }
00991
00992
00993 }
00994