1 /*---------------------------------------------------------------------------*
2   Project:  Dolphin/Revolution gx demo
3   File:     tf-stitch.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 <math.h>
16 
17 #define PI    3.14159265358979323846F
18 
19 /*---------------------------------------------------------------------------*
20    Forward references
21  *---------------------------------------------------------------------------*/
22 
23 void        main            ( void );
24 static void CameraInit      ( Mtx v );
25 static void DrawInit        ( void );
26 static void DrawTick        ( Mtx v );
27 static void AnimTick        ( void );
28 
29 static float ComputeScale   ( float position );
30 
31 /*---------------------------------------------------------------------------*
32   Model Data
33  *---------------------------------------------------------------------------*/
34 #define Black   MyColors[0]
35 #define White   MyColors[5]
36 #define Red     MyColors[1]
37 #define Green   MyColors[2]
38 #define Blue    MyColors[3]
39 #define Gray    MyColors[4]
40 
41 
42 u32 MyColors[] ATTRIBUTE_ALIGN(32) = {
43     0x00ffffff,
44     0xff0000ff,
45     0xffff00ff,
46     0x0000ffff,
47     0x08ff08ff,
48     0xff00ffff,
49 
50     0x808080ff,
51     0xffffffff,
52     0xffff00ff,
53     0x00ff00ff};
54 
55 GXLightObj MyLight;
56 
57 typedef struct {
58     GXPosNrmMtx mtx;
59     f32         xlate;
60     f32         recomputeNormalMtx;
61 } Segment;
62 
63 Segment segs[] ATTRIBUTE_ALIGN(32) = {
64         {GX_PNMTX0, -540.0F, 0},
65         {GX_PNMTX1, -520.0F, 0},
66         {GX_PNMTX2, -500.0F, 0},
67         {GX_PNMTX3, -480.0F, 0},
68         {GX_PNMTX4, -460.0F, 0},
69         {GX_PNMTX5, -440.0F, 0},
70         {GX_PNMTX6, -420.0F, 0},
71         {GX_PNMTX7, -400.0F, 0},
72         {GX_PNMTX8, -380.0F, 0},
73 
74         {GX_PNMTX9, -360.0F, 0},
75 
76         {GX_PNMTX0, -340.0F, 0},
77         {GX_PNMTX1, -320.0F, 0},
78         {GX_PNMTX2, -300.0F, 0},
79         {GX_PNMTX3, -280.0F, 0},
80         {GX_PNMTX4, -260.0F, 0},
81         {GX_PNMTX5, -240.0F, 0},
82         {GX_PNMTX6, -220.0F, 0},
83         {GX_PNMTX7, -200.0F, 0},
84 
85         {GX_PNMTX8, -180.0F, 0},
86 
87         {GX_PNMTX9, -160.0F, 0},
88         {GX_PNMTX0, -140.0F, 0},
89         {GX_PNMTX1, -120.0F, 0},
90         {GX_PNMTX2, -100.0F, 0},
91         {GX_PNMTX3, -80.0F, 0},
92         {GX_PNMTX4, -60.0F, 0},
93         {GX_PNMTX5, -40.0F, 0},
94         {GX_PNMTX6, -20.0F, 0},
95 
96         {GX_PNMTX7, 0.0F, 0},
97 
98         {GX_PNMTX8, 20.0F, 0},
99         {GX_PNMTX9, 40.0F, 0},
100         {GX_PNMTX0, 60.0F, 0},
101         {GX_PNMTX1, 80.0F, 0},
102         {GX_PNMTX2, 100.0F, 0},
103         {GX_PNMTX3, 120.0F, 0},
104         {GX_PNMTX4, 140.0F, 0},
105         {GX_PNMTX5, 160.0F, 0},
106 
107         {GX_PNMTX6, 180.0F, 0},
108 
109         {GX_PNMTX7, 200.0F, 0},
110         {GX_PNMTX8, 220.0F, 0},
111         {GX_PNMTX9, 240.0F, 0},
112         {GX_PNMTX0, 260.0F, 0},
113         {GX_PNMTX1, 280.0F, 0},
114         {GX_PNMTX2, 300.0F, 0},
115         {GX_PNMTX3, 320.0F, 0},
116         {GX_PNMTX4, 340.0F, 0},
117 
118         {GX_PNMTX5, 360.0F, 0},
119 
120         {GX_PNMTX6, 380.0F, 0},
121         {GX_PNMTX7, 400.0F, 0},
122         {GX_PNMTX8, 420.0F, 0},
123         {GX_PNMTX9, 440.0F, 0},
124         {GX_PNMTX0, 460.0F, 0},
125         {GX_PNMTX1, 480.0F, 0},
126         {GX_PNMTX2, 500.0F, 0},
127         {GX_PNMTX3, 520.0F, 0},
128 
129         {GX_PNMTX4, 540.0F, 0}};
130 
131 f32 MyVert[200] ATTRIBUTE_ALIGN(32);
132 
133 float rot = 0;
134 float rot2;
135 u8 direction = 0;
136 
137 float BallPosition = 800;
138 float BallStep = -10;
139 
140 Mtx         v;   // view matrix
141 
142 /*---------------------------------------------------------------------------*/
143 static void ComputeNormalRotMtx ( Segment *seg, u32 idx );
144 
145 /*---------------------------------------------------------------------------*
146    Application main loop
147  *---------------------------------------------------------------------------*/
148 
main(void)149 void main ( void )
150 {
151     DEMOInit(NULL);
152 
153     CameraInit(v); // Initialize the camera.
154     DrawInit();    // Define my vertex formats and set array pointers.
155 
156     while(!(DEMOPadGetButton(0) & PAD_BUTTON_MENU))
157     {
158         DEMOBeforeRender();
159 
160         DrawTick(v);        // Draw the model.
161 
162         DEMODoneRender();
163 
164         DEMOPadRead();      // Update pad status.
165         AnimTick();         // Update animation.
166     }
167 
168     OSHalt("End of test");
169 }
170 
171 
172 /*---------------------------------------------------------------------------*
173    Functions
174  *---------------------------------------------------------------------------*/
175 /*---------------------------------------------------------------------------*
176     Name:           CameraInit
177 
178     Description:    Initialize the projection matrix and load into hardware.
179                     Initialize the view matrix.
180 
181     Arguments:      v       view matrix
182 
183     Returns:        none
184  *---------------------------------------------------------------------------*/
CameraInit(Mtx v)185 static void CameraInit ( Mtx v )
186 {
187     Mtx44   p;      // projection matrix
188     Vec     up      = {0.0F, 1.0F, 0.0F};
189     Vec     camLoc  = {0.0F, 0.0F, 1200.0F};
190     Vec     objPt   = {0.0F, 0.0F, 0.0F};
191     f32     left    = 240.0F;
192     f32     top     = 320.0F;
193     f32     znear    = 500.0F;
194     f32     zfar     = 2000.0F;
195 
196     MTXFrustum(p, left, -left, -top, top, znear, zfar);
197     GXSetProjection(p, GX_PERSPECTIVE);
198 
199     MTXLookAt(v, &camLoc, &up, &objPt);
200 }
201 
202 /*---------------------------------------------------------------------------*
203     Name:           DrawInit
204 
205     Description:    Initializes the vertex attribute format 0, and sets
206                     the array pointers and strides for the indexed data.
207 
208     Arguments:      none
209 
210     Returns:        none
211  *---------------------------------------------------------------------------*/
DrawInit(void)212 static void DrawInit( void )
213 {
214     u32 i;
215     f32 a;
216     GXColor c = {255, 255, 255, 255};
217 
218     GXSetCullMode(GX_CULL_NONE);
219 
220     // for generated models
221     GXSetVtxAttrFmt(GX_VTXFMT3, GX_VA_POS, GX_POS_XYZ, GX_F32, 0);
222     GXSetVtxAttrFmt(GX_VTXFMT3, GX_VA_NRM, GX_NRM_XYZ, GX_F32, 0);
223     GXSetVtxAttrFmt(GX_VTXFMT3, GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8, 0);
224 
225     GXClearVtxDesc();
226     GXSetVtxDesc(GX_VA_PNMTXIDX, GX_DIRECT);
227     GXSetVtxDesc(GX_VA_POS, GX_INDEX8);
228     GXSetVtxDesc(GX_VA_NRM, GX_INDEX8);
229     GXSetVtxDesc(GX_VA_CLR0, GX_DIRECT);
230 
231     GXSetArray(GX_VA_POS, MyVert, 3*sizeof(f32));
232     GXSetArray(GX_VA_NRM, MyVert, 3*sizeof(f32));
233 
234     //
235     // set up light parameters
236     //
237 
238     GXInitLightPos(&MyLight, 0.0F, 0.0F, 0.0F);
239     GXInitLightColor(&MyLight, c);
240     GXLoadLightObjImm(&MyLight, GX_LIGHT0);
241 
242     c.g = c.b = 0;
243     GXSetChanMatColor(GX_COLOR0, c);
244 
245     GXSetNumChans( 1 );
246     GXSetNumTexGens( 0 );
247     GXSetTevOp( GX_TEVSTAGE0, GX_PASSCLR );
248     GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR0A0);
249 
250     a = 0.0F;
251     for (i = 0; i < 16; i++)
252     {
253         a = i * 2.0F * PI / 16.0F;
254         MyVert[3*i] = sinf(a);   // x
255         MyVert[3*i+1] = cosf(a); // y
256         MyVert[3*i+2] = 0.0F;   // z
257     }
258 
259     MyVert[3*16] = 0;   // x
260     MyVert[3*16+1] = 0; // y
261     MyVert[3*16+2] = 1; // z
262 
263     MyVert[3*17] = 0;   // x
264     MyVert[3*17+1] = 0; // y
265     MyVert[3*17+2] = -1;// z
266 
267     // flush  array from CPU $
268     DCFlushRange(MyVert, 54 * sizeof(f32));
269 }
270 
271 
272 /*---------------------------------------------------------------------------*
273     Name:           DrawTick
274 
275     Description:    Draw the model once.
276                     GXInit makes GX_PNMTX0 the default matrix.
277 
278     Arguments:      v       view matrix
279 
280     Returns:        none
281  *---------------------------------------------------------------------------*/
DrawTick(Mtx v)282 static void DrawTick( Mtx v )
283 {
284     u8  i, j, k;
285     Mtx  ms;  // Model matrix. scale
286     Mtx  mry, mrx;  // Model matrix. rotate
287     Mtx  mt;  // Model matrix. translate
288     Mtx  mv;  // Modelview matrix.
289     float scale;
290 
291 
292     GXSetChanCtrl(
293         GX_COLOR0,
294         GX_ENABLE,  // enable channel
295         GX_SRC_REG,  // amb source
296         GX_SRC_VTX,  // mat source
297         GX_LIGHT0,   // light mask
298         GX_DF_CLAMP, // diffuse function
299         GX_AF_NONE);
300 
301     // build each segment matrix
302     // assumes less than 10 segs for now...
303     for (k = 0; k < 6; k++)
304     {
305         for (i = 0; i < 10; i++)
306         {
307             scale = ComputeScale(segs[(i + (10 * k)) - k].xlate);
308             MTXScale(ms, scale, scale, 100.0F);
309             MTXTrans(mt, 0.0F, 0.0F, segs[(i + (10 * k)) - k].xlate);
310             MTXRotDeg(mry, 'Y', rot);
311             MTXRotDeg(mrx, 'X', rot2 * (segs[(i + (10 * k)) - k].xlate/800.0F));
312 
313             MTXConcat(mt, ms, mv);
314             MTXConcat(mrx, mv, mv);
315             MTXConcat(mry, mv, mv);
316             MTXConcat(v, mv, mv);
317             GXLoadPosMtxImm(mv, segs[(i + (10 * k)) - k].mtx);
318 
319             if(scale == 100.00F) // segment is not in the bulge, do not adjust normals
320             {
321                 MTXInverse(mv, mv);
322                 MTXTranspose(mv, mv);
323                 segs[(i + (10 * k)) - k].recomputeNormalMtx = 0;
324                 GXLoadNrmMtxImm(mv, segs[(i + (10 * k)) - k].mtx);
325             }
326             else
327                 segs[(i + (10 * k)) - k].recomputeNormalMtx = scale;
328         }
329 
330         // draw each segment
331         // assume number of segs less than matrix memory size for now
332         for (j = 0; j < 9; j++)
333         {
334 
335             for (i = 0; i < 16; i++)
336             {
337                 if(segs[((j + (10 * k)) - k) + 1].recomputeNormalMtx)
338                     ComputeNormalRotMtx(&(segs[((j + (10 * k)) - k) + 1]), i);
339                 if(segs[((j + (10 * k)) - k)].recomputeNormalMtx)
340                     ComputeNormalRotMtx(&(segs[((j + (10 * k)) - k)]), i);
341             }
342             // finish cylinder
343             if(segs[((j + (10 * k)) - k) + 1].recomputeNormalMtx)
344                 ComputeNormalRotMtx(&(segs[((j + (10 * k)) - k) + 1]), 0);
345             if(segs[((j + (10 * k)) - k)].recomputeNormalMtx)
346                 ComputeNormalRotMtx(&(segs[((j + (10 * k)) - k)]), 0);
347 
348             // make this a function of circle divisions
349             GXBegin(GX_TRIANGLESTRIP, GX_VTXFMT3, 17*2);
350             for (i = 0; i < 16; i++)
351             {
352                 GXMatrixIndex1u8(segs[((j + (10 * k)) - k) + 1].mtx);
353                 GXPosition1x8(i);
354                 GXNormal1x8(i);
355                 GXColor1u32(MyColors[k]);
356 
357                 GXMatrixIndex1u8(segs[((j + (10 * k)) - k)].mtx);
358                 GXPosition1x8(i);
359                 GXNormal1x8(i);
360                 GXColor1u32(MyColors[k]);
361             }
362                 // finish cylinder
363                 GXMatrixIndex1u8(segs[((j + (10 * k)) - k) + 1].mtx);
364                 GXPosition1x8(0);
365                 GXNormal1x8(0);
366                 GXColor1u32(MyColors[k]);
367 
368                 GXMatrixIndex1u8(segs[((j + (10 * k)) - k)].mtx);
369                 GXPosition1x8(0);
370                 GXNormal1x8(0);
371                 GXColor1u32(MyColors[k]);
372             GXEnd();
373         }
374     }
375 
376     GXSetChanCtrl(
377         GX_COLOR0,
378         GX_ENABLE,  // enable channel
379         GX_SRC_REG,  // amb source
380         GX_SRC_REG,  // mat source
381         GX_LIGHT0,   // light mask
382         GX_DF_CLAMP, // diffuse function
383         GX_AF_NONE);
384 
385     MTXTrans(mt, 0.0F, 0.0F, BallPosition);
386     MTXRotDeg(mry, 'Y', rot);
387     MTXScale(ms, 125.0F, 125.0F, 125.0F);
388     MTXRotDeg(mrx, 'X', rot2 * (BallPosition/800.0F));
389 
390     MTXConcat(mt, ms, mv);
391     MTXConcat(mrx, mv, mv);
392     MTXConcat(mry, mv, mv);
393     MTXConcat(v, mv, mv);
394     GXLoadPosMtxImm(mv, GX_PNMTX0);
395     MTXInverse(mv, mv);
396     MTXTranspose(mv, mv);
397     GXLoadNrmMtxImm(mv, GX_PNMTX0);
398 
399     GXSetCurrentMtx(GX_PNMTX0);
400 
401     GXDrawSphere1(2);
402 }
403 
404 /*---------------------------------------------------------------------------*
405     Name:           AnimTick
406 
407     Description:    Changes scene parameters.
408 
409     Arguments:      none
410 
411     Returns:        none
412  *---------------------------------------------------------------------------*/
AnimTick(void)413 static void AnimTick( void )
414 {
415     if (DEMOPadGetStickX(0) > 0)
416         rot += 2;
417     else if (DEMOPadGetStickX(0) < 0)
418         rot -= 2;
419 
420     if(direction)
421     {
422          rot2 --;
423          if(rot2 < -30)
424             direction = 0;
425     }
426     else
427     {
428         rot2 ++;
429         if(rot2 > 30)
430             direction = 1;
431     }
432 
433     BallPosition += BallStep;
434     if(BallPosition < -800) BallStep = 10;
435     if(BallPosition > 800) BallStep = -10;
436 }
437 
438 /*---------------------------------------------------------------------------*/
ComputeScale(float position)439 static float ComputeScale ( float position )
440 {
441     float distance;
442     float scale;
443 
444     distance = BallPosition - position;
445 
446     if(distance < 0) distance = -distance;
447 
448     scale = (150 * 150) - (distance * distance);
449 
450     if(scale < 0.0F)
451         return 100.0F;
452 
453     scale = sqrtf(scale);
454 
455     if(scale < 100.0F)
456         return 100.0F;
457 
458     return scale;
459 }
460 
461 /*---------------------------------------------------------------------------*/
ComputeNormalRotMtx(Segment * seg,u32 idx)462 static void ComputeNormalRotMtx ( Segment *seg, u32 idx )
463 {
464     Mtx mv, mra, mry, mrx;
465     float scale = seg->recomputeNormalMtx;
466     Vec axis;
467     Vec normal = ((VecPtr)MyVert)[idx];
468 
469     if(seg->xlate < BallPosition)
470         axis = ((VecPtr)MyVert)[16];
471     else
472         axis = ((VecPtr)MyVert)[17];
473 
474     VECCrossProduct(&axis, &normal, &axis);
475 
476     MTXRotAxisDeg(mra, &axis, ((150.0F - scale) / 50.0F) * 70.0F);
477 
478     MTXRotDeg(mry, 'Y', rot);
479     MTXRotDeg(mrx, 'X', rot2 * (seg->xlate/800.0F));
480 
481     MTXConcat(mrx, mra, mv);
482     MTXConcat(mrx, mv, mv);
483     MTXConcat(mry, mv, mv);
484     MTXConcat(v, mv, mv);
485 
486     MTXInverse(mv, mv);
487     MTXTranspose(mv, mv);
488 
489     GXLoadNrmMtxImm(mv, seg->mtx);
490 }
491 
492 /*===========================================================================*/
493