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