1 /*---------------------------------------------------------------------------*
2   Project:  Dolphin
3   File:     gd-texture-create.c
4 
5   Copyright 2001 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-create.c,v $
14   Revision 1.2  02/20/2006 04:13:10  mitu
15   changed include path from dolphin/ to revolution/.
16 
17   Revision 1.1  02/08/2006 11:19:43  mitu
18   1st version.
19 
20 
21     4     11/08/01 6:38p Carl
22     Added code to change TMEM configuration.
23 
24     3     10/13/01 2:29a Hirose
25     Fixes due to GDSetTexCoordGen API change.
26 
27     2     10/11/01 4:05p Carl
28     Added use of color-index texture and TLUT.
29 
30     1     9/19/01 4:27p Carl
31     Sources for GD texture demo.
32 
33   $NoKeywords: $
34  *---------------------------------------------------------------------------*/
35 
36 #include <revolution/gd.h>
37 #include <revolution/mtx/GeoTypes.h>
38 
39 #ifdef WIN32
40 #include <assert.h>
41 #include <stdlib.h>
42 #else
43 #include <revolution/os.h>
44 #endif
45 
46 /*---------------------------------------------------------------------------*/
47 
48 #ifdef WIN32
49 #define ASSERT           assert
50 #define OSRoundUp32B(x)  (((u32)(x) + 31) & ~31)
51 #define OSAlloc(x)       ((void*)OSRoundUp32B(malloc((x)+31)))
52 #define OSFree(x)        free(x)
53 #endif
54 
55 /*---------------------------------------------------------------------------*
56    Forward references
57  *---------------------------------------------------------------------------*/
58 
59 void CreateDLs( void );
60 
61 /*---------------------------------------------------------------------------*
62    Global variables
63  *---------------------------------------------------------------------------*/
64 
65 // Display lists *************************************************************
66 
67 // This DL is used with the "Draw" display list.
68 // It initializes state that will be used by the Draw DL.
69 
70 extern GDLObj InitDLO;
71 #define INIT_STATE_SIZE 2048  // maximum (not actual) size
72 
73 // This DL draws a textured cube.  It must be paired with the Init DL.
74 
75 extern GDLObj DrawDLO;
76 #define DRAW_SIZE 2048        // maximum (not actual) size
77 
78 // This array indicates the offsets to patch memory addresses for the
79 // primitive data arrays (positions, normals, texture coordinates)
80 // referred to in the Init DL.
81 
82 extern u32 *setArrayOffsets;
83 
84 // This array tells us the offsets for where to patch the memory addresses
85 // for the textures in the Draw DL.
86 
87 extern u32 *texAddrOffsets;
88 
89 // This array tells us the offsets for where to patch the main memory
90 // addresses for loading the TLUTs in the Init DL.
91 
92 extern u32 *tlutAddrOffsets;
93 
94 // This TLUT address (in TMEM) corresponds to the first 256-entry
95 // TLUT in the default GX allocation (tlut 0).  Consider using the
96 // array GXTlutRegions (from GDTexture.c) if you extensively use the
97 // default GX TLUT allocation scheme.
98 
99 #define TLUT0_ADDR 0xC0000
100 
101 /*---------------------------------------------------------------------------*/
102 
103 // This array is used to map texture cache regions in TMEM.  It
104 // follows GX's default TMEM configuration.  In the default configuration,
105 // texmap 0 uses the first pair of addresses in the list, texmap 1 uses the
106 // second, and so on.  In this demo, we use only texmap 0 and change its
107 // mapping based on the texture we draw, making sure that each different
108 // texture uses a unique cache region.  Of course, we could just as easily
109 // have used a unique texmap per texture, but for this demo we wanted to
110 // emphasize how you must pay attention to texture cache use.
111 
112 u32 MyTmemRegions[8][2] = {
113    // TMEM LO, TMEM HI
114     { 0x00000, 0x80000 },  // (default assignment for texmap 0)
115     { 0x08000, 0x88000 },  //                                1
116     { 0x10000, 0x90000 },  //                                2
117     { 0x18000, 0x98000 },  //                                3
118     { 0x20000, 0xa0000 },  //                                4
119     { 0x28000, 0xa8000 },  //                                5
120     { 0x30000, 0xb0000 },  //                                6
121     { 0x38000, 0xb8000 }   //                                7
122 };
123 
124 /*---------------------------------------------------------------------------*
125    Functions
126  *---------------------------------------------------------------------------*/
127 
128 /*---------------------------------------------------------------------------*
129     Name:           CreateDLs
130 
131     Description:    Creates the display lists used by the program.
132 
133     Arguments:      none
134 
135     Returns:        none
136  *---------------------------------------------------------------------------*/
CreateDLs(void)137 void CreateDLs ( void )
138 {
139     u8 *InitStateList;
140     u8 *DrawList;
141 
142     //
143     // Create the init-state DL
144     //
145 
146     // This display list initializes some important drawing state that will
147     // be used by the Draw DL.  We will initialize the VCD/VAT, the array
148     // base pointers, the texture lookup state, and the texcoord scaling.
149 
150     InitStateList = OSAlloc( INIT_STATE_SIZE );
151     ASSERT(InitStateList);
152 
153     setArrayOffsets = OSAlloc( 3 * sizeof(u32) );
154     ASSERT(setArrayOffsets);
155 
156     tlutAddrOffsets = OSAlloc( 1 * sizeof(u32) );
157     ASSERT(tlutAddrOffsets);
158 
159     GDInitGDLObj( &InitDLO, InitStateList, INIT_STATE_SIZE );
160     GDSetCurrent( &InitDLO );
161 
162     // Set the VCD and VAT
163     {
164         static GXVtxDescList vcd[] = {
165             { GX_VA_POS, GX_INDEX8 },
166             { GX_VA_NRM, GX_INDEX8 },
167             { GX_VA_TEX0, GX_INDEX8 },
168             { GX_VA_NULL, GX_NONE }, // NULL terminator is required
169         };
170         static GXVtxAttrFmtList vat[] = {
171             { GX_VA_POS, GX_POS_XYZ, GX_F32, 0 },
172             { GX_VA_NRM, GX_NRM_XYZ, GX_F32, 0 },
173             { GX_VA_TEX0, GX_TEX_ST, GX_F32, 0 },
174             { GX_VA_NULL, GX_POS_XY, GX_U8, 0 }, // NULL terminator is required
175         };
176 
177         GDSetVtxDescv( vcd );
178         GDSetVtxAttrFmtv( GX_VTXFMT0, vat );
179     }
180 
181     // Set the vertex array pointers and strides.  The actual array
182     // pointers will be patched in later, so we need to keep track of
183     // these patch points.
184     // We add a bit to skip over the command token and register ID bytes.
185 
186     setArrayOffsets[0] = GDGetCurrOffset() + CP_DATA_OFFSET;
187     GDSetArrayRaw(GX_VA_POS, 0, 12);
188 
189     setArrayOffsets[1] = GDGetCurrOffset() + CP_DATA_OFFSET;
190     GDSetArrayRaw(GX_VA_NRM, 0, 12);
191 
192     setArrayOffsets[2] = GDGetCurrOffset() + CP_DATA_OFFSET;
193     GDSetArrayRaw(GX_VA_TEX0, 0, 8);
194 
195     // Commands to initialize (most of) texture ID 0 and texcoord 0 scale:
196     // This DL is used with the Draw display list, which assumes that
197     // texture ID 0 and texcoord 0 have been set up in this way.
198 
199     // Since all the textures we're using are the same size and have mostly
200     // the same attributes, we can get away with this.  Otherwise, these
201     // registers would have to be loaded for each face in the DrawList.
202 
203     // Initialize TEXMAP0 lookup attributes.
204     GDSetTexLookupMode( GX_TEXMAP0,             // tmap
205                         GX_REPEAT,              // wrap s
206                         GX_REPEAT,              // wrap t
207                         GX_LIN_MIP_LIN,         // min filt
208                         GX_LINEAR,              // mag filt
209                         0.0f,                   // min LOD
210                         7.0f,                   // max LOD
211                         0.0f,                   // LOD bias
212                         GX_FALSE,               // bias clamp?
213                         GX_TRUE,                // do edge LOD?
214                         GX_ANISO_1 );           // max aniso
215 
216     // And texcoord0 scale parameters.
217     GDSetTexCoordScale2( GX_TEXCOORD0,               // tcoord
218                          128, GX_FALSE, GX_FALSE,    // s size, bias, wrap
219                          128, GX_FALSE, GX_FALSE );  // t size, bias, wrap
220 
221     // Set the texture TLUT parameters.  This will only be used by the
222     // texture format that is color-indexed.
223     GDSetTexTlut ( GX_TEXMAP0, TLUT0_ADDR, GX_TL_RGB565 );
224 
225     // Need to save this offset for the LoadTlut command.
226     tlutAddrOffsets[0] = GDGetCurrOffset() + BP_CMD_LENGTH*2 + BP_DATA_OFFSET;
227 
228     // Load the TLUT.  Again, this is only needed for the CI texture.
229     // We don't know the correct memory address now; it will be patched later.
230     GDLoadTlutRaw ( 0, TLUT0_ADDR, GX_TLUT_256 );
231 
232     // That's all the commands for that DL; now pad to 32-byte boundary.
233     GDPadCurr32();
234 
235     GDFlushCurrToMem(); // not strictly needed for PC-side, but not a bad idea
236 
237     //
238     // Create the cube drawing DL
239     //
240 
241     // Draw DL: commands to select textures and draw the actual geometry.
242     // This display list must be paired with the Init DL.  It assumes a
243     // particular texture setup which is setup by that DL.  As a result,
244     // it can switch textures by changing only the minimum number of
245     // registers.
246 
247     DrawList = OSAlloc( DRAW_SIZE );
248     ASSERT(DrawList);
249 
250     texAddrOffsets = OSAlloc( 6 * sizeof(u32) );
251     ASSERT(texAddrOffsets);
252 
253     GDInitGDLObj( &DrawDLO, DrawList, DRAW_SIZE );
254     GDSetCurrent( &DrawDLO );
255 
256     // face 1
257 
258     // Set texture format.  This changes among the various faces.
259     GDSetTexImgAttr( GX_TEXMAP0,        // tmap
260                      128,               // width
261                      128,               // height
262                      GX_TF_RGB5A3 );    // format
263 
264     // Set the texture TMEM cache usage for this texture.
265     // We make sure that each texture uses a different region.
266     // (See the comment for MyTmemRegions up above.)
267     GDSetTexCached( GX_TEXMAP0, MyTmemRegions[0][0], GX_TEXCACHE_32K,
268                                 MyTmemRegions[0][1], GX_TEXCACHE_32K );
269 
270     // Save the offset that will indicate the texture main-memory address.
271     // We add a bit to skip over the command token and register ID bytes.
272     texAddrOffsets[0] = GDGetCurrOffset() + BP_DATA_OFFSET;
273 
274     // Insert command to load the texture main-memory address.
275     // We use the raw form since we don't have a valid address to use now.
276     // The real address will be patched in later.
277     GDSetTexImgPtrRaw( GX_TEXMAP0, 0 );
278 
279     // Draw face.
280     GDBegin( GX_QUADS, GX_VTXFMT0, 4 );
281     GDPosition1x8( 0 ); GDNormal1x8( 0 ); GDTexCoord1x8( 0 );
282     GDPosition1x8( 1 ); GDNormal1x8( 1 ); GDTexCoord1x8( 1 );
283     GDPosition1x8( 2 ); GDNormal1x8( 2 ); GDTexCoord1x8( 2 );
284     GDPosition1x8( 3 ); GDNormal1x8( 3 ); GDTexCoord1x8( 3 );
285     GDEnd();
286 
287     // That's it for this face.
288     // The next 5 faces follow mostly the same layout.
289 
290     // face 2
291 
292     GDSetTexImgAttr( GX_TEXMAP0,        // tmap
293                      128,               // width
294                      128,               // height
295                      GX_TF_CMPR );      // format
296 
297     GDSetTexCached( GX_TEXMAP0, MyTmemRegions[1][0], GX_TEXCACHE_32K,
298                                 MyTmemRegions[1][1], GX_TEXCACHE_32K );
299 
300     texAddrOffsets[1] = GDGetCurrOffset() + BP_DATA_OFFSET;
301 
302     GDSetTexImgPtrRaw( GX_TEXMAP0, 0 );
303 
304     GDBegin( GX_QUADS, GX_VTXFMT0, 4 );
305     GDPosition1x8( 4 ); GDNormal1x8( 4 ); GDTexCoord1x8( 0 );
306     GDPosition1x8( 5 ); GDNormal1x8( 5 ); GDTexCoord1x8( 1 );
307     GDPosition1x8( 6 ); GDNormal1x8( 6 ); GDTexCoord1x8( 2 );
308     GDPosition1x8( 7 ); GDNormal1x8( 7 ); GDTexCoord1x8( 3 );
309     GDEnd();
310 
311     // face 3
312 
313     GDSetTexImgAttr( GX_TEXMAP0,        // tmap
314                      128,               // width
315                      128,               // height
316                      GX_TF_RGBA8 );     // format
317 
318     GDSetTexCached( GX_TEXMAP0, MyTmemRegions[2][0], GX_TEXCACHE_32K,
319                                 MyTmemRegions[2][1], GX_TEXCACHE_32K );
320 
321     texAddrOffsets[2] = GDGetCurrOffset() + BP_DATA_OFFSET;
322 
323     GDSetTexImgPtrRaw( GX_TEXMAP0, 0 );
324 
325     GDBegin( GX_QUADS, GX_VTXFMT0, 4 );
326     GDPosition1x8( 2 ); GDNormal1x8( 2 ); GDTexCoord1x8( 0 );
327     GDPosition1x8( 6 ); GDNormal1x8( 6 ); GDTexCoord1x8( 1 );
328     GDPosition1x8( 5 ); GDNormal1x8( 5 ); GDTexCoord1x8( 2 );
329     GDPosition1x8( 3 ); GDNormal1x8( 3 ); GDTexCoord1x8( 3 );
330     GDEnd();
331 
332     // face 4
333 
334     GDSetTexImgAttr( GX_TEXMAP0,        // tmap
335                      128,               // width
336                      128,               // height
337                      GX_TF_I4 );        // format
338 
339     GDSetTexCached( GX_TEXMAP0, MyTmemRegions[3][0], GX_TEXCACHE_32K,
340                                 MyTmemRegions[3][1], GX_TEXCACHE_32K );
341 
342     texAddrOffsets[3] = GDGetCurrOffset() + BP_DATA_OFFSET;
343 
344     GDSetTexImgPtrRaw( GX_TEXMAP0, 0 );
345 
346     GDBegin( GX_QUADS, GX_VTXFMT0, 4 );
347     GDPosition1x8( 1 ); GDNormal1x8( 1 ); GDTexCoord1x8( 0 );
348     GDPosition1x8( 0 ); GDNormal1x8( 0 ); GDTexCoord1x8( 1 );
349     GDPosition1x8( 4 ); GDNormal1x8( 4 ); GDTexCoord1x8( 2 );
350     GDPosition1x8( 7 ); GDNormal1x8( 7 ); GDTexCoord1x8( 3 );
351     GDEnd();
352 
353     // face 5
354 
355     GDSetTexImgAttr( GX_TEXMAP0,        // tmap
356                      128,               // width
357                      128,               // height
358                      GX_TF_IA8 );       // format
359 
360     GDSetTexCached( GX_TEXMAP0, MyTmemRegions[4][0], GX_TEXCACHE_32K,
361                                 MyTmemRegions[4][1], GX_TEXCACHE_32K );
362 
363     texAddrOffsets[4] = GDGetCurrOffset() + BP_DATA_OFFSET;
364 
365     GDSetTexImgPtrRaw( GX_TEXMAP0, 0 );
366 
367     GDBegin( GX_QUADS, GX_VTXFMT0, 4 );
368     GDPosition1x8( 5 ); GDNormal1x8( 5 ); GDTexCoord1x8( 0 );
369     GDPosition1x8( 4 ); GDNormal1x8( 4 ); GDTexCoord1x8( 1 );
370     GDPosition1x8( 0 ); GDNormal1x8( 0 ); GDTexCoord1x8( 2 );
371     GDPosition1x8( 3 ); GDNormal1x8( 3 ); GDTexCoord1x8( 3 );
372     GDEnd();
373 
374     // face 6
375 
376     GDSetTexImgAttr( GX_TEXMAP0,            // tmap
377                      128,                   // width
378                      128,                   // height
379                      (GXTexFmt)GX_TF_C8 );  // format
380 
381     GDSetTexCached( GX_TEXMAP0, MyTmemRegions[5][0], GX_TEXCACHE_32K,
382                                 MyTmemRegions[5][1], GX_TEXCACHE_32K );
383 
384     // The color-index texture has different lookup properties:
385 
386     GDSetTexLookupMode( GX_TEXMAP0,             // tmap
387                         GX_REPEAT,              // wrap s
388                         GX_REPEAT,              // wrap t
389                         GX_LIN_MIP_NEAR,        // min filt
390                         GX_LINEAR,              // mag filt
391                         0.0f,                   // min LOD
392                         0.0f,                   // max LOD
393                         0.0f,                   // LOD bias
394                         GX_FALSE,               // bias clamp?
395                         GX_TRUE,                // do edge LOD?
396                         GX_ANISO_1 );           // max aniso
397 
398     texAddrOffsets[5] = GDGetCurrOffset() + BP_DATA_OFFSET;
399 
400     GDSetTexImgPtrRaw( GX_TEXMAP0, 0 );
401 
402     GDBegin( GX_QUADS, GX_VTXFMT0, 4 );
403     GDPosition1x8( 6 ); GDNormal1x8( 6 ); GDTexCoord1x8( 0 );
404     GDPosition1x8( 2 ); GDNormal1x8( 2 ); GDTexCoord1x8( 1 );
405     GDPosition1x8( 1 ); GDNormal1x8( 1 ); GDTexCoord1x8( 2 );
406     GDPosition1x8( 7 ); GDNormal1x8( 7 ); GDTexCoord1x8( 3 );
407     GDEnd();
408 
409     // pad & flush
410     GDPadCurr32();
411     GDFlushCurrToMem(); // not strictly needed for PC-side, but not a bad idea
412 
413     GDSetCurrent(NULL); // bug-prevention
414 }
415