diff --git a/game_patch/CMakeLists.txt b/game_patch/CMakeLists.txt index 892fef24..42b4ec8e 100644 --- a/game_patch/CMakeLists.txt +++ b/game_patch/CMakeLists.txt @@ -85,7 +85,6 @@ set(SRCS graphics/d3d11/gr_d3d11_shader.cpp graphics/d3d11/gr_d3d11_shader.h graphics/d3d11/gr_d3d11_error.cpp - graphics/d3d11/gr_d3d11_transform.cpp graphics/d3d11/gr_d3d11_transform.h graphics/d3d11/gr_d3d11_solid.cpp graphics/d3d11/gr_d3d11_solid.h diff --git a/game_patch/graphics/d3d11/gr_d3d11.cpp b/game_patch/graphics/d3d11/gr_d3d11.cpp index 02acfcbf..90e69a99 100644 --- a/game_patch/graphics/d3d11/gr_d3d11.cpp +++ b/game_patch/graphics/d3d11/gr_d3d11.cpp @@ -387,6 +387,45 @@ namespace df::gr::d3d11 dyn_geo_renderer_->line_2d(x1, y1, x2, y2, mode); } + bool Renderer::poly(int nv, rf::gr::Vertex** vertices, int vertex_attributes, rf::gr::Mode mode, bool constant_sw, float sw) + { + rf::ubyte and_code = 0xFF; + for (int i = 0; i < nv; ++i) { + and_code &= vertices[i]->codes; + } + if (and_code) { + return false; + } + for (int i = 0; i < nv; ++i) { + auto v = vertices[i]; + if (!(v->flags & rf::gr::VF_PROJECTED)) { + project_vertex(v); + } + if (constant_sw) { + float unscaled_z = sw / matrix_scale.z; + v->sw = render_context_->projection().project_z(unscaled_z); + } + } + tmapper(nv, const_cast(vertices), vertex_attributes, mode); + return true; + } + + void Renderer::project_vertex(rf::gr::Vertex* v) + { + if (v->flags & rf::gr::VF_PROJECTED) { + return; + } + + rf::Vector3 unscaled_world_pos = v->world_pos / matrix_scale; + auto& proj = render_context_->projection(); + auto proj_pos = proj.project(unscaled_world_pos); + v->sx = screen.clip_width / 2.0f * (proj_pos.x + 1.0f) + screen.offset_x; + v->sy = screen.clip_height / 2.0f * (1.0f - proj_pos.y) + screen.offset_y; + v->sw = proj_pos.z; + + v->flags |= rf::gr::VF_PROJECTED; + } + bool Renderer::set_render_target(int bm_handle) { dyn_geo_renderer_->flush(); @@ -416,9 +455,14 @@ namespace df::gr::d3d11 return texture_manager_->read_back_buffer(back_buffer_, x, y, w, h, data); } - void Renderer::setup_3d() + void Renderer::setup_3d(Projection proj) { - render_context_->update_view_proj_transform(); + render_context_->update_view_proj_transform(proj); + } + + void Renderer::set_far_clip(bool enabled) + { + render_context_->set_depth_clip_enabled(enabled); } void Renderer::render_solid(rf::GSolid* solid, rf::GRoom** rooms, int num_rooms) @@ -504,4 +548,8 @@ namespace df::gr::d3d11 mesh_renderer_->flush_caches(); } + float Renderer::z_far() const + { + return render_context_->projection().z_far(); + } } diff --git a/game_patch/graphics/d3d11/gr_d3d11.h b/game_patch/graphics/d3d11/gr_d3d11.h index 2924a7df..b90b8a57 100644 --- a/game_patch/graphics/d3d11/gr_d3d11.h +++ b/game_patch/graphics/d3d11/gr_d3d11.h @@ -93,6 +93,7 @@ namespace df::gr::d3d11 void clear(); void zbuffer_clear(); void set_clip(); + void set_far_clip(bool enabled); void flip(); void texture_save_cache(); void texture_flush_cache(bool force); @@ -107,7 +108,9 @@ namespace df::gr::d3d11 void tmapper(int nv, const rf::gr::Vertex **vertices, int vertex_attributes, rf::gr::Mode mode); void line_3d(const rf::gr::Vertex& v0, const rf::gr::Vertex& v1, rf::gr::Mode mode); void line_2d(float x1, float y1, float x2, float y2, rf::gr::Mode mode); - void setup_3d(); + bool poly(int nv, rf::gr::Vertex** vertices, int vertex_attributes, rf::gr::Mode mode, bool constant_sw, float sw); + void project_vertex(rf::gr::Vertex* v); + void setup_3d(Projection proj); void render_solid(rf::GSolid* solid, rf::GRoom** rooms, int num_rooms); void render_movable_solid(rf::GSolid* solid, const rf::Vector3& pos, const rf::Matrix3& orient); void render_alpha_detail_room(rf::GRoom *room, rf::GSolid *solid); @@ -123,6 +126,7 @@ namespace df::gr::d3d11 void page_in_solid(rf::GSolid* solid); void page_in_movable_solid(rf::GSolid* solid); void flush_caches(); + float z_far() const; private: void init_device(); diff --git a/game_patch/graphics/d3d11/gr_d3d11_context.cpp b/game_patch/graphics/d3d11/gr_d3d11_context.cpp index b1d8d73d..d023584b 100644 --- a/game_patch/graphics/d3d11/gr_d3d11_context.cpp +++ b/game_patch/graphics/d3d11/gr_d3d11_context.cpp @@ -131,11 +131,11 @@ namespace df::gr::d3d11 DF_GR_D3D11_CHECK_HR(device->CreateBuffer(&desc, nullptr, &buffer_)); } - void ViewProjTransformBuffer::update(ID3D11DeviceContext* device_context) + void ViewProjTransformBuffer::update(const Projection& proj, ID3D11DeviceContext* device_context) { ViewProjTransformBufferData data; data.view_mat = build_view_matrix(rf::gr::eye_pos, rf::gr::eye_matrix); - data.proj_mat = build_proj_matrix(); + data.proj_mat = proj.matrix(); D3D11_MAPPED_SUBRESOURCE mapped_subres; DF_GR_D3D11_CHECK_HR( diff --git a/game_patch/graphics/d3d11/gr_d3d11_context.h b/game_patch/graphics/d3d11/gr_d3d11_context.h index 3d7b3088..b8fe5f90 100644 --- a/game_patch/graphics/d3d11/gr_d3d11_context.h +++ b/game_patch/graphics/d3d11/gr_d3d11_context.h @@ -48,7 +48,7 @@ namespace df::gr::d3d11 public: ViewProjTransformBuffer(ID3D11Device* device); - void update(ID3D11DeviceContext* device_context); + void update(const Projection& proj, ID3D11DeviceContext* device_context); operator ID3D11Buffer*() const { @@ -238,9 +238,10 @@ namespace df::gr::d3d11 void zbuffer_clear(); void set_clip(); - void update_view_proj_transform() + void update_view_proj_transform(Projection proj) { - view_proj_transform_cbuffer_.update(device_context_); + projection_ = proj; + view_proj_transform_cbuffer_.update(projection_, device_context_); } void update_per_frame_constants() @@ -312,10 +313,11 @@ namespace df::gr::d3d11 void set_cull_mode(D3D11_CULL_MODE cull_mode) { - if (current_cull_mode_ != cull_mode || zbias_changed_) { + if (current_cull_mode_ != cull_mode || zbias_changed_ || depth_clip_enabled_changed_) { current_cull_mode_ = cull_mode; zbias_changed_ = false; - set_rasterizer_state(state_manager_.lookup_rasterizer_state(current_cull_mode_, zbias_)); + depth_clip_enabled_changed_ = false; + set_rasterizer_state(state_manager_.lookup_rasterizer_state(current_cull_mode_, zbias_, depth_clip_enabled_)); } } @@ -332,6 +334,14 @@ namespace df::gr::d3d11 } } + void set_depth_clip_enabled(bool depth_clip_enabled) + { + if (depth_clip_enabled_ != depth_clip_enabled) { + depth_clip_enabled_ = depth_clip_enabled; + depth_clip_enabled_changed_ = true; + } + } + void update_lights() { lights_buffer_.update(device_context_); @@ -342,6 +352,11 @@ namespace df::gr::d3d11 device_context_->DrawIndexed(index_count, index_start_location, base_vertex_location); } + const Projection& projection() const + { + return projection_; + } + private: void bind_cbuffers(); @@ -391,5 +406,8 @@ namespace df::gr::d3d11 ID3D11RasterizerState* current_rasterizer_state_ = nullptr; int zbias_ = 0; bool zbias_changed_ = true; + bool depth_clip_enabled_ = true; + bool depth_clip_enabled_changed_ = true; + Projection projection_; }; } diff --git a/game_patch/graphics/d3d11/gr_d3d11_dynamic_geometry.cpp b/game_patch/graphics/d3d11/gr_d3d11_dynamic_geometry.cpp index 5cab6e6a..22776046 100644 --- a/game_patch/graphics/d3d11/gr_d3d11_dynamic_geometry.cpp +++ b/game_patch/graphics/d3d11/gr_d3d11_dynamic_geometry.cpp @@ -4,8 +4,6 @@ #include "gr_d3d11_shader.h" #include "gr_d3d11_context.h" #include "../../rf/os/frametime.h" -#define NO_D3D8 -#include "../../rf/gr/gr_direct3d.h" using namespace rf; @@ -77,6 +75,23 @@ namespace df::gr::d3d11 return color; } + inline std::array DynamicGeometryRenderer::convert_pos(const gr::Vertex& v, bool is_3d) + { + Vector3 ndc{ + ((v.sx - gr::screen.offset_x) / gr::screen.clip_width * 2.0f - 1.0f), + ((v.sy - gr::screen.offset_y) / gr::screen.clip_height * -2.0f + 1.0f), + v.sw, + }; + // Set w to depth in camera space (needed for 3D rendering) + float w = is_3d ? render_context_.projection().unproject_z(v.sw) : 1.0f; + return { + ndc.x * w, + ndc.y * w, + ndc.z * w, + w, + }; + } + void DynamicGeometryRenderer::add_poly(int nv, const gr::Vertex **vertices, int vertex_attributes, const std::array& tex_handles, gr::Mode mode) { int num_index = (nv - 2) * 3; @@ -106,16 +121,13 @@ namespace df::gr::d3d11 if (use_vert_alpha && !(vertex_attributes & gr::TMAP_FLAG_ALPHA)) { color.alpha = gr::screen.current_color.alpha; } - // Note: gr_matrix_scale is zero before first gr_setup_3d call - float matrix_scale_z = gr::matrix_scale.z ? gr::matrix_scale.z : 1.0f; for (int i = 0; i < nv; ++i) { const gr::Vertex& in_vert = *vertices[i]; GpuTransformedVertex& out_vert = gpu_verts[i]; - // Set w to depth in camera space (needed for 3D rendering) - float w = 1.0f / in_vert.sw / matrix_scale_z; - out_vert.x = ((in_vert.sx - gr::screen.offset_x) / gr::screen.clip_width * 2.0f - 1.0f) * w; - out_vert.y = ((in_vert.sy - gr::screen.offset_y) / gr::screen.clip_height * -2.0f + 1.0f) * w; - out_vert.z = in_vert.sw * gr::d3d::zm * w; + auto [x, y, z, w] = convert_pos(in_vert, true); + out_vert.x = x; + out_vert.y = y; + out_vert.z = z; out_vert.w = w; if (use_vert_color && (vertex_attributes & gr::TMAP_FLAG_RGB)) { @@ -154,16 +166,13 @@ namespace df::gr::d3d11 rf::Color color = get_vertex_color_from_screen(mode); int diffuse = pack_color(color); - // Note: gr_matrix_scale is zero before first gr_setup_3d call - float matrix_scale_z = gr::matrix_scale.z ? gr::matrix_scale.z : 1.0f; for (int i = 0; i < num_verts; ++i) { const gr::Vertex& in_vert = *vertices[i]; GpuTransformedVertex& out_vert = gpu_verts[i]; - out_vert.x = (in_vert.sx - gr::screen.offset_x) / gr::screen.clip_width * 2.0f - 1.0f; - out_vert.y = (in_vert.sy - gr::screen.offset_y) / gr::screen.clip_height * -2.0f + 1.0f; - float w = is_3d ? 1.0f / in_vert.sw / matrix_scale_z : 1.0f; - out_vert.z = in_vert.sw * gr::d3d::zm * w; - // Set w to depth in camera space (needed for 3D rendering) + auto [x, y, z, w] = convert_pos(in_vert, is_3d); + out_vert.x = x; + out_vert.y = y; + out_vert.z = z; out_vert.w = w; out_vert.diffuse = diffuse; } diff --git a/game_patch/graphics/d3d11/gr_d3d11_dynamic_geometry.h b/game_patch/graphics/d3d11/gr_d3d11_dynamic_geometry.h index 41c922bf..29195e46 100644 --- a/game_patch/graphics/d3d11/gr_d3d11_dynamic_geometry.h +++ b/game_patch/graphics/d3d11/gr_d3d11_dynamic_geometry.h @@ -65,6 +65,8 @@ namespace df::gr::d3d11 return {gpu_verts, gpu_inds, base_vertex}; } + std::array convert_pos(const rf::gr::Vertex& v, bool is_3d); + ComPtr device_; RenderContext& render_context_; RingBuffer vertex_ring_buffer_; diff --git a/game_patch/graphics/d3d11/gr_d3d11_hooks.cpp b/game_patch/graphics/d3d11/gr_d3d11_hooks.cpp index 78584323..dce16d37 100644 --- a/game_patch/graphics/d3d11/gr_d3d11_hooks.cpp +++ b/game_patch/graphics/d3d11/gr_d3d11_hooks.cpp @@ -198,6 +198,17 @@ namespace df::gr::d3d11 renderer->set_fullscreen_state(rf::gr::screen.window_mode == rf::gr::FULLSCREEN); } + rf::ubyte project_vertex_new(Vertex* v) + { + renderer->project_vertex(v); + return v->flags; + } + + bool poly(int nv, rf::gr::Vertex** vertices, int vertex_attributes, rf::gr::Mode mode, bool constant_sw, float sw) + { + return renderer->poly(nv, vertices, vertex_attributes, mode, constant_sw, sw); + } + static CodeInjection g_render_room_objects_render_liquid_injection{ 0x004D4106, [](auto& regs) { @@ -211,7 +222,27 @@ namespace df::gr::d3d11 static CodeInjection gr_d3d_setup_3d_injection{ 0x005473E4, []() { - renderer->setup_3d(); + float sx = matrix_scale.x / matrix_scale.z; + float sy = matrix_scale.y / matrix_scale.z; + static auto& zm = addr_as_ref(0x005A7DD8); + float zn = 0.1f; // static near plane (RF uses: zm / matrix_scale.z) + zm = 1.0f; // let's not use zm at all to simplify software projections + float zf = rf::level.distance_fog_far_clip > 0.0f ? rf::level.distance_fog_far_clip : 1700.0f; + renderer->setup_3d(Projection{sx, sy, zn, zf}); + }, + }; + + static CodeInjection gr_d3d_setup_fustrum_injection{ + 0x00546A40, + []() { + // Glares and volumetric lights use doubled far clip plane + // To avoid using "user clip planes" disable depth clipping + // Frustum culling should be enough + static auto& use_far_clip = addr_as_ref(0x01818B65); + static auto& far_clip_dist = addr_as_ref(0x01818B68); + float z_far = renderer->z_far(); + bool depth_clip_enable = use_far_clip && far_clip_dist < z_far * 1.1f; + renderer->set_far_clip(depth_clip_enable); }, }; @@ -281,6 +312,7 @@ void gr_d3d11_apply_patch() g_render_room_objects_render_liquid_injection.install(); gr_d3d_setup_3d_injection.install(); + gr_d3d_setup_fustrum_injection.install(); vif_lod_mesh_ctor_injection.install(); vif_lod_mesh_dtor_injection.install(); v3d_page_in_injection.install(); @@ -304,7 +336,7 @@ void gr_d3d11_apply_patch() //AsmWriter{0x00547150}.ret(); // gr_d3d_setup_3d //AsmWriter{0x005473F0}.ret(); // gr_d3d_start_instance //AsmWriter{0x00547540}.ret(); // gr_d3d_stop_instance - //AsmWriter{0x005477A0}.ret(); // gr_d3d_project_vertex + AsmWriter{0x005477A0}.jmp(project_vertex_new); // gr_d3d_project_vertex //AsmWriter{0x005478F0}.ret(); // gr_d3d_is_normal_facing //AsmWriter{0x00547960}.ret(); // gr_d3d_is_normal_facing_plane //AsmWriter{0x005479B0}.ret(); // gr_d3d_get_apparent_distance_from_camera @@ -344,7 +376,7 @@ void gr_d3d11_apply_patch() //AsmWriter{0x00558450}.ret(); // gr_d3d_render_glass_shard - uses gr_poly AsmWriter{0x00558550}.ret(); // gr_d3d_render_face_wireframe //AsmWriter{0x005585F0}.ret(); // gr_d3d_render_weapon_tracer - uses gr_poly - //AsmWriter{0x005587C0}.ret(); // gr_d3d_poly - uses gr_d3d_tmapper + AsmWriter{0x005587C0}.jmp(poly); // gr_d3d_poly AsmWriter{0x00558920}.ret(); // gr_d3d_render_geometry_wireframe AsmWriter{0x00558960}.ret(); // gr_d3d_render_geometry_in_editor AsmWriter{0x00558C40}.ret(); // gr_d3d_render_sel_face_in_editor diff --git a/game_patch/graphics/d3d11/gr_d3d11_state.cpp b/game_patch/graphics/d3d11/gr_d3d11_state.cpp index fbfb9925..2bf0a835 100644 --- a/game_patch/graphics/d3d11/gr_d3d11_state.cpp +++ b/game_patch/graphics/d3d11/gr_d3d11_state.cpp @@ -11,7 +11,7 @@ namespace df::gr::d3d11 { } - ComPtr StateManager::create_rasterizer_state(D3D11_CULL_MODE cull_mode, int depth_bias) + ComPtr StateManager::create_rasterizer_state(D3D11_CULL_MODE cull_mode, int depth_bias, bool depth_clip_enable) { CD3D11_RASTERIZER_DESC desc{CD3D11_DEFAULT{}}; desc.CullMode = cull_mode; @@ -19,6 +19,7 @@ namespace df::gr::d3d11 if (g_game_config.msaa) { desc.MultisampleEnable = TRUE; } + desc.DepthClipEnable = depth_clip_enable; ComPtr rasterizer_state; check_hr( diff --git a/game_patch/graphics/d3d11/gr_d3d11_state.h b/game_patch/graphics/d3d11/gr_d3d11_state.h index acdf3b9f..ec5ba7e4 100644 --- a/game_patch/graphics/d3d11/gr_d3d11_state.h +++ b/game_patch/graphics/d3d11/gr_d3d11_state.h @@ -12,15 +12,15 @@ namespace df::gr::d3d11 public: StateManager(ComPtr device); - ID3D11RasterizerState* lookup_rasterizer_state(D3D11_CULL_MODE cull_mode, int depth_bias = 0) + ID3D11RasterizerState* lookup_rasterizer_state(D3D11_CULL_MODE cull_mode, int depth_bias = 0, bool depth_clip_enable = true) { - auto key = std::make_tuple(cull_mode, depth_bias); + auto key = std::make_tuple(cull_mode, depth_bias, depth_clip_enable); auto it = rasterizer_state_cache_.find(key); if (it != rasterizer_state_cache_.end()) { return it->second; } - auto rasterizer_state = create_rasterizer_state(cull_mode, depth_bias); - auto p = rasterizer_state_cache_.emplace(key, create_rasterizer_state(cull_mode, depth_bias)); + auto rasterizer_state = create_rasterizer_state(cull_mode, depth_bias, depth_clip_enable); + auto p = rasterizer_state_cache_.emplace(key, create_rasterizer_state(cull_mode, depth_bias, depth_clip_enable)); return p.first->second; } @@ -70,7 +70,7 @@ namespace df::gr::d3d11 } private: - ComPtr create_rasterizer_state(D3D11_CULL_MODE cull_mode, int depth_bias); + ComPtr create_rasterizer_state(D3D11_CULL_MODE cull_mode, int depth_bias, bool depth_clip_enable); ComPtr create_sampler_state(rf::gr::TextureSource ts); ComPtr create_blend_state(rf::gr::AlphaBlend ab); ComPtr create_depth_stencil_state(gr::ZbufferType zbt); @@ -79,6 +79,6 @@ namespace df::gr::d3d11 std::unordered_map> sampler_state_cache_; std::unordered_map> blend_state_cache_; std::unordered_map> depth_stencil_state_cache_; - std::map, ComPtr> rasterizer_state_cache_; + std::map, ComPtr> rasterizer_state_cache_; }; } diff --git a/game_patch/graphics/d3d11/gr_d3d11_transform.cpp b/game_patch/graphics/d3d11/gr_d3d11_transform.cpp deleted file mode 100644 index b8833180..00000000 --- a/game_patch/graphics/d3d11/gr_d3d11_transform.cpp +++ /dev/null @@ -1,45 +0,0 @@ -#include -#include -#include "../../rf/gr/gr.h" -#define NO_D3D8 -#include "../../rf/gr/gr_direct3d.h" -#include "gr_d3d11_transform.h" - -using namespace rf; - -namespace df::gr::d3d11 -{ - GpuMatrix4x4 build_proj_matrix() - { - // TODO: use variable fov and far plane - #if 0 - // Standard D3D projection matrix, 1/z, maps near plane to 0 and far plane to 1. See: - // https://docs.microsoft.com/en-us/windows/win32/dxtecharts/the-direct3d-transformation-pipeline - // https://docs.microsoft.com/en-us/windows/win32/direct3d9/projection-transform - float z_near = 0.15f; - float z_far = 275.0f; - float q = z_far / (z_far - z_near); - float fov_w = 3.14592 / 180.0f * 120.0f; - float fov_h = fov_w * 3.0f / 4.0f; - float w = 1 / tanf(fov_w / 2.0f); - float h = 1 / tanf(fov_h / 2.0f); - return {{ - {w, 0.0f, 0.0f, 0.0f}, - {0.0f, h, 0.0f, 0.0f}, - {0.0f, 0.0f, q, -q * z_near}, - {0.0f, 0.0f, 1.0f, 0.0f}, - }}; - #else - // RF projection, 1/z, maps near plane to 1 and far plane to 0 - // It has some benefits, see "reversed-Z trick" in https://developer.nvidia.com/content/depth-precision-visualized - using rf::gr::matrix_scale; - using rf::gr::d3d::zm; - return {{ - {matrix_scale.x / matrix_scale.z, 0.0f, 0.0f, 0.0f}, - {0.0f, matrix_scale.y / matrix_scale.z, 0.0f, 0.0f}, - {0.0f, 0.0f, 0.0f, zm / matrix_scale.z}, - {0.0f, 0.0f, 1.0f, 0.0f}, - }}; - #endif - } -} diff --git a/game_patch/graphics/d3d11/gr_d3d11_transform.h b/game_patch/graphics/d3d11/gr_d3d11_transform.h index 78901745..453d44b1 100644 --- a/game_patch/graphics/d3d11/gr_d3d11_transform.h +++ b/game_patch/graphics/d3d11/gr_d3d11_transform.h @@ -11,6 +11,66 @@ namespace df::gr::d3d11 // 4 rows, 3 cols (column-major) using GpuMatrix4x3 = std::array, 3>; + class Projection + { + float sx_ = 1.0f; + float sy_ = 1.0f; + float sz_ = -0.1f; + float tz_ = 1.0f; + float zf_ = 1.0f; + + public: + Projection() = default; + Projection(float sx, float sy, float zn, float zf) : + sx_{sx}, sy_{sy}, + sz_{-zn / (zf - zn)}, + tz_{zf * zn / (zf - zn)}, + zf_{zf} + {} + + float project_z(float z) const + { + return (z * sz_ + tz_) / z; + } + + rf::Vector3 project(rf::Vector3 p) const + { + return { + p.x * sx_ / p.z, + p.y * sy_ / p.z, + project_z(p.z), + }; + } + + float unproject_z(float pz) const { + // (z * sz_ + tz_) / z == pz + // pz * z = z * sz_ + tz_ + // pz * z - sz_ * z = tz_ + // z * (pz - sz_) = tz_ + // z = tz_ / (pz - sz_) + return tz_ / (pz - sz_); + } + + GpuMatrix4x4 matrix() const + { + // RF projection (1/z) uses reversed-Z trick, maps near plane to 1 and infinity to 0 + // It has some benefits, see "reversed-Z trick" in https://developer.nvidia.com/content/depth-precision-visualized + // To support far plane clipping change it a bit and map far plane to 0 instead of infinity + // Matrix construction: https://iolite-engine.com/blog_posts/reverse_z_cheatsheet + return {{ + {sx_, 0.0f, 0.0f, 0.0f}, + {0.0f, sy_, 0.0f, 0.0f}, + {0.0f, 0.0f, sz_, tz_}, + {0.0f, 0.0f, 1.0f, 0.0f}, + }}; + } + + float z_far() const + { + return zf_; + } + }; + inline GpuMatrix4x4 build_identity_matrix() { return {{ @@ -52,6 +112,4 @@ namespace df::gr::d3d11 {orient.fvec.x, orient.fvec.y, orient.fvec.z, translation.z}, }}; } - - GpuMatrix4x4 build_proj_matrix(); } diff --git a/game_patch/rf/gr/gr.h b/game_patch/rf/gr/gr.h index b49275a2..7a855d4e 100644 --- a/game_patch/rf/gr/gr.h +++ b/game_patch/rf/gr/gr.h @@ -306,6 +306,11 @@ namespace rf::gr TMAP_FLAG_ALPHA = 8, }; + enum VertexFlags + { + VF_PROJECTED = 1, + }; + static auto& screen = addr_as_ref(0x017C7BC0); static auto& gamma_ramp = addr_as_ref(0x017C7C68); static auto& default_wfar = addr_as_ref(0x00596140); diff --git a/game_patch/rf/math/vector.h b/game_patch/rf/math/vector.h index a680cd76..ea81cb67 100644 --- a/game_patch/rf/math/vector.h +++ b/game_patch/rf/math/vector.h @@ -32,6 +32,22 @@ namespace rf return *this; } + Vector3& operator*=(const Vector3& other) + { + x *= other.x; + y *= other.y; + z *= other.z; + return *this; + } + + Vector3& operator/=(const Vector3& other) + { + x /= other.x; + y /= other.y; + z /= other.z; + return *this; + } + Vector3& operator+=(float scalar) { x += scalar; @@ -83,6 +99,20 @@ namespace rf return tmp; } + [[nodiscard]] Vector3 operator*(const Vector3& other) const + { + Vector3 tmp = *this; + tmp *= other; + return tmp; + } + + [[nodiscard]] Vector3 operator/(const Vector3& other) const + { + Vector3 tmp = *this; + tmp /= other; + return tmp; + } + [[nodiscard]] Vector3 operator+(float scalar) const { Vector3 tmp = *this;