-#include <3ds/types.h>
-#include <3ds/srv.h>
-#include <3ds/svc.h>
-#include <3ds/gpu/gx.h>
-#include <3ds/services/apt.h>
-#include <3ds/services/gsp.h>
-#include <3ds/services/hid.h>
-#include <3ds/services/fs.h>
-#include "costable.h"
-
-u8* gspHeap;
-u32* gxCmdBuf;
-
-u8 currentBuffer;
-u8* topLeftFramebuffers[2];
-
-Handle gspEvent, gspSharedMemHandle;
-
-void gspGpuInit()
-{
- gspInit();
-
- GSPGPU_AcquireRight(NULL, 0x0);
- GSPGPU_SetLcdForceBlack(NULL, 0x0);
-
- //set subscreen to blue
- u32 regData=0x01FF0000;
- GSPGPU_WriteHWRegs(NULL, 0x202A04, ®Data, 4);
-
- //grab main left screen framebuffer addresses
- GSPGPU_ReadHWRegs(NULL, 0x400468, (u32*)&topLeftFramebuffers, 8);
-
- //convert PA to VA (assuming FB in VRAM)
- topLeftFramebuffers[0]+=0x7000000;
- topLeftFramebuffers[1]+=0x7000000;
-
- //setup our gsp shared mem section
- u8 threadID;
- svcCreateEvent(&gspEvent, 0x0);
- GSPGPU_RegisterInterruptRelayQueue(NULL, gspEvent, 0x1, &gspSharedMemHandle, &threadID);
- svcMapMemoryBlock(gspSharedMemHandle, 0x10002000, 0x3, 0x10000000);
-
- //map GSP heap
- svcControlMemory((u32*)&gspHeap, 0x0, 0x0, 0x2000000, 0x10003, 0x3);
+///////////////////////////////////////
+// SDMC example //
+///////////////////////////////////////
- //wait until we can write stuff to it
- svcWaitSynchronization(gspEvent, 0x55bcb0);
+//this example shows you how to load a binary image file from the SD card and display it on the lower screen
+//for this to work you should copy test.bin to the root of your SD card
+//this file was generated with GIMP by saving a 240x320 image to raw RGB
- //GSP shared mem : 0x2779F000
- gxCmdBuf=(u32*)(0x10002000+0x800+threadID*0x200);
-
- currentBuffer=0;
-}
-
-void gspGpuExit()
-{
- GSPGPU_UnregisterInterruptRelayQueue(NULL);
-
- //unmap GSP shared mem
- svcUnmapMemoryBlock(gspSharedMemHandle, 0x10002000);
- svcCloseHandle(gspSharedMemHandle);
- svcCloseHandle(gspEvent);
-
- gspExit();
-
- //free GSP heap
- svcControlMemory((u32*)&gspHeap, (u32)gspHeap, 0x0, 0x2000000, MEMOP_FREE, 0x0);
-}
-
-
-void swapBuffers()
-{
- u32 regData;
- GSPGPU_ReadHWRegs(NULL, 0x400478, ®Data, 4);
- regData^=1;
- currentBuffer=regData&1;
- GSPGPU_WriteHWRegs(NULL, 0x400478, ®Data, 4);
-}
-
-void copyBuffer()
-{
- //copy topleft FB
- u8 copiedBuffer=currentBuffer^1;
- u8* bufAdr=&gspHeap[0x46500*copiedBuffer];
- GSPGPU_FlushDataCache(NULL, bufAdr, 0x46500);
+#include <3ds.h>
+#include "costable.h"
- GX_RequestDma(gxCmdBuf, (u32*)bufAdr, (u32*)topLeftFramebuffers[copiedBuffer], 0x46500);
-}
+//this will contain the data read from SDMC
+u8* buffer;
+//3DS has VFPs so we could just use cos
+//but we're old school so LUT4life
s32 pcCos(u16 v)
{
return costable[v&0x1FF];
void renderEffect()
{
- u8* bufAdr=&gspHeap[0x46500*currentBuffer];
+ static int cnt;
+ u8* bufAdr=gfxGetFramebuffer(GFX_TOP, GFX_LEFT, NULL, NULL);
- if(!currentBuffer)return;
int i, j;
for(i=1;i<400;i++)
{
for(j=1;j<240;j++)
{
u32 v=(j+i*240)*3;
- bufAdr[v]=(pcCos(i)+4096)/32;
- bufAdr[v+1]=0x00;
- bufAdr[v+2]=0xFF*currentBuffer;
+ bufAdr[v]=(pcCos(i+cnt)+4096)/32;
+ bufAdr[v+1]=(pcCos(j-256+cnt)+4096)/64;
+ bufAdr[v+2]=(pcCos(i+128-cnt)+4096)/32;
}
}
+
+ cnt++;
}
-int main()
+int main(int argc, char** argv)
{
- srvInit();
-
- aptInit(APPID_APPLICATION);
+ //initialize the services we're going to be using
+ srvInit(); //needed for everything
+ aptInit(); //needed for everything
+ hidInit(NULL); //needed for input
+ gfxInit(); //makes displaying to screen easier
+ fsInit(); //needed for filesystem stuff
+
+ u64 size;
+ u32 bytesRead;
+ Handle fileHandle;
+ //setup SDMC archive
+ FS_archive sdmcArchive=(FS_archive){ARCH_SDMC, (FS_path){PATH_EMPTY, 1, (u8*)""}};
+ //create file path struct (note : FS_makePath actually only supports PATH_CHAR, it will change in the future)
+ FS_path filePath=FS_makePath(PATH_CHAR, "/test.bin");
- gspGpuInit();
+ //open file
+ Result ret=FSUSER_OpenFileDirectly(NULL, &fileHandle, sdmcArchive, filePath, FS_OPEN_READ, FS_ATTRIBUTE_NONE);
+ //check for errors : exit if there is one
+ if(ret)goto exit;
- hidInit(NULL);
+ //get file size
+ ret=FSFILE_GetSize(fileHandle, &size);
+ if(ret)goto exit;
- Handle fsuHandle;
- srvGetServiceHandle(&fsuHandle, "fs:USER");
- FSUSER_Initialize(fsuHandle);
+ //allocate a buffer on linear heap (could just be a malloc fwiw)
+ buffer=linearAlloc(size);
+ if(!buffer)goto exit;
- Handle fileHandle;
- u32 bytesRead;
- FS_archive sdmcArchive=(FS_archive){ARCH_SDMC, (FS_path){PATH_EMPTY, 1, (u8*)""}};
- FS_path filePath=(FS_path){PATH_CHAR, 10, (u8*)"/test.bin"};
- FSUSER_OpenFileDirectly(fsuHandle, &fileHandle, sdmcArchive, filePath, FS_OPEN_READ, FS_ATTRIBUTE_NONE);
- FSFILE_Read(fileHandle, &bytesRead, 0x0, (u32*)gspHeap, 0x46500);
- FSFILE_Close(fileHandle);
+ //read contents !
+ ret=FSFILE_Read(fileHandle, &bytesRead, 0x0, buffer, size);
+ if(ret || size!=bytesRead)goto exit;
+
+ //close the file because we like being nice and tidy
+ ret=FSFILE_Close(fileHandle);
+ if(ret)goto exit;
- APP_STATUS status;
- while((status=aptGetStatus())!=APP_EXITING)
+ while(aptMainLoop())
{
- if(status==APP_RUNNING)
- {
- u32 PAD=hidSharedMem[7];
- renderEffect();
- swapBuffers();
- copyBuffer();
- u32 regData=PAD|0x01000000;
- GSPGPU_WriteHWRegs(NULL, 0x202A04, ®Data, 4);
- svcSleepThread(1000000000);
- }
- else if(status == APP_SUSPENDING)
- {
- aptReturnToMenu();
- }
- else if(status == APP_SLEEPMODE)
- {
- aptWaitStatusEvent();
- }
+ //exit when user hits B
+ hidScanInput();
+ if(keysHeld()&KEY_B)break;
+
+ //render rainbow
+ renderEffect();
+
+ //copy buffer to lower screen (don't have to do it every frame)
+ memcpy(gfxGetFramebuffer(GFX_BOTTOM, GFX_BOTTOM, NULL, NULL), buffer, size);
+
+ //wait & swap
+ gfxSwapBuffersGpu();
+ gspWaitForEvent(GSPEVENT_VBlank0, false);
}
- svcCloseHandle(fsuHandle);
+ //cleanup and return
+ //returning from main() returns to hbmenu when run under ninjhax
+ exit:
+ //closing all handles is super important
+ svcCloseHandle(fileHandle);
+ //closing all services even more so
+ gfxExit();
hidExit();
- gspGpuExit();
aptExit();
- svcExitProcess();
+ srvExit();
return 0;
}