// Integration test: real x86 ASM producer -> x64 editor -> DX11 WARP texture. static void RunViewportChecks(EditorApp& app, const char* actualEngine) { std::error_code ec; const auto testEngine = app.FindEnginePath(); fs::copy_file(actualEngine,testEngine,fs::copy_options::overwrite_existing,ec); Check(!ec,"stage real ASM renderer for editor integration"); ID3D11Device* device=nullptr; HRESULT hr=D3D11CreateDevice(nullptr,D3D_DRIVER_TYPE_WARP,nullptr,0,nullptr,0,D3D11_SDK_VERSION,&device,nullptr,nullptr); Check(SUCCEEDED(hr),"DX11 software device supports the embedded viewport"); if(!device || ec) return; app.LoadLevel("../assets/scene.dat"); app.showCutsceneTimeline=true; app.previewAttempted=false; app.InitD3D(device); auto pump = [&]() { int frames=0; ULONGLONG until=GetTickCount64()+5000; while(frames<3 && GetTickCount64()state,0,0)==2) ++frames; app.UpdateEnginePreview(); if(!app.previewError.empty()) break; Sleep(2); } return frames>=3 && app.previewError.empty(); }; Check(pump() && app.previewSRV && app.previewHasFrame,"real ASM frames arrive in the editor DX11 viewport"); auto before=app.previewPixels; app.map[3][4]=CELL_METAL; Check(pump() && app.previewPixels!=before,"unsaved geometry updates the live game view"); app.map[3][4]=CELL_EMPTY; app.ScrubCutscene(2); Check(pump() && app.previewPacket->x==224 && app.previewPacket->angle==0 && app.previewPacket->fade==8, "timeline scrub drives the actual ASM viewport camera and fade"); if(app.previewTexture) { D3D11_TEXTURE2D_DESC desc{};app.previewTexture->GetDesc(&desc); desc.Usage=D3D11_USAGE_STAGING;desc.BindFlags=0;desc.CPUAccessFlags=D3D11_CPU_ACCESS_READ; ID3D11Texture2D* staging=nullptr; device->CreateTexture2D(&desc,nullptr,&staging); ID3D11DeviceContext* context=nullptr;device->GetImmediateContext(&context); bool equal=false; if(staging) { context->CopyResource(staging,app.previewTexture); D3D11_MAPPED_SUBRESOURCE read{}; if(SUCCEEDED(context->Map(staging,0,D3D11_MAP_READ,0,&read))) { equal=true; for(int y=0;y<240;++y) if(memcmp(static_cast(read.pData)+y*read.RowPitch, app.previewPixels.data()+y*320,1280)) equal=false; context->Unmap(staging,0); } staging->Release(); } Check(equal,"DX11 texture pixels match the ASM framebuffer with opaque alpha"); context->Release(); } app.StopEnginePreview(); Check(!app.previewProcess.hProcess && !app.previewPacket && !app.previewMapping,"closing viewport releases renderer process and mapping"); app.ShutdownD3D();device->Release();app.showCutsceneTimeline=false; const auto demo=fs::path(actualEngine).parent_path()/"examples/cutscene_demo/assets/map.dat"; Check(app.LoadLevel(demo.string()),"isolated cutscene demo loads in the editor"); std::string start,executable; Check(app.PreparePlaytest(start,executable),"demo F5 validates both rooms and packages its WAV"); app.CleanupPlaytest(); CutscenePreview demoPreview; demoPreview.Start(app.playerStartX*64+32,app.playerStartY*64+32,app.playerStartAngle); while(demoPreview.active && demoPreview.tick<1000) demoPreview.Step(app.cutscene); Check(demoPreview.transition==0 && demoPreview.x==800 && demoPreview.y==544 && demoPreview.angle==0, "demo camera reaches final waypoint and dispatches its room transition"); }