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
+32 -4
View File
@@ -20,11 +20,14 @@
// - Version 5: adds per-draw fog color, mode, range and distance/density state.
// - Version 6: adds texture address and filtering state for both stages.
// - Version 7: adds two fixed-function lights and material color sources.
// - Version 8: eight lights, back-buffer clear entries, viewport MinZ/MaxZ, border color,
// TEXCOORDINDEX / TEXTURETRANSFORMFLAGS / D3DTS_TEXTUREn per stage, emissive
// material source, NORMALIZENORMALS and LOCALVIEWER; UVs are raw vertex sets.
// Capture is opt-in and never runs in the normal game path.
namespace native_draw_capture {
struct Capture {
std::uint32_t version = 7;
std::uint32_t version = 8;
std::vector<Render3DDraw> draws;
std::unordered_map<std::string, std::vector<std::uint8_t>> textures;
std::uint32_t ui_width = 960;
@@ -110,7 +113,7 @@ inline void write(
std::ofstream file(path, std::ios::binary | std::ios::trunc);
if (!file) throw std::runtime_error("cannot create native draw capture: " + path);
const std::uint32_t magic = 0x4d544452; // MTDR
const std::uint32_t version = 7;
const std::uint32_t version = 8;
const auto count = static_cast<std::uint32_t>(draws.size());
write_scalar(file, magic); write_scalar(file, version); write_scalar(file, count);
for (const auto& draw : draws) {
@@ -174,6 +177,17 @@ inline void write(
write_scalar(file, draw.diffuse_material_source);
write_scalar(file, draw.ambient_material_source);
write_scalar(file, draw.color_vertex);
file.write(reinterpret_cast<const char*>(draw.viewport_z), sizeof(draw.viewport_z));
write_scalar(file, draw.clear_flags);
write_scalar(file, draw.clear_color);
write_scalar(file, draw.clear_z);
file.write(reinterpret_cast<const char*>(draw.border_color), sizeof(draw.border_color));
file.write(reinterpret_cast<const char*>(draw.texcoord_index), sizeof(draw.texcoord_index));
file.write(reinterpret_cast<const char*>(draw.texture_transform_flags), sizeof(draw.texture_transform_flags));
file.write(reinterpret_cast<const char*>(draw.texture_matrix), sizeof(draw.texture_matrix));
write_scalar(file, draw.emissive_material_source);
write_scalar(file, draw.normalize_normals);
write_scalar(file, draw.local_viewer);
write_vector(file, draw.bone_indices);
write_vector(file, draw.bone_weights);
write_vector(file, draw.bone_matrices);
@@ -223,7 +237,7 @@ inline Capture read_capture(const std::string& path) {
if (!file) throw std::runtime_error("cannot open native draw capture: " + path);
std::uint32_t magic = 0, version = 0, count = 0;
read_scalar(file, magic); read_scalar(file, version); read_scalar(file, count);
if (magic != 0x4d544452 || (version < 1 || version > 7) || count > 10'000)
if (magic != 0x4d544452 || (version < 1 || version > 8) || count > 10'000)
throw std::runtime_error("unsupported native draw capture format");
Capture capture;
capture.version = version;
@@ -296,10 +310,24 @@ inline Capture read_capture(const std::string& path) {
file.read(reinterpret_cast<char*>(draw.mip_filter), sizeof(draw.mip_filter));
}
if (version >= 7) {
file.read(reinterpret_cast<char*>(draw.lights), sizeof(draw.lights));
file.read(reinterpret_cast<char*>(draw.lights),
(version >= 8 ? 8 : 2) * sizeof(draw.lights[0]));
read_scalar(file, draw.diffuse_material_source);
read_scalar(file, draw.ambient_material_source);
read_scalar(file, draw.color_vertex);
}
if (version >= 8) {
file.read(reinterpret_cast<char*>(draw.viewport_z), sizeof(draw.viewport_z));
read_scalar(file, draw.clear_flags);
read_scalar(file, draw.clear_color);
read_scalar(file, draw.clear_z);
file.read(reinterpret_cast<char*>(draw.border_color), sizeof(draw.border_color));
file.read(reinterpret_cast<char*>(draw.texcoord_index), sizeof(draw.texcoord_index));
file.read(reinterpret_cast<char*>(draw.texture_transform_flags), sizeof(draw.texture_transform_flags));
file.read(reinterpret_cast<char*>(draw.texture_matrix), sizeof(draw.texture_matrix));
read_scalar(file, draw.emissive_material_source);
read_scalar(file, draw.normalize_normals);
read_scalar(file, draw.local_viewer);
} else if (draw.light0) {
auto& light = draw.lights[0];
light.type = 3;