Use rust land generator in hwengine transitional_engine
authorunC0Rr
Wed, 04 Jan 2023 10:42:21 +0100
branchtransitional_engine
changeset 15904 33798b649d9c
parent 15903 230dc46487ea
child 15905 022ec6b916b7
Use rust land generator in hwengine
.gitignore
hedgewars/uLand.pas
hedgewars/uLandUtils.pas
rust/land2d/src/lib.rs
rust/lib-hwengine-future/Cargo.toml
rust/lib-hwengine-future/src/lib.rs
--- a/.gitignore	Wed Jan 04 10:40:40 2023 +0100
+++ b/.gitignore	Wed Jan 04 10:42:21 2023 +0100
@@ -32,7 +32,7 @@
 misc/libphysfs/Xcode/build/
 misc/libphyslayer/Xcode/build/
 moc_*.cxx_parameters
-relre:^release\/
+relre:^release/
 *.log
 *.cmd
 *.diff
--- a/hedgewars/uLand.pas	Wed Jan 04 10:40:40 2023 +0100
+++ b/hedgewars/uLand.pas	Wed Jan 04 10:42:21 2023 +0100
@@ -793,7 +793,7 @@
         begin
         WriteLnToConsole('Generating land...');
         case cMapGen of
-            mgRandom: GenTemplated(EdgeTemplates[SelectTemplate]);
+            mgRandom: CreateTemplatedLand(cFeatureSize, cSeed, PathPrefix, Theme);
             mgMaze  : begin ResizeLand(4096,2048); GenMaze; end;
             mgPerlin: begin ResizeLand(4096,2048); GenPerlin; end;
             mgDrawn : GenDrawnMap;
@@ -801,7 +801,7 @@
         else
             OutError('Unknown mapgen', true);
         end;
-        if cMapGen <> mgForts then
+        if (cMapGen <> mgForts) and (cMapGen <> mgRandom) then
             GenLandSurface
         end;
 
@@ -948,7 +948,7 @@
 begin
     WriteLnToConsole('Generating preview...');
     case cMapGen of
-        mgRandom: GenTemplated(EdgeTemplates[SelectTemplate]);
+        mgRandom: CreateTemplatedLand(cFeatureSize, cSeed, PathPrefix, Theme);
         mgMaze: begin ResizeLand(4096,2048); GenMaze; end;
         mgPerlin: begin ResizeLand(4096,2048); GenPerlin; end;
         mgDrawn: begin GenDrawnMap; end;
@@ -1007,7 +1007,7 @@
 begin
     WriteLnToConsole('Generating preview...');
     case cMapGen of
-        mgRandom: GenTemplated(EdgeTemplates[SelectTemplate]);
+        mgRandom: CreateTemplatedLand(cFeatureSize, cSeed, PathPrefix, Theme);
         mgMaze: begin ResizeLand(4096,2048); GenMaze; end;
         mgPerlin: begin ResizeLand(4096,2048); GenPerlin; end;
         mgDrawn: begin GenDrawnMap; end;
--- a/hedgewars/uLandUtils.pas	Wed Jan 04 10:40:40 2023 +0100
+++ b/hedgewars/uLandUtils.pas	Wed Jan 04 10:42:21 2023 +0100
@@ -2,6 +2,7 @@
 interface
 uses SDLh;
 
+procedure CreateTemplatedLand(featureSize: Longword; seed, dataPath, theme: shortstring);
 procedure ResizeLand(width, height: LongWord);
 procedure DisposeLand();
 procedure InitWorldEdges();
@@ -20,8 +21,11 @@
 uses uUtils, uConsts, uVariables, uTypes;
 
 const LibFutureName = 'hwengine_future';
-function  create_game_field(width, height: Longword): pointer; cdecl; external LibFutureName;
+
+function  create_empty_game_field(width, height: Longword): pointer; cdecl; external LibFutureName;
+procedure get_game_field_parameters(game_field: pointer; var width: LongInt; var height: LongInt); cdecl; external LibFutureName;
 procedure dispose_game_field(game_field: pointer); cdecl; external LibFutureName;
