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