EBLAN_ENGINE/tests/viewport_editor_checks.inl
Artvasil09 a1d1baa869 feat: complete engine and editor subsystems (Stages 1-5 from TODO_ARTEM)
- Stage 1: Eliminate fish-eye distortion with precomputed tangential ray offset table and fractional DDA depth
- Stage 2: Full asset management in EblanStudio (stb_image/stb_image_write, 128x128 BGRA texture packaging, WAV sound manager)
- Stage 3: Multi-level room streaming, LevelTransition/CELL_PORTAL trigger system, 16-frame screen fade to black
- Stage 4: 60Hz cutscene engine in pure x86 ASM (v4 binary track, waypoint camera motion, shortest-arc pan, CP1251 Russian subtitles, letterbox overlay, audio)
- Stage 5: EblanStudio cutscene timeline (F6) and windowless Live ASM Viewport over shared-memory IPC directly rendered into DX11
- Tooling & Tests: comprehensive regression test suite (94 editor + 107 engine tests), IPC tests, and cutscene demo
2026-10-22 16:24:22 +03:00

65 lines
3.7 KiB
C++

// 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()<until) {
if(app.previewPacket && InterlockedCompareExchange(&app.previewPacket->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<const char*>(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");
}