feat: Introduce terrain SVG export functionality via FFI to a Windows DLL, providing an Arma 3 exportSVG command.

This commit is contained in:
Jacob Schmidt 2026-02-16 19:42:03 -06:00
parent 082f0c6f8f
commit 4d7e3520eb

View File

@ -4,29 +4,31 @@
//! rendering options (location names, grid, contour lines, etc.). //! rendering options (location names, grid, contour lines, etc.).
use arma_rs::Group; use arma_rs::Group;
use std::ffi::CString;
use std::os::raw::{c_char, c_void};
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
#[link(name = "kernel32")] mod windows_ffi {
unsafe extern "stdcall" { use std::os::raw::{c_char, c_void};
fn GetModuleHandleA(lpModuleName: *const u8) -> *mut c_void;
fn LoadLibraryA(lpLibFileName: *const u8) -> *mut c_void; #[link(name = "kernel32")]
fn GetProcAddress(hModule: *mut c_void, lpProcName: *const u8) -> *mut c_void; unsafe extern "system" {
pub(super) fn GetModuleHandleA(lpModuleName: *const u8) -> *mut c_void;
pub(super) fn LoadLibraryA(lpLibFileName: *const u8) -> *mut c_void;
pub(super) fn GetProcAddress(hModule: *mut c_void, lpProcName: *const u8) -> *mut c_void;
}
/// Mangled C++ name for the ExportSVG function.
/// Format: `?ExportSVG@@YAXPEBD_N11111@Z` matches signature:
/// `void ExportSVG(const char*, bool, bool, bool, bool, bool, bool)`
pub(super) const EXPORT_SVG_PROC_NAME: &[u8] = b"?ExportSVG@@YAXPEBD_N11111@Z\0";
/// Name of the DLL containing the ExportSVG function.
/// Update this to match your actual DLL name.
pub(super) const TERRAIN_DLL_NAME: &[u8] = b"TerrainExport.dll\0";
pub(super) type FnExportSVG =
extern "system" fn(*const c_char, bool, bool, bool, bool, bool, bool) -> *const c_void;
} }
/// Mangled C++ name for the ExportSVG function.
/// Format: `?ExportSVG@@YAXPEBD_N11111@Z` matches signature:
/// `void ExportSVG(const char*, bool, bool, bool, bool, bool, bool)`
const EXPORT_SVG_PROC_NAME: &[u8] = b"?ExportSVG@@YAXPEBD_N11111@Z\0";
/// Name of the DLL containing the ExportSVG function.
/// Update this to match your actual DLL name.
const TERRAIN_DLL_NAME: &[u8] = b"TerrainExport.dll\0";
type FnExportSVG =
extern "stdcall" fn(*const c_char, bool, bool, bool, bool, bool, bool) -> *const c_void;
/// Creates the Arma 3 command group for the terrain module. /// Creates the Arma 3 command group for the terrain module.
/// ///
/// Registers the `exportSVG` command with the Arma 3 extension. /// Registers the `exportSVG` command with the Arma 3 extension.
@ -59,6 +61,8 @@ pub fn export_terrain_svg(
simple_roads: bool, simple_roads: bool,
) -> Result<(), String> { ) -> Result<(), String> {
unsafe { unsafe {
use windows_ffi::*;
// Try to get already loaded module, or load the DLL // Try to get already loaded module, or load the DLL
let module = GetModuleHandleA(TERRAIN_DLL_NAME.as_ptr()); let module = GetModuleHandleA(TERRAIN_DLL_NAME.as_ptr());
let module = if module.is_null() { let module = if module.is_null() {
@ -85,7 +89,7 @@ pub fn export_terrain_svg(
// Convert file path to C string // Convert file path to C string
let file_path_cstr = let file_path_cstr =
CString::new(file_path).map_err(|e| format!("Invalid file path: {}", e))?; std::ffi::CString::new(file_path).map_err(|e| format!("Invalid file path: {}", e))?;
// Call the export function // Call the export function
export_svg( export_svg(
@ -137,15 +141,27 @@ struct ExportSvgOptions {
/// ///
/// # SQF Usage /// # SQF Usage
/// ```sqf /// ```sqf
/// ["forge", ["terrain", "exportSVG", "{ /// // Register callback handler (optional, for async result)
/// ""filePath"": ""C:\\path\\to\\output.svg"", /// ["terrain:exportSVG", {
/// ""drawLocationNames"": true, /// params ["_response"];
/// ""drawGrid"": true, /// systemChat format ["Export %1: %2",
/// ""drawContourlines"": true, /// _response get "status",
/// ""drawTreeObjects"": false, /// _response get "message"
/// ""drawMountainHeightpoints"": true, /// ];
/// ""simpleRoads"": false /// }] call forge_x_extension_fnc_setHandler;
/// }"]] call forge_fnc_callExtension; ///
/// // Create options and call extension
/// private _options = createHashMapFromArray [
/// ["filePath", "C:\terrain.svg"],
/// ["drawLocationNames", true],
/// ["drawGrid", true],
/// ["drawContourlines", true],
/// ["drawTreeObjects", false],
/// ["drawMountainHeightpoints", true],
/// ["simpleRoads", false]
/// ];
///
/// ["terrain:exportSVG", [toJSON _options]] call forge_x_extension_fnc_extCall;
/// ``` /// ```
fn export_svg(options_json: String) -> String { fn export_svg(options_json: String) -> String {
// Parse options from JSON // Parse options from JSON