1 /*---------------------------------------------------------------------------*
2   Project:  Dolphin/Revolution gx demo
3   File:     tg-emboss.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 #include <demo.h>
14 #include <math.h>
15 #include "cmn-model.h"
16 
17 #define SCREEN_DEPTH    128.0f
18 #define SCREEN_ZNEAR    0.0f    // near plane Z in screen coordinates
19 #define SCREEN_ZFAR     1.0f    // far  plane Z in screen coordinates
20 #define ZBUFFER_MAX     0x00ffffff
21 
22 /*---------------------------------------------------------------------------*
23    Typedefs
24  *---------------------------------------------------------------------------*/
25 typedef struct
26 {
27     Camera*     camera;
28     ViewPort*   viewport;
29     GXColor*    bgcolor;
30 }   Scene;
31 
32 /*---------------------------------------------------------------------------*
33    Forward references
34  *---------------------------------------------------------------------------*/
35 void    SceneDraw      ( Scene* );
36 void    SceneControl   ( Scene*, DEMOPadStatus* );
37 void    myInitModel    ( void );
38 void    myAnimeModel   ( Scene*, DEMOPadStatus* );
39 void    myDrawModel    ( Scene* );
40 void    myInfoModel    ( Scene* );
41 static void PrintIntro( void );
42 
43 /*---------------------------------------------------------------------------*
44    Rendering parameters
45  *---------------------------------------------------------------------------*/
46 Camera   myCamera =
47 {
48     { 0.0f,-300.0f, 0.0f },     // position
49     { 0.0f,   0.0f, 0.0f },     // target
50     { 0.0f,   0.0f, 1.0f },     // upVec
51        33.3f,                   // fovy
52        16.0f,                   // near plane Z in camera coordinates
53      1024.0f,                   // far  plane Z in camera coordinates
54 };
55 
56 ViewPort        myViewPort = { 0, 0, 0, 0 };
57 GXColor         myBgColor  = {  32,  32, 255, 255};
58 Scene           myScene    = { &myCamera, &myViewPort, &myBgColor };
59 
60 /*---------------------------------------------------------------------------*
61    Application main loop
62  *---------------------------------------------------------------------------*/
main(void)63 void    main ( void )
64 {
65     GXRenderModeObj *rmp;
66 
67     // initialize render settings and set clear color for first frame
68     DEMOInit(NULL);
69 
70     OSReport("\n\n");
71     OSReport("**********************************************\n");
72     OSReport("tg-emboss: Emboss Texture demo\n");
73     OSReport("**********************************************\n");
74     OSReport("To quit hit the start button.\n");
75     OSReport("\n");
76     OSReport("Main stick moves light position.\n");
77     OSReport("A button changes the indicated parameter.\n");
78     OSReport("B/X buttons move the parameter cursor.\n");
79     OSReport("**********************************************\n");
80     OSReport("\n\n");
81 
82     GXInvalidateTexAll( );
83     GXSetCopyClear( *(myScene.bgcolor), GX_MAX_Z24 );
84 
85     // Dummy copy operation to clear the eFB by specified color
86     GXCopyDisp( DEMOGetCurrentBuffer(), GX_TRUE );
87 
88     rmp = DEMOGetRenderModeObj();
89     myViewPort.width  = (s16) rmp->fbWidth;
90     myViewPort.height = (s16) rmp->efbHeight;
91 
92     myInitModel( );
93 
94     while ( ! ( DEMOPadGetButton(0) & PAD_BUTTON_MENU ) )
95     {
96         // get pad status
97         DEMOPadRead( );
98 
99         // General control & model animation
100         SceneControl( &myScene, &DemoPad[0] );
101         myAnimeModel( &myScene, &DemoPad[0] );
102 
103         // Draw scene
104         DEMOBeforeRender( );
105         SceneDraw( &myScene );
106         DEMODoneRender( );
107     }
108 
109     OSHalt("End of demo");
110 }
111 
112 /*---------------------------------------------------------------------------*
113    Functions
114  *---------------------------------------------------------------------------*/
115 
116 //============================================================================
117 //  Scene
118 //============================================================================
119 
120 /*---------------------------------------------------------------------------*
121     Name:           SceneControl
122     Description:    user interface for parameter control
123     Arguments:
124     Returns:        none
125  *---------------------------------------------------------------------------*/
SceneControl(Scene * s,DEMOPadStatus * pad)126 void    SceneControl( Scene* s, DEMOPadStatus* pad )
127 {
128     #pragma  unused( s, pad )
129     return;
130 }
131 
132 /*---------------------------------------------------------------------------*
133     Name:           SceneDraw
134     Description:    Draw model
135     Arguments:      Scene* s
136     Returns:        none
137  *---------------------------------------------------------------------------*/
SceneDraw(Scene * s)138 void    SceneDraw( Scene* s )
139 {
140     Camera*     c  = s->camera;
141     ViewPort*   v  = s->viewport;
142     float       aspect = (float) (4.0 / 3.0);
143 
144     // Set projection matrix
145     MTXPerspective ( c->projMtx, c->fovy, aspect, c->znear, c->zfar );
146     GXSetProjection( c->projMtx, GX_PERSPECTIVE );
147 
148     // Set CameraView matrix
149     MTXLookAt( c->viewMtx, &c->position, &c->up, &c->target );
150 
151     // Set Viewport
152     GXSetViewport( v->xorg, v->yorg, v->width, v->height,
153                    SCREEN_ZNEAR, SCREEN_ZFAR );
154     GXSetScissor ( v->xorg, v->yorg, v->width, v->height );
155 
156     // Set rendering mode
157     GXSetCullMode ( GX_CULL_BACK );
158 
159     // Draw objects
160     myDrawModel( s );
161 
162     // draw information
163     myInfoModel( s );
164     return;
165 }
166 
167 //============================================================================
168 //  Model
169 //  Rectangles
170 //============================================================================
171 typedef struct
172 {
173     GXColor        color;
174     Point3d        pos;         // in world space
175     f32            dist;
176     GXLightObj     obj;
177 }   MyLight;
178 
179 typedef struct
180 {
181     Mtx            modelMtx;
182     u8             bumpScale;   // 0-128 on Emulator, 0-255 on HW
183     s32            invNrmScale;
184     s32            blendSteps;
185     u32            texNo;
186     GXTexObj       texObj;
187 }   MyModel;
188 
189 typedef struct
190 {
191     s32            cursor;
192     s32            animation;
193     GXTexCoordID   coord, coord1; // to show all tex coord pairs work
194 }   MyControl;
195 
196 MyLight         myLight;
197 MyModel         myModel;
198 MyControl       myControl;
199 TPLPalettePtr   texPalette = 0;
200 
201 #ifndef M_SQRT3
202 #define M_SQRT3     1.732050808f
203 #endif
204 
205 /*---------------------------------------------------------------------------*
206     Name:           myDrawModel
207     Description:    draw model
208     Arguments:      Camera *c
209     Returns:        none
210  *---------------------------------------------------------------------------*/
myInitModel(void)211 void    myInitModel( void )
212 {
213     Vec   axis = { 1.0f, 0.0f, 1.0f };
214 
215     //------------------------------------------------------------------------
216     //  MODEL
217     //------------------------------------------------------------------------
218 
219     //  Matrix
220     MTXRotAxisDeg( myModel.modelMtx, &axis, -150.0f );
221 
222     //  Texture
223     myModel.texNo = 1;
224     TPLGetPalette( &texPalette, "gxTests/tg-02.tpl" );
225     TPLGetGXTexObjFromPalette( texPalette, &myModel.texObj, myModel.texNo-1 );
226 
227     //  Bump Mapping
228     myModel.bumpScale   = 128;
229     myModel.blendSteps  = 3;
230     myModel.invNrmScale = 48;
231 
232     //------------------------------------------------------------------------
233     //  LIGHT
234     //------------------------------------------------------------------------
235 
236     //  Light color
237     myLight.color.r = 32;
238     myLight.color.g = 64;
239     myLight.color.b = 96;
240 
241     //  Light position in world space
242     myLight.dist  = 100.0f;
243     myLight.pos.x = - myLight.dist * 1.0f / M_SQRT3;
244     myLight.pos.y = - myLight.dist * 1.0f / M_SQRT3;
245     myLight.pos.z = + myLight.dist * 1.0f / M_SQRT3;
246 
247     //  Set white light with no attenuation
248     GXInitLightSpot    ( &myLight.obj, 0.0f, GX_SP_OFF );
249     GXInitLightDistAttn( &myLight.obj, 0.0f, 0.0f, GX_DA_OFF );
250 
251     //------------------------------------------------------------------------
252     //  CONTROL
253     //------------------------------------------------------------------------
254     myControl.cursor = 0;
255     myControl.animation = 1;
256     myControl.coord = GX_TEXCOORD0;
257     myControl.coord1 = GX_TEXCOORD1;
258 }
259 
260 /*---------------------------------------------------------------------------*
261     Name:           myAnimeModel
262     Description:    animate model
263     Arguments:      Scene *s
264     Returns:        none
265  *---------------------------------------------------------------------------*/
myAnimeModel(Scene * s,DEMOPadStatus * pad)266 void    myAnimeModel( Scene* s, DEMOPadStatus* pad )
267 {
268 #   pragma  unused(s)
269     f32  r2, y2, scale;
270     Mtx  tmp;
271     Vec  axis;
272 
273     //---------------------------------------------------------------------
274     //  Move cursor
275     //---------------------------------------------------------------------
276     if ( pad->buttonDown & PAD_BUTTON_X )
277     {
278         myControl.cursor ++;
279     }
280     if ( pad->buttonDown & PAD_BUTTON_B )
281     {
282         myControl.cursor += 4;
283     }
284     myControl.cursor %= 5;
285 
286     //---------------------------------------------------------------------
287     //  Cycle though all texture coordinates
288     //---------------------------------------------------------------------
289     if ( pad->buttonDown & PAD_BUTTON_Y )
290     {
291         myControl.coord++;
292         if (myControl.coord > GX_TEXCOORD6)
293             myControl.coord = GX_TEXCOORD0;
294         myControl.coord1 = (GXTexCoordID)(myControl.coord + 1);
295         OSReport("Using texture coord %d and %d\n",
296                 myControl.coord, myControl.coord1);
297     }
298     //---------------------------------------------------------------------
299     //  Change item
300     //---------------------------------------------------------------------
301     if ( pad->buttonDown & PAD_BUTTON_A )
302     {
303         switch ( myControl.cursor )
304         {
305         case  0:
306             //  Texture
307             myModel.texNo %= 3;
308             myModel.texNo ++;
309             TPLGetGXTexObjFromPalette( texPalette,
310                                   &myModel.texObj, myModel.texNo-1 );
311             break;
312 
313         case  1:
314             //  Animation
315             myControl.animation ^= 1;
316             break;
317 
318         case  2:
319             //  Bump scale
320             myModel.bumpScale = (u8)( ( myModel.bumpScale < 128 )
321                                       ? myModel.bumpScale + 32 : 0 );
322             break;
323 
324         case  3:
325             //  Normal scale    ( 8 - 96 )
326             myModel.invNrmScale %= 96;
327             myModel.invNrmScale += 8;
328             break;
329 
330         case  4:
331             //  Show step of blending
332             myModel.blendSteps %= 3;
333             myModel.blendSteps ++;
334             break;
335         }
336     }
337 
338     //---------------------------------------------------------------------
339     //  Animation
340     //---------------------------------------------------------------------
341     if ( myControl.animation )
342     {
343         axis.x = 1.0f;
344         axis.y = 2.0f;
345         axis.z = 0.5f;
346         MTXRotAxisDeg( tmp, &axis, 1.0f );
347         MTXConcat( myModel.modelMtx, tmp, myModel.modelMtx );
348     }
349 
350     //---------------------------------------------------------------------
351     //  Change light position
352     //---------------------------------------------------------------------
353     if ( pad->dirs & DEMO_STICK_LEFT  ) myLight.pos.x -= 2.0f;
354     if ( pad->dirs & DEMO_STICK_RIGHT ) myLight.pos.x += 2.0f;
355     if ( pad->dirs & DEMO_STICK_UP    ) myLight.pos.z += 2.0f;
356     if ( pad->dirs & DEMO_STICK_DOWN  ) myLight.pos.z -= 2.0f;
357 
358     r2 = myLight.pos.x * myLight.pos.x + myLight.pos.z * myLight.pos.z;
359     y2 = myLight.dist * myLight.dist - r2;
360 
361     if ( y2 < 0 )
362     {
363         scale = myLight.dist / sqrtf(r2);
364         myLight.pos.x *= scale;
365         myLight.pos.z *= scale;
366         myLight.pos.y  = 0.0f;
367     }
368     else
369     {
370         myLight.pos.y = - sqrtf(y2);
371     }
372 }
373 
374 /*---------------------------------------------------------------------------*
375     Name:           myDrawModel
376     Description:    draw model
377     Arguments:      Scene *c
378     Returns:        none
379  *---------------------------------------------------------------------------*/
380 
myDrawModel(Scene * s)381 void    myDrawModel( Scene* s )
382 {
383     Camera*     c = s->camera;
384     Mtx         mvmtx, posMtx, nrmMtx;
385     Point3d     lpos;
386     f32         nrmScale = 1.0f / (f32)myModel.invNrmScale;
387     GXColor color1 = {255,64,64,255};
388 
389     // set a light object
390     MTXMultVec( c->viewMtx, &myLight.pos, &lpos );
391     GXInitLightPos   ( &myLight.obj, lpos.x, lpos.y, lpos.z );
392     GXInitLightColor ( &myLight.obj, myLight.color );
393     GXLoadLightObjImm( &myLight.obj, GX_LIGHT0 );
394 
395     // set modelview matrix
396     GXSetCurrentMtx( GX_PNMTX0 );
397 
398     // Load ModelView matrix for pos/nrm into view space
399     // Note: mvmtx is uniform transformation here, then (mvmtx)^(-T) = mvmtx
400     //       With bump mapping, normal must be scaled to match texel size in
401     //       texture space.
402     MTXConcat      ( c->viewMtx, myModel.modelMtx, mvmtx );
403     MTXScale       ( posMtx, 75.0f, 75.0f, 75.0f );
404     MTXConcat      ( mvmtx,  posMtx, posMtx );
405     GXLoadPosMtxImm( posMtx, GX_PNMTX0 );
406     MTXScale       ( nrmMtx, nrmScale, nrmScale, nrmScale );
407     MTXConcat      ( mvmtx,  nrmMtx, nrmMtx );
408     GXLoadNrmMtxImm( nrmMtx, GX_PNMTX0 );
409 
410     // Set texture
411     GXLoadTexObj( &myModel.texObj, GX_TEXMAP0 );
412 
413     // Render mode for Box
414     GXClearVtxDesc( );
415 
416     //  z update for 1st stage
417     GXSetZMode  ( GX_TRUE, GX_LESS, GX_TRUE );
418 
419     //------------------------------------------------------------------------
420     //   Actual code for bump mapping on dolphin HW.
421     //------------------------------------------------------------------------
422     {
423         GXColor bumpScale;
424         u32     i;
425         GXColor white = {255,255,255,255};
426         GXColor grey = {128,128,128,128};
427 
428         //  Vertex component
429         GXClearVtxDesc();
430         GXSetVtxDesc( GX_VA_POS,  GX_DIRECT );
431         GXSetVtxDesc( GX_VA_NBT,  GX_DIRECT );
432         GXSetVtxDesc( GX_VA_TEX0, GX_DIRECT );
433 
434         //  Light 0 for bump mapping
435         GXSetNumChans(1); // GX_COLOR0A0
436         GXSetChanCtrl( GX_COLOR0, GX_ENABLE,     GX_SRC_REG,  GX_SRC_REG,
437                                   GX_LIGHT0,     GX_DF_CLAMP, GX_AF_NONE );
438         GXSetChanCtrl( GX_ALPHA0, GX_DISABLE,    GX_SRC_REG,  GX_SRC_REG,
439                                   GX_LIGHT_NULL, GX_DF_CLAMP, GX_AF_NONE );
440         GXSetChanMatColor( GX_COLOR0A0, white );
441         GXSetChanAmbColor( GX_COLOR0A0, grey );
442 
443         // clear out unused tex gens
444         for (i = 0; i < myControl.coord; i++)
445             GXSetTexCoordGen( (GXTexCoordID)i, GX_TG_MTX2x4,
446                               GX_TG_POS, GX_IDENTITY );
447 
448         //  Tex Gen
449         //     GX_TEXCOORD0: Base texcoord of bump mapping
450         //     GX_TEXCOORD1: Tex gen by bump mapping
451         GXSetNumTexGens((u8)(myControl.coord1+1)); // coord1 is always the max coord
452         GXSetTexCoordGen( myControl.coord, GX_TG_MTX2x4,
453                           GX_TG_TEX0,      GX_IDENTITY );
454         GXSetTexCoordGen( myControl.coord1, GX_TG_BUMP0,
455                           (GXTexGenSrc)((u32)myControl.coord + GX_TG_TEXCOORD0),
456                           GX_IDENTITY );
457 
458         //  Tev Order
459         //     GX_TEVSTAGE0: send base    texture + diffuse color
460         //     GX_TEVSTAGE1: send shifted texture
461         GXSetTevOrder( GX_TEVSTAGE0,
462                        myControl.coord, GX_TEXMAP0, GX_COLOR0A0   );
463         GXSetTevOrder( GX_TEVSTAGE1,
464                        myControl.coord1, GX_TEXMAP0, GX_COLOR_NULL );
465 
466         //  Tev Register
467         //     GX_TEVREG0: ( X, X, X, bumpScale )
468         bumpScale.a = myModel.bumpScale;
469         GXSetTevColor( GX_TEVREG0, bumpScale );
470 
471         //
472         //  In many case, bump mapping needs 3 tev stage, but here,
473         //  use only 2 tev stages, since no material texture map
474         //
475         GXSetNumTevStages( 2 );
476 
477         //
478         //  Tev stage0
479         //     Color:   BumpTexture * bumpScale + DiffuseColor => R
480         //     Alpha:   Not used
481         //
482         GXSetTevColorIn( GX_TEVSTAGE0, GX_CC_ZERO,
483                                        GX_CC_TEXC,  /* Bump Texture   */
484                                        GX_CC_A0,    /* BumpScale      */
485                                        GX_CC_RASC   /* Diffuse color  */ );
486         GXSetTevColorOp( GX_TEVSTAGE0, GX_TEV_ADD,
487                                        GX_TB_ZERO,
488                                        GX_CS_SCALE_1,
489                                        GX_DISABLE,
490                                        GX_TEVPREV   /* To next stage  */ );
491 
492         GXSetTevAlphaIn( GX_TEVSTAGE0, GX_CA_ZERO, GX_CA_ZERO,
493                                        GX_CA_ZERO, GX_CA_ZERO );
494         GXSetTevAlphaOp( GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO,
495                                        GX_CS_SCALE_1, GX_DISABLE, GX_TEVPREV );
496 
497         //
498         //  Tev stage1
499         //     Color:   ShiftTexture * bumpScale * (-1) + R  =>  R
500         //     Alpha:   Not used
501         //
502         GXSetTevColorIn( GX_TEVSTAGE1, GX_CC_ZERO,
503                                        GX_CC_TEXC,  /* Shift Texture  */
504                                        GX_CC_A0,    /* BumpScale      */
505                                        GX_CC_CPREV  /* Last stage out */ );
506         GXSetTevColorOp( GX_TEVSTAGE1, GX_TEV_SUB,  /* mult (-1)      */
507                                        GX_TB_ZERO,
508                                        GX_CS_SCALE_1,
509                                        GX_ENABLE,
510                                        GX_TEVPREV                        );
511 
512         GXSetTevAlphaIn( GX_TEVSTAGE1, GX_CA_ZERO, GX_CA_ZERO,
513                                        GX_CA_ZERO, GX_CA_ZERO );
514         GXSetTevAlphaOp( GX_TEVSTAGE1, GX_TEV_ADD, GX_TB_ZERO,
515                                        GX_CS_SCALE_1, GX_DISABLE, GX_TEVPREV );
516 
517         //-------------------------------------------------
518         //  Draw objects
519         //-------------------------------------------------
520         GXDrawCube( );
521     }
522 
523     //-------------------------------------------------
524     //  Draw light direction
525     //-------------------------------------------------
526 
527     // Shade mode
528     GXSetChanCtrl    ( GX_COLOR0, GX_DISABLE,    GX_SRC_REG,  GX_SRC_REG,
529                                   GX_LIGHT_NULL, GX_DF_CLAMP, GX_AF_NONE );
530     GXSetChanMatColor( GX_COLOR0, color1 );
531 
532     GXSetNumTexGens  ( 0 );
533 
534     // Tev mode
535     GXSetNumTevStages( 1 );
536     GXSetTevOrder    ( GX_TEVSTAGE0,
537                        GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR0A0 );
538     GXSetTevOp       ( GX_TEVSTAGE0, GX_PASSCLR );
539 
540     // Render mode
541     GXSetBlendMode   ( GX_BM_BLEND, GX_BL_ONE, GX_BL_ZERO, GX_LO_CLEAR );
542     GXSetZMode       ( GX_TRUE, GX_LESS, GX_TRUE );
543 
544     // Draw lines
545     GXClearVtxDesc   ( );
546     GXSetVtxDesc     ( GX_VA_POS, GX_DIRECT );
547     GXSetVtxAttrFmt  ( GX_VTXFMT1, GX_VA_POS, GX_POS_XYZ, GX_F32, 0 );
548     GXLoadPosMtxImm  ( c->viewMtx, GX_PNMTX0 );
549     GXBegin( GX_LINES, GX_VTXFMT1, 2 );
550        GXPosition3f32( 0.0f, 0.0f, 0.0f );
551        GXPosition3f32( myLight.pos.x, myLight.pos.y, myLight.pos.z );
552     GXEnd( );
553     GXBegin( GX_LINESTRIP, GX_VTXFMT1, 5 );
554        GXPosition3f32( myLight.pos.x+2.0f, myLight.pos.y, myLight.pos.z+2.0f );
555        GXPosition3f32( myLight.pos.x+2.0f, myLight.pos.y, myLight.pos.z-2.0f );
556        GXPosition3f32( myLight.pos.x-2.0f, myLight.pos.y, myLight.pos.z-2.0f );
557        GXPosition3f32( myLight.pos.x-2.0f, myLight.pos.y, myLight.pos.z+2.0f );
558        GXPosition3f32( myLight.pos.x+2.0f, myLight.pos.y, myLight.pos.z+2.0f );
559     GXEnd( );
560 
561     return;
562 }
563 
564 /*---------------------------------------------------------------------------*
565     Name:           ModelDrawInfo
566     Description:    Draw scene information
567     Arguments:
568     Returns:        none
569  *---------------------------------------------------------------------------*/
myInfoModel(Scene * s)570 void    myInfoModel( Scene* s )
571 {
572     ViewPort*   v = s->viewport;
573 
574     // Z mode for drawing captions
575     GXSetZMode( GX_TRUE, GX_ALWAYS, GX_TRUE );
576 
577     // Draw parameters to the window
578     DEMOInitCaption( DM_FT_XLU, v->width, v->height );
579     DEMOPuts  ( 10, (s16)(myControl.cursor*8+10), 0, "\x7f" );
580     DEMOPrintf( 18, 10, 0, "Texture      %d", myModel.texNo );
581     DEMOPrintf( 18, 18, 0,
582                 "Animation    %s", myControl.animation ? "ON" : "OFF" );
583     DEMOPrintf( 18, 26, 0, "Bump   scale %d", myModel.bumpScale );
584     DEMOPrintf( 18, 34, 0, "Normal scale 1/%d", myModel.invNrmScale );
585     DEMOPrintf( 18, 42, 0, "Blend  steps %d", myModel.blendSteps );
586 
587     return;
588 }
589 
590 /*---------------------------------------------------------------------------*
591     Name:           PrintIntro
592 
593     Description:    Prints the directions on how to use this demo.
594 
595     Arguments:      none
596 
597     Returns:        none
598  *---------------------------------------------------------------------------*/
PrintIntro(void)599 static void PrintIntro( void )
600 {
601     OSReport("\n\n");
602     OSReport("**********************************************\n");
603     OSReport("tg-emboss: demonstrate bump mapping using the \n");
604     OSReport("           embossing technique.               \n");
605     OSReport("**********************************************\n");
606     OSReport("to quit hit the start button\n");
607     OSReport("\n");
608     OSReport("Main Stick   : Move Light Position\n");
609     OSReport("Sub  Stick   : Rotate the Model\n");
610     OSReport("X/B Buttons  : Select parameter\n");
611     OSReport("A Button     : Change selected parameter\n");
612     OSReport("Y Button     : Change texture coordinate\n");
613     OSReport("**********************************************\n");
614 }
615 
616 
617 
618 /*======== End of tg-emboss.c ========*/
619