/*---------------------------------------------------------------------------* Project: Dolphin/Revolution cx demo File: cx_uncompress_stream.c Copyright 2006 Nintendo. All rights reserved. These coded instructions, statements, and computer programs contain proprietary information of Nintendo of America Inc. and/or Nintendo Company Ltd., and are protected by Federal copyright law. They may not be disclosed to third parties or copied or duplicated in any form, in whole or in part, without the prior written consent of Nintendo. *---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------* cx_uncompress Data uncompress demo *---------------------------------------------------------------------------*/ #include #include // For camera typedef struct { Vec location; Vec up; Vec target; f32 left; f32 top; f32 znear; f32 zfar; } CameraConfig; typedef struct { CameraConfig cfg; Mtx view; Mtx44 proj; } MyCameraObj; // For entire scene control typedef struct { MyCameraObj cam; u32 texNum[ 4 ]; } MySceneCtrlObj; void main ( void ); static void DrawInit ( MySceneCtrlObj* sc ); static void DrawTick ( MySceneCtrlObj* sc ); static void AnimTick ( MySceneCtrlObj* sc ); static void SetCamera ( MyCameraObj* cam ); static void PrintIntro( void ); static void DrawRect ( void ); static void* LoadTexData ( const char* path ); static void* LoadTexDataLZ ( const char* path ); static void* LoadTexDataRL ( const char* path ); static void* LoadTexDataHuff( const char* path ); /*---------------------------------------------------------------------------* Camera configuration *---------------------------------------------------------------------------*/ static CameraConfig DEFAULT_CAMERA = { { 0.0F, 0.0F, 100.0F }, // location { 0.0F, 1.0F, 0.0F }, // up { 0.0F, 0.0F, 0.0F }, // target -320.0F, // left -224.0F, // top (note: was 240, now adjusted for over scan) 0.1F, // near 2000.0F // far }; #if !defined(RVL_OS) // Replacing Dolphin-SDK static void TEXBind( TEXPalettePtr pal ) { u16 i; if(pal->versionNumber != 2142000 ) OSHalt("invalid version number for texture palette"); pal->descriptorArray = (TEXDescriptorPtr)(((u32)(pal->descriptorArray)) + ((u32)pal)); for ( i = 0; i < pal->numDescriptors; i++ ) { if(pal->descriptorArray[i].textureHeader) { pal->descriptorArray[i].textureHeader = (TEXHeaderPtr)(((u32)(pal->descriptorArray[i].textureHeader)) + ((u32)pal)); if(!(pal->descriptorArray[i].textureHeader->unpacked)) { pal->descriptorArray[i].textureHeader->data = (Ptr)((u32)(pal->descriptorArray[i].textureHeader->data) + (u32)pal); pal->descriptorArray[i].textureHeader->unpacked = 1; } } if(pal->descriptorArray[i].CLUTHeader) { pal->descriptorArray[i].CLUTHeader = (CLUTHeaderPtr)((u32)(pal->descriptorArray[i].CLUTHeader) + (u32)pal); if(!(pal->descriptorArray[i].CLUTHeader->unpacked)) { pal->descriptorArray[i].CLUTHeader->data = (Ptr)((u32)(pal->descriptorArray[i].CLUTHeader->data) + (u32)pal); pal->descriptorArray[i].CLUTHeader->unpacked = 1; } } } } #define TPLPalettePtr TEXPalettePtr #define TPLDescriptorPtr TEXDescriptorPtr #define TPLGet TEXGet #define TPLBind TEXBind #endif /* !defined(RVL_OS) */ static inline void* DEMOAlloc( u32 size ) { #ifdef RVL_OS return MEMAllocFromAllocator( &DemoAllocator1, size ); #else return OSAlloc( size ); #endif } static inline void DEMOFree( void* mem ) { #ifdef RVL_OS MEMFreeToAllocator( &DemoAllocator1, mem ); #else OSFree( mem ); #endif } /*---------------------------------------------------------------------------* Data for views and parameters *---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------* Global variables *---------------------------------------------------------------------------*/ static TPLPalettePtr sMyTplObj[ 4 ] = { NULL, NULL, NULL, NULL }; // A pointer to the texture/palette data /* Double buffer used for streaming decompression (to load and decompress in parallel) */ #define BUF_SIZE 0x4000 static u8 sReadBuf[ 2 ][ BUF_SIZE ] ATTRIBUTE_ALIGN(32); /*---------------------------------------------------------------------------* Application main loop *---------------------------------------------------------------------------*/ void main( void ) { MySceneCtrlObj sceneCtrl; DEMOInit( NULL ); // OS, Pad, GX and VI initialization PrintIntro(); DrawInit( &sceneCtrl ); // Camera initialization and loading of texture data from optical disc // Compressed data is loaded as streaming decompression takes place while ( !(DEMOPadGetButton( 0 ) & PAD_BUTTON_MENU) ) { DEMOBeforeRender(); DrawTick( &sceneCtrl ); // Render process for every frame DEMODoneRender(); DEMOPadRead(); AnimTick( &sceneCtrl ); // Pad input process for each frame } OSHalt("End of demo"); } /*---------------------------------------------------------------------------* Name: SetCamera Description: Calculates and sets the view and projection matrices. Arguments: cam : A pointer to MyCameraObj Returns: None. *---------------------------------------------------------------------------*/ static void SetCamera( MyCameraObj* cam ) { MTXLookAt( cam->view, &cam->cfg.location, &cam->cfg.up, &cam->cfg.target ); MTXOrtho( cam->proj, cam->cfg.top, -(cam->cfg.top), cam->cfg.left, -(cam->cfg.left), cam->cfg.znear, cam->cfg.zfar ); GXSetProjection( cam->proj, GX_ORTHOGRAPHIC ); } /*---------------------------------------------------------------------------* Name: LoadTexData Description: Loads non-compressed texture/palette data from the DVD Arguments: path the path to the texture/palette file on the DVD Returns: Returns the pointer to the loaded data. *---------------------------------------------------------------------------*/ static void* LoadTexData( const char* path ) { DVDFileInfo fileInfo; void* buf; DVDOpen( path, &fileInfo ); buf = DEMOAlloc( OSRoundUp32B( fileInfo.length ) ); DVDRead( &fileInfo, buf, (s32)OSRoundUp32B( fileInfo.length ), 0 ); DVDClose( &fileInfo ); return buf; } /*---------------------------------------------------------------------------* Name: LoadTexDataRL Description: Loads run-length compressed texture/palette data from the DVD and performs streaming decompression. Data is decompressed as it is asynchronously read from the DVD, using a double buffer. Arguments: path the path to the texture/palette file on the DVD Returns: Returns the pointer to the decompressed data. *---------------------------------------------------------------------------*/ static void* LoadTexDataRL( const char* path ) { void* uncompBuf; // Decompression buffer u32 uncompSize; // Data size after decompression DVDFileInfo fileInfo; // DVD file context u32 len[ 2 ]; // Size of read data in the temporary buffer s32 currIdx = 0; // Index to control double buffer s32 nextIdx = 1; // Index to control double buffer s32 offset = 0; // DVD offset CXUncompContextRL context; // Streaming decompression context DVDOpen( path, &fileInfo ); DVDRead( &fileInfo, sReadBuf[ currIdx ], 32, 0 ); len[ currIdx ] = 32; offset += 32; // Loads at least the first four bytes of data and then allocates memory for the decompressed data size. uncompSize = CXGetUncompressedSize ( sReadBuf[ currIdx ] ); uncompBuf = DEMOAlloc( uncompSize ); // Initializes the context for streaming decompression. CXInitUncompContextRL( &context, uncompBuf ); // Data is decompressed in order until the file decompression is complete. while ( ! CXIsFinishedUncompRL( &context ) ) { while ( DVDGetFileInfoStatus( &fileInfo ) != DVD_FILEINFO_READY ) {} len[ nextIdx ] = OSRoundUp32B( fileInfo.length - offset ); if ( len[ nextIdx ] > BUF_SIZE ) { len[ nextIdx ] = BUF_SIZE; } if ( len[ nextIdx ] > 0 ) { DVDReadAsync( &fileInfo, sReadBuf[ nextIdx ], (s32)len[ nextIdx ], offset, NULL ); offset += len[ nextIdx ]; } // Only the loaded data is passed in order to the CX functions ASSERT( len[ currIdx ] != 0 ); CXReadUncompRL( &context, sReadBuf[ currIdx ], len[ currIdx ] ); // Double buffer swap currIdx = (currIdx == 0)? 1 : 0; nextIdx = (nextIdx == 0)? 1 : 0; } DCFlushRange( uncompBuf, uncompSize ); DVDClose( &fileInfo ); return uncompBuf; } /*---------------------------------------------------------------------------* Name: LoadTexDataLZ Description: Loads LZ77 compressed texture/palette data from the DVD and performs streaming decompression. Data is decompressed as it is asynchronously read from the DVD, using a double buffer. Arguments: path the path to the texture/palette file on the DVD Returns: Returns the pointer to the decompressed data. *---------------------------------------------------------------------------*/ static void* LoadTexDataLZ( const char* path ) { void* uncompBuf; // Decompression buffer u32 uncompSize; // Data size after decompression DVDFileInfo fileInfo; // DVD file context u32 len[ 2 ]; // Size of read data in the temporary buffer s32 currIdx = 0; // Index to control double buffer s32 nextIdx = 1; // Index to control double buffer s32 offset = 0; // DVD offset CXUncompContextLZ context; // Streaming decompression context DVDOpen( path, &fileInfo ); DVDRead( &fileInfo, sReadBuf[ currIdx ], 32, 0 ); len[ currIdx ] = 32; offset += 32; // Loads at least the first four bytes of data and then allocates memory for the decompressed data size. uncompSize = CXGetUncompressedSize ( sReadBuf[ currIdx ] ); uncompBuf = DEMOAlloc( uncompSize ); // Initializes the context for streaming decompression. CXInitUncompContextLZ( &context, uncompBuf ); // Data is decompressed in order until the file decompression is complete. while ( ! CXIsFinishedUncompLZ( &context ) ) { while ( DVDGetFileInfoStatus( &fileInfo ) != DVD_FILEINFO_READY ) {} len[ nextIdx ] = OSRoundUp32B( fileInfo.length - offset ); if ( len[ nextIdx ] > BUF_SIZE ) { len[ nextIdx ] = BUF_SIZE; } if ( len[ nextIdx ] > 0 ) { DVDReadAsync( &fileInfo, sReadBuf[ nextIdx ], (s32)len[ nextIdx ], offset, NULL ); offset += len[ nextIdx ]; } // Only the loaded data is passed in order to the CX functions ASSERT( len[ currIdx ] != 0 ); CXReadUncompLZ( &context, sReadBuf[ currIdx ], len[ currIdx ] ); // Double buffer swap currIdx = (currIdx == 0)? 1 : 0; nextIdx = (nextIdx == 0)? 1 : 0; } DCFlushRange( uncompBuf, uncompSize ); DVDClose( &fileInfo ); return uncompBuf; } /*---------------------------------------------------------------------------* Name: LoadTexDataHuff Description: Loads Huffman compressed texture/palette data from the DVD and performs streaming decompression. Data is decompressed as it is asynchronously read from the DVD, using a double buffer. Arguments: path the path to the texture/palette file on the DVD Returns: Returns the pointer to the decompressed data. *---------------------------------------------------------------------------*/ static void* LoadTexDataHuff( const char* path ) { void* uncompBuf; // Decompression buffer u32 uncompSize; // Data size after decompression DVDFileInfo fileInfo; // DVD file context u32 len[ 2 ]; // Size of read data in the temporary buffer s32 currIdx = 0; // Index to control double buffer s32 nextIdx = 1; // Index to control double buffer s32 offset = 0; // DVD offset CXUncompContextHuffman context; // Streaming decompression context DVDOpen( path, &fileInfo ); DVDRead( &fileInfo, sReadBuf[ currIdx ], 32, 0 ); len[ currIdx ] = 32; offset += 32; // Loads at least the first four bytes of data and then allocates memory for the decompressed data size. uncompSize = CXGetUncompressedSize ( sReadBuf[ currIdx ] ); uncompBuf = DEMOAlloc( uncompSize ); // Initializes the context for streaming decompression. CXInitUncompContextHuffman( &context, uncompBuf ); // Data is decompressed in order until the file decompression is complete. while ( ! CXIsFinishedUncompHuffman( &context ) ) { while ( DVDGetFileInfoStatus( &fileInfo ) != DVD_FILEINFO_READY ) {} len[ nextIdx ] = OSRoundUp32B( fileInfo.length - offset ); if ( len[ nextIdx ] > BUF_SIZE ) { len[ nextIdx ] = BUF_SIZE; } if ( len[ nextIdx ] > 0 ) { DVDReadAsync( &fileInfo, sReadBuf[ nextIdx ], (s32)len[ nextIdx ], offset, NULL ); offset += len[ nextIdx ]; } // Only the loaded data is passed in order to the CX functions ASSERT( len[ currIdx ] != 0 ); CXReadUncompHuffman( &context, sReadBuf[ currIdx ], len[ currIdx ] ); // Double buffer swap currIdx = (currIdx == 0)? 1 : 0; nextIdx = (nextIdx == 0)? 1 : 0; } DCFlushRange( uncompBuf, uncompSize ); DVDClose( &fileInfo ); return uncompBuf; } /*---------------------------------------------------------------------------* Functions *---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------* Name: DrawInit Description: Initializes camera and loads and decompresses texture/palette data from DVD Arguments: sc : a pointer to the scene parameter Returns: None. *---------------------------------------------------------------------------*/ static void DrawInit( MySceneCtrlObj* sc ) { u32 i; for ( i = 0; i < 4; i++ ) { sc->texNum[ i ] = 0; } // Loads from the DVD while performing streaming decompression of the TPL file. sMyTplObj[ 0 ] = (TPLPalettePtr)LoadTexData ( "/cxdemo/tex-01.tpl" ); sMyTplObj[ 1 ] = (TPLPalettePtr)LoadTexDataRL ( "/cxdemo/tex-01_RL.bin" ); sMyTplObj[ 2 ] = (TPLPalettePtr)LoadTexDataLZ ( "/cxdemo/tex-01_LZ.bin" ); sMyTplObj[ 3 ] = (TPLPalettePtr)LoadTexDataHuff( "/cxdemo/tex-01_Huff.bin" ); // Bind the TPL object TPLBind( sMyTplObj[ 0 ] ); TPLBind( sMyTplObj[ 1 ] ); TPLBind( sMyTplObj[ 2 ] ); TPLBind( sMyTplObj[ 3 ] ); // Camera initialization sc->cam.cfg = DEFAULT_CAMERA; SetCamera( &sc->cam ); // Sets the view matrix GXLoadPosMtxImm( sc->cam.view, GX_PNMTX0 ); } /*---------------------------------------------------------------------------* Name: DrawTick Description: Render process for every frame Arguments: sc : a pointer to the scene parameter Returns: None. *---------------------------------------------------------------------------*/ static void DrawTick( MySceneCtrlObj* sc ) { TPLDescriptorPtr tdp; GXTexObj texObj; s32 i; SetCamera( &sc->cam ); GXLoadPosMtxImm( sc->cam.view, GX_PNMTX0 ); for ( i = 0; i < 4; i++ ) { { // Sets the texture index specified from the TPL object tdp = TPLGet( sMyTplObj[ i ], sc->texNum[ i ] ); GXInitTexObj( &texObj, tdp->textureHeader->data, tdp->textureHeader->width, tdp->textureHeader->height, (GXTexFmt)tdp->textureHeader->format, tdp->textureHeader->wrapS, tdp->textureHeader->wrapT, GX_FALSE ); // Tev, TexGen and Zmode GXSetTevOp ( GX_TEVSTAGE0, GX_REPLACE ); GXSetTevOrder ( GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR_NULL ); GXSetTexCoordGen( GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, GX_IDENTITY ); GXSetZMode ( GX_ENABLE, GX_LEQUAL, GX_ENABLE ); GXSetNumTexGens( 1 ); GXSetCurrentMtx( GX_PNMTX0 ); GXLoadTexObj( &texObj, GX_TEXMAP0 ); } { // Renders after applying Scale and Trans Mtx mv; Mtx m; f32 transX = (i % 2)? -112 : 112; f32 transY = (i / 2)? -112 : 112; MTXScale( m, 0.5f, 0.5f, 0.5f ); MTXConcat( m, sc->cam.view, mv ); MTXTrans( m, transX, transY, 0 ); MTXConcat( m, mv, mv ); GXLoadPosMtxImm( mv, GX_PNMTX0 ); DrawRect(); } } DEMOInitCaption( DM_FT_OPQ, 320, 224 ); DEMOPrintf(48, 0, 0, "Raw"); DEMOPrintf(160, 0, 0, "RunLength"); DEMOPrintf(48, 112, 0, "LZ77"); DEMOPrintf(160, 112, 0, "Huffman"); } /*---------------------------------------------------------------------------* Name: AnimTick Description: Pad process for every frame Arguments: sc : a pointer to the scene parameter Returns: none *---------------------------------------------------------------------------*/ static void AnimTick ( MySceneCtrlObj* sc ) { if ( DEMOPadGetButtonDown( 0 ) & PAD_BUTTON_A ) { s32 i; for ( i = 0; i < 4; i++ ) { if ( ++sc->texNum[ i ] >= sMyTplObj[ i ]->numDescriptors ) { sc->texNum[ i ] = 0; } } } } /*---------------------------------------------------------------------------* Name: DrawRect Description: Renders a rectangle with a texture. Arguments: none Returns: none *---------------------------------------------------------------------------*/ static void DrawRect( void ) { const s16 VERTEX_POS = 224; // Vertex Attribute // Vertex Attribute ( VTXFMT0 is used by DEMOPuts lib.) GXSetVtxAttrFmt( GX_VTXFMT1, GX_VA_POS, GX_POS_XY, GX_S16, 0 ); GXSetVtxAttrFmt( GX_VTXFMT1, GX_VA_TEX0, GX_TEX_ST, GX_S16, 0 ); // Array Pointers and Strides GXInvalidateVtxCache(); // Set vertex descriptor GXClearVtxDesc(); GXSetVtxDesc( GX_VA_POS, GX_DIRECT ); GXSetVtxDesc( GX_VA_TEX0, GX_DIRECT ); // Draw a cube GXBegin( GX_QUADS, GX_VTXFMT1, 4 ); GXPosition2s16( -VERTEX_POS, -VERTEX_POS ); GXTexCoord2s16( 0, 0 ); GXPosition2s16( VERTEX_POS, -VERTEX_POS ); GXTexCoord2s16( 1, 0 ); GXPosition2s16( VERTEX_POS, VERTEX_POS ); GXTexCoord2s16( 1, 1 ); GXPosition2s16( -VERTEX_POS, VERTEX_POS ); GXTexCoord2s16( 0, 1 ); GXEnd(); } /*---------------------------------------------------------------------------* Name: PrintIntro Description: Prints the directions on how to use this demo. Arguments: none Returns: none *---------------------------------------------------------------------------*/ static void PrintIntro( void ) { OSReport("\n\n"); OSReport("************************************************\n"); OSReport("cx_uncompress_stream: Streaming Uncompression demo\n"); OSReport("************************************************\n"); OSReport("to quit hit the start button\n"); OSReport("\n"); OSReport("A button : change texture index to next\n"); OSReport("************************************************\n\n"); } /*============================================================================*/