1 /* $Id: PlayerView.cpp,v 1.36 2003/07/28 16:57:35 nan Exp $ */
2 
3 // Copyright (C) 2000-2003  ���� �ȹ�(Kanna Yoshihiro)
4 //
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 2 of the License, or
8 // (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software
17 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18 
19 
20 #include "ttinc.h"
21 
22 #include "PlayerView.h"
23 #include "Player.h"
24 #include "parts.h"
25 #if defined(CHIYO)
26 #include "loadparts.h"
27 #endif
28 #include "Ball.h"
29 #include "BaseView.h"
30 #include "RCFile.h"
31 #include "Control.h"
32 
33 extern RCFile *theRC;
34 
35 extern SDL_mutex *loadMutex;
36 
37 extern Ball   theBall;
38 
39 extern long mode;
40 
41 partsmotion_t *PlayerView::motion_Fnormal = NULL;
42 partsmotion_t *PlayerView::motion_Bnormal = NULL;
43 partsmotion_t *PlayerView::motion_Fdrive = NULL;
44 partsmotion_t *PlayerView::motion_Fcut = NULL;
45 partsmotion_t *PlayerView::motion_Bcut = NULL;
46 partsmotion_t *PlayerView::motion_Fpeck = NULL;
47 partsmotion_t *PlayerView::motion_Bpeck = NULL;
48 partsmotion_t *PlayerView::motion_Fsmash = NULL;
49 
PlayerView()50 PlayerView::PlayerView() {
51   m_player = NULL;
52 
53   m_Fnormal = m_Bnormal = NULL;
54   m_Fdrive  = m_Bdrive  = NULL;
55   m_Fcut    = m_Bcut    = NULL;
56   m_Fpeck   = m_Bpeck   = NULL;
57   m_Fsmash  = m_Bsmash  = NULL;
58 
59   m_xdiff = m_ydiff = m_zdiff = 0.0;
60 }
61 
~PlayerView()62 PlayerView::~PlayerView() {
63 }
64 
65 void *
LoadData(void * dum)66 PlayerView::LoadData(void *dum) {
67 #if !defined(CHIYO)
68   motion_Fnormal = new partsmotion("Parts/Fnormal/Fnormal");
69   motion_Bnormal = new partsmotion("Parts/Bnormal/Bnormal");
70   motion_Fdrive = new partsmotion("Parts/Fdrive/Fdrive");
71   motion_Fcut = new partsmotion("Parts/Fcut/Fcut");
72   motion_Bcut = new partsmotion("Parts/Bcut/Bcut");
73   motion_Fpeck = new partsmotion("Parts/Fpeck/Fpeck");
74   motion_Bpeck = new partsmotion("Parts/Bpeck/Bpeck");
75   motion_Fsmash = new partsmotion("Parts/Fsmash/Fsmash");
76 #else /* CHIYO */
77   chdir("Parts");
78   parts::loadobjects("body.txt");
79   chdir("..");
80 #endif /* !CHIYO */
81 
82   return NULL;
83 }
84 
85 bool
Init(Player * player)86 PlayerView::Init( Player *player ) {
87   m_player = player;
88 
89   SDL_mutexP( loadMutex );
90 
91 #if !defined(CHIYO)
92   m_Fnormal = motion_Fnormal;
93   m_Bnormal = motion_Bnormal;
94   m_Fdrive = motion_Fdrive;
95   m_Fcut = motion_Fcut;
96   m_Bcut = motion_Bcut;
97   m_Fpeck = motion_Fpeck;
98   m_Bpeck = motion_Bpeck;
99   m_Fsmash = motion_Fsmash;
100 #else /* CHIYO */
101 # define GETBODY(name, ptype) \
102     m_##name = reinterpret_cast<body_parts*>(parts::getobject(#name#ptype)); \
103 	if (!m_##name || parts::sym_body != m_##name->type()) {\
104         printf("Could not load " #name #ptype "\n"); exit(1); \
105     }
106 
107   switch ( m_player->GetPlayerType() ) {
108   case PLAYER_PENATTACK:
109   case PLAYER_PENDRIVE:
110     GETBODY(Fnormal, Pen);
111     GETBODY(Bnormal, Pen);
112     GETBODY(Fdrive, Pen);
113     GETBODY(Fcut, Pen);
114     GETBODY(Bcut, Pen);
115     GETBODY(Fpeck, Pen);
116     GETBODY(Bpeck, Pen);
117     GETBODY(Fsmash, Pen);
118     break;
119   case PLAYER_SHAKECUT:
120     GETBODY(Fnormal, Shake);
121     GETBODY(Bnormal, Shake);
122     GETBODY(Fdrive, Shake);
123     GETBODY(Fcut, Shake);
124     GETBODY(Bcut, Shake);
125     GETBODY(Fpeck, Shake);
126     GETBODY(Bpeck, Shake);
127     GETBODY(Fsmash, Shake);
128     break;
129   default:
130     GETBODY(Fnormal, Pen);
131     GETBODY(Bnormal, Pen);
132     GETBODY(Fdrive, Pen);
133     GETBODY(Fcut, Pen);
134     GETBODY(Bcut, Pen);
135     GETBODY(Fpeck, Pen);
136     GETBODY(Bpeck, Pen);
137     GETBODY(Fsmash, Pen);
138     break;
139   }
140 
141 # undef GETBODY
142 #endif /* !CHIYO */
143 
144   SDL_mutexV( loadMutex );
145   return true;
146 }
147 
148 bool
Redraw()149 PlayerView::Redraw() {
150   static GLfloat mat_green[] = { 0.1F, 0.1F, 0.1F, 1.0F };
151 
152   if ( Control::TheControl()->GetComPlayer() == m_player ) {
153     glColor4f( 0.4F, 0.4F, 0.4F, 0.0F );
154     glMaterialfv(GL_FRONT, GL_SPECULAR, mat_green);
155 
156     return SubRedraw();
157   }
158 
159   return true;
160 }
161 
162 bool
RedrawAlpha()163 PlayerView::RedrawAlpha() {
164   static GLfloat mat_black[] = { 0.0F, 0.0F, 0.0F, 1.0F };
165 
166   if ( Control::TheControl()->GetThePlayer() == m_player ) {
167     if ( theRC->myModel == MODEL_WIREFRAME ||
168 	 theRC->myModel == MODEL_ARMONLY ) {
169       glColor4f( 1.0F, 1.0F, 1.0F, 1.0F );
170     } else {
171       glColor4f( 0.05F, 0.05F, 0.05F, 1.0F );
172       glMaterialfv(GL_FRONT, GL_SPECULAR, mat_black);
173     }
174 
175     return SubRedraw();
176   }
177 
178   return true;
179 }
180 
181 bool
SubRedraw()182 PlayerView::SubRedraw() {
183 
184   DrawPlayer();
185 
186   // Target
187   if ( Control::TheControl()->GetThePlayer() == m_player ) {
188     DrawTarget();
189 #if 0
190     if ( mode == MODE_SOLOPLAY || mode == MODE_MULTIPLAY ||
191 	 mode == MODE_PRACTICE )
192       DrawMeter();
193 #endif
194   }
195 
196   return true;
197 }
198 
199 void
DrawTargetCircle(double diff)200 PlayerView::DrawTargetCircle( double diff ) {
201   Ball *tmpBall;
202   double vx, vy, vz;
203   double rad;
204   static double ballHeight = 1.4F;
205   static bool count = true;
206 
207   if ( theRC->gmode == GMODE_SIMPLE ) {
208     count = !count;
209     if ( count )
210       return;
211   }
212 
213   // Make pseudo ball near the Player
214   if ( (m_player->GetSide() == 1 &&
215 	(theBall.GetStatus() == 2 || theBall.GetStatus() == 3 ||
216        theBall.GetStatus() == 5)) ||
217        (m_player->GetSide() == -1 &&
218 	(theBall.GetStatus() == 0 || theBall.GetStatus() == 1 ||
219        theBall.GetStatus() == 4)) ) {
220     ballHeight = theBall.GetZ();
221     tmpBall = new Ball( theBall.GetX(), theBall.GetY(), theBall.GetZ(),
222 			theBall.GetVX(), theBall.GetVY(), theBall.GetVZ(),
223 			theBall.GetSpin(), theBall.GetStatus() );
224 
225     while ( tmpBall->GetStatus() >= 0 &&
226 	    tmpBall->GetY()*m_player->GetSide() >
227 	    m_player->GetY()*m_player->GetSide() )
228       tmpBall->Move();
229 
230     if ( tmpBall->GetStatus() < 0 )
231       tmpBall->Warp( m_player->GetX()+0.3F*m_player->GetSide(),
232 		     m_player->GetY(), ballHeight,
233 		     0.0F, 0.0F, 0.0F, 0.0F, 3 );
234   } else {
235     tmpBall = new Ball( m_player->GetX()+0.3F*m_player->GetSide(),
236 			m_player->GetY(), ballHeight,
237 			0.0F, 0.0F, 0.0F, 0.0F, 3 );
238   }
239 
240   // Calc initial speed of the ball when the player hit the ball
241   double dum, level, maxVy;
242 
243   m_player->CalcLevel( tmpBall, dum, level, maxVy );
244   tmpBall->TargetToV( m_player->GetTargetX(), m_player->GetTargetY(),
245 		      level, m_player->GetSpin(), vx, vy, vz, 0.1F, maxVy );
246 
247   // Add difference to the initial speed. Calc bound location
248   double v, v1x, v1y, v1z;
249   double n1x, n1y, n1z, n2x, n2y, n2z;
250   double bx = tmpBall->GetX(), by = tmpBall->GetY(), bz = tmpBall->GetZ();
251   double polygon1[64][3], polygon2[64][3];
252   int polyNum1 = 0, polyNum2 = 0;
253   int i;
254 
255   v = sqrt(vx*vx+vy*vy+vz*vz);
256   n1x = vy/hypot(vx, vy) * v*tan(diff);
257   n1y = -vx/hypot(vx, vy) * v*tan(diff);
258   n1z = 0;
259   n2x = vx*vz/(v*hypot(vx, vy)) * v*tan(diff);
260   n2y = vy*vz/(v*hypot(vx, vy)) * v*tan(diff);
261   n2z = (vx*vx+vy*vy)/(v*hypot(vx, vy)) * v*tan(diff);
262 
263   for ( rad = 0.0 ; rad < 3.141592F*2 ; rad += 3.141592F/32 ) {
264     v1x = vx+n1x*cos(rad)+n2x*sin(rad);
265     v1y = vy+n1y*cos(rad)+n2y*sin(rad);
266     v1z = vz+n1z*cos(rad)+n2z*sin(rad);
267 
268     if ( m_player->GetSide() > 0 ) {
269       tmpBall->Warp( bx, by, bz,
270 		     v1x, v1y, v1z, m_player->GetSpin(), 0 );
271       while ( tmpBall->GetZ() > TABLEHEIGHT &&
272 	      tmpBall->GetZ()+tmpBall->GetVZ()*TICK > TABLEHEIGHT &&
273 	      tmpBall->GetVY() > 0.0 &&	// When the ball hits the net
274 	      tmpBall->GetStatus() == 0 )
275 	tmpBall->Move();
276     } else {
277       tmpBall->Warp( bx, by, bz,
278 		     v1x, v1y, v1z, m_player->GetSpin(), 2 );
279       while ( tmpBall->GetZ() > TABLEHEIGHT &&
280 	      tmpBall->GetZ()+tmpBall->GetVZ()*TICK > TABLEHEIGHT &&
281 	      tmpBall->GetVY() < 0.0 &&	// When the ball hits the net
282 	      tmpBall->GetStatus() == 2 )
283 	tmpBall->Move();
284     }
285 
286     if ( tmpBall->GetY()*m_player->GetSide() > 0.0 ) {
287       polygon1[polyNum1][0] = tmpBall->GetX();
288       polygon1[polyNum1][1] = tmpBall->GetY();
289       polygon1[polyNum1][2] = TABLEHEIGHT+0.01F;
290       polyNum1++;
291     } else {
292       polygon2[polyNum2][0] = tmpBall->GetX();
293       polygon2[polyNum2][1] = tmpBall->GetY();
294       polygon2[polyNum2][2] = tmpBall->GetZ();
295       polyNum2++;
296     }
297   }
298 
299   glBegin(GL_POLYGON);
300     for ( i = 0 ; i < polyNum1 ; i++ )
301       glVertex3f( polygon1[i][0], polygon1[i][1], polygon1[i][2] );
302   glEnd();
303 
304   glBegin(GL_POLYGON);
305     for ( i = 0 ; i < polyNum2 ; i++ )
306       glVertex3f( polygon2[i][0], polygon2[i][1], polygon2[i][2] );
307   glEnd();
308 
309   delete tmpBall;
310 }
311 
312 // BallView �Ȥ��֤�.
313 double
GetHitpointY()314 PlayerView::GetHitpointY() {
315   Ball* tmpBall;
316 
317   if ( Control::TheControl()->GetThePlayer() &&
318        (((theBall.GetStatus() == 2 || theBall.GetStatus() == 3) &&
319 	 Control::TheControl()->GetThePlayer()->GetSide() > 0) ||
320 	((theBall.GetStatus() == 0 || theBall.GetStatus() == 1) &&
321 	 Control::TheControl()->GetThePlayer()->GetSide() < 0)) ) {
322     tmpBall = new Ball( theBall.GetX(), theBall.GetY(), theBall.GetZ(),
323 			theBall.GetVX(), theBall.GetVY(), theBall.GetVZ(),
324 			theBall.GetSpin(), theBall.GetStatus() );
325     long t1 = 0, t2 = 0;
326     // get time until the ball reaches hit point
327     while ( tmpBall->GetStatus() != -1 ){
328       tmpBall->Move();
329       if ( tmpBall->GetY() < Control::TheControl()->GetThePlayer()->GetY() &&
330 	   tmpBall->GetStatus() == 3 )
331 	break;
332       t1++;
333     }
334     if ( tmpBall->GetStatus() == -1 )
335       return m_player->GetY()+0.6;
336 
337     delete tmpBall;
338 
339     tmpBall = new Ball( theBall.GetX(), theBall.GetY(), theBall.GetZ(),
340 			theBall.GetVX(), theBall.GetVY(), theBall.GetVZ(),
341 			theBall.GetSpin(), theBall.GetStatus() );
342 
343     while ( tmpBall->GetStatus() != -1 ){
344       tmpBall->Move();
345       t2++;
346       if ( t1-10 == t2 ){
347 	return tmpBall->GetY();
348       }
349     }
350     delete tmpBall;
351   }
352 
353   return m_player->GetY()+0.6;
354 }
355 
356 void
DrawPlayer()357 PlayerView::DrawPlayer() {
358   double swing;
359   partsmotion_t *motion;
360 
361   swing = m_player->GetSwing();
362   switch( m_player->GetSwingType() ) {
363   case SWING_NORMAL:
364     if ( m_player->ForeOrBack() )
365       motion = m_Fnormal;
366     else
367       motion = m_Bnormal;
368     break;
369   case SWING_POKE:
370     if ( m_player->ForeOrBack() )
371       motion = m_Fpeck ? m_Fpeck : m_Fnormal;
372     else
373       motion = m_Bpeck ? m_Bpeck : m_Bnormal;
374     break;
375   case SWING_SMASH:
376     if ( m_player->ForeOrBack() )
377       motion = m_Fsmash ? m_Fsmash : m_Fnormal;
378     else
379       motion = m_Bsmash ? m_Bsmash : m_Bnormal;
380     break;
381   case SWING_DRIVE:
382     if ( m_player->ForeOrBack() )
383       motion = m_Fdrive ? m_Fdrive : m_Fnormal;
384     else
385       motion = m_Bdrive ? m_Bdrive : m_Bnormal;
386     break;
387   case SWING_CUT:
388     if ( m_player->ForeOrBack() )
389       motion = m_Fcut ? m_Fcut : m_Fnormal;
390     else
391       motion = m_Bcut ? m_Bcut : m_Bnormal;
392     break;
393   default:
394     return;
395   }
396 
397   float xdiff = 0.0, ydiff = 0.0, zdiff = 0.0;
398 
399   if ( m_player->GetSwing() > 10 && m_player->GetSwing() < 20 ) {
400     Ball *tmpBall;
401 
402     tmpBall = new Ball( theBall.GetX(), theBall.GetY(), theBall.GetZ(),
403 			theBall.GetVX(), theBall.GetVY(), theBall.GetVZ(),
404 			theBall.GetSpin(), theBall.GetStatus() );
405 
406     for ( int i = m_player->GetSwing() ; i < 20 ; i++ )
407       tmpBall->Move();
408 
409     if ( ((tmpBall->GetStatus() == 3 && m_player->GetSide() == 1) ||
410 	  (tmpBall->GetStatus() == 1 && m_player->GetSide() == -1)) ) {
411       double hitpointX = m_player->GetSwingSide() ?
412 	m_player->GetX()+0.3*m_player->GetSide() :
413 	m_player->GetX()-0.3*m_player->GetSide();
414 
415       xdiff = tmpBall->GetX() -
416 	(hitpointX+m_player->GetX()*(20-m_player->GetSwing())*TICK);
417 
418       ydiff =
419         (tmpBall->GetY() -
420          (m_player->GetY()+m_player->GetVY()*(20-m_player->GetSwing())*TICK))*
421         m_player->GetSide();
422 
423       zdiff = tmpBall->GetZ() - 0.85;	/* temporary */
424     }
425 
426     if ( xdiff > 0.3 )
427       xdiff = 0.3;
428     if ( xdiff < -0.3 )
429       xdiff = -0.3;
430     if ( ydiff > 0.3 )
431       ydiff = 0.3;
432     if ( ydiff < -0.3 )
433       ydiff = -0.3;
434   }
435 
436   if ( m_player->GetSwing() >= 30 ) {
437     m_xdiff *= 0.95;
438     m_ydiff *= 0.95;
439     m_zdiff *= 0.95;
440   } else {
441     m_xdiff = xdiff;
442     m_ydiff = ydiff;
443     m_zdiff = zdiff;
444   }
445 
446   glPushMatrix();
447     glTranslatef( m_player->GetX()-0.3F*m_player->GetSide(),
448 		  m_player->GetY(), 0 );
449 
450     glRotatef( -atan2( m_player->GetTargetX()-m_player->GetX(),
451 		       m_player->GetTargetY()-m_player->GetY() )*180/3.141592F,
452 	       0.0F, 0.0F, 1.0F );
453 
454     if ( theRC->gmode == GMODE_SIMPLE ) {
455       if ( Control::TheControl()->GetThePlayer() == m_player &&
456 	   theRC->myModel == MODEL_ARMONLY )
457 	motion->renderArmOnly(swing, m_xdiff, m_ydiff, m_zdiff);
458       else
459 	motion->renderWire(swing, m_xdiff, m_ydiff, m_zdiff);
460     } else {
461       if (Control::TheControl()->GetComPlayer() == m_player) {
462 	motion->render(swing, m_xdiff, m_ydiff, m_zdiff);
463       }
464       if (Control::TheControl()->GetThePlayer() == m_player) {
465 	switch ( theRC->myModel ) {
466 	case MODEL_TRANSPARENT:
467 	  glEnable(GL_CULL_FACE);
468 	  glDisable(GL_DEPTH_TEST);
469 	  glDepthMask(0);
470 	  motion->render(swing, m_xdiff, m_ydiff, m_zdiff);
471 	  glDepthMask(1);
472 	  glEnable(GL_DEPTH_TEST);
473 	  glDisable(GL_CULL_FACE);
474 	  break;
475 	case MODEL_WIREFRAME:
476 	  motion->renderWire(swing, m_xdiff, m_ydiff, m_zdiff);
477 	  break;
478 	case MODEL_ARMONLY:
479 	  motion->renderArmOnly(swing, m_xdiff, m_ydiff, m_zdiff);
480 	  break;
481 	}
482       }
483     }
484 
485   glPopMatrix();
486 }
487 
488 void
DrawTarget()489 PlayerView::DrawTarget() {
490   glColor4f( 1.0F, 0.0F, 0.0F, 0.5F );
491 
492   static GLfloat mat_default[] = { 0.0F, 0.0F, 0.0F, 1.0F };
493   glMaterialfv(GL_FRONT, GL_SPECULAR, mat_default);
494 
495   double targetX, targetY;
496   if ( theBall.GetStatus() == 2 || theBall.GetStatus() == 3 )
497     m_player->GetModifiedTarget( targetX, targetY );
498   else {
499     targetX = m_player->GetTargetX();
500     targetY = m_player->GetTargetY();
501   }
502 
503   double diff;
504 
505   diff = (double)(220-m_player->GetStatus())/220*3.141592F/18;
506   //DrawTargetCircle( diff );
507 
508   targetX = Control::TheControl()->GetThePlayer()->GetTargetX();
509   targetY = Control::TheControl()->GetThePlayer()->GetTargetY();
510 
511   glColor4f( 1.0F, 0.0F, 0.0F, 1.0F );
512   glBegin(GL_POLYGON);
513     glNormal3f( 0.0F, 1.0F, 0.0F );
514     glVertex3f( targetX-0.08F, targetY, TABLEHEIGHT+1.7320508F*0.08F );
515     glVertex3f( targetX+0.08F, targetY, TABLEHEIGHT+1.7320508F*0.08F );
516     glVertex3f( targetX, targetY, TABLEHEIGHT );
517   glEnd();
518 }
519 
520 void
DrawMeter()521 PlayerView::DrawMeter() {
522   static long count = 0;
523 
524   count++;
525 
526   long status = m_player->GetStatus();
527 
528   if ( status < m_player->StatusBorder() && count%10 < 5 )
529     return;
530 
531   glDisable(GL_DEPTH_TEST);
532   glDepthMask(0);
533 
534   glPushMatrix();
535   glMatrixMode(GL_PROJECTION);
536   glPushMatrix();
537   glLoadIdentity();
538   gluOrtho2D( 0.0, (GLfloat)BaseView::GetWinWidth(),
539 	      (GLfloat)BaseView::GetWinHeight(), 0.0 );
540   glMatrixMode(GL_MODELVIEW);
541   glLoadIdentity();
542 
543   long statusBarX, statusBarY, statusBarWidth, statusBarHeight;
544   statusBarX = 0;
545   statusBarY = 1;
546 
547   statusBarWidth = BaseView::GetWinWidth()-2;
548   statusBarHeight = BaseView::GetWinHeight()/20;
549 
550   glColor4f( 0.8F, 0.8F, 0.4F, 1.0F );
551   glBegin(GL_QUADS);
552     glVertex2i( statusBarX, statusBarY );
553     glVertex2i( statusBarX+statusBarWidth*status/200,
554 		statusBarY );
555     glVertex2i( statusBarX+statusBarWidth*status/200,
556 		statusBarY+statusBarHeight );
557     glVertex2i( statusBarX, statusBarY+statusBarHeight );
558   glEnd();
559 
560   glColor4f( 1.0F, 0.0F, 0.0F, 1.0F );
561   glBegin(GL_QUADS);
562     glVertex2i( statusBarX+statusBarWidth*status/200,
563 		statusBarY );
564     glVertex2i( statusBarX+statusBarWidth*status/200,
565 		statusBarY+statusBarHeight );
566     glVertex2i( statusBarX+statusBarWidth, statusBarY+statusBarHeight );
567     glVertex2i( statusBarX+statusBarWidth, statusBarY );
568   glEnd();
569 
570   glColor4f( 1.0F, 1.0F, 1.0F, 1.0F );
571   glBegin(GL_LINE_LOOP);
572     glVertex2i( statusBarX, statusBarY );
573     glVertex2i( statusBarX+statusBarWidth, statusBarY );
574     glVertex2i( statusBarX+statusBarWidth, statusBarY+statusBarHeight );
575     glVertex2i( statusBarX, statusBarY+statusBarHeight );
576   glEnd();
577 
578   glColor4f( 1.0F, 0.0F, 0.0F, 1.0F );
579   glBegin(GL_LINES);
580     glVertex2i( statusBarX+statusBarWidth*m_player->StatusBorder()/200,
581 		statusBarY );
582     glVertex2i( statusBarX+statusBarWidth*m_player->StatusBorder()/200,
583 		statusBarY+statusBarHeight );
584   glEnd();
585 
586   glMatrixMode(GL_PROJECTION);
587   glPopMatrix();
588   glMatrixMode(GL_MODELVIEW);
589   glPopMatrix();
590 
591   glDepthMask(1);
592   if ( theRC->gmode != GMODE_SIMPLE )
593     glEnable(GL_DEPTH_TEST);
594 }
595