rust/lib-hedgewars-engine/src/world.rs
author sheepluva
Mon, 05 Aug 2019 00:20:45 +0200
changeset 15295 f382ec6dba11
parent 15275 66c987015f2d
child 15755 2eb3469a28a0
permissions -rw-r--r--
In hindsight my emscripten-ifdef (70d416a8f63f) is nonsense. As fpcrtl_glShaderSource() would not be defined and lead to compiling issues. So either it's 3 ifdefs (in pas2cRedo, pas2cSystem and misc.c), in order to toggle between fpcrtl_ and the native function, or alternatively have no ifdef for it at all. I'm going with none at all, which means emscripten will compile with the original (const) function prototype, being wrapped by the fpcrtl_ function, same as non-emscripten builds.

use fpnum::{fp, FPNum, FPPoint};
use hwphysics::{
    self as hwp,
    common::{GearId, Millis},
};
use integral_geometry::{Point, Rect, Size};
use land2d::Land2D;
use landgen::{
    outline_template::OutlineTemplate, template_based::TemplatedLandGenerator,
    LandGenerationParameters, LandGenerator,
};
use lfprng::LaggedFibonacciPRNG;

use crate::render::{camera::Camera, GearRenderer, MapRenderer};

struct GameState {
    land: Land2D<u32>,
    physics: hwp::World,
}

impl GameState {
    fn new(land: Land2D<u32>, physics: hwp::World) -> Self {
        Self { land, physics }
    }
}

pub struct World {
    random_numbers_gen: LaggedFibonacciPRNG,
    preview: Option<Land2D<u8>>,
    game_state: Option<GameState>,
    map_renderer: Option<MapRenderer>,
    gear_renderer: Option<GearRenderer>,
    camera: Camera,
}

impl World {
    pub fn new() -> Self {
        Self {
            random_numbers_gen: LaggedFibonacciPRNG::new(&[]),
            preview: None,
            game_state: None,
            map_renderer: None,
            gear_renderer: None,
            camera: Camera::new(),
        }
    }

    pub fn create_renderer(&mut self, width: u16, height: u16) {
        let land_tile_size = Size::square(512);
        self.map_renderer = Some(MapRenderer::new(land_tile_size));
        self.gear_renderer = Some(GearRenderer::new());
        self.camera = Camera::with_size(Size::new(width as usize, height as usize));

        use mapgen::{theme::Theme, MapGenerator};
        use std::path::Path;

        if let Some(ref state) = self.game_state {
            self.camera.position = state.land.play_box().center();

            let theme =
                Theme::load(Path::new("../../share/hedgewars/Data/Themes/Cheese/")).unwrap();
            let texture = MapGenerator::new().make_texture(&state.land, &theme);
            if let Some(ref mut renderer) = self.map_renderer {
                renderer.init(&texture);
            }
        }
    }

    pub fn set_seed(&mut self, seed: &[u8]) {
        self.random_numbers_gen = LaggedFibonacciPRNG::new(seed);
    }

    pub fn preview(&self) -> &Option<Land2D<u8>> {
        &self.preview
    }

    pub fn generate_preview(&mut self) {
        fn template() -> OutlineTemplate {
            let mut template = OutlineTemplate::new(Size::new(4096, 2048));
            template.islands = vec![vec![
                Rect::from_size_coords(100, 2050, 1, 1),
                Rect::from_size_coords(100, 500, 400, 1200),
                Rect::from_size_coords(3600, 500, 400, 1200),
                Rect::from_size_coords(3900, 2050, 1, 1),
            ]];
            template.fill_points = vec![Point::new(1, 0)];

            template
        }

        let params = LandGenerationParameters::new(0u8, u8::max_value(), 5, false, false);
        let landgen = TemplatedLandGenerator::new(template());
        self.preview = Some(landgen.generate_land(&params, &mut self.random_numbers_gen));
    }

    pub fn dispose_preview(&mut self) {
        self.preview = None
    }

    pub fn init(&mut self, template: OutlineTemplate) {
        let physics = hwp::World::new(template.size);

        let params = LandGenerationParameters::new(0u32, u32::max_value(), 5, false, false);
        let landgen = TemplatedLandGenerator::new(template);
        let land = landgen.generate_land(&params, &mut self.random_numbers_gen);

        self.game_state = Some(GameState::new(land, physics));
    }

    pub fn move_camera(&mut self, position_shift: Point, zoom_shift: f32) {
        self.camera.zoom += zoom_shift;
        self.camera.position += Point::new(
            (position_shift.x as f32 / self.camera.zoom) as i32,
            (position_shift.y as f32 / self.camera.zoom) as i32,
        );
    }

    pub fn render(&mut self) {
        if let Some(ref mut renderer) = self.map_renderer {
            unsafe {
                gl::ClearColor(0.4f32, 0f32, 0.2f32, 1f32);
                gl::Clear(gl::COLOR_BUFFER_BIT);
            }

            renderer.render(&self.camera);
        }
        if let Some(ref mut renderer) = self.gear_renderer {
            renderer.render(&self.camera)
        }
    }

    fn create_gear(&mut self, position: Point) {
        if let Some(ref mut state) = self.game_state {
            let id = state.physics.new_gear().unwrap();
            let fp_position = FPPoint::new(position.x.into(), position.y.into());
            state.physics.add_gear_data(
                id,
                hwp::physics::PhysicsData::new(fp_position, FPPoint::zero()),
            )
        }
    }

    pub fn step(&mut self) {
        if let Some(ref mut state) = self.game_state {
            let next = self.random_numbers_gen.next().unwrap();
            if next % 32 == 0 {
                let position = Point::new(
                    (self.random_numbers_gen.next().unwrap() % state.land.width() as u32) as i32,
                    0,
                );
                self.create_gear(position);
            }
        }

        if let Some(ref mut state) = self.game_state {
            state.physics.step(Millis::new(1), &state.land);
        }
    }
}