1 /*---------------------------------------------------------------------------*
2   Project:  Dolphin
3   File:     gd-texture-gc.c
4 
5   Copyright 2001-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   $Log: gd-texture-gc.c,v $
14   Revision 1.4  2006/08/18 21:50:57  carlmu
15   Added explanatory output.
16 
17   Revision 1.3  02/20/2006 04:13:10  mitu
18   changed include path from dolphin/ to revolution/.
19 
20   Revision 1.2  02/09/2006 01:17:32  hirose
21   Replaced TEX library calls by TPL library.
22 
23   Revision 1.1  02/08/2006 11:19:43  mitu
24   1st version.
25 
26 
27     5     02/09/06 11:26:00 Hirose
28     Resolved future time stamp problem.
29 
30     5     10/19/02 6:53p Hirose
31     Changed location of data file.
32 
33     4     10/11/01 4:05p Carl
34     Added use of color-index texture and TLUT.
35 
36     3     9/25/01 6:46p Carl
37     Adjusted #pragma usage.
38 
39     2     9/24/01 2:23p Hirose
40     Changed flag definition.
41 
42     1     9/19/01 4:27p Carl
43     Sources for GD texture demo.
44 
45   $NoKeywords: $
46  *---------------------------------------------------------------------------*/
47 
48 #include <demo.h>
49 #include <math.h>
50 
51 #include <revolution/gd.h>
52 
53 /*---------------------------------------------------------------------------*
54    Defines
55  *---------------------------------------------------------------------------*/
56 
57 // This macro is used to copy a 3x4 matrix into a 3x3 matrix
58 #define COPY3x3(ms, md) \
59     { md[0][0]=ms[0][0]; md[0][1]=ms[0][1]; md[0][2]=ms[0][2]; \
60       md[1][0]=ms[1][0]; md[1][1]=ms[1][1]; md[1][2]=ms[1][2]; \
61       md[2][0]=ms[2][0]; md[2][1]=ms[2][1]; md[2][2]=ms[2][2]; }
62 
63 /*---------------------------------------------------------------------------*
64    Forward references
65  *---------------------------------------------------------------------------*/
66 
67 void        main            ( void );
68 
69 static void CameraInit      ( void );
70 static void DrawInit        ( void );
71 static void DrawTick        ( void );
72 
73 static void AnimTick        ( void );
74 
75 static void ParameterInit   ( void );
76 
77 static void PatchTexPtrs(u32 numTplFiles, TPLPalettePtr tplFilePtrs[],
78                          u32 numTextures, u32 tplFileNums[], u32 tplTexNums[],
79                          GDLObj *dlObj, u32 dlOffsets[]);
80 
81 #ifdef LOAD_DL_FROM_FILE
82 static void LoadDLs   ( void );
83 #else
84 extern void CreateDLs( void );
85 #endif
86 
87 /*---------------------------------------------------------------------------*
88    Global variables
89  *---------------------------------------------------------------------------*/
90 
91 // Display lists *************************************************************
92 
93 // These are only created during runtime if LOAD_DL_FROM_FILE is not defined.
94 // Otherwise, these are loaded from a file.
95 
96 // This DL is used with the "Draw" display list.
97 // It initializes state that will be used by the Draw DL.
98 
99 GDLObj InitDLO;
100 
101 // This DL draws a textured cube.  It must be paired with the Init DL.
102 
103 GDLObj DrawDLO;
104 
105 // This array indicates the offsets to patch memory addresses for the
106 // primitive data arrays (positions, normals, texture coordinates)
107 // referred to in the Init DL.
108 
109 u32 *setArrayOffsets;
110 
111 // This array tells us the offsets for where to patch the memory addresses
112 // for the textures in the Draw DL.
113 
114 u32 *texAddrOffsets;
115 
116 // This array tells us the offsets for where to patch the main memory
117 // addresses for loading the TLUTs in the Init DL.
118 
119 u32 *tlutAddrOffsets;
120 
121 /*---------------------------------------------------------------------------*/
122 
123 // Actual primitive data follows
124 
125 #define SIDE 30
126 #define NORM (sqrt(3.0))/3.0
127 
128 // Remember:  Alignment of vertex arrays to 32B IS NOT required, but it
129 // may result in a slight performance improvement.
130 
131 float FloatVert[] ATTRIBUTE_ALIGN(32) =
132 {
133     -SIDE,  SIDE, -SIDE,
134     -SIDE,  SIDE,  SIDE,
135     -SIDE, -SIDE,  SIDE,
136     -SIDE, -SIDE, -SIDE,
137      SIDE,  SIDE, -SIDE,
138      SIDE, -SIDE, -SIDE,
139      SIDE, -SIDE,  SIDE,
140      SIDE,  SIDE,  SIDE,
141 };
142 
143 float FloatNorm[] ATTRIBUTE_ALIGN(32) =
144 {
145     -1,  1, -1,
146     -1,  1,  1,
147     -1, -1,  1,
148     -1, -1, -1,
149      1,  1, -1,
150      1, -1, -1,
151      1, -1,  1,
152      1,  1,  1,
153 };
154 
155 float FloatTex[] ATTRIBUTE_ALIGN(32) =
156 {
157     0.0F, 0.0F,
158     1.0F, 0.0F,
159     1.0F, 1.0F,
160     0.0F, 1.0F,
161 };
162 
163 // Misc data...
164 
165 Mtx v;          // view matrix
166 u32 rot;        // current cube rotation
167 
168 /*---------------------------------------------------------------------------*
169    Application main loop
170  *---------------------------------------------------------------------------*/
171 
main(void)172 void main ( void )
173 {
174     DEMOInit(NULL);
175 
176     OSReport("\n\n");
177     OSReport("**********************************************\n");
178     OSReport("gd-texture-gc: Texture display list demo\n");
179     OSReport("**********************************************\n");
180     OSReport("To quit hit the start button.\n");
181     OSReport("\n");
182     OSReport("A button toggles animation.\n");
183     OSReport("**********************************************\n");
184     OSReport("\n\n");
185 
186     DrawInit();         // Prepare the display lists and such
187 
188     ParameterInit();
189 
190     DEMOPadRead();      // Read the joystick for this frame
191 
192     // While the quit button is not pressed
193     while(!(DEMOPadGetButton(0) & PAD_BUTTON_MENU))
194     {
195         DEMOPadRead();  // Read the joystick for this frame
196 
197         AnimTick();     // Do animation based on input
198 
199         DEMOBeforeRender();
200 
201         DrawTick();     // Draw the model.
202 
203         DEMODoneRender();
204     }
205 
206     OSHalt("End of test");
207 }
208 
209 /*---------------------------------------------------------------------------*
210    Functions
211  *---------------------------------------------------------------------------*/
212 
213 /*---------------------------------------------------------------------------*
214     Name:           PatchTexPtrs
215 
216     Description:    This routine will look up TPL texture references and will
217                     patch a DL with HW pointers to the actual texture data.
218                     The references are provided as a list of TPL file numbers
219                     and a list of texture numbers within the given TPL's, as
220                     well as a list of TPL TexPalettePtr's.
221 
222                     This function uses a GDLObj to reference the DL.  The
223                     dlOffsets point to two bytes after the GDSetTexImgPtr
224                     commands within the DL (ie, they point directly to the
225                     bytes to be patched).
226 
227                     Texture Lists: (length = numTextures)
228 
229                     entry   TPL file #   TPL texture #    DL offset
230                            (tplFileNums) (tplTexNums)    (dlOffsets)
231                     -----   ----------   -------------   -----------
232                       0         a              i              x
233                       1         b              j              y
234                       2         c              k              z
235 
236                     TPL List: (length = numTplFiles)
237 
238                     entry   TPLPalettePtr's
239                              (tplFilePtrs)
240                     -----   ---------------
241                       0           A
242                       1           B
243                       2           C
244 
245                     You should have already called TPLGetPalette for all the
246                     TPL files you are going to use.
247 
248     Arguments:      numTplFiles: input, length of tplFilePtrs list
249                     tplFilePtrs: input, list of pointers to TPL file data
250                     numTextures: input, number of textures to be looked up
251                     tplFileNums: input, which TPL file number per texture
252                     tplTexNums:  input, which TPL texture number per texture
253                     dlObj:       input, should point to the DL to patch
254                     dlOffsets:   input, offsets to GDSetTexImgPtr data in DL
255                                         (data = command start + 2)
256     Returns:        none
257  *---------------------------------------------------------------------------*/
258 
PatchTexPtrs(u32 numTplFiles,TPLPalettePtr tplFilePtrs[],u32 numTextures,u32 tplFileNums[],u32 tplTexNums[],GDLObj * dlObj,u32 dlOffsets[])259 static void PatchTexPtrs(u32 numTplFiles, TPLPalettePtr tplFilePtrs[],
260                          u32 numTextures, u32 tplFileNums[], u32 tplTexNums[],
261                          GDLObj *dlObj, u32 dlOffsets[])
262 {
263 #ifndef _DEBUG
264 #pragma unused(numTplFiles)
265 #endif
266     u32   i;
267     u32   fn;
268     TPLDescriptorPtr tdescp;
269     void *tp;
270     void *cp;
271     u32   saveOffset;
272 
273     GDSetCurrent(dlObj);
274 
275     // Note: we preserve the current offset just in case it is used
276     // to hold something important, such as the actual data length.
277     saveOffset = GDGetCurrOffset();
278 
279     for(i=0; i<numTextures; i++)
280     {
281         fn = tplFileNums[i];
282         ASSERTMSG( fn < numTplFiles, "TPL number out of range");
283 
284         // Get the texture descriptor
285         tdescp = TPLGet(tplFilePtrs[fn], tplTexNums[i]);
286         // Get the data ptr
287         tp = (void *) tdescp->textureHeader->data;
288 
289         // Now patch it in
290         GDSetCurrOffset(dlOffsets[i]);  // set the offset
291         cp = GDGetCurrPointer();        // save ptr for flushing later
292         GDPatchTexImgPtr(tp);           // patch in the texture address ptr
293 
294         // We assume that the patches will lie within separate
295         // 32B ranges, so go ahead and flush it to memory now.
296         // If more than 1 patch is in the same range, then we're
297         // just doing extra work (no harm done).
298         DCStoreRange(cp, BP_DATA_LENGTH);
299     }
300 
301     // Because we are flushing as we go along, we don't have
302     // to flush the entire list to memory later.  If we didn't
303     // flush as we went along, we'd need this:
304     //
305     // GDFlushCurrToMem();
306 
307     // Restore the offset
308     GDSetCurrOffset(saveOffset);
309 
310     GDSetCurrent(NULL); // bug-prevention
311 }
312 
313 
314 /*---------------------------------------------------------------------------*
315     Name:           CameraInit
316 
317     Description:    Initialize the projection matrix and load into hardware.
318 
319     Arguments:      v   view matrix to be passed to ViewInit
320                     cameraLocScale  scale for the camera's distance from the
321                                     object - to be passed to ViewInit
322 
323     Returns:        none
324  *---------------------------------------------------------------------------*/
CameraInit(void)325 static void CameraInit      ( void )
326 {
327     Mtx44 p;
328     Vec camPt = {0.0F, 0.0F, 650.0F};
329     Vec up = {0.0F, 1.0F, 0.0F};
330     Vec origin = {0.0F, 0.0F, 0.0F};
331 
332     MTXFrustum(p, 112, -112, -160, 160, 500, 2000);
333 
334     GXSetProjection(p, GX_PERSPECTIVE);
335 
336     MTXLookAt(v, &camPt, &up, &origin);
337 }
338 
339 
340 /*---------------------------------------------------------------------------*
341     Name:           LoadDLs
342 
343     Description:    Loads the display lists used by the program from a file.
344                     This routine is only called if LOAD_DL_FROM_FILE is defined.
345 
346     Arguments:      none
347 
348     Returns:        none
349  *---------------------------------------------------------------------------*/
350 #ifdef LOAD_DL_FROM_FILE
LoadDLs(void)351 static void LoadDLs ( void )
352 {
353     s32 err;
354     GDGList *DLDescArray;
355     GDGList *PLDescArray;
356     u32 numDLs, numPLs;
357 
358     err = GDReadDLFile("gddemo/gdTextr.gdl", &numDLs, &numPLs,
359                        &DLDescArray, &PLDescArray);
360 
361     OSReport("(%d) Read %d DLs, %d PLs\n", err, numDLs, numPLs);
362 
363     ASSERTMSG(!err, "Error reading GDL file.\n");
364 
365     ASSERTMSG(numDLs == 2 && numPLs == 3, "Incorrect data in GDL file.\n");
366 
367     // Note: We put the DL length into the "offset" field, since that's
368     // where the run-time code expects it.  We do this since the CreateDLs
369     // function uses an oversize "length" field, and the actual valid data
370     // length is saved in the "offset" field in that case.  Thus we do the
371     // same thing here for consistency.
372 
373     GDInitGDLObj( &InitDLO, DLDescArray[0].ptr, DLDescArray[0].byteLength );
374     GDSetCurrent( &InitDLO );
375     GDSetCurrOffset( DLDescArray[0].byteLength );
376 
377     GDInitGDLObj( &DrawDLO, DLDescArray[1].ptr, DLDescArray[1].byteLength );
378     GDSetCurrent( &DrawDLO );
379     GDSetCurrOffset( DLDescArray[1].byteLength );
380 
381     GDSetCurrent( NULL );
382 
383     ASSERTMSG(PLDescArray[0].byteLength == 3 * sizeof(u32),
384               "Incorrect data in Patch List 0.\n");
385 
386     ASSERTMSG(PLDescArray[1].byteLength == 6 * sizeof(u32),
387               "Incorrect data in Patch List 1.\n");
388 
389     ASSERTMSG(PLDescArray[2].byteLength == 1 * sizeof(u32),
390               "Incorrect data in Patch List 2.\n");
391 
392     setArrayOffsets = (u32 *) PLDescArray[0].ptr;
393     texAddrOffsets  = (u32 *) PLDescArray[1].ptr;
394     tlutAddrOffsets = (u32 *) PLDescArray[2].ptr;
395 }
396 #endif
397 
398 
399 /*---------------------------------------------------------------------------*
400     Name:           DrawInit
401 
402     Description:    Calls the correct initialization function for the current
403                     model.
404 
405     Arguments:      none
406 
407     Returns:        none
408  *---------------------------------------------------------------------------*/
DrawInit(void)409 static void DrawInit( void )
410 {
411     u32           i;
412     u32           numTpls = 1; // How many TPL files we have
413     TPLPalettePtr tpls[1];     // pointer to each
414     u32           numTexs = 6; // How many textures in our display list
415     static u32    tplFileNums[6]={0, 0, 0, 0, 0, 0};   // which file for each
416     static u32    tplTexNums[6] ={1, 2, 6, 10, 13, 3}; // which descriptor
417     static void  *basePtrs[3] = { FloatVert, FloatNorm, FloatTex };
418     void         *cp;
419     u32           length;
420 
421     TPLDescriptorPtr tdescp;
422 
423     GXLightObj MyLight;
424     GXColor White = {255, 255, 255, 255};
425 
426     // Load or create all the display lists and patch lists.
427 
428 #ifdef LOAD_DL_FROM_FILE
429     LoadDLs();
430 #else
431     CreateDLs();
432 #endif
433 
434     tpls[0] = 0; // important: this must be initialized to 0!
435 
436     // In tex-06.tpl:
437     //
438     // index width height format ws wt mnf mgf mnl mxl lb mm face
439     //   0    128   128   RGBA8  r  r  l/l  l   0   7   0 Y
440     //   1    128   128   RGB5A3 r  r  l/l  l   0   7   0 Y   1
441     //   2    128   128   CMPR   r  r  l/l  l   0   7   0 Y   2
442     //   3    128   128   CI8    r  r  l/l  l   0   7   0 N   6
443     //   4    128   128   RGB565 r  r  l/l  l   0   7   0 Y
444     //   5    128   128   RGBA8  r  r  l/l  l   0   7   0 Y
445     //   6    128   128   RGBA8  r  r  l/l  l   0   7   0 Y   3
446     //   7    128   128   RGB565 r  r  l/l  l   0   7   0 Y
447     //   8    128   128   CMPR   r  r  l/l  l   0   7   0 Y
448     //   9    128   128   RGB5A3 r  r  l/l  l   0   7   0 Y
449     //  10    128   128   I4     r  r  l/l  l   0   7   0 Y   4
450     //  11    128   128   IA4    r  r  l/l  l   0   7   0 Y
451     //  12    128   128   I8     r  r  l/l  l   0   7   0 Y
452     //  13    128   128   IA8    r  r  l/l  l   0   7   0 Y   5
453 
454     // Load all the TPL files
455     TPLGetPalette(&tpls[0], "gxTests/tex-06.tpl");
456 
457     // Set up the textures in the DrawList
458     //
459     // We need to insert their memory addresses into the DrawList.
460 
461     // We get the texture data addresses from the TPL file(s)
462     // and patch them into the GDLObj using texAddrOffsets to tell where.
463     PatchTexPtrs(numTpls, tpls, numTexs, tplFileNums, tplTexNums,
464                  &DrawDLO, texAddrOffsets);
465 
466     // Now, we need to patch in the vertex array base pointers
467     GDSetCurrent(&InitDLO);
468     length = GDGetCurrOffset(); // preserve the offset!
469 
470     for(i=0; i<3; i++)
471     {
472         GDSetCurrOffset( setArrayOffsets[i] );
473         cp = GDGetCurrPointer();
474         GDPatchArrayPtr( basePtrs[i] );
475         DCStoreRange( cp, CP_DATA_LENGTH );
476     }
477 
478     // Patch the address for the TLUT for texture #3 (the color-index one).
479     tdescp = TPLGet( tpls[0], 3 );
480     GDSetCurrOffset( tlutAddrOffsets[0] );
481     cp = GDGetCurrPointer();
482     GDPatchTlutPtr( tdescp->CLUTHeader->data );
483     DCStoreRange( cp, BP_DATA_LENGTH );
484 
485     // Restore the original offset, which reflects the valid data length.
486     GDSetCurrOffset(length);
487     GDSetCurrent(NULL);
488 
489     // Set ALL texture coordinates to scale manually.
490     // This way, GX won't try to do any automatic scaling.
491     GXSetTexCoordScaleManually(GX_TEXCOORD0, GX_ENABLE, 1, 1);
492     GXSetTexCoordScaleManually(GX_TEXCOORD1, GX_ENABLE, 1, 1);
493     GXSetTexCoordScaleManually(GX_TEXCOORD2, GX_ENABLE, 1, 1);
494     GXSetTexCoordScaleManually(GX_TEXCOORD3, GX_ENABLE, 1, 1);
495     GXSetTexCoordScaleManually(GX_TEXCOORD4, GX_ENABLE, 1, 1);
496     GXSetTexCoordScaleManually(GX_TEXCOORD5, GX_ENABLE, 1, 1);
497     GXSetTexCoordScaleManually(GX_TEXCOORD6, GX_ENABLE, 1, 1);
498     GXSetTexCoordScaleManually(GX_TEXCOORD7, GX_ENABLE, 1, 1);
499 
500     // Proceed with the usual sort of initialization...
501 
502     CameraInit();   // Initialize the camera.
503 
504     // Set up a light
505     GXInitLightPos(&MyLight, 0.0F, 0.0F, 0.0F);
506     GXInitLightColor(&MyLight, White);
507     GXLoadLightObjImm(&MyLight, GX_LIGHT0);
508     GXSetChanCtrl(
509         GX_COLOR0,
510         GX_ENABLE,   // enable channel
511         GX_SRC_REG,  // amb source
512         GX_SRC_REG,  // mat source
513         GX_LIGHT0,   // light mask
514         GX_DF_CLAMP, // diffuse function
515         GX_AF_NONE);
516 
517     // Set up TEV
518     GXSetNumChans(1);
519     GXSetNumTevStages(1);
520     GXSetTevOp   (GX_TEVSTAGE0, GX_MODULATE);
521     GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR0A0);
522 
523     // Fix up normals
524     for(i = 0; i < 24; i++)
525     {
526         FloatNorm[i] *= NORM;
527     }
528 
529     // Flush new normals to memory
530     DCFlushRange((void *)FloatNorm, sizeof(FloatNorm));
531 }
532 
533 /*---------------------------------------------------------------------------*
534     Name:           DrawTick
535 
536     Description:    Draw the current model once.
537 
538     Arguments:      v       view matrix
539                     m       model matrix
540 
541     Returns:        none
542  *---------------------------------------------------------------------------*/
DrawTick(void)543 static void DrawTick( void )
544 {
545     // Draw the cube
546 
547     // Call the init DL to set up the parameters for the draw DL.
548     GXCallDisplayList(GDGetGDLObjStart(&InitDLO), GDGetGDLObjOffset(&InitDLO));
549 
550     // Call the draw DL to draw the cube.
551     GXCallDisplayList(GDGetGDLObjStart(&DrawDLO), GDGetGDLObjOffset(&DrawDLO));
552 }
553 
554 /*---------------------------------------------------------------------------*
555     Name:           AnimTick
556 
557     Description:    Animates the camera and object based on the joystick's
558                     state.
559 
560     Arguments:      none
561 
562     Returns:        none
563  *---------------------------------------------------------------------------*/
AnimTick(void)564 static void AnimTick ( void )
565 {
566     Mtx ry, rz, mv, tm, mn;
567     f32 tx, ty;
568     u16 buttons = DEMOPadGetButton(0);
569 
570     // Just simple controls right now...
571 
572     if(buttons & PAD_BUTTON_A)
573     {
574         // suspend animation
575     } else {
576 
577         rot ++;
578         if(rot > 2159)
579             rot = 0;
580     }
581 
582     // Set up our transformations...
583 
584     tx = 0.0f;
585     ty = 0.0f;
586 
587     MTXRotDeg(ry, 'X', (float)rot);
588     MTXRotDeg(rz, 'Y', (float)rot / 3.0F);
589     MTXTrans(tm, tx, ty, 0);
590 
591     MTXConcat(rz, ry, mv);
592     MTXConcat(tm, mv, mv);
593     MTXConcat(v, mv, mv);
594     GXLoadPosMtxImm(mv, GX_PNMTX0);
595 
596     MTXInverse(mv, mn);
597     MTXTranspose(mn, mn);
598     GXLoadNrmMtxImm(mn, GX_PNMTX0);
599 }
600 
601 /*---------------------------------------------------------------------------*
602     Name:           ParameterInit
603 
604     Description:    Initialize parameters for single frame display
605 
606     Arguments:      none
607 
608     Returns:        none
609  *---------------------------------------------------------------------------*/
ParameterInit(void)610 static void ParameterInit ( void )
611 {
612     rot = 45;
613 }
614 
615 /****************************************************************************/
616