native render: transliterate D3D8 fixed-function pipeline (unit A)

- Texture coordinates: TEXCOORDINDEX generation (camera-space normal /
  position / reflection vector, LOCALVIEWER) and D3DTS_TEXTUREn under
  TEXTURETRANSFORMFLAGS (incl. PROJECTED) now run in native.vert; the
  RecordingDevice CPU uv baking and the sphere-map / multiplicative-shadow
  shader hacks are removed. Godot consumer uses Render3DStageTexcoords.
- Lighting: 8 D3D lights in camera space, 1/(a0+a1d+a2d^2) without clamp,
  spot cone theta/2 phi/2 with falloff, diffuse/ambient/emissive material
  sources, NORMALIZENORMALS, inverse-transpose normal matrix.
- Alpha test compares 8-bit alpha against ALPHAREF with ALPHAFUNC.
- Back-buffer Clear() is recorded in draw order and executed with
  vkCmdClearAttachments; render pass clears to 0xff000000.
- D3DVIEWPORT8 (incl. MinZ/MaxZ) is dynamic per-draw state.
- Missing vertex diffuse is opaque white; alpha blend mirrors SRC/DESTBLEND.
- CScreen::ms_clearDepth / ms_diffuseColor initialised to 40250's
  1.0f / 0xffffffff (were zero; exposed once clears were executed).
- Capture format v8; --screenshot-out FILE.bmp swapchain readback.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
shenlei
2026-09-28 12:54:13 +09:00
co-authored by Claude Opus 5.5
parent 425e6f37fb
commit 5285ca85fd
11 changed files with 585 additions and 321 deletions
+1
View File
@@ -557,3 +557,4 @@
{"time": "2026-09-24T07:31:08Z", "event": "platform_adapter_fix", "unit": "EterLib/GrpScreen.cpp + MilesLib/SoundManager.cpp", "detail": "Implemented reached 40250 UI box and vertical gradient command bridge; audio bridge now preserves named three-slot music fades, frame-step fade speed and limit, indexed 3D volume, 3D play counts, and SaveVolume/RestoreVolume mute state. Remaining sky/water/shadow/culling/IME adapters stay TODO.", "evidence": ["./script/port_gate.sh macos", "./script/python_game_render_test.sh", "godot --headless --path project -s res://audio_driver_test.gd", "port_map.py check"]}
{"date": "2026-09-28T01:31:59+00:00", "unit": "GameLib/MapOutdoorRenderHTP.cpp + GameLib/MapOutdoorCharacterShadow.cpp", "action": "native 40250 render parity: terrain near/mid/far LOD/fog/splat cap, character shadow RTT CPU raster, per-draw depth/sampler states and two-light fixed-function shading", "evidence": "mt_native_render fake-server game 90 frames; 178 3D draws; shadow mem texture 205 nonwhite pixels; matched Windows screenshot pending"}
{"date": "2026-09-28T01:35:06+00:00", "unit": "GameLib/MapOutdoorRenderHTP.cpp", "action": "match 40250 lighting state in terrain splat passes: unlit base textures, temporary lit shadow pass, white fog color only for shadow pass", "evidence": "reference MapOutdoorRenderHTP.cpp non-WORLD_EDITOR branch; native fake-server scene rerun pending"}
{"date": "2026-09-28T03:54:13+00:00", "unit": "EterLib/GrpScreen.cpp + native D3D8 fixed-function emulation (RecordingDevice / native_render)", "action": "unit A: D3D8 texcoord generation + D3DTS_TEXTUREn in shader (CPU uv baking removed), 8-light D3D lighting (no attenuation clamp, spot theta/2 phi/2, emissive source, NORMALIZENORMALS, inverse-transpose normals), 8-bit alpha test, clears in draw order, dynamic D3D viewport + MinZ/MaxZ, black back-buffer clear, white default diffuse, alpha blend mirrors colour factors; removed sphere-map and multiplicative-shadow hacks; CScreen ms_clearDepth/ms_diffuseColor initialisers fixed to 40250 values; capture v8; --screenshot-out readback", "evidence": "ctest 35/35 (login_live excluded); mt_native_render fake-server 240/900-frame screenshots vs baseline: game frame mean abs diff 0.55/255, char select model now placed by introselect.py grp.SetViewport(270/w,...); Windows reference frame pending (NEEDS_LIVE)"}
+2 -1
View File
@@ -14,7 +14,8 @@
"status": "PORTED",
"impl": [
"extension/src/port/EterGrnLib/Material.cpp:CGrannyMaterial::ApplyRenderState"
]
],
"note": "Native renderer no longer special-cases the sphere map: stage 1 CAMERASPACEREFLECTIONVECTOR, D3DTS_TEXTURE1 (ms_matSpecular) and MODULATEALPHA_ADDCOLOR run through the generic D3D8 texcoord/stage emulation. Visual parity NEEDS_LIVE."
},
"CGrannyMaterial::RestoreRenderState": {
"status": "PORTED",
+10 -2
View File
@@ -104,10 +104,18 @@
"status": "TODO"
},
"CScreen::ClearDepthBuffer": {
"status": "TODO"
"status": "NEEDS_LIVE",
"impl": [
"extension/src/platform/EterLib/GrpScreen.cpp:CScreen::ClearDepthBuffer"
],
"note": "Statement-equivalent Clear(ZBUFFER, ms_clearColor, ms_clearDepth, ms_clearStencil). The port had ms_clearDepth/ms_diffuseColor zero-initialized instead of 40250's 1.0f/0xffffffff; fixed. RecordingDevice now records back-buffer clears in draw order and the native renderer executes them (vkCmdClearAttachments over the current viewport); before, the clear was dropped. Native fake-server char select shows the model again with the clear executed; Windows screenshot parity open."
},
"CScreen::Clear": {
"status": "TODO"
"status": "NEEDS_LIVE",
"impl": [
"extension/src/platform/EterLib/GrpScreen.cpp:CScreen::Clear"
],
"note": "Statement-equivalent Clear(TARGET|ZBUFFER); executed in draw order by the native renderer since the clear-entry change. Windows screenshot parity open."
},
"CScreen::IsLostDevice": {
"status": "TODO"