+
 function  land_get(game_field: pointer; x, y: LongInt): Word; cdecl; external LibFutureName;
 procedure land_set(game_field: pointer; x, y: LongInt; value: Word); cdecl; external LibFutureName;
 function  land_row(game_field: pointer; row: LongInt): PWordArray; cdecl; external LibFutureName;
@@ -31,6 +35,8 @@
 procedure land_pixel_set(game_field: pointer; x, y: LongInt; value: Longword); cdecl; external LibFutureName;
 function  land_pixel_row(game_field: pointer; row: LongInt): PLongwordArray; cdecl; external LibFutureName;
 
+function  generate_templated_game_field(feature_size: Longword; seed, data_path, theme_name: PChar): pointer; cdecl; external LibFutureName;
+
 var gameField: pointer;
 
 function  LandGet(y, x: LongInt): Word;
@@ -68,6 +74,23 @@
     LandPixelRow:= land_pixel_row(gameField, row)
 end;
 
+procedure CreateTemplatedLand(featureSize: Longword; seed, dataPath, theme: shortstring);
+begin
+    seed[byte(seed[0]) + 1]:= #0;
+    theme[byte(theme[0]) + 1]:= #0;
+
+    gameField:= generate_templated_game_field(featureSize, @seed[1], Str2PChar(dataPath), @theme[1]);
+    get_game_field_parameters(gameField, LAND_WIDTH, LAND_HEIGHT);
+
+    // let's assume those are powers of two
+    LAND_WIDTH_MASK:= not(LAND_WIDTH-1);
+    LAND_HEIGHT_MASK:= not(LAND_HEIGHT-1);
+
+    SetLength(LandDirty, (LAND_HEIGHT div 32), (LAND_WIDTH div 32));
+
+    initScreenSpaceVars();
+end;
+
 procedure ResizeLand(width, height: LongWord);
 var potW, potH: LongInt;
 begin
@@ -81,7 +104,7 @@
     LAND_HEIGHT_MASK:= not(LAND_HEIGHT-1);
     cWaterLine:= LAND_HEIGHT;
 
-    gameField:= create_game_field(LAND_WIDTH, LAND_HEIGHT);
+    gameField:= create_empty_game_field(LAND_WIDTH, LAND_HEIGHT);
     SetLength(LandDirty, (LAND_HEIGHT div 32), (LAND_WIDTH div 32));
     // 0.5 is already approaching on unplayable
     if (width div 4096 >= 2) or (height div 2048 >= 2) then cMaxZoomLevel:= cMaxZoomLevel/2;
--- a/rust/land2d/src/lib.rs	Wed Jan 04 10:40:40 2023 +0100
+++ b/rust/land2d/src/lib.rs	Wed Jan 04 10:42:21 2023 +0100
@@ -1,5 +1,5 @@
 use std::{cmp, ops::Index, ops::IndexMut};
-
+use vec2d::Vec2D;
 use integral_geometry::{ArcPoints, EquidistantPoints, Line, Point, PotSize, Rect, Size, SizeMask};
 
 pub struct Land2D<T> {
@@ -295,6 +295,23 @@
     }
 }
 
