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