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     OSReport("\n\n");
154     OSReport("**********************************************\n");
155     OSReport("tf-stitch: Stitched Object demo\n");
156     OSReport("**********************************************\n");
157     OSReport("To quit hit the start button.\n");
158     OSReport("\n");
159     OSReport("Main stick L/R rotates model.\n");
160     OSReport("**********************************************\n");
161     OSReport("\n\n");
162 
163     CameraInit(v); // Initialize the camera.
164     DrawInit();    // Define my vertex formats and set array pointers.
165 
166     while(!(DEMOPadGetButton(0) & PAD_BUTTON_MENU))
167     {
168         DEMOBeforeRender();
169 
170         DrawTick(v);        // Draw the model.
171 
172         DEMODoneRender();
173 
174         DEMOPadRead();      // Update pad status.
175         AnimTick();         // Update animation.
176     }
177 
178     OSHalt("End of test");
179 }
180 
181 
182 /*---------------------------------------------------------------------------*
183    Functions
184  *---------------------------------------------------------------------------*/
185 /*---------------------------------------------------------------------------*
186     Name:           CameraInit
187 
188     Description:    Initialize the projection matrix and load into hardware.
189                     Initialize the view matrix.
190 
191     Arguments:      v      view matrix
192 
193     Returns:        none
194  *---------------------------------------------------------------------------*/
CameraInit(Mtx v)195 static void CameraInit ( Mtx v )
196 {
197     Mtx44   p;      // projection matrix
198     Vec     up      = {0.0F, 1.0F, 0.0F};
199     Vec     camLoc  = {0.0F, 0.0F, 1200.0F};
200     Vec     objPt   = {0.0F, 0.0F, 0.0F};
201     f32     left    = 240.0F;
202     f32     top     = 320.0F;
203     f32     znear    = 500.0F;
204     f32     zfar     = 2000.0F;
205 
206     MTXFrustum(p, left, -left, -top, top, znear, zfar);
207     GXSetProjection(p, GX_PERSPECTIVE);
208 
209     MTXLookAt(v, &camLoc, &up, &objPt);
210 }
211 
212 /*---------------------------------------------------------------------------*
213     Name:           DrawInit
214 
215     Description:    Initializes the vertex attribute format 0, and sets
216                     the array pointers and strides for the indexed data.
217 
218     Arguments:      none
219 
220     Returns:        none
221  *---------------------------------------------------------------------------*/
DrawInit(void)222 static void DrawInit( void )
223 {
224     u32 i;
225     f32 a;
226     GXColor c = {255, 255, 255, 255};
227 
228     GXSetCullMode(GX_CULL_NONE);
229 
230     // for generated models
231     GXSetVtxAttrFmt(GX_VTXFMT3, GX_VA_POS, GX_POS_XYZ, GX_F32, 0);
232     GXSetVtxAttrFmt(GX_VTXFMT3, GX_VA_NRM, GX_NRM_XYZ, GX_F32, 0);
233     GXSetVtxAttrFmt(GX_VTXFMT3, GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8, 0);
234 
235     GXClearVtxDesc();
236     GXSetVtxDesc(GX_VA_PNMTXIDX, GX_DIRECT);
237     GXSetVtxDesc(GX_VA_POS, GX_INDEX8);
238     GXSetVtxDesc(GX_VA_NRM, GX_INDEX8);
239     GXSetVtxDesc(GX_VA_CLR0, GX_DIRECT);
240 
241     GXSetArray(GX_VA_POS, MyVert, 3*sizeof(f32));
242     GXSetArray(GX_VA_NRM, MyVert, 3*sizeof(f32));
243 
244     //
245     // set up light parameters
246     //
247 
248     GXInitLightPos(&MyLight, 0.0F, 0.0F, 0.0F);
249     GXInitLightColor(&MyLight, c);
250     GXLoadLightObjImm(&MyLight, GX_LIGHT0);
251 
252     c.g = c.b = 0;
253     GXSetChanMatColor(GX_COLOR0, c);
254 
255     GXSetNumChans( 1 );
256     GXSetNumTexGens( 0 );
257     GXSetTevOp( GX_TEVSTAGE0, GX_PASSCLR );
258     GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR0A0);
259 
260     a = 0.0F;
261     for (i = 0; i < 16; i++)
262     {
263         a = i * 2.0F * PI / 16.0F;
264         MyVert[3*i] = sinf(a);   // x
265         MyVert[3*i+1] = cosf(a); // y
266         MyVert[3*i+2] = 0.0F;   // z
267     }
268 
269     MyVert[3*16] = 0;   // x
270     MyVert[3*16+1] = 0; // y
271     MyVert[3*16+2] = 1; // z
272 
273     MyVert[3*17] = 0;   // x
274     MyVert[3*17+1] = 0; // y
275     MyVert[3*17+2] = -1;// z
276 
277     // flush  array from CPU $
278     DCFlushRange(MyVert, 54 * sizeof(f32));
279 }
280 
281 
282 /*---------------------------------------------------------------------------*
283     Name:           DrawTick
284 
285     Description:    Draw the model once.
286                     GXInit makes GX_PNMTX0 the default matrix.
287 
288     Arguments:      v        view matrix
289 
290     Returns:        none
291  *---------------------------------------------------------------------------*/
DrawTick(Mtx v)292 static void DrawTick( Mtx v )
293 {
294     u8  i, j, k;
295     Mtx  ms;  // Model matrix. scale
296     Mtx  mry, mrx;  // Model matrix. rotate
297     Mtx  mt;  // Model matrix. translate
298     Mtx  mv;  // Modelview matrix.
299     float scale;
300 
301 
302     GXSetChanCtrl(
303         GX_COLOR0,
304         GX_ENABLE,  // enable channel
305         GX_SRC_REG,  // amb source
306         GX_SRC_VTX,  // mat source
307         GX_LIGHT0,   // light mask
308         GX_DF_CLAMP, // diffuse function
309         GX_AF_NONE);
310 
311     // build each segment matrix
312     // assumes less than 10 segs for now...
313     for (k = 0; k < 6; k++)
314     {
315         for (i = 0; i < 10; i++)
316         {
317             scale = ComputeScale(segs[(i + (10 * k)) - k].xlate);
318             MTXScale(ms, scale, scale, 100.0F);
319             MTXTrans(mt, 0.0F, 0.0F, segs[(i + (10 * k)) - k].xlate);
320             MTXRotDeg(mry, 'Y', rot);
321             MTXRotDeg(mrx, 'X', rot2 * (segs[(i + (10 * k)) - k].xlate/800.0F));
322 
323             MTXConcat(mt, ms, mv);
324             MTXConcat(mrx, mv, mv);
325             MTXConcat(mry, mv, mv);
326             MTXConcat(v, mv, mv);
327             GXLoadPosMtxImm(mv, segs[(i + (10 * k)) - k].mtx);
328 
329             if(scale == 100.00F) // segment is not in the bulge, do not adjust normals
330             {
331                 MTXInverse(mv, mv);
332                 MTXTranspose(mv, mv);
333                 segs[(i + (10 * k)) - k].recomputeNormalMtx = 0;
334                 GXLoadNrmMtxImm(mv, segs[(i + (10 * k)) - k].mtx);
335             }
336             else
337                 segs[(i + (10 * k)) - k].recomputeNormalMtx = scale;
338         }
339 
340         // draw each segment
341         // assume number of segs less than matrix memory size for now
342         for (j = 0; j < 9; j++)
343         {
344 
345             for (i = 0; i < 16; i++)
346             {
347                 if(segs[((j + (10 * k)) - k) + 1].recomputeNormalMtx)
348                     ComputeNormalRotMtx(&(segs[((j + (10 * k)) - k) + 1]), i);
349                 if(segs[((j + (10 * k)) - k)].recomputeNormalMtx)
350                     ComputeNormalRotMtx(&(segs[((j + (10 * k)) - k)]), i);
351             }
352             // finish cylinder
353             if(segs[((j + (10 * k)) - k) + 1].recomputeNormalMtx)
354                 ComputeNormalRotMtx(&(segs[((j + (10 * k)) - k) + 1]), 0);
355             if(segs[((j + (10 * k)) - k)].recomputeNormalMtx)
356                 ComputeNormalRotMtx(&(segs[((j + (10 * k)) - k)]), 0);
357 
358             // make this a function of circle divisions
359             GXBegin(GX_TRIANGLESTRIP, GX_VTXFMT3, 17*2);
360             for (i = 0; i < 16; i++)
361             {
362                 GXMatrixIndex1u8(segs[((j + (10 * k)) - k) + 1].mtx);
363                 GXPosition1x8(i);
364                 GXNormal1x8(i);
365                 GXColor1u32(MyColors[k]);
366 
367                 GXMatrixIndex1u8(segs[((j + (10 * k)) - k)].mtx);
368                 GXPosition1x8(i);
369                 GXNormal1x8(i);
370                 GXColor1u32(MyColors[k]);
371             }
372                 // finish cylinder
373                 GXMatrixIndex1u8(segs[((j + (10 * k)) - k) + 1].mtx);
374                 GXPosition1x8(0);
375                 GXNormal1x8(0);
376                 GXColor1u32(MyColors[k]);
377 
378                 GXMatrixIndex1u8(segs[((j + (10 * k)) - k)].mtx);
379                 GXPosition1x8(0);
380                 GXNormal1x8(0);
381                 GXColor1u32(MyColors[k]);
382             GXEnd();
383         }
384     }
385 
386     GXSetChanCtrl(
387         GX_COLOR0,
388         GX_ENABLE,  // enable channel
389         GX_SRC_REG,  // amb source
390         GX_SRC_REG,  // mat source
391         GX_LIGHT0,   // light mask
392         GX_DF_CLAMP, // diffuse function
393         GX_AF_NONE);
394 
395     MTXTrans(mt, 0.0F, 0.0F, BallPosition);
396     MTXRotDeg(mry, 'Y', rot);
397     MTXScale(ms, 125.0F, 125.0F, 125.0F);
398     MTXRotDeg(mrx, 'X', rot2 * (BallPosition/800.0F));
399 
400     MTXConcat(mt, ms, mv);
401     MTXConcat(mrx, mv, mv);
402     MTXConcat(mry, mv, mv);
403     MTXConcat(v, mv, mv);
404     GXLoadPosMtxImm(mv, GX_PNMTX0);
405     MTXInverse(mv, mv);
406     MTXTranspose(mv, mv);
407     GXLoadNrmMtxImm(mv, GX_PNMTX0);
408 
409     GXSetCurrentMtx(GX_PNMTX0);
410 
411     GXDrawSphere1(2);
412 }
413 
414 /*---------------------------------------------------------------------------*
415     Name:           AnimTick
416 
417     Description:    Changes scene parameters.
418 
419     Arguments:      none
420 
421     Returns:        none
422  *---------------------------------------------------------------------------*/
AnimTick(void)423 static void AnimTick( void )
424 {
425     if (DEMOPadGetStickX(0) > 0)
426         rot += 2;
427     else if (DEMOPadGetStickX(0) < 0)
428         rot -= 2;
429 
430     if(direction)
431     {
432          rot2 --;
433          if(rot2 < -30)
434             direction = 0;
435     }
436     else
437     {
438         rot2 ++;
439         if(rot2 > 30)
440             direction = 1;
441     }
442 
443     BallPosition += BallStep;
444     if(BallPosition < -800) BallStep = 10;
445     if(BallPosition > 800) BallStep = -10;
446 }
447 
448 /*---------------------------------------------------------------------------*/
ComputeScale(float position)449 static float ComputeScale ( float position )
450 {
451     float distance;
452     float scale;
453 
454     distance = BallPosition - position;
455 
456     if(distance < 0) distance = -distance;
457 
458     scale = (150 * 150) - (distance * distance);
459 
460     if(scale < 0.0F)
461         return 100.0F;
462 
463     scale = sqrtf(scale);
464 
465     if(scale < 100.0F)
466         return 100.0F;
467 
468     return scale;
469 }
470 
471 /*---------------------------------------------------------------------------*/
ComputeNormalRotMtx(Segment * seg,u32 idx)472 static void ComputeNormalRotMtx ( Segment *seg, u32 idx )
473 {
474     Mtx mv, mra, mry, mrx;
475     float scale = seg->recomputeNormalMtx;
476     Vec axis;
477     Vec normal = ((VecPtr)MyVert)[idx];
478 
479     if(seg->xlate < BallPosition)
480         axis = ((VecPtr)MyVert)[16];
481     else
482         axis = ((VecPtr)MyVert)[17];
483 
484     VECCrossProduct(&axis, &normal, &axis);
485 
486     MTXRotAxisDeg(mra, &axis, ((150.0F - scale) / 50.0F) * 70.0F);
487 
488     MTXRotDeg(mry, 'Y', rot);
489     MTXRotDeg(mrx, 'X', rot2 * (seg->xlate/800.0F));
490 
491     MTXConcat(mrx, mra, mv);
492     MTXConcat(mrx, mv, mv);
493     MTXConcat(mry, mv, mv);
494     MTXConcat(v, mv, mv);
495 
496     MTXInverse(mv, mv);
497     MTXTranspose(mv, mv);
498 
499     GXLoadNrmMtxImm(mv, seg->mtx);
500 }
501 
502 /*===========================================================================*/
503