#pragma once #include #include #include // The 3D draw calls the ported game render (CPythonApplication::RenderGame) issues through // CStateManager, recorded by the platform's IDirect3DDevice8 (RecordingDevice.cpp) and consumed by // Godot. Like UIRenderCommands.h this header stays free of D3D and godot-cpp types. // // Matrices are D3D8's row-vector layout (translation in elements 12..14), exactly as 40250 set them. struct Render3DDraw { // Stable source-buffer identity and content version. Zero key means an immediate-mode draw // without a reusable D3D buffer. Geometry may be reused only while both values match. std::uint64_t geometry_key = 0; std::uint64_t geometry_revision = 0; float world[16]; float view[16]; float proj[16]; float viewport[4] = {}; // x, y, width, height float viewport_z[2] = {0, 1}; // MinZ, MaxZ // PORT: UIRenderOffsetX() when recorded (a draw from a shifted window layer); the host moves the // viewport (and a pretransformed draw's screen positions) right by it. float ui_offset_x = 0; // IDirect3DDevice8::Clear on the back buffer, kept in draw order. A clear entry has no geometry; // clear_flags holds D3DCLEAR_TARGET / D3DCLEAR_ZBUFFER / D3DCLEAR_STENCIL. std::uint32_t clear_flags = 0; std::uint32_t clear_color = 0; // 0xAARRGGBB float clear_z = 1; // Non-zero: the draw (or clear) targets an offscreen render-target texture instead of the back // buffer -- the 40250 character shadow map. The renderer draws these into the texture named // Render3DRenderTargetName(render_target, ...) ahead of the back-buffer pass, in recorded order. // viewport is then in the target's pixels. Only emitted while GPU render targets are enabled. std::uint32_t render_target = 0; std::uint32_t target_width = 0, target_height = 0; // Stage 0/1 textures, named like UIRenderTextureName: the pack path of a file texture or // "mem:@"; empty when the stage has no texture. std::string texture0; std::string texture1; // The referenced vertices, rebased so indices start at 0. normals/uv0/uv1/diffuse are empty when // the vertex format has no such element. pretransformed: D3DFVF_XYZRHW (screen-space x, y, z, rhw // in positions + rhw). bool pretransformed = false; std::vector positions; // x, y, z std::vector rhw; // D3D8 vertex fog of an XYZRHW draw: the D3DFVF_SPECULAR alpha (0..1); empty otherwise. std::vector vertex_fog; std::vector normals; // x, y, z std::vector uv0; // u, v std::vector uv1; // u, v std::vector diffuse; // 0xAARRGGBB std::vector indices; // triangle list (strips and fans are expanded), or line list std::vector bone_indices; // 4 uint8 per vertex (mesh-local bone palette index) std::vector bone_weights; // 4 floats per vertex std::vector bone_matrices; // 16 floats per bone in the mesh's palette (D3D row-vector layout) bool lines = false; // D3DRS_* / D3DTSS_* values in effect for the draw. std::uint32_t alpha_blend = 0, src_blend = 0, dest_blend = 0; std::uint32_t alpha_test = 0, alpha_ref = 0, alpha_func = 0; std::uint32_t cull_mode = 0, z_enable = 0, z_write = 0, z_func = 0; std::uint32_t lighting = 0, texture_factor = 0, fog_enable = 0; std::uint32_t fog_color = 0, fog_vertex_mode = 0, fog_table_mode = 0, fog_range_enable = 0; float fog_start = 0, fog_end = 0, fog_density = 0; std::uint32_t color_op[2] = {}, color_arg1[2] = {}, color_arg2[2] = {}; std::uint32_t alpha_op[2] = {}, alpha_arg1[2] = {}, alpha_arg2[2] = {}; std::uint32_t address_u[2] = {}, address_v[2] = {}; std::uint32_t min_filter[2] = {}, mag_filter[2] = {}, mip_filter[2] = {}; std::uint32_t border_color[2] = {}; // D3DTSS_TEXCOORDINDEX (set index | D3DTSS_TCI_* generation mode), D3DTSS_TEXTURETRANSFORMFLAGS and // D3DTS_TEXTURE0/1 per stage. The renderer generates and transforms texture coordinates from // these the way the D3D8 fixed-function vertex pipeline does; uv0/uv1 stay the raw vertex sets. std::uint32_t texcoord_index[2] = {0, 1}; std::uint32_t texture_transform_flags[2] = {}; float texture_matrix[2][16] = {{1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1}, {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1}}; // D3DMATERIAL8 diffuse/ambient/emissive (r, g, b, a) and light 0 when enabled. float material_diffuse[4] = {1, 1, 1, 1}; float material_ambient[4] = {}; float material_emissive[4] = {}; bool light0 = false; float light0_direction[3] = {}; float light0_diffuse[4] = {}; float light0_ambient[4] = {}; std::uint32_t ambient = 0; // D3DRS_AMBIENT struct Light { std::uint32_t type = 0; // zero when disabled; D3DLIGHT_POINT/SPOT/DIRECTIONAL otherwise float position[3] = {}; float direction[3] = {}; float diffuse[4] = {}; float ambient[4] = {}; float attenuation[3] = {}; float range = 0; float theta = 0, phi = 0, falloff = 0; } lights[8]; std::uint32_t diffuse_material_source = 0; std::uint32_t ambient_material_source = 0; std::uint32_t emissive_material_source = 0; std::uint32_t color_vertex = 0; std::uint32_t normalize_normals = 0; // D3DRS_NORMALIZENORMALS std::uint32_t local_viewer = 1; // D3DRS_LOCALVIEWER }; // The texture coordinates stage 0/1 samples at each vertex, computed on the CPU with the same // D3D8 fixed-function rules the native renderer's vertex shader applies (TEXCOORDINDEX generation, // then D3DTS_TEXTUREn under TEXTURETRANSFORMFLAGS). For consumers without that shader (Godot). void Render3DStageTexcoords(const Render3DDraw& draw, int stage, std::vector& out); struct GpuSkinSubrangeView { std::uint64_t source_mesh_key = 0; std::uint32_t mesh_base_vertex = 0; std::uint32_t mesh_vertex_count = 0; const std::uint8_t* bone_indices = nullptr; // mesh_vertex_count * 4 const float* bone_weights = nullptr; // mesh_vertex_count * 4 const float* bone_matrices = nullptr; // bone_count * 16 std::uint32_t bone_count = 0; }; void SetNativeTerrainRenderEnabled(bool enabled); bool IsNativeTerrainRenderEnabled(); void SetGpuSkinningEnabled(bool enabled); bool IsGpuSkinningEnabled(); bool LookupGpuSkinSubrange(const void* vertex_buffer_base, std::uint32_t stride, std::uint32_t lo_vertex, std::uint32_t hi_vertex, GpuSkinSubrangeView* out_view); // GPU render targets: shadow-map draws are recorded with render_target set and sampled as // "rt::x" instead of being rasterized on the CPU into a "mem:cpu_" texture. Off by // default (the Godot consumer has no offscreen pass); the native Vulkan renderer turns it on. void SetGpuRenderTargetsEnabled(bool enabled); bool IsGpuRenderTargetsEnabled(); std::string Render3DRenderTargetName(std::uint32_t id, std::uint32_t width, std::uint32_t height); void Render3DBeginFrame(); void Render3DAdd(Render3DDraw draw); const std::vector& Render3DDraws();