It has been a long time that I wanted to see FCEUltra ported to the PSP. Mainly a version that could be ran on the slim/newest versions which don't support kernel 1.5.
Searching a little, I discovered that Hamsterburt atually did a port of it. The sound is not perfect and the sources weren't released (I've even sent him an email asking for it, but I didn't get an answer). My idea was to use his port as my first (and PSPSDK learning) project, so I could try to improve it.
As I didn't get any sources from him, I've decided to get FCEUltra 0.98.12 original source code and try to port it for the PSP. This is my first PSP related thing and I'm completely ignorant regarding several specific PSP dev topics. And that's why I'm coming here and making this post, so you guys may help me! :)
Now, to the funny part! Right now, the emulator doesn't have any menu or file browser. It just runs whatever the ROM is placed on the root of your memory stick with the "nesrom.nes" name. It supports "basic" input (only the necessary to play the game) and NO sound.
The video is not perfect: it's not smooth, it stutters sometimes, and if you check Super Mario Bros, you're going to see that weird "crispy" effect on the green pipes and on the floor. I would like to make the video rendering the most optimized as possible before moving to the sound and menu areas. Maybe It's because I'm not using the VRAM? Or calling some unnecessary functions in the main loop rendering function (PSPVideoRenderFrame)? Or even calling the GU functions without the most suitable parameters/options? I don't have a clue:
GU Init code:
Code: Select all
void PSPVideoInit() {
// Setup GU
sceGuInit(); // Turn on the GU
sceGuStart(GU_DIRECT,list); // Start filling a command list.
sceGuDrawBuffer(GU_PSM_8888,(void*)0,BUF_WIDTH); // Point out the drawing buffer
sceGuDispBuffer(SCR_WIDTH,SCR_HEIGHT,(void*)FRAME_SIZE,BUF_WIDTH); // Point out the display buffer
sceGuDepthBuffer((void*)(FRAME_SIZE*2),BUF_WIDTH); // Point out the depth buffer
sceGuOffset(2048 - (SCR_WIDTH/2),2048 - (SCR_HEIGHT/2)); // Define current drawing area.
sceGuViewport(2048,2048,SCR_WIDTH,SCR_HEIGHT); // Center screen in virtual space.
sceGuDepthRange(0xc350,0x2710); // Tells the GU what value range to use within the depth buffer.
sceGuScissor(0,0,SCR_WIDTH,SCR_HEIGHT); // Sets up a scissor rect for the screen.
sceGuEnable(GU_SCISSOR_TEST); // Enables scissor mode: pixels outside the scissor rect are not rendered.
sceGuFrontFace(GU_CW);
sceGuEnable(GU_TEXTURE_2D); // Enables texturing of primitives.
sceGuClear(GU_COLOR_BUFFER_BIT|GU_DEPTH_BUFFER_BIT); // Clears current drawbuffer
sceGuFinish(); // End of command list
sceGuSync(0,0); // Wait for list to finish executing
sceDisplayWaitVblankStart(); // Wait for vertical blank start
sceGuDisplay(GU_TRUE); // VRAM should be displayed on screen.
// Clear screen
sceGuClearColor(0xff00ff); // Sets current clear color
sceGuClear(GU_COLOR_BUFFER_BIT); // Clears current drawbuffer
}
Code: Select all
void PSPVideoRenderFrame(uint8 *XBuf) {
sceGuStart(GU_DIRECT,list);
// setup CLUT texture
sceGuClutMode(GU_PSM_8888,0,0xff,0); // 32-bit palette
sceGuClutLoad((256/8),clut256); // upload 32*8 entries (256)
sceGuTexMode(GU_PSM_T8,0,0,0); // 8-bit image
sceGuTexImage(0,256,256,256,XBuf);
sceGuTexFunc(GU_TFX_REPLACE,GU_TCC_RGB);
sceGuTexFilter(GU_LINEAR,GU_LINEAR);
//sceGuTexFilter(GU_NEAREST, GU_NEAREST);
sceGuTexScale(1.0f,1.0f);
sceGuTexOffset(0.0f,0.0f);
sceGuAmbientColor(0xffffffff);
// render sprite
sceGuColor(0xffffffff);
struct Vertex* vertices = (struct Vertex*)sceGuGetMemory(2 * sizeof(struct Vertex));
vertices[0].u = 0; vertices[0].v = 0;
vertices[0].x = 85; vertices[0].y = 0; vertices[0].z = 0;
vertices[1].u = 256; vertices[1].v = 256;
//vertices[1].x = 480; vertices[1].y = 272; vertices[1].z = 0;
vertices[1].x = 394; vertices[1].y = 290; vertices[1].z = 0;
sceGuDrawArray(GU_SPRITES,GU_TEXTURE_32BITF|GU_VERTEX_32BITF|GU_TRANSFORM_2D,2,0,vertices);
// wait for next frame
sceGuFinish();
sceGuSync(0,0);
//sceDisplayWaitVblankStart();
sceGuSwapBuffers();
}
Code: Select all
int main(int argc, char *argv[])
{
SetupCallbacks();
sceKernelDcacheWritebackAll();
scePowerSetClockFrequency(333, 333, 166);
//XBuf = getStaticVramBuffer(512,272,3);
if(!(FCEUI_Initialize())) {
printf("FCEUltra did not initialize.\n");
return(0);
}
FCEUI_SetVidSystem(0); // 0 - NTSC
FCEUI_SetGameGenie(0);
FCEUI_DisableSpriteLimitation(1);
FCEUI_SetSoundVolume(0);
FCEUI_SetSoundQuality(0);
FCEUI_SetLowPass(0);
FCEUI_Sound(0);
FCEUGI *tmp;
if((tmp=FCEUI_LoadGame("ms0:/nesrom.nes"))) {
printf("Game Loaded!\n");
CurGame=tmp;
}
else {
printf("Didn't load Game!\n");
}
PSPInputInitPads();
PSPVideoInit();
PSPVideoOverrideNESClut();
while(CurGame) {//FCEUI_CloseGame turns this false
DoFun();
}
sceGuTerm();
sceKernelExitGame();
return 0;
}
void FCEUD_Update(uint8 *XBuf, int32 *tmpsnd, int32 ssize)
{
PSPVideoRenderFrame(XBuf);
PSPInputReadPad();
//printf("FCEUD_Update\n");
// OutputSound(tmpsnd, ssize);
// if (Get_NESInput()) {
// FCEUI_CloseGame();
// CurGame=0;
// }
}
void DoFun()
{
uint8 *gfx;
int32 *sound;
int32 ssize;
FCEUI_Emulate(&gfx, &sound, &ssize, 0);
FCEUD_Update(gfx, sound, ssize);
}
http://code.google.com/p/fceupsp/
If you need look further on the source code, you can always point your browser to:
http://fceupsp.googlecode.com/svn/trunk/
The PSP related modifications are pretty much the following:
:. http://fceupsp.googlecode.com/svn/trunk ... u/Makefile -> PSPSDK specific Makefile
:. http://fceupsp.googlecode.com/svn/trunk ... ivers/psp/ -> PSP specific code
Thanks!
bootsector