+impl<T> From<Vec2D<T>> for Land2D<T> {
+    fn from(vec: Vec2D<T>) -> Self {
+        let actual_size = vec.size();
+        let pot_size = actual_size.next_power_of_two();
+
+        assert_eq!(actual_size, pot_size.size());
+
+        let top_left = Point::new(0, 0);
+        let play_box = Rect::from_size(top_left, actual_size);
+        Self {
+            play_box,
+            pixels: vec,
+            mask: pot_size.to_mask(),
+        }
+    }
+}
+
 #[cfg(test)]
 mod tests {
     use super::*;
--- a/rust/lib-hwengine-future/Cargo.toml	Wed Jan 04 10:40:40 2023 +0100
+++ b/rust/lib-hwengine-future/Cargo.toml	Wed Jan 04 10:42:21 2023 +0100
@@ -9,6 +9,9 @@
 [dependencies]
 land2d = { path = "../land2d" }
 integral-geometry = { path = "../integral-geometry" }
+mapgen = { path = "../mapgen" }
+landgen = { path = "../landgen" }
+lfprng = { path = "../lfprng" }
 
 [lib]
 name = "hwengine_future"
--- a/rust/lib-hwengine-future/src/lib.rs	Wed Jan 04 10:40:40 2023 +0100
+++ b/rust/lib-hwengine-future/src/lib.rs	Wed Jan 04 10:42:21 2023 +0100
@@ -1,5 +1,10 @@
 use integral_geometry::{Point, Size};
 use land2d;
+use landgen::{template_based::TemplatedLandGenerator, LandGenerationParameters, LandGenerator};
+use lfprng::LaggedFibonacciPRNG;
+use mapgen::{theme::Theme, MapGenerator};
+use std::fs;
+use std::{ffi::CStr, path::Path};
 
 #[repr(C)]
 pub struct GameField {
@@ -8,7 +13,19 @@
 }
 
 #[no_mangle]
-pub extern "C" fn create_game_field(width: u32, height: u32) -> *mut GameField {
+pub extern "C" fn get_game_field_parameters(
+    game_field: &GameField,
+    width: *mut i32,
+    height: *mut i32,
+) {
+    unsafe {
+        *width = game_field.collision.width() as i32;
+        *height = game_field.collision.height() as i32;
+    }
+}
+
+#[no_mangle]
+pub extern "C" fn create_empty_game_field(width: u32, height: u32) -> *mut GameField {
     let game_field = Box::new(GameField {
         collision: land2d::Land2D::new(Size::new(width as usize, height as usize), 0),
         pixels: land2d::Land2D::new(Size::new(width as usize, height as usize), 0),
@@ -18,6 +35,53 @@
 }
 
 #[no_mangle]
+pub extern "C" fn generate_templated_game_field(
+    feature_size: u32,
+    seed: *const i8,
+    data_path: *const i8,
+    theme_name: *const i8,
+) -> *mut GameField {
+    let data_path: &str = unsafe { CStr::from_ptr(data_path) }.to_str().unwrap();
+    let data_path = Path::new(&data_path);
+
+    let seed: &str = unsafe { CStr::from_ptr(seed) }.to_str().unwrap();
+    let theme_name: &str = unsafe { CStr::from_ptr(theme_name) }.to_str().unwrap();
+
+    let mut random_numbers_gen = LaggedFibonacciPRNG::new(seed.as_bytes());
+
+    let yaml_templates =
+        fs::read_to_string(data_path.join(Path::new("map_templates.yaml")).as_path())
+            .expect("Error reading map templates file");
+    let mut map_gen = MapGenerator::new();
+    map_gen.import_yaml_templates(&yaml_templates);
+
+    let distance_divisor = feature_size.pow(2) / 8 + 10;
+    let params = LandGenerationParameters::new(0u16, 0x8000u16, distance_divisor, false, false);
+    let template = map_gen
+        .get_template("medium", &mut random_numbers_gen)
+        .expect("Error reading map templates file")
+        .clone();
+    let landgen = TemplatedLandGenerator::new(template);
+    let collision = landgen.generate_land(&params, &mut random_numbers_gen);
+
+    let theme = Theme::load(
+        data_path
+            .join(Path::new("Themes"))
+            .join(Path::new(theme_name))
+            .as_path(),
+    )
+    .unwrap();
+    let pixels = map_gen.make_texture(&collision, &params, &theme);
+
+    let game_field = Box::new(GameField {
+        collision,
+        pixels: pixels.into(),
+    });
+
+    Box::leak(game_field)
+}
+
+#[no_mangle]
 pub extern "C" fn land_get(game_field: &mut GameField, x: i32, y: i32) -> u16 {
     game_field.collision.map(y, x, |p| *p)
 }