#define __STDC_FORMAT_MACROS
#include <inttypes.h>
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <citro2d.h>
#include <3ds.h>
#include "fb_conv.h"
#include "CLUT_blues.h"
#include "CLUT_reds.h"
#include "CLUT_greens.h"
#include "fb8bpp.h"
extern const uint8_t FBImage[ ];
uint16_t ConversionTable[ 256 ];
#define MainTextureWidth 512
#define MainTextureHeight 512
#define MainTextureSize ( MainTextureWidth * MainTextureHeight * sizeof( uint16_t ) )
#define EmuScreenWidth 512
#define EmuScreenHeight 384
#define EmuScreenSize ( ( EmuScreenWidth * EmuScreenHeight ) / 2 )
#define MainScreenWidth 400
#define MainScreenHeight 240
// Cobbled together main framebuffer sprite
C2D_Sprite ScreenSprite = {
.image = ( C2D_Image ) {
.tex = &( C3D_Tex ) {
// Gets initialized later
},
.subtex = &( const Tex3DS_SubTexture ) {
.width = MainTextureWidth,
.height = MainTextureHeight,
.left = 0.0f,
.right = 1.0f,
.top = 0.0f,
.bottom = 1.0f
}
},
.params = ( C2D_DrawParams ) {
.pos.x = 0.0f,
.pos.y = 0.0f,
.pos.w = MainTextureWidth,
.pos.h = MainTextureHeight,
.center.x = 0.5f,
.center.y = 0.5f,
.depth = 1.0f,
.angle = 0.0f //C3D_AngleFromDegrees( 270.0f )
}
};
float ScaleX = 1.0f; //0.78125f;
float ScaleY = 1.0f; //0.625f;
int ScrollX = 0;
int ScrollY = 0;
void SetUnscaled( void ) {
C3D_TexSetFilter( ScreenSprite.image.tex, GPU_NEAREST, GPU_NEAREST );
C2D_SpriteSetScale( &ScreenSprite, 1.0f, 1.0f );
}
void SetScaled( void ) {
C3D_TexSetFilter( ScreenSprite.image.tex, GPU_LINEAR, GPU_LINEAR );
C2D_SpriteSetScale( &ScreenSprite, ScaleX, ScaleY );
}
void Scroll( void ) {
C2D_SpriteSetPos( &ScreenSprite, ( float ) ScrollX, ( float ) ScrollY );
}
C3D_RenderTarget* MainRenderTarget = NULL;
uint16_t* MainScreenBuffer = NULL;
bool CreateMainScreen( void ) {
MainRenderTarget = C2D_CreateScreenTarget( GFX_TOP, GFX_LEFT );
if ( MainRenderTarget ) {
MainScreenBuffer = ( uint16_t* ) linearAlloc( MainTextureSize );
if ( MainScreenBuffer ) {
memset( MainScreenBuffer, 0, MainTextureSize );
return C3D_TexInit( ScreenSprite.image.tex, 512, 512, GPU_RGB565 );
}
}
return false;
}
void DestroyMainScreen( void ) {
if ( MainScreenBuffer ) {
linearFree( MainScreenBuffer );
}
C3D_TexDelete( ScreenSprite.image.tex );
}
void Init_8BPP( void ) {
int r = 0;
int g = 0;
int b = 0;
int i = 0;
for ( i = 0; i < 256; i++ ) {
r = ( ( uint16_t* ) CLUT_reds )[ i ] >> 11;
g = ( ( uint16_t* ) CLUT_greens )[ i ] >> 10;
b = ( ( uint16_t* ) CLUT_blues )[ i ] >> 11;
ConversionTable[ i ] = RGB565( r, g, b );
}
}
void Unpack8BPP( const uint8_t* PixelsIn, uint16_t* PixelsOut, size_t InputLength ) {
while ( InputLength-- ) {
*PixelsOut++ = ConversionTable[ *PixelsIn++ ];
}
}
void UpdateMainScreen_8BPP( void ) {
Unpack8BPP( ( const uint8_t* ) fb8bpp, MainScreenBuffer, 512 * 384 );
GSPGPU_FlushDataCache( MainScreenBuffer, 512 * 384 * 2 );
GX_DisplayTransfer(
( uint32_t* ) MainScreenBuffer,
GX_BUFFER_DIM( MainTextureWidth, MainTextureHeight ),
ScreenSprite.image.tex->data,
GX_BUFFER_DIM( MainTextureWidth, MainTextureHeight ),
GX_TRANSFER_OUT_FORMAT( GX_TRANSFER_FMT_RGB565 ) |
GX_TRANSFER_IN_FORMAT( GX_TRANSFER_FMT_RGB565 ) |
GX_TRANSFER_OUT_TILED( 1 ) |
GX_TRANSFER_FLIP_VERT( 0 )
);
}
#if 0
void UpdateMainScreen_4BPP( void ) {
const size_t Size = ( 512 * 384 ) / 2;
Unpack4BPP( &( ( unsigned char* ) fb4bpp )[ 0 ], ( uint32_t* ) &MainScreenBuffer[ 0 ], Size );
GSPGPU_FlushDataCache( MainScreenBuffer, Size );
GX_DisplayTransfer(
( uint32_t* ) MainScreenBuffer,
GX_BUFFER_DIM( MainTextureWidth, MainTextureHeight ),
ScreenSprite.image.tex->data,
GX_BUFFER_DIM( MainTextureWidth, MainTextureHeight ),
GX_TRANSFER_OUT_FORMAT( GX_TRANSFER_FMT_RGB565 ) |
GX_TRANSFER_IN_FORMAT( GX_TRANSFER_FMT_RGB565 ) |
GX_TRANSFER_OUT_TILED( 1 ) |
GX_TRANSFER_FLIP_VERT( 0 )
);
}
void UpdateMainScreen_1BPP( void ) {
const size_t Size = ( 512 * 342 ) / 8;
Unpack_1BPP( FBImage, MainScreenBuffer, Size );
GSPGPU_FlushDataCache( MainScreenBuffer, Size );
GX_DisplayTransfer(
( uint32_t* ) MainScreenBuffer,
GX_BUFFER_DIM( MainTextureWidth, MainTextureHeight ),
ScreenSprite.image.tex->data,
GX_BUFFER_DIM( MainTextureWidth, MainTextureHeight ),
GX_TRANSFER_OUT_FORMAT( GX_TRANSFER_FMT_RGB565 ) |
GX_TRANSFER_IN_FORMAT( GX_TRANSFER_FMT_RGB565 ) |
GX_TRANSFER_OUT_TILED( 1 ) |
GX_TRANSFER_FLIP_VERT( 0 )
);
}
void UpdateMainScreenPartial_1BPP( int Top, int Bottom ) {
Unpack_1BPP(
&FBImage[ ( Top * EmuScreenWidth ) / 8 ],
&MainScreenBuffer[ Top * MainTextureWidth ],
( ( Bottom - Top ) * EmuScreenWidth ) / 8
);
GSPGPU_FlushDataCache( MainScreenBuffer, MainTextureSize );
GX_DisplayTransfer(
( uint32_t* ) MainScreenBuffer,
GX_BUFFER_DIM( MainTextureWidth, MainTextureHeight ),
ScreenSprite.image.tex->data,
GX_BUFFER_DIM( MainTextureWidth, MainTextureHeight ),
GX_TRANSFER_OUT_FORMAT( GX_TRANSFER_FMT_RGB565 ) |
GX_TRANSFER_IN_FORMAT( GX_TRANSFER_FMT_RGB565 ) |
GX_TRANSFER_OUT_TILED( 1 ) |
GX_TRANSFER_FLIP_VERT( 0 )
);
}
#endif
int main( void ) {
uint32_t Keys_Held = 0;
uint32_t Keys_Down = 0;
uint32_t Keys_Up = 0;
uint64_t a = 0;
uint64_t b = 0;
float Time = 0.0f;
gfxInitDefault( );
consoleInit( GFX_BOTTOM, NULL );
C3D_Init( C3D_DEFAULT_CMDBUF_SIZE );
C2D_Init( C2D_DEFAULT_MAX_OBJECTS );
C2D_Prepare( );
if ( CreateMainScreen( ) ) {
//Init_1BPP( );
//Init_4BPP( );
Init_8BPP( );
printf( "hi!\n" );
printf( "%d\n", sizeof( CLUT_reds ) );
//APT_SetAppCpuTimeLimit( 75 );
//osSetSpeedupEnable( true );
a = svcGetSystemTick( );
//UpdateMainScreenPartial_1BPP( 0, 342 );
//UpdateMainScreen_4BPP( );
UpdateMainScreen_8BPP( );
b = svcGetSystemTick( );
Time = ( float ) b - ( float ) a;
Time = Time / CPU_TICKS_PER_MSEC;
printf( "Full update took %.2fms\n", Time );
//C2D_SpriteScale( &ScreenSprite, 0.78125, 0.78125 );
//C3D_TexSetFilter( ScreenSprite.image.tex, GPU_LINEAR, GPU_LINEAR );
SetUnscaled( );
//SetScaled( );
Scroll( );
while ( aptMainLoop( ) ) {
hidScanInput( );
Keys_Held = hidKeysHeld( );
Keys_Down = hidKeysDown( );
Keys_Up = hidKeysUp( );
if ( Keys_Held & KEY_LEFT ) {
ScrollX--;
}
if ( Keys_Held & KEY_RIGHT ) {
ScrollX++;
}
if ( Keys_Held & KEY_UP ) {
ScrollY--;
}
if ( Keys_Held & KEY_DOWN ) {
ScrollY++;
}
Scroll( );
C3D_FrameBegin( C3D_FRAME_SYNCDRAW );
C2D_TargetClear( MainRenderTarget, C2D_Color32( 0, 255, 255, 255 ) );
C2D_SceneBegin( MainRenderTarget );
C3D_SetViewport( 0, 0, 240, 400 );
C3D_SetScissor( GPU_SCISSOR_NORMAL, 0, 0, 240, 400 );
C2D_DrawSprite( &ScreenSprite );
C3D_FrameEnd( 0 );
if ( Keys_Up & KEY_START ) {
break;
}
printf( "\x1b[2J" );
printf( "X: %d, Y: %d\n", ScrollX, ScrollY );
}
}
DestroyMainScreen( );
C2D_Fini( );
C3D_Fini( );
gfxExit( );
return 0;
}