#include "pch.h" #include "..\Common\DirectXHelper.h" #include "EmulatorRenderer.h" #include "EmulatorFileHandler.h" #include "EmulatorSettings.h" #include #include #include "Vector4.h" #include "TextureLoader.h" //#include "VBAM\filters\hq2x.h" #define CROSS_TEXTURE_FILE_NAME L"Assets/Direct3D/pad_cross.dds" #define START_TEXTURE_FILE_NAME L"Assets/Direct3D/pad_start.dds" #define SELECT_TEXTURE_FILE_NAME L"Assets/Direct3D/pad_select.dds" #define TURBO_TEXTURE_FILE_NAME L"Assets/Direct3D/pad_turbo_button.dds" #define COMBO_TEXTURE_FILE_NAME L"Assets/Direct3D/pad_combo_button.dds" #define A_TEXTURE_FILE_NAME L"Assets/Direct3D/pad_a_button.dds" #define B_TEXTURE_FILE_NAME L"Assets/Direct3D/pad_b_button.dds" #define L_TEXTURE_FILE_NAME L"Assets/Direct3D/pad_l_button.dds" #define R_TEXTURE_FILE_NAME L"Assets/Direct3D/pad_r_button.dds" #define STICK_TEXTURE_FILE_NAME L"Assets/Direct3D/thumbstick.dds" #define STICK_CENTER_TEXTURE_FILE_NAME L"Assets/Direct3D/thumbstickcenter.dds" #define CROSS_COLOR_TEXTURE_FILE_NAME L"Assets/Direct3D/pad_cross_color.dds" #define START_COLOR_TEXTURE_FILE_NAME L"Assets/Direct3D/pad_start_color.dds" #define SELECT_COLOR_TEXTURE_FILE_NAME L"Assets/Direct3D/pad_select_color.dds" #define TURBO_COLOR_TEXTURE_FILE_NAME L"Assets/Direct3D/pad_turbo_button_color.dds" #define COMBO_COLOR_TEXTURE_FILE_NAME L"Assets/Direct3D/pad_combo_button_color.dds" #define A_COLOR_TEXTURE_FILE_NAME L"Assets/Direct3D/pad_a_button_color.dds" #define B_COLOR_TEXTURE_FILE_NAME L"Assets/Direct3D/pad_b_button_color.dds" #define L_COLOR_TEXTURE_FILE_NAME L"Assets/Direct3D/pad_l_button_color.dds" #define R_COLOR_TEXTURE_FILE_NAME L"Assets/Direct3D/pad_r_button_color.dds" #define STICK_COLOR_TEXTURE_FILE_NAME L"Assets/Direct3D/thumbstick_color.dds" #define CROSS_GBASP_TEXTURE_FILE_NAME L"Assets/Direct3D/pad_cross_gbasp.dds" #define START_GBASP_TEXTURE_FILE_NAME L"Assets/Direct3D/pad_start_gbasp.dds" #define SELECT_GBASP_TEXTURE_FILE_NAME L"Assets/Direct3D/pad_select_gbasp.dds" #define TURBO_GBASP_TEXTURE_FILE_NAME L"Assets/Direct3D/pad_turbo_button_gbasp.dds" #define COMBO_GBASP_TEXTURE_FILE_NAME L"Assets/Direct3D/pad_combo_button_gbasp.dds" #define A_GBASP_TEXTURE_FILE_NAME L"Assets/Direct3D/pad_a_button_gbasp.dds" #define B_GBASP_TEXTURE_FILE_NAME L"Assets/Direct3D/pad_b_button_gbasp.dds" #define L_GBASP_TEXTURE_FILE_NAME L"Assets/Direct3D/pad_l_button_gbasp.dds" #define R_GBASP_TEXTURE_FILE_NAME L"Assets/Direct3D/pad_r_button_gbasp.dds" #define STICK_GBASP_TEXTURE_FILE_NAME L"Assets/Direct3D/thumbstick_gbasp.dds" #define DIVIDER_TEXTURE_FILE_NAME L"Assets/Direct3D/divider.dds" #define AUTOSAVE_INTERVAL 60.0f using namespace Windows::Foundation; using namespace Windows::Graphics::Display; HANDLE swapEvent = NULL; HANDLE updateEvent = NULL; bool lastSkipped = false; int framesNotRendered = 0; bool monitorTypeSkipped = false; int turboSkip; extern u8 *pix; size_t gbaPitch; void(*filterFunction)(u8*, u32, u8*, u8*, u32, int, int); extern void hq2x32(u8*, u32, u8*, u8*, u32, int, int); extern void Scanlines32(u8*, u32, u8*, u8*, u32, int, int); extern void ScanlinesTV32(u8*, u32, u8*, u8*, u32, int, int); void ContinueEmulation(void) { if(swapEvent && updateEvent) { ResetEvent(swapEvent); SetEvent(updateEvent); } } inline void cpyImg32( unsigned char *dst, unsigned int dstPitch, unsigned char *src, unsigned int srcPitch, unsigned short width, unsigned short height ) { // fast, iterative C version // copies an width*height array of visible pixels from src to dst // srcPitch and dstPitch are the number of garbage bytes after a scanline register unsigned short lineSize = width<<2; while( height-- ) { memcpy( dst, src, lineSize ); src += srcPitch; dst += dstPitch; } } //inline void cpyImg32(unsigned char *dst, unsigned int dstPitch, unsigned char *src, unsigned int srcPitch, unsigned short width, unsigned short height, unsigned short srcStart) //{ // //srcStart == 0 if want to copy from the top row // src += srcPitch * srcStart; // // register unsigned short lineSize = width << 2; // // while (height--) { // memcpy(dst, src, lineSize); // src += srcPitch; // dst += dstPitch; // } //} namespace VBA10 { //extern bool timeMeasured; extern bool autosaving; extern bool gbaROMLoaded; EmulatorRenderer::EmulatorRenderer(const std::shared_ptr& deviceResources) : emulator(EmulatorGame::GetInstance()), frontbuffer(0), controller(nullptr), elapsedTime(0.0f), frames(0), autosaveElapsed(0.0f), m_deviceResources(deviceResources) { this->gameTime = ref new GameTime(); this->waitEvent = CreateEventEx(NULL, NULL, NULL, EVENT_ALL_ACCESS); swapEvent = CreateEventEx(NULL, NULL, NULL, EVENT_ALL_ACCESS); updateEvent = CreateEventEx(NULL, NULL, NULL, EVENT_ALL_ACCESS); this->pixtmp = (u8 *)malloc(4 * 240 * 160); //240 x 160 is size of gba screen //this->pixtmp2 = (u8 *)malloc(4 * 480 * 320); //double the size for filter /*this->stopThread = false; this->autosaveDoneEvent = CreateEventEx(NULL, NULL, NULL, EVENT_ALL_ACCESS); this->autosaveEvent = CreateEventEx(NULL, NULL, NULL, EVENT_ALL_ACCESS); this->threadAction = ThreadPool::RunAsync(ref new WorkItemHandler([this](IAsyncAction ^action) { this->AutosaveAsync(); }), WorkItemPriority::High, WorkItemOptions::None);*/ //m_window = CoreWindow::GetForCurrentThread(); //load textures and similar stuff CreateDeviceDependentResources(); CreateWindowSizeDependentResources(); this->controller = this->emulator->GetVirtualController(); //this->emulator->ResizeBuffer(m_deviceResources->GetOutputSize().Width, m_deviceResources->GetOutputSize().Height); // //this->width = m_deviceResources->GetOutputSize().Width; //this->height = m_deviceResources->GetOutputSize().Height; //if (!this->dxSpriteBatch) //{ // this->dxSpriteBatch = new DXSpriteBatch(m_deviceResources->GetD3DDevice(), m_deviceResources->GetD3DDeviceContext(), this->width, this->height); //} //else //{ // this->dxSpriteBatch->OnResize(this->width, this->height); //} } EmulatorRenderer::~EmulatorRenderer(void) { if(m_deviceResources->GetD3DDeviceContext()) { m_deviceResources->GetD3DDeviceContext()->Unmap(this->buffers[(this->frontbuffer + 1) % 2].Get(), 0); } CloseHandle(this->waitEvent); CloseHandle(swapEvent); CloseHandle(updateEvent); /*this->stopThread = true; SetEvent(this->autosaveEvent); WaitForSingleObjectEx(this->autosaveDoneEvent, INFINITE, false);*/ delete this->dxSpriteBatch; this->dxSpriteBatch = nullptr; } GameTime ^EmulatorRenderer::GetGameTime(void) { return this->gameTime; } void EmulatorRenderer::CreateDeviceDependentResources() { //intialize the shader loader this->shaderManager = new ShaderManager(m_deviceResources->GetD3DDevice(), m_deviceResources->GetD3DDeviceContext()); this->shaderManager->LoadShader(EmulatorSettings::Current->PixelShader); //this does not seem neccessary m_deviceResources->GetD3DDevice()->GetImmediateContext2(m_deviceResources->GetD3DDeviceContextAddress()); LoadTextureFromFile( m_deviceResources->GetD3DDevice(), DIVIDER_TEXTURE_FILE_NAME, this->dividerResource.GetAddressOf(), this->dividerSRV.GetAddressOf() ); LoadTextureFromFile( m_deviceResources->GetD3DDevice(), STICK_GBASP_TEXTURE_FILE_NAME, this->stickResource.GetAddressOf(), this->stickSRV.GetAddressOf() ); LoadTextureFromFile( m_deviceResources->GetD3DDevice(), STICK_CENTER_TEXTURE_FILE_NAME, this->stickCenterResource.GetAddressOf(), this->stickCenterSRV.GetAddressOf() ); LoadTextureFromFile( m_deviceResources->GetD3DDevice(), CROSS_GBASP_TEXTURE_FILE_NAME, this->crossResource.GetAddressOf(), this->crossSRV.GetAddressOf() ); LoadTextureFromFile( m_deviceResources->GetD3DDevice(), A_GBASP_TEXTURE_FILE_NAME, this->aResource.GetAddressOf(), this->aSRV.GetAddressOf() ); LoadTextureFromFile( m_deviceResources->GetD3DDevice(), B_GBASP_TEXTURE_FILE_NAME, this->bResource.GetAddressOf(), this->bSRV.GetAddressOf() ); LoadTextureFromFile( m_deviceResources->GetD3DDevice(), START_GBASP_TEXTURE_FILE_NAME, this->startResource.GetAddressOf(), this->startSRV.GetAddressOf() ); LoadTextureFromFile( m_deviceResources->GetD3DDevice(), SELECT_GBASP_TEXTURE_FILE_NAME, this->selectResource.GetAddressOf(), this->selectSRV.GetAddressOf() ); LoadTextureFromFile( m_deviceResources->GetD3DDevice(), TURBO_GBASP_TEXTURE_FILE_NAME, this->turboResource.GetAddressOf(), this->turboSRV.GetAddressOf() ); LoadTextureFromFile( m_deviceResources->GetD3DDevice(), COMBO_GBASP_TEXTURE_FILE_NAME, this->comboResource.GetAddressOf(), this->comboSRV.GetAddressOf() ); LoadTextureFromFile( m_deviceResources->GetD3DDevice(), L_GBASP_TEXTURE_FILE_NAME, this->lButtonResource.GetAddressOf(), this->lButtonSRV.GetAddressOf() ); LoadTextureFromFile( m_deviceResources->GetD3DDevice(), R_GBASP_TEXTURE_FILE_NAME, this->rButtonResource.GetAddressOf(), this->rButtonSRV.GetAddressOf() ); // Create Textures and SRVs for front and backbuffer D3D11_TEXTURE2D_DESC desc; ZeroMemory(&desc, sizeof(D3D11_TEXTURE2D_DESC)); desc.ArraySize = 1; desc.BindFlags = D3D11_BIND_SHADER_RESOURCE; desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; //desc.Format = DXGI_FORMAT_B5G6R5_UNORM; desc.Format = DXGI_FORMAT_B8G8R8X8_UNORM; desc.Width = 480;//241; //DL: 2 times regular size to use in pixel filter desc.Height = 320; // 161; desc.MipLevels = 1; desc.SampleDesc.Count = 1; desc.SampleDesc.Quality = 0; desc.Usage = D3D11_USAGE_DYNAMIC; DX::ThrowIfFailed( m_deviceResources->GetD3DDevice()->CreateTexture2D(&desc, nullptr, this->buffers[0].GetAddressOf()) ); DX::ThrowIfFailed( m_deviceResources->GetD3DDevice()->CreateTexture2D(&desc, nullptr, this->buffers[1].GetAddressOf()) ); //pixel filter resource //desc.Width = 480; //2 times regular size to use in pixel filter //desc.Height = 320; //DX::ThrowIfFailed( // m_deviceResources->GetD3DDevice()->CreateTexture2D(&desc, nullptr, this->bufferBig.GetAddressOf()) // ); D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; ZeroMemory(&srvDesc, sizeof(D3D11_SHADER_RESOURCE_VIEW_DESC)); srvDesc.Format = DXGI_FORMAT_UNKNOWN; srvDesc.Texture2D.MipLevels = 1; srvDesc.Texture2D.MostDetailedMip = 0; srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; DX::ThrowIfFailed( m_deviceResources->GetD3DDevice()->CreateShaderResourceView(this->buffers[0].Get(), &srvDesc, this->bufferSRVs[0].GetAddressOf()) ); DX::ThrowIfFailed( m_deviceResources->GetD3DDevice()->CreateShaderResourceView(this->buffers[1].Get(), &srvDesc, this->bufferSRVs[1].GetAddressOf()) ); //DX::ThrowIfFailed( // m_deviceResources->GetD3DDevice()->CreateShaderResourceView(this->bufferBig.Get(), &srvDesc, this->bufferSRVBig.GetAddressOf()) // ); // Map backbuffer so it can be unmapped on first update int backbuffer = (this->frontbuffer + 1) % 2; this->backbufferPtr = (uint8 *) this->MapBuffer(backbuffer, &this->pitch); pix = this->backbufferPtr; D3D11_BLEND_DESC blendDesc; ZeroMemory(&blendDesc, sizeof(D3D11_BLEND_DESC)); blendDesc.RenderTarget[0].BlendEnable = true; blendDesc.RenderTarget[0].SrcBlend = blendDesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_SRC_ALPHA; blendDesc.RenderTarget[0].DestBlend = blendDesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA; blendDesc.RenderTarget[0].BlendOp = blendDesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD; blendDesc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL; DX::ThrowIfFailed( m_deviceResources->GetD3DDevice()->CreateBlendState(&blendDesc, this->alphablend.GetAddressOf()) ); } void EmulatorRenderer::CreateWindowSizeDependentResources() { //float scale = ((int)Windows::Graphics::Display::DisplayProperties::ResolutionScale) / 100.0f; this->width = m_deviceResources->GetOutputSize().Width;// width * scale; this->height = m_deviceResources->GetOutputSize().Height;//height * scale; this->renderwidth = m_deviceResources->GetRenderTargetSize().Width; this->renderheight = m_deviceResources->GetRenderTargetSize().Height; //resize buffers take the render width and height, regardless of orientation if(!this->dxSpriteBatch) { this->dxSpriteBatch = new DXSpriteBatch(m_deviceResources->GetD3DDevice(), m_deviceResources->GetD3DDeviceContext(), this->renderwidth, this->renderheight); }else { this->dxSpriteBatch->OnResize(this->renderwidth, this->renderheight); } this->emulator->ResizeBuffer(this->width, this->height); } void EmulatorRenderer::ReleaseDeviceDependentResources() { // Reset these member variables to ensure that UpdateForWindowSizeChange recreates all resources. //NOTE: may not be correct //m_windowBounds.Width = 0; //m_windowBounds.Height = 0; //m_swapChain = nullptr; } void EmulatorRenderer::FPSCounter(void) { float lastElapsed = this->gameTime->GetLastFrameElapsed(); this->fpsElapsedTime += lastElapsed; if(this->fpsElapsedTime >= 1.0) { this->fps = this->frames; this->frames = 0; this->fpsElapsedTime -= 1.0; } } /*void EmulatorRenderer::MeasureTime(void) { float lastElapsed = this->gameTime->GetLastFrameElapsed(); this->elapsedTimeMeasure += lastElapsed; if(this->elapsedTimeMeasure >= 3.0) { timeMeasured = true; if(this->fps < 34) { EnableLowDisplayRefreshMode(true); } } }*/ void EmulatorRenderer::AutosaveAsync(void) { /*WaitForSingleObjectEx(this->autosaveEvent, INFINITE, false); while(!this->stopThread) { this->emulator->Pause(); SaveSRAMAsync().wait(); int oldSlot = SavestateSlot; SavestateSlot = AUTOSAVESTATE_SLOT; SaveStateAsync().wait(); SavestateSlot = oldSlot; Settings.Mute = !SoundEnabled(); SetEvent(this->autosaveDoneEvent); WaitForSingleObjectEx(this->autosaveEvent, INFINITE, false); } SetEvent(this->autosaveDoneEvent);*/ } void EmulatorRenderer::Autosave(void) { if(AutosavingEnabled() && !this->emulator->IsPaused() && IsROMLoaded()) { float lastElapsed = this->gameTime->GetLastFrameElapsed(); this->autosaveElapsed += lastElapsed; if(this->autosaveElapsed >= AUTOSAVE_INTERVAL) { this->autosaveElapsed -= AUTOSAVE_INTERVAL; create_task([this]() { SaveSRAMCopyAsync(); }); } } } void EmulatorRenderer::Update(DX::StepTimer const& timer) { this->gameTime->Update(); float timeDelta = this->gameTime->GetLastFrameElapsed(); /*if(!timeMeasured) { this->MeasureTime(); }*/ if (!emulator->IsPaused()) { this->elapsedTime += timeDelta; this->lastElapsed = timeDelta; systemFrameSkip = 0; turboSkip = EmulatorSettings::Current->TurboFrameSkip; systemFrameSkip = 0; //GetPowerFrameSkip(); float targetFPS = 60.0f; if(GetMonitorType() == 0) { systemFrameSkip = systemFrameSkip * 2 + 1; targetFPS = 30.0f; } if(EmulatorSettings::Current->FrameSkip == -1 ) //&& GetPowerFrameSkip() == 0) { if(!lastSkipped && (this->lastElapsed * 1.0f) > (1.0f / targetFPS)) { int skip = (int)((this->lastElapsed * 1.0f) / (1.0f / targetFPS)); systemFrameSkip += (skip < 2) ? skip : 2; //systemFrameSkip++; lastSkipped = true; }else { lastSkipped = false; } } else if (EmulatorSettings::Current->FrameSkip >= 0) { systemFrameSkip += EmulatorSettings::Current->FrameSkip; } this->Autosave(); this->emulator->Update(timeDelta); } else if (this->emulator->IsButtonEditMode()) { this->emulator->Update(timeDelta); } this->FPSCounter(); } void EmulatorRenderer::Render() { m_deviceResources->GetD3DDeviceContext()->OMSetRenderTargets( 1, m_deviceResources->GetBackBufferRenderTargetViewAddress(), m_deviceResources->GetDepthStencilView() ); float bgcolor[] = { 0.0f, 0.0f, 0.0f, 1.000f }; //black if (this->height > this->width) //portrait { bgcolor[0] = 210.0f / 255; bgcolor[1] = 210.0f / 255; bgcolor[2] = 210.0f / 255; } m_deviceResources->GetD3DDeviceContext()->ClearRenderTargetView( m_deviceResources->GetBackBufferRenderTargetView(), bgcolor ); m_deviceResources->GetD3DDeviceContext()->ClearDepthStencilView( m_deviceResources->GetDepthStencilView(), D3D11_CLEAR_DEPTH, 1.0f, 0 ); if(!this->emulator->IsPaused()/* || autosaving*/) { if((GetMonitorType() != MONITOR_120HZ) || (monitorTypeSkipped)) { monitorTypeSkipped = false; //if(framesNotRendered >= GetPowerFrameSkip()) { framesNotRendered = 0; WaitForSingleObjectEx(swapEvent, INFINITE, false); //<<<<<< apply filter to the back buffer if (EmulatorSettings::Current->PixelFilter != 0) { //set filter function if (EmulatorSettings::Current->PixelFilter == 1) //hq2x filterFunction = hq2x32; else if (EmulatorSettings::Current->PixelFilter == 2) //TV Mode filterFunction = ScanlinesTV32; else if (EmulatorSettings::Current->PixelFilter == 3) //Scanlines filterFunction = Scanlines32; ////copy pix to temporary memory if (pixtmp) cpyImg32(this->pixtmp, 240*4, pix + this->pitch, this->pitch, 240, 160); //skip 1 line of sources (garbage) //apply filter from pixtmp to pix filterFunction(this->pixtmp, 240 * 4, (u8*)this->delta, pix, this->pitch, 240, 160); } //end of apply filter >>>>>>>>>>>>>>>> //flip the buffer int backbuffer = this->frontbuffer; this->frontbuffer = (this->frontbuffer + 1) % 2; //get the address of the new back buffer uint8 *buffer = (uint8 *) this->MapBuffer(backbuffer, &gbaPitch); this->backbufferPtr = buffer; this->pitch = gbaPitch; //assign pix to the address of the new back buffer, pix will be modified by GBA.cpp pix = buffer; //release the memory of new front buffer to the gpu m_deviceResources->GetD3DDeviceContext()->Unmap(this->buffers[this->frontbuffer].Get(), 0); SetEvent(updateEvent); } /*else { framesNotRendered++; }*/ }else { monitorTypeSkipped = true; } } int height; int width; RECT rect; height = this->height; // *(GetImageScale() / 100.0f); switch (GetAspectRatio()) { default: case AspectRatioMode::Original: if (gbaROMLoaded) { width = (int)(height * (240.0f / 160.0f)); } else { width = (int)(height * (160.0f / 144.0f)); } break; case AspectRatioMode::Stretch: width = this->width; //* (GetImageScale() / 100.0f); break; case AspectRatioMode::FourToThree: width = (int)(height * (4.0f / 3.0f)); break; case AspectRatioMode::FiveToFour: width = (int)(height * (5.0f / 4.0f)); break; case AspectRatioMode::One: width = height; break; } if (width > this->width) //fix the position of the image { height = height * 1.0f / width * this->width; width = this->width; } int leftOffset = (this->width - width) / 2; rect.left = leftOffset; rect.right = width + leftOffset; rect.top = 0; rect.bottom = height; RECT dividerRect = RECT(); if (this->height > this->width) //portrait { dividerRect.left = 0; dividerRect.right = width; dividerRect.top = height; float scale = DisplayInformation::GetForCurrentView()->RawPixelsPerViewPixel; dividerRect.bottom = height + 4 * scale; } RECT source; if (EmulatorSettings::Current->PixelFilter == 0) { if (gbaROMLoaded) { source.left = 0; source.right = 239; source.top = 2; source.bottom = 160; } else { source.left = 0; source.right = 159; source.top = 2; source.bottom = 144; } } else { if (gbaROMLoaded) { source.left = 0; source.right = 480; source.top = 0; source.bottom = 320; } else { source.left = 0; source.right = 320; source.top = 0; source.bottom = 288; } } this->controller->GetARectangle(&aRectangle); this->controller->GetBRectangle(&bRectangle); this->controller->GetCrossRectangle(&crossRectangle); this->controller->GetStartRectangle(&startRectangle); this->controller->GetSelectRectangle(&selectRectangle); this->controller->GetTurboRectangle(&turboRectangle); this->controller->GetComboRectangle(&comboRectangle); this->controller->GetLRectangle(&lRectangle); this->controller->GetRRectangle(&rRectangle); //XMFLOAT4A colorf = XMFLOAT4A(1.0f, 1.0f, 1.0f, GetControllerOpacity() / 100.0f); //XMFLOAT4A colorf2 = XMFLOAT4A(1.0f, 1.0f, 1.0f, (GetControllerOpacity() / 100.0f) + 0.2f); //XMVECTOR colorv = XMLoadFloat4A(&colorf); //XMVECTOR colorv2 = XMLoadFloat4A(&colorf2); // Render current frame to screen Color white(1.0f, 1.0f, 1.0f, 1.0f); Color color(1.0f, 1.0f, 1.0f, 1.0f); if (this->width > this->height) //landscape color = Color(1.0f, 1.0f, 1.0f, GetControllerOpacity()/100.0f); XMMATRIX x = XMLoadFloat4x4(&this->outputTransform); //<-------begin drawing main picture if (EmulatorSettings::Current->PixelShader == 1 ) //bilinear filtering this->dxSpriteBatch->Begin(x, true); else //force linear filter to disabled if using pixel shader or when using nearest neighbor this->dxSpriteBatch->Begin(x, false); if (EmulatorSettings::Current->PixelShader > 1) { //custom pixel shader this->dxSpriteBatch->SetCustomPixelShader(this->shaderManager->GetCurrentShader()); //set look up table (for hqnx) this->dxSpriteBatch->SetCustomShaderResourceView(this->shaderManager->GetLookUpTable()); } Engine::Rectangle sourceRect(source.left, source.top, source.right - source.left, source.bottom - source.top); Engine::Rectangle targetRect(rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top); this->dxSpriteBatch->Draw(targetRect, &sourceRect, this->bufferSRVs[this->frontbuffer].Get(), this->buffers[this->frontbuffer].Get(), white); this->dxSpriteBatch->End(); //-------> end of drawing main game picture //drawing virtual buttons this->dxSpriteBatch->Begin(x, true); //divider Color dividerColor(86.0f / 255, 105.0f / 255, 108.0f / 255, 1.0f); if (this->height > this->width) { ComPtr tex; this->dividerResource.As(&tex); Engine::Rectangle targetRect(dividerRect.left, dividerRect.top, dividerRect.right - dividerRect.left, dividerRect.bottom - dividerRect.top); this->dxSpriteBatch->Draw(targetRect, this->dividerSRV.Get(), tex.Get(), dividerColor); } if(TouchControlsEnabled()) { int dpad = EmulatorSettings::Current->DPadStyle; if(dpad == 0) { Engine::Rectangle crossRect (this->crossRectangle.left, this->crossRectangle.top, this->crossRectangle.right - this->crossRectangle.left, this->crossRectangle.bottom - this->crossRectangle.top); ComPtr tex; this->crossResource.As(&tex); this->dxSpriteBatch->Draw(crossRect, this->crossSRV.Get(), tex.Get(), color); } else if(dpad == 1 || (dpad == 2 && this->controller->StickFingerDown())) { RECT centerRect; RECT stickRect; this->controller->GetStickRectangle(&stickRect); this->controller->GetStickCenterRectangle(¢erRect); Engine::Rectangle stickRectE (stickRect.left, stickRect.top, stickRect.right - stickRect.left, stickRect.bottom - stickRect.top); Engine::Rectangle stickRectCenterE (centerRect.left, centerRect.top, centerRect.right - centerRect.left, centerRect.bottom - centerRect.top); ComPtr tex; this->stickResource.As(&tex); ComPtr tex2; this->stickCenterResource.As(&tex2); this->dxSpriteBatch->Draw(stickRectCenterE, this->stickCenterSRV.Get(), tex2.Get(), color); this->dxSpriteBatch->Draw(stickRectE, this->stickSRV.Get(), tex.Get(), color); } Engine::Rectangle aRect(this->aRectangle.left, this->aRectangle.top, this->aRectangle.right - this->aRectangle.left, this->aRectangle.bottom - this->aRectangle.top); ComPtr tex; this->aResource.As(&tex); this->dxSpriteBatch->Draw(aRect, this->aSRV.Get(), tex.Get(), color); Engine::Rectangle bRect(this->bRectangle.left, this->bRectangle.top, this->bRectangle.right - this->bRectangle.left, this->bRectangle.bottom - this->bRectangle.top); ComPtr tex2; this->bResource.As(&tex2); this->dxSpriteBatch->Draw(bRect, this->bSRV.Get(), tex2.Get(), color); Engine::Rectangle startRectE (startRectangle.left, startRectangle.top, startRectangle.right - startRectangle.left, startRectangle.bottom - startRectangle.top); ComPtr texStart; this->startResource.As(&texStart); this->dxSpriteBatch->Draw(startRectE, this->startSRV.Get(), texStart.Get(), color); Engine::Rectangle selectRectE(selectRectangle.left, selectRectangle.top, selectRectangle.right - selectRectangle.left, selectRectangle.bottom - selectRectangle.top); ComPtr texSelect; this->selectResource.As(&texSelect); this->dxSpriteBatch->Draw(selectRectE, this->selectSRV.Get(), texSelect.Get(), color); Engine::Rectangle turboRectE(turboRectangle.left, turboRectangle.top, turboRectangle.right - turboRectangle.left, turboRectangle.bottom - turboRectangle.top); ComPtr texTurbo; this->turboResource.As(&texTurbo); this->dxSpriteBatch->Draw(turboRectE, this->turboSRV.Get(), texTurbo.Get(), color); Engine::Rectangle comboRectE(comboRectangle.left, comboRectangle.top, comboRectangle.right - comboRectangle.left, comboRectangle.bottom - comboRectangle.top); ComPtr texCombo; this->comboResource.As(&texCombo); this->dxSpriteBatch->Draw(comboRectE, this->comboSRV.Get(), texCombo.Get(), color); if(gbaROMLoaded) { Engine::Rectangle lRectE (lRectangle.left, lRectangle.top, lRectangle.right - lRectangle.left, lRectangle.bottom - lRectangle.top); Engine::Rectangle rRectE (rRectangle.left, rRectangle.top, rRectangle.right - rRectangle.left, rRectangle.bottom - rRectangle.top); ComPtr tex; this->lButtonResource.As(&tex); ComPtr tex2; this->rButtonResource.As(&tex2); this->dxSpriteBatch->Draw(lRectE, this->lButtonSRV.Get(), tex.Get(), color); this->dxSpriteBatch->Draw(rRectE, this->rButtonSRV.Get(), tex2.Get(), color); } } /*if(ShowingFPS()) { wstringstream wss; wss << L"FPS: "; wss << this->fps; XMFLOAT4A fpscolor = XMFLOAT4A(1.0f, 1.0f, 1.0f, 1.0f); XMVECTOR fpscolorA = XMLoadFloat4A(&fpscolor); XMFLOAT2A pos = XMFLOAT2A(10.0f, 10.0f); XMVECTOR posA = XMLoadFloat2A(&pos); XMFLOAT2A origin = XMFLOAT2A(0.0f, 0.0f); XMVECTOR originA = XMLoadFloat2A(&origin); this->font->DrawString(this->spriteBatch, wss.str().c_str(), posA, fpscolorA, 0.0f, originA, 1.0f); }*/ this->dxSpriteBatch->End(); frames++; } void *EmulatorRenderer::MapBuffer(int index, size_t *rowPitch) { D3D11_MAPPED_SUBRESOURCE map; ZeroMemory(&map, sizeof(D3D11_MAPPED_SUBRESOURCE)); DX::ThrowIfFailed( m_deviceResources->GetD3DDeviceContext()->Map(this->buffers[index].Get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &map) ); *rowPitch = map.RowPitch; return map.pData; } void EmulatorRenderer::GetBackbufferData(uint8 **backbufferPtr, size_t *pitch, int *imageWidth, int *imageHeight) { *backbufferPtr = this->backbufferPtr + this->pitch; *pitch = this->pitch; if (gbaROMLoaded) { *imageWidth = 240; *imageHeight = 160; } else { *imageWidth = 160; *imageHeight = 144; } } void EmulatorRenderer::CreateTransformMatrix(void) { if (m_deviceResources->GetRotation() == DXGI_MODE_ROTATION_IDENTITY) { XMStoreFloat4x4(&this->outputTransform, XMMatrixIdentity()); } else if (m_deviceResources->GetRotation() == DXGI_MODE_ROTATION_ROTATE180) { XMStoreFloat4x4(&this->outputTransform, XMMatrixMultiply(XMMatrixRotationZ(XM_PI), XMMatrixTranslation(this->renderwidth, this->renderheight, 0.0f))); } else if (m_deviceResources->GetRotation() == DXGI_MODE_ROTATION_ROTATE90) { XMStoreFloat4x4(&this->outputTransform, XMMatrixMultiply(XMMatrixRotationZ(XM_PIDIV2), XMMatrixTranslation(this->renderwidth, 0.0f, 0.0f))); } else if (m_deviceResources->GetRotation() == DXGI_MODE_ROTATION_ROTATE270) { XMStoreFloat4x4(&this->outputTransform, XMMatrixMultiply(XMMatrixRotationZ(-XM_PIDIV2), XMMatrixTranslation(0.0f, this->renderheight, 0.0f))); } } } void systemDrawScreen() { ///*EnterCriticalSection(&swapCS); //cpyImg32(tmpBuf + 964, 964, pix + 964, 964, 240, 160); //LeaveCriticalSection(&swapCS);*/ LeaveCriticalSection(&pauseSync); SetEvent(swapEvent); WaitForSingleObjectEx(updateEvent, INFINITE, false); EnterCriticalSection(&pauseSync); }