1 /*---------------------------------------------------------------------------*
2   Project:  Dolphin/Revolution gx demo
3   File:     smp-toy-anim.c
4 
5   Copyright 1998-2006 Nintendo.  All rights reserved.
6 
7   These coded instructions, statements, and computer programs contain
8   proprietary information of Nintendo of America Inc. and/or Nintendo
9   Company Ltd., and are protected by Federal copyright law.  They may
10   not be disclosed to third parties or copied or duplicated in any form,
11   in whole or in part, without the prior written consent of Nintendo.
12  *---------------------------------------------------------------------------*/
13 
14 #include <demo.h>
15 #include "toy-stick.h"
16 #include "toy-anim.h"
17 
18 #define WALLX_BOUNCE            0.6F
19 #define WALLZ_BOUNCE            0.5F
20 #define OUT_CORNER_BOUNCE       1.2F
21 #define IN_CORNER_BOUNCE        0.4F
22 #define SLOPE_ACCEL             1.01F
23 
24 #define BALL_CSIZEX             (BALL_SIZEX / 2.0F)
25 #define BALL_CSIZEZ             (BALL_SIZEZ / 2.0F)
26 
27 #define AX_SCALE                0.01F
28 #define AY_SCALE                0.01F
29 #define VX_FRICTION             0.999F
30 #define VY_FRICTION             0.999F
31 
32 /*---------------------------------------------------------------------------*
33    Global variables
34  *---------------------------------------------------------------------------*/
35 /*
36  *  Flags for collision
37  */
38 typedef enum
39 {
40     GO       = 0,
41     NOGO     = 1,
42     TELEPORT = 2,
43     LANDED   = 4,
44     ONSLOPE  = 8,
45     FLIPA    = 16,
46     FLIPB    = 32
47 } CollisionType;
48 
49 /*
50  *  Collision Symbol/Flag relationship
51  */
52 static u32 CollSymTab[][2]=
53 {
54     ' ',NOGO,
55     '.',GO,
56     'a',GO|FLIPA,
57     'b',GO|FLIPB,
58     '-',GO|LANDED,
59     '|',GO|ONSLOPE,
60     '<',GO|TELEPORT|ONSLOPE,
61     '>',GO|TELEPORT|ONSLOPE,
62     '\0',0
63 };
64 
65 /*
66  *  Collision Grid
67  *
68  *  Two levels needed since bridges intersect.  In order to make
69  *  collision logic easier, sloped bridge is straight in collision grid
70  *  and the ball is translated to the proper slope when drawing.
71  */
72 static unsigned char CollisionGrid[2][2*9][2*9] =
73 {
74   {
75 "                  ",
76 "                  ",
77 "  ...aaaa.bbbb..  ",
78 "  ...aaaa.bbbb..  ",
79 "  ..  ..      ..  ",
80 "  ..  ..      ..  ",
81 "  ..  ..      ..  ",
82 "  ..  ..      ..  ",
83 "  ..  ......  ..  ",
84 "  ..  ......  ..  ",
85 "  ..      ..  ..  ",
86 "  ..      ..  ..  ",
87 "  ..      ..  ..  ",
88 "  ..      ..  ..  ",
89 "  ..bbbb.aaaa...  ",
90 "  ..bbbb.aaaa...  ",
91 "                  ",
92 "                  "
93   },
94 
95   {
96 "                  ",
97 "                  ",
98 "  ..aaaa.bbbb...  ",
99 "  ..aaaa.bbbb...  ",
100 "  ..      --  ..  ",
101 "  ..  >>  --  ..  ",
102 "  ..  ||      ..  ",
103 "  ..  ||      ..  ",
104 "  ..  ||      ..  ",
105 "  ..  ||      ..  ",
106 "  ..  ||      ..  ",
107 "  ..  ||      ..  ",
108 "  ..  ..      ..  ",
109 "  ..  ..      ..  ",
110 "  ...bbbb.aaaa..  ",
111 "  ...bbbb.aaaa..  ",
112 "                  ",
113 "                  "
114   }
115 };
116 
117 
118 static Vec CurPos = {90.0F, 0.0F, 10.0F}; // current position
119 static u32 CurMask = 0;  // current collision mask at center of sphere
120 static u32 Teleport = 0; // teleporting this frame
121 
122 
123 
124 /*---------------------------------------------------------------------------*
125     Name:           GetCurPos
126 
127     Description:    Get current position
128 
129     Arguments:      none
130 
131     Returns:        Vec, current position
132  *---------------------------------------------------------------------------*/
GetCurPos(void)133 Vec GetCurPos( void )
134 {
135     return(CurPos);
136 }
137 
138 /*---------------------------------------------------------------------------*
139     Name:           OnSlope
140 
141     Description:    Returns 1 if center of ball is currently on the sloped
142                     bridge.
143 
144     Arguments:      none
145 
146     Returns:        u32, 1 = on slope, 0 = not on slope
147  *---------------------------------------------------------------------------*/
OnSlope(void)148 u32 OnSlope( void )
149 {
150     return(CurMask & ONSLOPE);
151 }
152 
153 /*---------------------------------------------------------------------------*
154     Name:           DoTeleport
155 
156     Description:    Returns 1 if ball will be teleported this tick
157 
158     Arguments:      none
159 
160     Returns:        u32, 1 = teleporting, 0 = not teleporting
161  *---------------------------------------------------------------------------*/
DoTeleport(void)162 u32 DoTeleport( void )
163 {
164     return(Teleport);
165 }
166 
167 /*---------------------------------------------------------------------------*
168     Name:           TestPoint
169 
170     Description:    Test point for collision
171 
172     Arguments:      curgrid   which collision grid to test
173                     x         x coordinate to test
174                     y         y coordinate to test
175 
176     Returns:        collision mask at point, u32
177  *---------------------------------------------------------------------------*/
TestPoint(u32 curgrid,f32 x,f32 y)178 static u32 TestPoint( u32 curgrid, f32 x, f32 y )
179 {
180     s32     xt;  // truncated x coordinate
181     s32     yt;  // truncated y coordinate
182     u32     i;
183     u8      tilec;
184 
185     // stay inside NOGO border
186     xt = (s32)((x + 20.0) / 10.0);
187     yt = (s32)((y + 20.0) / 10.0);
188 
189     // clamp to table size
190     if (xt < 0)  xt = 0;
191     if (xt > 17) xt = 17;
192     if (yt < 0)  yt = 0;
193     if (yt > 17) yt = 17;
194 
195     tilec = CollisionGrid[curgrid][yt][xt];
196 
197     for (i = 0; CollSymTab[i][0]; i++)
198     {
199         if (CollSymTab[i][0]==tilec)
200             return(CollSymTab[i][1]);
201     }
202     return(0);
203 }
204 
205 /*---------------------------------------------------------------------------*
206     Name:           AnimTick
207 
208     Description:    React to collision.  Computes next position and velocity.
209 
210     Arguments:      none
211 
212     Returns:        none
213  *---------------------------------------------------------------------------*/
AnimTick(void)214 void AnimTick( void )
215 {
216     static u32 curGrid    = 0;  // current collision grid
217     static Vec curVel     = { 0.0F, 0.0F, 0.0F };
218     // four points to test collision against
219     static Vec offsets[4] = {{-BALL_CSIZEX, 0.0F, -BALL_CSIZEZ},
220                              { BALL_CSIZEX, 0.0F, -BALL_CSIZEZ},
221                              { BALL_CSIZEX, 0.0F,  BALL_CSIZEZ},
222                              {-BALL_CSIZEX, 0.0F,  BALL_CSIZEZ}};
223     u32   i;             // loop variable
224     u32   fullMask;      // all flags
225     u32   wallMask = 0;  // only GO/NOGO bits
226     Vec   tp;            // test point
227     Vec   nextPos;
228     Vec   nextVel;
229 
230     // switch collision grids? test center point
231     CurMask = TestPoint(curGrid, CurPos.x, CurPos.z);
232     if (CurMask & FLIPA)
233         curGrid = 0;
234     else if (CurMask & FLIPB)
235         curGrid = 1;
236 
237     // all points must be in teleport area in order to teleport
238     Teleport = TELEPORT;
239 
240     // build collision detection mask
241     for (i = 0; i < 4; i++)
242     {
243         VECAdd(&CurPos, &curVel, &tp);
244         VECAdd(&tp, &offsets[i], &tp);
245         fullMask = TestPoint(curGrid, tp.x, tp.z);
246         Teleport &= fullMask & TELEPORT;
247         wallMask |= ((fullMask & NOGO) ? 1 : 0) << i;
248     }
249 
250     // teleport to the bottom of the ramp
251     if (Teleport)
252         CurPos.x -= (CurPos.z - SLOPE_ZSTART) * SLOPE_SLOPE;
253 
254     nextVel = curVel; // default
255 
256     switch(wallMask)
257     {
258         case 0x3:
259         case 0xc: // reflect velocity z
260             nextVel.x = curVel.x;
261             nextVel.z = -curVel.z * WALLZ_BOUNCE;
262             break;
263 
264         case 0x9:
265         case 0x6: // reflect velocity x
266             nextVel.x = -curVel.x * WALLX_BOUNCE;
267             nextVel.z = curVel.z;
268             break;
269 
270         case 0x1:
271             if (curVel.x < 0.0F) nextVel.x = -curVel.x * OUT_CORNER_BOUNCE;
272             if (curVel.z < 0.0F) nextVel.z = -curVel.z * OUT_CORNER_BOUNCE;
273             break;
274 
275         case 0x2:
276             if (curVel.x > 0.0F) nextVel.x = -curVel.x * OUT_CORNER_BOUNCE;
277             if (curVel.z < 0.0F) nextVel.z = -curVel.z * OUT_CORNER_BOUNCE;
278             break;
279 
280         case 0x4:
281             if (curVel.x > 0.0F) nextVel.x = -curVel.x * OUT_CORNER_BOUNCE;
282             if (curVel.z > 0.0F) nextVel.z = -curVel.z * OUT_CORNER_BOUNCE;
283             break;
284 
285         case 0x8:
286             if (curVel.x < 0.0F) nextVel.x = -curVel.x * OUT_CORNER_BOUNCE;
287             if (curVel.z > 0.0F) nextVel.z = -curVel.z * OUT_CORNER_BOUNCE;
288             break;
289 
290         case 0x7:
291         case 0xb:
292         case 0xd:
293         case 0xe: // invert velocity
294             nextVel.x = -curVel.x * IN_CORNER_BOUNCE;
295             nextVel.z = -curVel.z * IN_CORNER_BOUNCE;
296             break;
297 
298         case 0x0: // no collision
299             break;
300 
301         default:  // illegal case
302             OSReport("Illegal case in React()\n");
303             break;
304     }
305 
306     if ((CurMask & ONSLOPE) && (nextVel.z < 0.0F))
307         nextVel.z *= SLOPE_ACCEL; // accelerate down slope
308 
309     VECAdd(&CurPos, &nextVel, &nextPos);
310 
311     CurPos = nextPos;
312     curVel = nextVel;
313     curVel.x += -GetAnalogX() * AX_SCALE;
314     curVel.z += GetAnalogY() * AY_SCALE;
315     curVel.x *= VX_FRICTION;
316     curVel.z *= VY_FRICTION;
317 }
318