1 /*---------------------------------------------------------------------------*
2   Project:  Dolphin/Revolution gx demo
3   File:     tex-tlut32.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     tex-tlut32
15         Uses 2 TEV stages to emulate 32-bit palette support for CI textures
16  *---------------------------------------------------------------------------*/
17 
18 /*
19 Explanation of the 32-bit color indexed format:
20 
21 The Gamecube does not have native support for 32-bit color indexed format.
22 This is due to tradeoffs in the graphics pipeline which resulted in it
23 being optimized for 16-bits per texture sample per read cycle.
24 However 32-bit palettes with 8-bit index is a format which some
25 developers find very useful.
26 Luckily it is fairly easy to support 32-bit indexed format at the cost
27 of using 2 TEV stages.
28 
29 The best way to implement 32-bit indexed format, which was suggested
30 by Jack Mathews from Retro on the US developers gamecube.graphics newsgroup,
31 is by splitting the 32-bit palette into two 16-bit palettes - one with
32 the Red and Green components, the other with the Blue and Alpha components of the
33 color, and referencing them from the same texture map in 2 TEV stages.
34 This produces the same result as a texture with a single palette of
35 GX_TL_RGBA8 format.
36 
37 A demo is provided which demonstrates a texture using a 256 entry palette.
38 The texture is created procedurally as a set of concentric circles,
39 and alpha-blended on top of a checkered background.
40 The palette is set to be a smooth gradient between two RGBA values in
41 order to demonstrate that the palette is indeed 32-bit.
42 The palette is animated in real-time (without animating the texture
43 pattern), by changing the endpoints of the gradient to give
44 a color cycling effect.
45 */
46 
47 #include <demo.h>
48 #include <math.h>
49 
50 #define NUM_ENTRIES 256
51 #define TEX_SIZE    256
52 #define TEX_HALF    (TEX_SIZE>>1)
53 #define SCR_WIDTH   640
54 #define SCR_HEIGHT  448
55 
56 static GXColor tlut32[NUM_ENTRIES] ATTRIBUTE_ALIGN(32);
57 static u16 tlutPalette0[NUM_ENTRIES] ATTRIBUTE_ALIGN(32);
58 static u16 tlutPalette1[NUM_ENTRIES] ATTRIBUTE_ALIGN(32);
59 static u8 indexTexture[TEX_SIZE * TEX_SIZE] ATTRIBUTE_ALIGN(32);
60 
61 #define COLA 255
62 #define COLB 128
63 static u8 checkTexture[8*8] ATTRIBUTE_ALIGN(32) =
64 {
65     COLA, COLA, COLA, COLA, COLB, COLB, COLB, COLB,
66     COLA, COLA, COLA, COLA, COLB, COLB, COLB, COLB,
67     COLA, COLA, COLA, COLA, COLB, COLB, COLB, COLB,
68     COLA, COLA, COLA, COLA, COLB, COLB, COLB, COLB,
69     COLB, COLB, COLB, COLB, COLA, COLA, COLA, COLA,
70     COLB, COLB, COLB, COLB, COLA, COLA, COLA, COLA,
71     COLB, COLB, COLB, COLB, COLA, COLA, COLA, COLA,
72     COLB, COLB, COLB, COLB, COLA, COLA, COLA, COLA,
73 };
74 
75 static GXTexObj texObj1, texObj0, texObjCheck;
76 static GXTlutObj tlutObj0, tlutObj1;
77 
78 void CreatePalettes();
79 void CreateTexture();
80 void SetCITEVMode();
81 void SetUpRegisters();
82 void DrawTick();
83 
84 static f32 rR0, rG0, rB0, rA0;
85 static f32 rR1, rG1, rB1, rA1;
86 
87 
88 void
CreateTexture()89 CreateTexture()
90 {
91     s32 nX, nY;
92     s32 nI;
93     f32 rDist;
94 
95     // Make a test pattern
96     for(nY=0; nY<TEX_SIZE; nY++)
97     {
98         for(nX=0; nX<TEX_SIZE; nX++)
99         {
100             //    Y         X             Addr
101             // aaaaaabb ccdddeee -> aaaaaaccdddbbeee  (TEXTURE SWIZZLE)
102             nI = ((nY<<8)&0xfc00) + ((nX<<2)&0x3e0) + ((nY<<3)&0x18) + (nX&0x7);
103             rDist = 1.4f*(f32)sqrt(((TEX_HALF-nX)*(TEX_HALF-nX))+((TEX_HALF-nY)*(TEX_HALF-nY)));
104             indexTexture[nI] = (u8)(rDist);
105         }
106     }
107     DCFlushRange(indexTexture, TEX_SIZE * TEX_SIZE);
108 }
109 
110 void
CreatePalettes()111 CreatePalettes()
112 {
113     s32 nI;
114 
115     for(nI=0; nI<NUM_ENTRIES; nI++)
116     {
117 
118         tlut32[nI].r = (u8)(rR0+(nI*(rR1-rR0)*0.00390625f));
119         tlut32[nI].g = (u8)(rG0+(nI*(rG1-rG0)*0.00390625f));
120         tlut32[nI].b = (u8)(rB0+(nI*(rB1-rB0)*0.00390625f));
121         tlut32[nI].a = (u8)(rA0+(nI*(rA1-rA0)*0.00390625f));
122 
123         // IA8 format:  aaaaaaaaiiiiiiii
124         tlutPalette0[nI] = (u16)((tlut32[nI].g<<8) + (u8)tlut32[nI].r);
125         tlutPalette1[nI] = (u16)((tlut32[nI].a<<8) + (u8)tlut32[nI].b);
126     }
127     DCFlushRange(tlutPalette0, NUM_ENTRIES*2);
128     DCFlushRange(tlutPalette1, NUM_ENTRIES*2);
129 
130     GXInitTlutObj(
131         &tlutObj0,                  // GXTlutObj*      tlut_obj
132         tlutPalette0,               // void*           lut
133         GX_TL_IA8,                  // GXTlutFmt       fmt
134         NUM_ENTRIES);               // u16             n_entries
135 
136     GXInitTlutObj(
137         &tlutObj1,                  // GXTlutObj*      tlut_obj
138         tlutPalette1,               // void*           lut
139         GX_TL_IA8,                  // GXTlutFmt       fmt
140         NUM_ENTRIES);               // u16             n_entries
141 
142     GXLoadTlut(&tlutObj0,           // GXTlutObj*      tlut_obj
143                GX_TLUT0);           // GXTlut          tlut_name
144 
145     GXLoadTlut(&tlutObj1,           // GXTlutObj*      tlut_obj
146                GX_TLUT1);           // GXTlut          tlut_name
147 
148     // initialize texture objects
149     GXInitTexObjCI(&texObj0,        // GXTexObj*      obj
150                    indexTexture,    // void*          image_ptr
151                    TEX_SIZE,        // u16            width
152                    TEX_SIZE,        // u16            height
153                    GX_TF_C8,        // GXCITexFmt     format
154                    GX_CLAMP,        // GXTexWrapMode  wrap_s
155                    GX_CLAMP,        // GXTexWrapMode  wrap_t
156                    GX_DISABLE,      // GXBool         mipmap
157                    GX_TLUT0);       // GXTlut         tlut_name
158 
159     GXInitTexObjLOD(&texObj0,       // GXTexObj*      obj
160                     GX_NEAR,        // GXTexFilter    min_filt
161                     GX_NEAR,        // GXTexFilter    mag_filt
162                     0.0f,           // f32            min_lod
163                     0.0f,           // f32            max_lod
164                     0.0f,           // f32            lod_bias
165                     GX_ENABLE,      // GXBool         bias_clamp
166                     GX_TRUE,        // GXBool         do_edge_lod
167                     GX_ANISO_1);    // GXAnisotropy   max_aniso
168 
169     GXLoadTexObj(&texObj0,          // GXTexObj*      obj
170                  GX_TEXMAP0);       // GXTexMapID     id
171 
172     GXInitTexObjCI(&texObj1,        // GXTexObj*      obj
173                    indexTexture,       // void*          image_ptr
174                    TEX_SIZE,        // u16            width
175                    TEX_SIZE,        // u16            height
176                    GX_TF_C8,        // GXCITexFmt     format
177                    GX_CLAMP,        // GXTexWrapMode  wrap_s
178                    GX_CLAMP,        // GXTexWrapMode  wrap_t
179                    GX_DISABLE,      // GXBool         mipmap
180                    GX_TLUT1);       // GXTlut         tlut_name
181 
182     GXInitTexObjLOD(&texObj1,       // GXTexObj*      obj
183                     GX_NEAR,        // GXTexFilter    min_filt
184                     GX_NEAR,        // GXTexFilter    mag_filt
185                     0.0f,           // f32            min_lod
186                     0.0f,           // f32            max_lod
187                     0.0f,           // f32            lod_bias
188                     GX_ENABLE,      // GXBool         bias_clamp
189                     GX_TRUE,        // GXBool         do_edge_lod
190                     GX_ANISO_1);    // GXAnisotropy   max_aniso
191 
192     GXLoadTexObj(&texObj1,          // GXTexObj*      obj
193                  GX_TEXMAP1);       // GXTexMapID     id
194 }
195 
196 void
SetCITEVMode()197 SetCITEVMode()
198 {
199     // 32 bit index texture using 2 TEV stages
200 
201     GXColor const firstTev = { 255, 255, 0, 0 };    // { r,g,b,a }
202     GXColor const secondTev = { 0, 0, 255, 255 };   // { r,g,b,a }
203 
204     GXSetNumTevStages(2);
205 
206     GXSetTevSwapModeTable(
207             GX_TEV_SWAP1,   // GXTevSwapSel   id
208             GX_CH_RED,      // GXTevColorChan red
209             GX_CH_ALPHA,    // GXTevColorChan green
210             GX_CH_ALPHA,    // GXTevColorChan blue
211             GX_CH_ALPHA);   // GXTevColorChan alpha
212 
213     GXSetTevSwapModeTable(
214             GX_TEV_SWAP2,   // GXTevSwapSel   id
215             GX_CH_BLUE,     // GXTevColorChan red
216             GX_CH_BLUE,     // GXTevColorChan green
217             GX_CH_BLUE,     // GXTevColorChan blue
218             GX_CH_ALPHA);   // GXTevColorChan alpha
219 
220     GXSetTevSwapMode(
221             GX_TEVSTAGE0,   // GXTevStageID   stage
222             GX_TEV_SWAP0,   // GXTevSwapSel   ras_sel
223             GX_TEV_SWAP1);  // GXTevSwapSel   tex_sel
224 
225     GXSetTevSwapMode(
226             GX_TEVSTAGE1,   // GXTevStageID   stage
227             GX_TEV_SWAP0,   // GXTevSwapSel   ras_sel
228             GX_TEV_SWAP2);  // GXTevSwapSel   tex_sel
229 
230     GXSetTevColor(
231             GX_TEVREG0,     // GXTevRegID     id
232             firstTev);      // GXColor        color
233 
234     GXSetTevColor(
235             GX_TEVREG1,     // GXTevRegID     id
236             secondTev);     // GXColor        color
237 
238     GXSetTevColorIn(
239             GX_TEVSTAGE0,   // GXTevStageID   stage
240             GX_CC_ZERO,     // GXTevColorArg  a
241             GX_CC_TEXC,     // GXTevColorArg  b     // Applying Color as Arg B to give 0x0..0xFF range
242             GX_CC_C0,       // GXTevColorArg  c     // Constant { 255, 255, 0, 0 } masks off Blue channel
243             GX_CC_ZERO);    // GXTevColorArg  d
244 
245     GXSetTevColorOp(
246             GX_TEVSTAGE0,   // GXTevStageID   stage
247             GX_TEV_ADD,     // GXTevOp        op
248             GX_TB_ZERO,     // GXTevBias      bias
249             GX_CS_SCALE_1,  // GXTevScale     scale
250             GX_DISABLE,     // GXBool         clamp
251             GX_TEVPREV);    // GXTevRegID     out_reg
252 
253     GXSetTevOrder(
254             GX_TEVSTAGE0,   // GXTevStageID   stage
255             GX_TEXCOORD0,   // GXTexCoordID    coord
256             GX_TEXMAP0,     // GXTexMapID      map
257             GX_COLOR_NULL); // GXChannelID     color
258 
259     GXSetTevColorIn(
260             GX_TEVSTAGE1,   // GXTevStageID   stage
261             GX_CC_ZERO,     // GXTevColorArg  a
262             GX_CC_TEXC,     // GXTevColorArg  b     // Applying Color as Arg B to give 0x0..0xFF range
263             GX_CC_C1,       // GXTevColorArg  c     // Constant { 0, 0, 255, 255 } masks off Red and Green channels
264             GX_CC_CPREV);   // GXTevColorArg  d
265 
266     GXSetTevAlphaIn(
267             GX_TEVSTAGE1,   // GXTevStageID   stage
268             GX_CA_ZERO,     // GXTevColorArg  a
269             GX_CA_ONE,      // GXTevColorArg  b
270             GX_CA_TEXA,     // GXTevColorArg  c     // Applying Alpha as Arg C to give full 0x0..0x100 range
271             GX_CA_ZERO);    // GXTevColorArg  d
272 
273     GXSetTevColorOp(
274             GX_TEVSTAGE1,   // GXTevStageID   stage
275             GX_TEV_ADD,     // GXTevOp        op
276             GX_TB_ZERO,     // GXTevBias      bias
277             GX_CS_SCALE_1,  // GXTevScale     scale
278             GX_ENABLE,      // GXBool         clamp
279             GX_TEVPREV);    // GXTevRegID     out_reg
280 
281     GXSetTevAlphaOp(
282             GX_TEVSTAGE1,   // GXTevStageID   stage
283             GX_TEV_ADD,     // GXTevOp        op
284             GX_TB_ZERO,     // GXTevBias      bias
285             GX_CS_SCALE_1,  // GXTevScale     scale
286             GX_ENABLE,      // GXBool         clamp
287             GX_TEVPREV);    // GXTevRegID     out_reg
288 
289     GXSetTevOrder(
290             GX_TEVSTAGE1,   // GXTevStageID   stage
291             GX_TEXCOORD0,   // GXTexCoordID    coord
292             GX_TEXMAP1,     // GXTexMapID      map
293             GX_COLOR_NULL); // GXChannelID     color
294 }
295 
296 void
SetUpRegisters()297 SetUpRegisters()
298 {
299     // set up texture map registers for checker board texture
300     {
301         GXInitTexObj(&texObjCheck,      // GXTexObj*      obj
302                      checkTexture,      // void*          image_ptr
303                      8,                 // u16            width
304                      8,                 // u16            height
305                      GX_TF_I8,          // GXCITexFmt     format
306                      GX_REPEAT,         // GXTexWrapMode  wrap_s
307                      GX_REPEAT,         // GXTexWrapMode  wrap_t
308                      GX_DISABLE);       // GXBool         mipmap
309 
310         GXInitTexObjLOD(&texObjCheck,   // GXTexObj*      obj
311                         GX_NEAR,        // GXTexFilter    min_filt
312                         GX_NEAR,        // GXTexFilter    mag_filt
313                         0.0f,           // f32            min_lod
314                         0.0f,           // f32            max_lod
315                         0.0f,           // f32            lod_bias
316                         GX_ENABLE,      // GXBool         bias_clamp
317                         GX_TRUE,        // GXBool         do_edge_lod
318                         GX_ANISO_1);    // GXAnisotropy   max_aniso
319 
320         // load texture data into TMEM
321         GXLoadTexObj(&texObjCheck,      // GXTexObj*      obj
322                      GX_TEXMAP2);       // GXTexMapID     id
323     }
324 
325     // set up orthographic projection
326     {
327         Mtx44 mProjection;
328 
329         MTXOrtho(mProjection,           // Mtx44          matrix
330                  SCR_HEIGHT>>1,         // f32            top
331                  -(SCR_HEIGHT>>1),      // f32            bottom
332                  -(SCR_WIDTH>>1),       // f32            left
333                  SCR_WIDTH>>1,          // f32            right
334                  1,                     // f32            near
335                  1000);                 // f32            far
336 
337         GXSetProjection(mProjection,        // Mtx44              matrix
338                         GX_ORTHOGRAPHIC);   // GXProjectionType   type
339     }
340 
341     // set up Camera
342     {
343         Mtx mView;
344         Vec vCamPos = { 0, 0, -300 };
345         Vec vCamUp  = { 0, 1, 0 };
346         Vec vCamTarget = { 0, 0, 0 };
347 
348         MTXLookAt(mView,                // Mtx         mView
349                   &vCamPos,             // Point3dPtr  camPos
350                   &vCamUp,              // VecPtr      camUp
351                   &vCamTarget);         // Point3dPtr  target
352 
353         GXLoadPosMtxImm(mView,          // Mtx         mView
354                         GX_PNMTX0);     // u32         id
355     }
356 
357     // set up vertex attributes
358     {
359         GXClearVtxDesc();
360 
361         // Set Position Params
362         GXSetVtxAttrFmt(GX_VTXFMT0,     // GXVtxFmt       vtxfmt
363                         GX_VA_POS,      // GXAttr         attr
364                         GX_POS_XY,      // GXCompCnt      component
365                         GX_F32,         // GXCompType     type
366                         0);             // u8             frac
367 
368         GXSetVtxDesc(GX_VA_POS,         // GXAttr         attr
369                      GX_DIRECT);        // GXAttrType     type
370 
371         // Set Tex Coord Params
372         GXSetVtxAttrFmt(GX_VTXFMT0,     // GXVtxFmt       vtxfmt
373                         GX_VA_TEX0,     // GXAttr         attr
374                         GX_TEX_ST,      // GXCompCnt      component
375                         GX_F32,         // GXCompType     type
376                         0);             // u8             frac
377 
378         GXSetVtxDesc(GX_VA_TEX0,        // GXAttr         attr
379                      GX_DIRECT);        // GXAttrType     type
380 
381         GXSetNumTexGens(1);             // u8             nTexGens
382         GXSetNumChans(0);               // u8             nChans
383     }
384 }
385 
386 void
DrawTick()387 DrawTick()
388 {
389     // render background checker pattern
390     GXSetNumTevStages(1);
391     GXSetTevOp(GX_TEVSTAGE0, GX_REPLACE);
392     GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP2, GX_COLOR_NULL);
393 
394     // Turn off alpha blending
395     GXSetBlendMode(GX_BM_NONE,          // GXBlendMode        type
396                    GX_BL_ONE,           // GXBlendFactor      src_factor
397                    GX_BL_ZERO,          // GXBlendFactor      dst_factor
398                    GX_LO_CLEAR);        // GXLogicOp          op
399 
400     GXBegin(GX_QUADS, GX_VTXFMT0, 4);
401     {
402         GXPosition2f32( -320,  224 );
403         GXTexCoord2f32(    0,   14 );
404 
405         GXPosition2f32( -320, -224 );
406         GXTexCoord2f32(    0,    0 );
407 
408         GXPosition2f32(  320, -224 );
409         GXTexCoord2f32(   20,    0 );
410 
411         GXPosition2f32(  320,  224 );
412         GXTexCoord2f32(   20,   14 );
413     }
414     GXEnd();
415 
416 
417     // set up for 32-bit CI texture render
418     SetCITEVMode();
419 
420     // Turn on alpha blending
421     GXSetBlendMode(GX_BM_BLEND,         // GXBlendMode        type
422                    GX_BL_SRCALPHA,      // GXBlendFactor      src_factor
423                    GX_BL_INVSRCALPHA,   // GXBlendFactor      dst_factor
424                    GX_LO_CLEAR);        // GXLogicOp          op
425 
426     // render a quad
427     {
428         f32 rRectHalfWidth;
429         f32 rRectHalfHeight;
430 
431         rRectHalfWidth = TEX_SIZE;
432         rRectHalfHeight = TEX_SIZE * 0.5f;
433 
434         GXBegin(GX_QUADS, GX_VTXFMT0, 4);
435         {
436             GXPosition2f32( -rRectHalfWidth,  rRectHalfHeight );
437             GXTexCoord2f32( 0, 1 );
438 
439             GXPosition2f32( -rRectHalfWidth, -rRectHalfHeight );
440             GXTexCoord2f32( 0, 0 );
441 
442             GXPosition2f32(  rRectHalfWidth, -rRectHalfHeight );
443             GXTexCoord2f32( 1, 0 );
444 
445             GXPosition2f32(  rRectHalfWidth,  rRectHalfHeight );
446             GXTexCoord2f32( 1, 1 );
447         }
448         GXEnd();
449     }
450 }
451 
452 void
main()453 main()
454 {
455     s32 nT=0;
456 
457     DEMOInit(NULL);
458 
459     OSReport("\n\n");
460     OSReport("**********************************************\n");
461     OSReport("tex-tlut32: 32-bit color indexed texture demo\n");
462     OSReport("**********************************************\n");
463     OSReport("To quit hit the start button.\n");
464     OSReport("\n");
465     OSReport("This demo has no other controls.\n");
466     OSReport("Refer to the source code for more information.\n");
467     OSReport("**********************************************\n");
468     OSReport("\n\n");
469 
470     CreateTexture();
471 
472     GXSetDispCopyGamma( GX_GM_1_0 );
473 
474     SetUpRegisters();
475 
476     DEMOPadRead();      // Read the joystick for this frame
477 
478     // While the quit button is not pressed
479     while (!(DEMOPadGetButton(0) & PAD_BUTTON_MENU))
480     {
481         // A bit of good old color cycling
482         nT++;
483         rR0 = 127.5f * (1.0f + (f32)sin(nT*0.210));
484         rG0 = 127.5f * (1.0f + (f32)sin(nT*0.152));
485         rB0 = 127.5f * (1.0f + (f32)sin(nT*0.085));
486         rA0 = 127.5f * (1.0f + (f32)sin(nT*0.119));
487         rA1 = 127.5f * (1.0f + (f32)cos(nT*0.179));
488         rR1 = 255.0f - rR0;
489         rG1 = 255.0f - rG0;
490         rB1 = 255.0f - rB0;
491 
492         CreatePalettes();
493 
494         DEMOPadRead();  // Read the joystick for this frame
495 
496         DEMOBeforeRender();
497 
498         DrawTick();     // Draw the model.
499 
500         DEMODoneRender();
501     }
502 
503     OSHalt("End of demo");
504 }
505