diff options
-rw-r--r-- | melonDS.cbp | 2 | ||||
-rw-r--r-- | src/ARM.cpp | 3 | ||||
-rw-r--r-- | src/GPU2D.cpp | 8 | ||||
-rw-r--r-- | src/GPU3D.cpp | 11 | ||||
-rw-r--r-- | src/GPU3D_Soft.cpp | 2 | ||||
-rw-r--r-- | src/NDS.cpp | 5 | ||||
-rw-r--r-- | src/wx/main.cpp | 306 | ||||
-rw-r--r-- | src/wx/main.h | 28 |
8 files changed, 259 insertions, 106 deletions
diff --git a/melonDS.cbp b/melonDS.cbp index c838beb..71156cb 100644 --- a/melonDS.cbp +++ b/melonDS.cbp @@ -80,6 +80,8 @@ <Unit filename="src/ARM_InstrTable.h" /> <Unit filename="src/CP15.cpp" /> <Unit filename="src/CP15.h" /> + <Unit filename="src/Config.cpp" /> + <Unit filename="src/Config.h" /> <Unit filename="src/DMA.cpp" /> <Unit filename="src/DMA.h" /> <Unit filename="src/FIFO.h" /> diff --git a/src/ARM.cpp b/src/ARM.cpp index 382f56e..f15ce74 100644 --- a/src/ARM.cpp +++ b/src/ARM.cpp @@ -171,6 +171,9 @@ void ARM::JumpTo(u32 addr, bool restorecpsr) else addr &= ~0x1; } + if (addr == 0x0201764C) printf("capture test %d: R1=%08X\n", R[6], R[1]); + if (addr == 0x020175D8) printf("capture test %d: res=%08X\n", R[6], R[0]); + if (addr & 0x1) { addr &= ~0x1; diff --git a/src/GPU2D.cpp b/src/GPU2D.cpp index 55c3e94..799714a 100644 --- a/src/GPU2D.cpp +++ b/src/GPU2D.cpp @@ -38,6 +38,14 @@ // // for VRAM display mode, VRAM must be mapped to LCDC // +// FIFO display mode: +// * the 'FIFO' is a circular buffer of 32 bytes (16 pixels) +// * the buffer doesn't get empty, the display controller keeps reading from it +// -> if it isn't updated, the contents will be repeated every 16 pixels +// * the write pointer is incremented when writing to the higher 16 bits of the FIFO register (0x04000068) +// * the write pointer is reset upon VBlank +// * FIFO DMA (mode 4) is triggered every 8 pixels. start bit is cleared upon VBlank. +// // sprite blending rules // * destination must be selected as 2nd target // * sprite must be semitransparent or bitmap sprite diff --git a/src/GPU3D.cpp b/src/GPU3D.cpp index 6f7e7b7..9881760 100644 --- a/src/GPU3D.cpp +++ b/src/GPU3D.cpp @@ -52,6 +52,12 @@ // if (clearZ >= 0x010000 && clearZ < 0xFFFFFF) clearZ++; // // alpha is 5-bit +// +// matrix push/pop on the position matrix are always applied to the vector matrix too, even in position-only mode +// store/restore too, probably (TODO: confirm) +// (the idea is that each position matrix has an associated vector matrix) +// +// TODO: check if translate works on the vector matrix? seems pointless namespace GPU3D @@ -729,7 +735,10 @@ void SubmitPolygon() } if (farplaneclip && (!(CurPolygonAttr & (1<<12)))) + { + LastStripPolygon = NULL; return; + } nverts = c; c = clipstart; for (int i = clipstart; i < nverts; i++) @@ -903,6 +912,8 @@ void SubmitVertex() s64 vertex[4] = {(s64)CurVertex[0], (s64)CurVertex[1], (s64)CurVertex[2], 0x1000}; Vertex* vertextrans = &TempVertexBuffer[VertexNumInPoly]; + //printf("vertex: %08X %08X %08X, %d %d %d\n", CurVertex[0], CurVertex[1], CurVertex[2], VertexColor[0], VertexColor[1], VertexColor[2]); + UpdateClipMatrix(); vertextrans->Position[0] = (vertex[0]*ClipMatrix[0] + vertex[1]*ClipMatrix[4] + vertex[2]*ClipMatrix[8] + vertex[3]*ClipMatrix[12]) >> 12; vertextrans->Position[1] = (vertex[0]*ClipMatrix[1] + vertex[1]*ClipMatrix[5] + vertex[2]*ClipMatrix[9] + vertex[3]*ClipMatrix[13]) >> 12; diff --git a/src/GPU3D_Soft.cpp b/src/GPU3D_Soft.cpp index 5c9dc8e..a981bd5 100644 --- a/src/GPU3D_Soft.cpp +++ b/src/GPU3D_Soft.cpp @@ -721,7 +721,7 @@ void RenderPolygon(Polygon* polygon) { // edge fill rules for opaque pixels // TODO, eventually: antialiasing - if (!wireframe) + if (!wireframe)// && !(edge & 0x4)) { if ((edge & 0x1) && slope_start > 0x1000) continue; diff --git a/src/NDS.cpp b/src/NDS.cpp index 39136ec..0a5afb4 100644 --- a/src/NDS.cpp +++ b/src/NDS.cpp @@ -1780,6 +1780,11 @@ void ARM9IOWrite32(u32 addr, u32 val) case 0x040002B8: SqrtVal[0] = val; StartSqrt(); return; case 0x040002BC: SqrtVal[1] = val; StartSqrt(); return; + + case 0x04000304: + PowerControl9 = val & 0xFFFF; + GPU::DisplaySwap(PowerControl9>>15); + return; } if (addr >= 0x04000000 && addr < 0x04000060) diff --git a/src/wx/main.cpp b/src/wx/main.cpp index b195636..b4813af 100644 --- a/src/wx/main.cpp +++ b/src/wx/main.cpp @@ -19,26 +19,15 @@ #include "../types.h" #include "main.h" #include "../version.h" +#include "../Config.h" #include "../NDS.h" #include "../GPU.h" -const int DefaultKeyMapping[18] = -{ - 15, 54, - 44, 40, - 22, 4, 26, 29, - 19, 20, - 0, 0, 0, 0, 0, 0, - 18, 14 -}; - -int KeyMapping[18]; -int JoyMapping[18]; - bool Touching; int WindowX, WindowY; +int WindowW, WindowH; wxIMPLEMENT_APP(wxApp_melonDS); @@ -54,6 +43,8 @@ bool wxApp_melonDS::OnInit() printf("melonDS " MELONDS_VERSION "\n" MELONDS_URL "\n"); + Config::Load(); + MainFrame* melon = new MainFrame(); melon->Show(true); @@ -62,13 +53,18 @@ bool wxApp_melonDS::OnInit() wxBEGIN_EVENT_TABLE(MainFrame, wxFrame) + EVT_CLOSE(MainFrame::OnClose) + EVT_MENU(ID_OPENROM, MainFrame::OnOpenROM) + EVT_MENU(ID_EXIT, MainFrame::OnCloseFromMenu) + EVT_PAINT(MainFrame::OnPaint) + EVT_IDLE(MainFrame::OnIdle) wxEND_EVENT_TABLE() MainFrame::MainFrame() - : wxFrame(NULL, wxID_ANY, "melonDS") + : wxFrame(NULL, wxID_ANY, "melonDS " MELONDS_VERSION) { wxMenu* filemenu = new wxMenu(); filemenu->Append(ID_OPENROM, "Open ROM..."); @@ -81,18 +77,29 @@ MainFrame::MainFrame() systemmenu->AppendSeparator(); systemmenu->Append(ID_RESET, "Reset"); + wxMenu* settingsmenu = new wxMenu(); + settingsmenu->Append(ID_INPUTCONFIG, "Input"); + wxMenuBar* melonbar = new wxMenuBar(); melonbar->Append(filemenu, "File"); melonbar->Append(systemmenu, "System"); + melonbar->Append(settingsmenu, "Settings"); SetMenuBar(melonbar); SetClientSize(256, 384); + SetMinSize(GetSize()); + + emustatus = 2; + + emustatuschangemutex = new wxMutex(); + emustatuschange = new wxCondition(*emustatuschangemutex); - emumutex = new wxMutex(); - emucond = new wxCondition(*emumutex); + emustopmutex = new wxMutex(); + emustop = new wxCondition(*emustopmutex); + emustopmutex->Lock(); - emuthread = new EmuThread(this, emumutex, emucond); + emuthread = new EmuThread(this); if (emuthread->Run() != wxTHREAD_NO_ERROR) { printf("thread shat itself :( giving up now\n"); @@ -102,17 +109,53 @@ MainFrame::MainFrame() sdlwin = SDL_CreateWindowFrom(GetHandle()); - sdlrend = SDL_CreateRenderer(sdlwin, -1, SDL_RENDERER_ACCELERATED); // SDL_RENDERER_PRESENTVSYNC + sdlrend = SDL_CreateRenderer(sdlwin, -1, SDL_RENDERER_ACCELERATED);// | SDL_RENDERER_PRESENTVSYNC); sdltex = SDL_CreateTexture(sdlrend, SDL_PIXELFORMAT_RGBA32, SDL_TEXTUREACCESS_STREAMING, 256, 384); - NDS::Init(); + texmutex = new wxMutex(); + SDL_LockTexture(sdltex, NULL, &texpixels, &texstride); + texmutex->Unlock(); - memcpy(KeyMapping, DefaultKeyMapping, 18*sizeof(int)); - memset(JoyMapping, 0, 18*sizeof(int)); + NDS::Init(); Touching = false; SDL_GetWindowPosition(sdlwin, &WindowX, &WindowY); + SDL_GetWindowSize(sdlwin, &WindowW, &WindowH); +} + +void MainFrame::OnClose(wxCloseEvent& event) +{ + emustatus = 0; + emustatuschangemutex->Lock(); + emustatuschange->Signal(); + emustatuschangemutex->Unlock(); + + emuthread->Wait(); + delete emuthread; + delete emustatuschange; + delete emustatuschangemutex; + delete emustop; + delete emustopmutex; + + NDS::DeInit(); + + SDL_UnlockTexture(sdltex); + delete texmutex; + + SDL_DestroyTexture(sdltex); + SDL_DestroyRenderer(sdlrend); + + SDL_DestroyWindow(sdlwin); + + SDL_Quit(); + + Destroy(); +} + +void MainFrame::OnCloseFromMenu(wxCommandEvent& event) +{ + Close(); } void MainFrame::OnOpenROM(wxCommandEvent& event) @@ -121,35 +164,118 @@ void MainFrame::OnOpenROM(wxCommandEvent& event) if (opener.ShowModal() == wxID_CANCEL) return; + if (emustatus == 1) + { + emustatus = 2; + emustop->Wait(); + } + wxString filename = opener.GetPath(); NDS::LoadROM(filename.mb_str(), true); - emuthread->EmuStatus = 1; - emumutex->Lock(); - emucond->Signal(); - emumutex->Unlock(); + emustatus = 1; + emustatuschangemutex->Lock(); + emustatuschange->Signal(); + emustatuschangemutex->Unlock(); +} + +void MainFrame::ProcessSDLEvents() +{ + bool running = (emustatus == 1); + SDL_Event evt; + + while (SDL_PollEvent(&evt)) + { + switch (evt.type) + { + case SDL_WINDOWEVENT: + if (evt.window.event != SDL_WINDOWEVENT_EXPOSED) + { + SDL_GetWindowPosition(sdlwin, &WindowX, &WindowY); + SDL_GetWindowSize(sdlwin, &WindowW, &WindowH); + } + break; + + case SDL_MOUSEBUTTONDOWN: + if (!running) return; + if (evt.button.y >= 192 && evt.button.button == SDL_BUTTON_LEFT) + { + Touching = true; + NDS::PressKey(16+6); + } + break; + + case SDL_KEYDOWN: + if (!running) return; + for (int i = 0; i < 10; i++) + if (evt.key.keysym.scancode == Config::KeyMapping[i]) NDS::PressKey(i); + if (evt.key.keysym.scancode == Config::KeyMapping[10]) NDS::PressKey(16); + if (evt.key.keysym.scancode == Config::KeyMapping[11]) NDS::PressKey(17); + break; + + case SDL_KEYUP: + if (!running) return; + for (int i = 0; i < 10; i++) + if (evt.key.keysym.scancode == Config::KeyMapping[i]) NDS::ReleaseKey(i); + if (evt.key.keysym.scancode == Config::KeyMapping[10]) NDS::ReleaseKey(16); + if (evt.key.keysym.scancode == Config::KeyMapping[11]) NDS::ReleaseKey(17); + break; + } + } + + if (Touching) + { + int mx, my; + u32 btn = SDL_GetGlobalMouseState(&mx, &my); + if (!(btn & SDL_BUTTON(SDL_BUTTON_LEFT))) + { + Touching = false; + NDS::ReleaseKey(16+6); + NDS::ReleaseScreen(); + } + else + { + mx -= WindowX; + my -= (WindowY + 192); + + if (mx < 0) mx = 0; + else if (mx > 255) mx = 255; + + if (my < 0) my = 0; + else if (my > 191) my = 191; + + NDS::TouchScreen(mx, my); + } + } } void MainFrame::OnPaint(wxPaintEvent& event) { - /*wxPaintDC dc(this); - wxGraphicsContext* gc = wxGraphicsContext::Create(dc); - if (!gc) return; + wxPaintDC dc(this); - // + texmutex->Lock(); + SDL_UnlockTexture(sdltex); - delete gc;*/ + //SDL_RenderClear(sdlrend); + SDL_RenderCopy(sdlrend, sdltex, NULL, NULL); + SDL_RenderPresent(sdlrend); + + SDL_LockTexture(sdltex, NULL, &texpixels, &texstride); + texmutex->Unlock(); + + ProcessSDLEvents(); +} + +void MainFrame::OnIdle(wxIdleEvent& event) +{ + ProcessSDLEvents(); } -EmuThread::EmuThread(MainFrame* parent, wxMutex* mutex, wxCondition* cond) +EmuThread::EmuThread(MainFrame* parent) : wxThread(wxTHREAD_JOINABLE) { this->parent = parent; - this->mutex = mutex; - this->cond = cond; - - EmuStatus = 2; } EmuThread::~EmuThread() @@ -158,87 +284,75 @@ EmuThread::~EmuThread() wxThread::ExitCode EmuThread::Entry() { - mutex->Lock(); + parent->emustatuschangemutex->Lock(); for (;;) { - cond->Wait(); - - if (EmuStatus == 0) - break; + parent->emustatuschange->Wait(); - while (EmuStatus == 1) + if (parent->emustatus == 1) { - NDS::RunFrame(); + u32 nframes = 0; + u32 lasttick = SDL_GetTicks(); + u32 fpslimitcount = 0; - SDL_Event evt; - while (SDL_PollEvent(&evt)) + while (parent->emustatus == 1) { - switch (evt.type) - { - case SDL_WINDOWEVENT: - SDL_GetWindowPosition(parent->sdlwin, &WindowX, &WindowY); - break; + u32 starttick = SDL_GetTicks(); - case SDL_MOUSEBUTTONDOWN: - if (evt.button.y >= 192 && evt.button.button == SDL_BUTTON_LEFT) - { - Touching = true; - NDS::PressKey(16+6); - } - break; - - case SDL_KEYDOWN: - for (int i = 0; i < 10; i++) - if (evt.key.keysym.scancode == KeyMapping[i]) NDS::PressKey(i); - if (evt.key.keysym.scancode == KeyMapping[16]) NDS::PressKey(16); - if (evt.key.keysym.scancode == KeyMapping[17]) NDS::PressKey(17); - break; - - case SDL_KEYUP: - for (int i = 0; i < 10; i++) - if (evt.key.keysym.scancode == KeyMapping[i]) NDS::ReleaseKey(i); - if (evt.key.keysym.scancode == KeyMapping[16]) NDS::ReleaseKey(16); - if (evt.key.keysym.scancode == KeyMapping[17]) NDS::ReleaseKey(17); - break; - } - } + NDS::RunFrame(); - if (Touching) - { - int mx, my; - u32 btn = SDL_GetGlobalMouseState(&mx, &my); - if (!(btn & SDL_BUTTON(SDL_BUTTON_LEFT))) + parent->texmutex->Lock(); + + if (parent->texstride == 256*4) { - Touching = false; - NDS::ReleaseKey(16+6); - NDS::ReleaseScreen(); + memcpy(parent->texpixels, GPU::Framebuffer, 256*384*4); } else { - mx -= WindowX; - my -= (WindowY + 192); + int dsty = 0; + for (int y = 0; y < 256*384; y+=256) + { + memcpy(&((u8*)parent->texpixels)[dsty], &GPU::Framebuffer[y], 256*4); + dsty += parent->texstride; + } + } + + parent->texmutex->Unlock(); + parent->Refresh(); + + fpslimitcount++; + if (fpslimitcount >= 3) fpslimitcount = 0; + u32 frametime = (fpslimitcount == 0) ? 16 : 17; - if (mx < 0) mx = 0; - else if (mx > 255) mx = 255; + u32 endtick = SDL_GetTicks(); + u32 diff = endtick - starttick; + if (diff < frametime) + Sleep(frametime - diff); - if (my < 0) my = 0; - else if (my > 191) my = 191; + nframes++; + if (nframes >= 30) + { + u32 tick = SDL_GetTicks(); + u32 diff = tick - lasttick; + lasttick = tick; + + u32 fps = (nframes * 1000) / diff; + nframes = 0; - NDS::TouchScreen(mx, my); + char melontitle[100]; + sprintf(melontitle, "%d FPS - melonDS " MELONDS_VERSION, fps); + parent->SetTitle(melontitle); } } - void* pixels; int zorp; - SDL_LockTexture(parent->sdltex, NULL, &pixels, &zorp); - memcpy(pixels, GPU::Framebuffer, 256*384*4); - SDL_UnlockTexture(parent->sdltex); - - SDL_SetRenderTarget(parent->sdlrend, parent->sdltex); - SDL_RenderClear(parent->sdlrend); - SDL_RenderCopy(parent->sdlrend, parent->sdltex, NULL, NULL); - SDL_RenderPresent(parent->sdlrend); + parent->emustopmutex->Lock(); + parent->emustop->Signal(); + parent->emustopmutex->Unlock(); } + + if (parent->emustatus == 0) + break; } return (wxThread::ExitCode)0; diff --git a/src/wx/main.h b/src/wx/main.h index 0ee41be..f60e381 100644 --- a/src/wx/main.h +++ b/src/wx/main.h @@ -34,6 +34,8 @@ enum ID_RUN, ID_PAUSE, ID_RESET, + + ID_INPUTCONFIG, }; class EmuThread; @@ -53,32 +55,40 @@ public: SDL_Renderer* sdlrend; SDL_Texture* sdltex; + wxMutex* texmutex; + void* texpixels; + int texstride; + + int emustatus; + EmuThread* emuthread; + wxMutex* emustatuschangemutex; + wxCondition* emustatuschange; + wxMutex* emustopmutex; + wxCondition* emustop; + private: wxDECLARE_EVENT_TABLE(); + void OnClose(wxCloseEvent& event); + void OnCloseFromMenu(wxCommandEvent& event); void OnOpenROM(wxCommandEvent& event); - void OnPaint(wxPaintEvent& event); + void ProcessSDLEvents(); - EmuThread* emuthread; - wxMutex* emumutex; - wxCondition* emucond; + void OnPaint(wxPaintEvent& event); + void OnIdle(wxIdleEvent& event); }; class EmuThread : public wxThread { public: - EmuThread(MainFrame* parent, wxMutex* mutex, wxCondition* cond); + EmuThread(MainFrame* parent); ~EmuThread(); - u32 EmuStatus; - protected: virtual ExitCode Entry(); MainFrame* parent; - wxMutex* mutex; - wxCondition* cond; }; #endif // WX_MAIN_H |