diff --git a/melonDS.cbp b/melonDS.cbp
index a9a7b722..a1fd6d5d 100644
--- a/melonDS.cbp
+++ b/melonDS.cbp
@@ -67,6 +67,8 @@
+
+
diff --git a/src/libui_sdl/MelonCap.cpp b/src/libui_sdl/MelonCap.cpp
index aea187fe..0383ec14 100644
--- a/src/libui_sdl/MelonCap.cpp
+++ b/src/libui_sdl/MelonCap.cpp
@@ -19,25 +19,320 @@
#include
#include
#include "MelonCap.h"
+#include "libui/ui.h"
+#include "../NDS.h"
+#include "../GPU.h"
+
+#include
+#include
+#include
+#include
namespace MelonCap
{
+uiWindow* Window;
+uiArea* Area;
+uiAreaHandler AreaHandler;
+uiDrawBitmap* WinBitmap;
+bool WinBitmapInited;
+
+u32* WinBitmapData;
+
+// this crap was built from the reverse-engineering of ds_capture.exe
+
+GUID InterfaceClass = {0xA0B880F6, 0xD6A5, 0x4700, {0xA8, 0xEA, 0x22, 0x28, 0x2A, 0xCA, 0x55, 0x87}};
+HANDLE CapHandle;
+WINUSB_INTERFACE_HANDLE CapUSBHandle;
+
+
+void OnAreaDraw(uiAreaHandler* handler, uiArea* area, uiAreaDrawParams* params)
+{
+ if (!WinBitmapInited)
+ {
+ if (WinBitmap) uiDrawFreeBitmap(WinBitmap);
+
+ WinBitmapInited = true;
+ WinBitmap = uiDrawNewBitmap(params->Context, 768, 384, 0);
+ }
+
+ if (!WinBitmap) return;
+ if (!WinBitmapData) return;
+
+ uiRect rc = {0, 0, 768, 384};
+
+ uiDrawBitmapUpdate(WinBitmap, WinBitmapData);
+ uiDrawBitmapDraw(params->Context, WinBitmap, &rc, &rc, 0);
+}
+
+void OnAreaMouseEvent(uiAreaHandler* handler, uiArea* area, uiAreaMouseEvent* evt)
+{
+}
+
+void OnAreaMouseCrossed(uiAreaHandler* handler, uiArea* area, int left)
+{
+}
+
+void OnAreaDragBroken(uiAreaHandler* handler, uiArea* area)
+{
+}
+
+int OnAreaKeyEvent(uiAreaHandler* handler, uiArea* area, uiAreaKeyEvent* evt)
+{
+ return 1;
+}
+
+void OnAreaResize(uiAreaHandler* handler, uiArea* area, int width, int height)
+{
+}
+
+
void Init()
{
printf("MelonCap init\n");
+
+ // TODO: flags value!!!!!
+ HDEVINFO devinfo = SetupDiGetClassDevsW(&InterfaceClass, NULL, NULL, 0x12);
+ if (devinfo == INVALID_HANDLE_VALUE) return;
+
+ int member = 0;
+ bool good = false;
+ for (;;)
+ {
+ SP_DEVICE_INTERFACE_DATA interfacedata;
+ memset(&interfacedata, 0, sizeof(interfacedata));
+ interfacedata.cbSize = sizeof(interfacedata);
+
+ BOOL ret = SetupDiEnumDeviceInterfaces(devinfo, NULL, &InterfaceClass, member, &interfacedata);
+ if (!ret)
+ {
+ printf("found %d interfaces\n", member);
+ break;
+ }
+
+ DWORD requiredsize = 0;
+ SetupDiGetDeviceInterfaceDetailW(devinfo, &interfacedata, NULL, NULL, &requiredsize, NULL);
+ printf("%d: required size %d\n", member, requiredsize);
+
+ PSP_DEVICE_INTERFACE_DETAIL_DATA_W interfacedetail = (PSP_DEVICE_INTERFACE_DETAIL_DATA_W)new u8[requiredsize];
+ interfacedetail->cbSize = sizeof(SP_INTERFACE_DEVICE_DETAIL_DATA_W);
+ ret = SetupDiGetDeviceInterfaceDetailW(devinfo, &interfacedata, interfacedetail, requiredsize, NULL, NULL);
+ if (ret)
+ {
+ printf("got interface detail: path=%S\n", interfacedetail->DevicePath);
+ HANDLE file = CreateFileW(interfacedetail->DevicePath, 0xC0000000, 3, NULL, 3, 0x40000080, NULL);
+ if (file != INVALID_HANDLE_VALUE)
+ {
+ WINUSB_INTERFACE_HANDLE usbhandle;
+ ret = WinUsb_Initialize(file, &usbhandle);
+ if (ret)
+ {
+ int val;
+ val = 0x1E;
+ WinUsb_SetPipePolicy(usbhandle, 0x00, 3, 4, &val);
+ val = 0x32;
+ WinUsb_SetPipePolicy(usbhandle, 0x82, 3, 4, &val);
+ val = 0x01;
+ WinUsb_SetPipePolicy(usbhandle, 0x82, 7, 1, &val);
+
+ printf("looking good\n");
+ good = true;
+
+ CapHandle = file;
+ CapUSBHandle = usbhandle;
+ }
+ else
+ CloseHandle(file);
+ }
+ }
+
+ delete[] (u8*)interfacedetail;
+
+ if (good) break;
+
+ member++;
+ }
+
+ SetupDiDestroyDeviceInfoList(devinfo);
+
+
+ AreaHandler.Draw = OnAreaDraw;
+ AreaHandler.MouseEvent = OnAreaMouseEvent;
+ AreaHandler.MouseCrossed = OnAreaMouseCrossed;
+ AreaHandler.DragBroken = OnAreaDragBroken;
+ AreaHandler.KeyEvent = OnAreaKeyEvent;
+ AreaHandler.Resize = OnAreaResize;
+
+ WinBitmapInited = false;
+ WinBitmapData = new u32[768*384];
+
+ Window = uiNewWindow("melonDS - topnotch pixel checker", 768, 384, 0, 0, 0);
+ Area = uiNewArea(&AreaHandler);
+ uiWindowSetChild(Window, uiControl(Area));
+
+ uiControlShow(uiControl(Window));
}
void DeInit()
{
- //
+ uiControlDestroy(uiControl(Window));
+ uiDrawFreeBitmap(WinBitmap);
+ WinBitmapInited = false;
+ delete[] WinBitmapData;
+
+ WinUsb_Free(CapUSBHandle);
+ CloseHandle(CapHandle);
}
+u32 VendorIn(u8 req, u16 len, u8* buf)
+{
+ WINUSB_SETUP_PACKET pkt;
+ pkt.RequestType = 0xC0; // device to host
+ pkt.Request = req;
+ pkt.Value = 0; // ?????
+ pkt.Index = 0;
+ pkt.Length = len;
+
+ ULONG ret = 0;
+ BOOL res = WinUsb_ControlTransfer(CapUSBHandle, pkt, buf, len, &ret, NULL);
+ if (!res) return -1;
+ return ret;
+}
+
+u32 VendorOut(u8 req, u16 val, u16 len, u8* buf)
+{
+ WINUSB_SETUP_PACKET pkt;
+ pkt.RequestType = 0x40; // device to host
+ pkt.Request = req;
+ pkt.Value = val;
+ pkt.Index = 0;
+ pkt.Length = len;
+
+ ULONG ret = 0;
+ BOOL res = WinUsb_ControlTransfer(CapUSBHandle, pkt, buf, len, &ret, NULL);
+ if (!res) return -1;
+ return ret;
+}
+
+u32 BulkIn(u8* buf, u32 len)
+{
+ ULONG ret = 0;
+ BOOL res = WinUsb_ReadPipe(CapUSBHandle, 0x82, buf, len, &ret, NULL);
+ if (!res) return -1;
+ return ret;
+}
+
+
+u32 ConvertColor(u16 col)
+{
+ u32 b = col & 0x001F;
+ u32 g = (col & 0x07E0) >> 5;
+ u32 r = (col & 0xF800) >> 11;
+
+ u32 ret = 0xFF000000;
+ ret |= ((r << 3) | (r >> 2)) << 16;
+ ret |= ((g << 2) | (g >> 4)) << 8;
+ ret |= (b << 3) | (b >> 2);
+ return ret;
+}
+
+void CaptureFrame()
+{
+ u32 ret;
+ u8 derp;
+ u32 framelen = 256*384*2;
+ u16 frame[framelen/2];
+ u32 framepos = 0;
+ u8 frameinfo[64];
+
+ ret = VendorOut(0x30, 0, 0, &derp);
+ if (ret < 0) return;
+
+ while (framepos < framelen)
+ {
+ ret = BulkIn((u8*)&frame[framepos/2], framelen-framepos);
+ if (ret < 0) break;
+ if (ret > 0) framepos += ret;
+ }
+
+ ret = VendorIn(0x30, 64, frameinfo);
+ if (ret < 0) return;
+ if ((frameinfo[0] & 0x03) != 0x03) return;
+ if (!frameinfo[52]) return;
+
+ u16* in = &frame[0];
+ u32* out = &WinBitmapData[256];
+
+ for (int y = 0; y < 384; y++)
+ {
+ u32* out = &WinBitmapData[((y/2)*768) + ((y&1)*128) + 256];
+
+ if (!(frameinfo[y>>3] & (1<<(y&7))))
+ {
+ continue;
+ }
+
+ for (int x = 0; x < 256/2; x++)
+ {
+ out[0] = ConvertColor(in[1]);
+ out[768*192] = ConvertColor(in[0]);
+ out++;
+ in += 2;
+ }
+ }
+}
+
void Update()
{
- //
+ // melonDS output
+
+ int frontbuf = GPU::FrontBuffer;
+
+ u32* topbuf = GPU::Framebuffer[frontbuf][0];
+ if (topbuf)
+ {
+ for (int y = 0; y < 192; y++)
+ {
+ memcpy(&WinBitmapData[y*768], &topbuf[y*256], 256*4);
+ }
+ }
+
+ u32* botbuf = GPU::Framebuffer[frontbuf][1];
+ if (botbuf)
+ {
+ for (int y = 0; y < 192; y++)
+ {
+ memcpy(&WinBitmapData[(y+192)*768], &botbuf[y*256], 256*4);
+ }
+ }
+
+ // DS capture
+
+ CaptureFrame();
+
+ // compare
+
+ for (int y = 0; y < 384; y++)
+ {
+ for (int x = 0; x < 256; x++)
+ {
+ u32 colA = WinBitmapData[(y*768) + x + 0];
+ u32 colB = WinBitmapData[(y*768) + x + 256];
+
+ // best we get from the capture card is RGB565
+ // so we'll ignore the lower bits
+ const u32 mask = 0x00F8FCF8;
+ colA &= mask;
+ colB &= mask;
+
+ if (colA == colB) WinBitmapData[(y*768) + x + 512] = 0xFF00FF00;
+ else WinBitmapData[(y*768) + x + 512] = 0xFFFF0000;
+ }
+ }
+
+ uiAreaQueueRedrawAll(Area);
}
}