#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"
#include "sub_ui.h"
extern const uint8_t FBImage[ ];
#define MainTextureWidth 512
#define MainTextureHeight 512
#define MainTextureSize ( MainTextureWidth * MainTextureHeight * 4 )
// 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 = 1.0f,
.bottom = 0.0f
}
},
.params = ( C2D_DrawParams ) {
.pos.x = 0.0f,
.pos.y = 0.0f,
.pos.w = MainTextureWidth,
.pos.h = MainTextureHeight,
.center.x = 1.0f,
.center.y = 1.0f,
.depth = 1.0f,
.angle = 0.0f //-C3D_AngleFromDegrees( 90.0f )
}
};
C3D_RenderTarget* MainRenderTarget = NULL;
uint32_t* MainScreenBuffer = NULL;
bool CreateMainScreen( void ) {
MainRenderTarget = C2D_CreateScreenTarget( GFX_TOP, GFX_LEFT );
if ( MainRenderTarget ) {
MainScreenBuffer = ( uint32_t* ) linearAlloc( MainTextureSize );
if ( MainScreenBuffer ) {
memset( MainScreenBuffer, 0, MainTextureSize );
return C3D_TexInit( ScreenSprite.image.tex, 512, 512, GPU_RGBA8 );
}
}
return false;
}
void DestroyMainScreen( void ) {
if ( MainScreenBuffer ) {
linearFree( MainScreenBuffer );
}
C3D_TexDelete( ScreenSprite.image.tex );
}
int ShowError( const char* ErrorText ) {
errorConf e;
errorInit( &e, ERROR_TEXT_WORD_WRAP, CFG_LANGUAGE_EN );
errorText( &e, ErrorText );
errorDisp( &e );
return 1;
}
volatile bool RenderThreadRun = true;
volatile bool RenderThreadReady = false;
volatile bool RenderThreadBusy = false;
volatile bool RenderThreadReqUpdate = false;
Thread RenderThreadHandle = NULL;
void RenderThread( void* Param ) {
gfxInitDefault( );
consoleInit( GFX_BOTTOM, NULL );
C3D_Init( C3D_DEFAULT_CMDBUF_SIZE );
C2D_Init( C2D_DEFAULT_MAX_OBJECTS );
C2D_Prepare( );
if ( CreateMainScreen( ) ) {
RenderThreadReady = true;
while ( RenderThreadRun ) {
if ( RenderThreadReqUpdate == true ) {
RenderThreadReqUpdate = false;
RenderThreadBusy = true;
Unpack8BPP( ( const uint8_t* ) fb8bpp, MainScreenBuffer, 512 * 384 );
RenderThreadBusy = false;
}
C3D_FrameBegin( C3D_FRAME_SYNCDRAW );
// Flush and transfer main screen to texture
GSPGPU_FlushDataCache( MainScreenBuffer, MainTextureSize );
C3D_SyncDisplayTransfer(
( uint32_t* ) MainScreenBuffer,
GX_BUFFER_DIM( MainTextureWidth, MainTextureHeight ),
ScreenSprite.image.tex->data,
GX_BUFFER_DIM( MainTextureWidth, MainTextureHeight ),
GX_TRANSFER_OUT_FORMAT( GX_TRANSFER_FMT_RGBA8 ) |
GX_TRANSFER_IN_FORMAT( GX_TRANSFER_FMT_RGBA8 ) |
GX_TRANSFER_OUT_TILED( 1 ) |
GX_TRANSFER_FLIP_VERT( 0 )
);
// Draw
C2D_TargetClear( MainRenderTarget, C2D_Color32( 0, 255, 255, 255 ) );
C2D_SceneBegin( MainRenderTarget );
C2D_DrawSprite( &ScreenSprite );
C3D_FrameEnd( 0 );
}
DestroyMainScreen( );
}
C2D_Fini( );
C3D_Fini( );
gfxExit( );
threadExit( 0 );
}
int main( void ) {
uint32_t Keys_Down = false;
osSetSpeedupEnable( false );
APT_SetAppCpuTimeLimit( 75 );
RenderThreadHandle = threadCreate( RenderThread, NULL, 4096, 0x20, 1, false );
if ( ! RenderThreadHandle ) {
return ShowError( "Failed to create render thread" );
}
// Wait for render thread to init and start running
while ( RenderThreadReady == false )
;
// Initial render req
RenderThreadReqUpdate = true;
// Spin until it finishes
while ( RenderThreadBusy )
;
printf( "Hi!\n" );
while ( aptMainLoop( ) ) {
hidScanInput( );
Keys_Down = hidKeysDown( );
if ( Keys_Down & KEY_A ) {
RenderThreadReqUpdate = true;
RenderThreadBusy = true;
while ( RenderThreadBusy )
;
}
if ( Keys_Down & KEY_START ) {
break;
}
}
RenderThreadReqUpdate = false;
RenderThreadRun = false;
threadJoin( RenderThreadHandle, U64_MAX );
threadFree( RenderThreadHandle );
return 0;
}