2 * Copyright (C) 2003 Robert Kooima
4 * NEVERPUTT is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published
6 * by the Free Software Foundation; either version 2 of the License,
7 * or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
30 /*---------------------------------------------------------------------------*/
32 static struct s_file file
;
35 static float view_a
; /* Ideal view rotation about Y axis */
37 static float view_ry
; /* Angular velocity about Y axis */
38 static float view_dy
; /* Ideal view distance above ball */
39 static float view_dz
; /* Ideal view distance behind ball */
41 static float view_c
[3]; /* Current view center */
42 static float view_v
[3]; /* Current view vector */
43 static float view_p
[3]; /* Current view position */
44 static float view_e
[3][3]; /* Current view orientation */
46 static int swch_e
= 1; /* Switching enabled flag */
47 static float jump_e
= 1; /* Jumping enabled flag */
48 static float jump_b
= 0; /* Jump-in-progress flag */
49 static float jump_dt
; /* Jump duration */
50 static float jump_p
[3]; /* Jump destination */
52 /*---------------------------------------------------------------------------*/
54 static void view_init(void)
81 void game_init(const char *s
)
87 sol_load(&file
, config_data(s
), config_get_d(CONFIG_TEXTURES
),
88 config_get_d(CONFIG_SHADOW
));
96 /*---------------------------------------------------------------------------*/
98 static void game_draw_vect_prim(const struct s_file
*fp
, GLenum mode
)
105 v_cpy(p
, fp
->uv
[ball
].p
);
113 glColor4f(1.0f
, 1.0f
, 0.5f
, 0.5f
);
114 glVertex3f(p
[0] - x
[0] * r
,
118 glColor4f(1.0f
, 0.0f
, 0.0f
, 0.5f
);
119 glVertex3f(p
[0] + z
[0] * view_m
,
120 p
[1] + z
[1] * view_m
,
121 p
[2] + z
[2] * view_m
);
123 glColor4f(1.0f
, 1.0f
, 0.0f
, 0.5f
);
124 glVertex3f(p
[0] + x
[0] * r
,
131 static void game_draw_vect(const struct s_file
*fp
)
135 glPushAttrib(GL_TEXTURE_BIT
);
136 glPushAttrib(GL_POLYGON_BIT
);
137 glPushAttrib(GL_LIGHTING_BIT
);
138 glPushAttrib(GL_DEPTH_BUFFER_BIT
);
140 glEnable(GL_COLOR_MATERIAL
);
141 glDisable(GL_LIGHTING
);
142 glDisable(GL_TEXTURE_2D
);
143 glDepthMask(GL_FALSE
);
145 glEnable(GL_DEPTH_TEST
);
146 game_draw_vect_prim(fp
, GL_TRIANGLES
);
148 glDisable(GL_DEPTH_TEST
);
149 game_draw_vect_prim(fp
, GL_LINE_STRIP
);
158 static void game_draw_balls(const struct s_file
*fp
)
160 static const GLfloat color
[5][4] = {
161 { 1.0f
, 1.0f
, 1.0f
, 0.7f
},
162 { 1.0f
, 0.0f
, 0.0f
, 1.0f
},
163 { 0.0f
, 1.0f
, 0.0f
, 1.0f
},
164 { 0.0f
, 0.0f
, 1.0f
, 1.0f
},
165 { 1.0f
, 1.0f
, 0.0f
, 1.0f
},
171 for (ui
= curr_party(); ui
> 0; ui
--)
177 m_basis(M
, fp
->uv
[ui
].e
[0], fp
->uv
[ui
].e
[1], fp
->uv
[ui
].e
[2]);
179 glTranslatef(fp
->uv
[ui
].p
[0],
180 fp
->uv
[ui
].p
[1] + BALL_FUDGE
,
183 glScalef(fp
->uv
[ui
].r
,
187 glColor4fv(color
[ui
]);
197 glTranslatef(fp
->uv
[ui
].p
[0],
198 fp
->uv
[ui
].p
[1] - fp
->uv
[ui
].r
+ BALL_FUDGE
,
200 glScalef(fp
->uv
[ui
].r
,
204 glColor4f(color
[ui
][0],
215 static void game_draw_goals(const struct s_file
*fp
, float rx
, float ry
)
219 for (zi
= 0; zi
< fp
->zc
; zi
++)
223 glTranslatef(fp
->zv
[zi
].p
[0],
232 static void game_draw_jumps(const struct s_file
*fp
)
236 for (ji
= 0; ji
< fp
->jc
; ji
++)
240 glTranslatef(fp
->jv
[ji
].p
[0],
244 glScalef(fp
->jv
[ji
].r
, 1.f
, fp
->jv
[ji
].r
);
251 static void game_draw_swchs(const struct s_file
*fp
)
255 for (xi
= 0; xi
< fp
->xc
; xi
++)
259 glTranslatef(fp
->xv
[xi
].p
[0],
263 glScalef(fp
->xv
[xi
].r
, 1.f
, fp
->xv
[xi
].r
);
264 swch_draw(fp
->xv
[xi
].f
);
270 /*---------------------------------------------------------------------------*/
272 void game_draw(int pose
)
274 const float light_p
[4] = { 8.f
, 32.f
, 8.f
, 1.f
};
276 const struct s_file
*fp
= &file
;
280 if (jump_b
) fov
*= 2.0f
* fabsf(jump_dt
- 0.5f
);
282 config_push_persp(fov
, 0.1f
, FAR_DIST
);
283 glPushAttrib(GL_LIGHTING_BIT
);
288 v_sub(v
, view_c
, view_p
);
290 rx
= V_DEG(fatan2f(-v
[1], fsqrtf(v
[0] * v
[0] + v
[2] * v
[2])));
291 ry
= V_DEG(fatan2f(+v
[0], -v
[2]));
293 glTranslatef(0.f
, 0.f
, -v_len(v
));
294 glRotatef(rx
, 1.f
, 0.f
, 0.f
);
295 glRotatef(ry
, 0.f
, 1.f
, 0.f
);
296 glTranslatef(-view_c
[0], -view_c
[1], -view_c
[2]);
298 /* Center the skybox about the position of the camera. */
302 glTranslatef(view_p
[0], view_p
[1], view_p
[2]);
308 glLightfv(GL_LIGHT0
, GL_POSITION
, light_p
);
310 /* Draw the floor. */
314 if (config_get_d(CONFIG_SHADOW
) && !pose
)
316 shad_draw_set(fp
->uv
[ball
].p
, fp
->uv
[ball
].r
);
321 /* Draw the game elements. */
324 glBlendFunc(GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
);
332 game_draw_goals(fp
, -rx
, -ry
);
341 /*---------------------------------------------------------------------------*/
343 void game_update_view(float dt
)
345 const float y
[3] = { 0.f
, 1.f
, 0.f
};
354 /* Center the view about the ball. */
356 v_cpy(view_c
, file
.uv
[ball
].p
);
357 v_inv(view_v
, file
.uv
[ball
].v
);
359 switch (config_get_d(CONFIG_CAMERA
))
362 /* Camera 2: View vector is given by view angle. */
364 view_e
[2][0] = fsinf(V_RAD(view_a
));
366 view_e
[2][2] = fcosf(V_RAD(view_a
));
372 /* View vector approaches the ball velocity vector. */
374 v_mad(e
, view_v
, y
, v_dot(view_v
, y
));
377 k
= v_dot(view_v
, view_v
);
379 v_sub(view_e
[2], view_p
, view_c
);
380 v_mad(view_e
[2], view_e
[2], view_v
, k
* dt
* 0.1f
);
383 /* Orthonormalize the basis of the view in its new position. */
385 v_crs(view_e
[0], view_e
[1], view_e
[2]);
386 v_crs(view_e
[2], view_e
[0], view_e
[1]);
387 v_nrm(view_e
[0], view_e
[0]);
388 v_nrm(view_e
[2], view_e
[2]);
390 /* The current view (dy, dz) approaches the ideal (view_dy, view_dz). */
392 v_sub(d
, view_p
, view_c
);
394 dy
= v_dot(view_e
[1], d
);
395 dz
= v_dot(view_e
[2], d
);
397 dy
+= (view_dy
- dy
) * s
;
398 dz
+= (view_dz
- dz
) * s
;
400 /* Compute the new view position. */
402 view_p
[0] = view_p
[1] = view_p
[2] = 0.f
;
404 v_mad(view_p
, view_c
, view_e
[1], dy
);
405 v_mad(view_p
, view_p
, view_e
[2], dz
);
407 view_a
= V_DEG(fatan2f(view_e
[2][0], view_e
[2][2]));
410 static int game_update_state(float dt
)
412 static float t
= 0.f
;
414 struct s_file
*fp
= &file
;
423 /* Test for a switch. */
425 if ((swch_e
= sol_swch_test(fp
, swch_e
, ball
)) != e
&& e
)
426 audio_play(AUD_SWITCH
, 1.f
);
428 /* Test for a jump. */
430 if (jump_e
== 1 && jump_b
== 0 && sol_jump_test(fp
, jump_p
, ball
) == 1)
436 audio_play(AUD_JUMP
, 1.f
);
438 if (jump_e
== 0 && jump_b
== 0 && sol_jump_test(fp
, jump_p
, ball
) == 0)
441 /* Test for fall-out. */
443 if (fp
->uv
[ball
].p
[1] < -10.f
)
446 /* Test for a goal or stop. */
452 if (sol_goal_test(fp
, p
, ball
))
462 * On most hardware, rendering requires much more computing power than
463 * physics. Since physics takes less time than graphics, it make sense to
464 * detach the physics update time step from the graphics frame rate. By
465 * performing multiple physics updates for each graphics update, we get away
466 * with higher quality physics with little impact on overall performance.
468 * Toward this end, we establish a baseline maximum physics time step. If
469 * the measured frame time exceeds this maximum, we cut the time step in
470 * half, and do two updates. If THIS time step exceeds the maximum, we do
471 * four updates. And so on. In this way, the physics system is allowed to
472 * seek an optimal update rate independant of, yet in integral sync with, the
473 * graphics frame rate.
476 int game_step(const float g
[3], float dt
)
478 struct s_file
*fp
= &file
;
480 static float s
= 0.f
;
481 static float t
= 0.f
;
488 s
= (7.f
* s
+ dt
) / 8.f
;
499 fp
->uv
[ball
].p
[0] = jump_p
[0];
500 fp
->uv
[ball
].p
[1] = jump_p
[1];
501 fp
->uv
[ball
].p
[2] = jump_p
[2];
510 while (t
> MAX_DT
&& n
< MAX_DN
)
516 for (i
= 0; i
< n
; i
++)
518 d
= sol_step(fp
, g
, t
, ball
, &m
);
526 /* Mix the sound of a ball bounce. */
529 audio_play(AUD_BUMP
, (float) (b
- 0.5) * 2.0f
);
532 game_update_view(dt
);
533 return game_update_state(st
);
539 * HACK: The BALL_FUDGE here guarantees that a putt doesn't drive
540 * the ball too directly down toward a lump, triggering rolling
541 * friction too early and stopping the ball prematurely.
544 file
.uv
[ball
].v
[0] = -4.f
* view_e
[2][0] * view_m
;
545 file
.uv
[ball
].v
[1] = -4.f
* view_e
[2][1] * view_m
+ BALL_FUDGE
;
546 file
.uv
[ball
].v
[2] = -4.f
* view_e
[2][2] * view_m
;
551 /*---------------------------------------------------------------------------*/
553 void game_set_rot(int d
)
555 view_a
+= (float) (30.f
* d
) / config_get_d(CONFIG_MOUSE_SENSE
);
558 void game_clr_mag(void)
563 void game_set_mag(int d
)
565 view_m
-= (float) (1.f
* d
) / config_get_d(CONFIG_MOUSE_SENSE
);
571 void game_set_fly(float k
)
573 struct s_file
*fp
= &file
;
575 float x
[3] = { 1.f
, 0.f
, 0.f
};
576 float y
[3] = { 0.f
, 1.f
, 0.f
};
577 float z
[3] = { 0.f
, 0.f
, 1.f
};
578 float c0
[3] = { 0.f
, 0.f
, 0.f
};
579 float p0
[3] = { 0.f
, 0.f
, 0.f
};
580 float c1
[3] = { 0.f
, 0.f
, 0.f
};
581 float p1
[3] = { 0.f
, 0.f
, 0.f
};
586 v_sub(view_e
[2], fp
->uv
[ball
].p
, fp
->zv
[0].p
);
588 if (fabs(v_dot(view_e
[1], view_e
[2])) > 0.999)
591 v_crs(view_e
[0], view_e
[1], view_e
[2]);
592 v_crs(view_e
[2], view_e
[0], view_e
[1]);
594 v_nrm(view_e
[0], view_e
[0]);
595 v_nrm(view_e
[2], view_e
[2]);
597 /* k = 0.0 view is at the ball. */
601 v_cpy(c0
, fp
->uv
[ball
].p
);
602 v_cpy(p0
, fp
->uv
[ball
].p
);
605 v_mad(p0
, p0
, view_e
[1], view_dy
);
606 v_mad(p0
, p0
, view_e
[2], view_dz
);
608 /* k = +1.0 view is s_view 0 */
610 if (k
>= 0 && fp
->wc
> 0)
612 v_cpy(p1
, fp
->wv
[0].p
);
613 v_cpy(c1
, fp
->wv
[0].q
);
616 /* k = -1.0 view is s_view 1 */
618 if (k
<= 0 && fp
->wc
> 1)
620 v_cpy(p1
, fp
->wv
[1].p
);
621 v_cpy(c1
, fp
->wv
[1].q
);
624 /* Interpolate the views. */
627 v_mad(view_p
, p0
, v
, k
* k
);
630 v_mad(view_c
, c0
, v
, k
* k
);
632 /* Orthonormalize the view basis. */
634 v_sub(view_e
[2], view_p
, view_c
);
635 v_crs(view_e
[0], view_e
[1], view_e
[2]);
636 v_crs(view_e
[2], view_e
[0], view_e
[1]);
637 v_nrm(view_e
[0], view_e
[0]);
638 v_nrm(view_e
[2], view_e
[2]);
640 view_a
= V_DEG(fatan2f(view_e
[2][0], view_e
[2][2]));
643 void game_ball(int i
)
652 for (ui
= 0; ui
< file
.uc
; ui
++)
654 file
.uv
[ui
].v
[0] = 0.f
;
655 file
.uv
[ui
].v
[1] = 0.f
;
656 file
.uv
[ui
].v
[2] = 0.f
;
658 file
.uv
[ui
].w
[0] = 0.f
;
659 file
.uv
[ui
].w
[1] = 0.f
;
660 file
.uv
[ui
].w
[2] = 0.f
;
664 void game_get_pos(float p
[3], float e
[3][3])
666 v_cpy(p
, file
.uv
[ball
].p
);
667 v_cpy(e
[0], file
.uv
[ball
].e
[0]);
668 v_cpy(e
[1], file
.uv
[ball
].e
[1]);
669 v_cpy(e
[2], file
.uv
[ball
].e
[2]);
672 void game_set_pos(float p
[3], float e
[3][3])
674 v_cpy(file
.uv
[ball
].p
, p
);
675 v_cpy(file
.uv
[ball
].e
[0], e
[0]);
676 v_cpy(file
.uv
[ball
].e
[1], e
[1]);
677 v_cpy(file
.uv
[ball
].e
[2], e
[2]);
680 /*---------------------------------------------------------------------------*/