organicomplex 0.7.0

Interactive complex-valued cellular automaton on 2D and 3D grids in search of that stuff - emergence, open-endedness, organicity etc.
use core::slice::ChunksMut;

use sdl2::{
	pixels::Color,
	pixels::PixelFormatEnum,
	render::Texture,
	render::WindowCanvas
};

use crate::base::{
	PROG_TITLE,
	PrependErrorString
};

use super::config::Config;

mod geom;
mod image;
mod pixel;
mod text;

pub use self::image::Image;

pub struct System {
    width: i32,
    height: i32,

    buffer: Vec<u8>,

    sdl_screen_canvas: WindowCanvas,
	sdl_screen_texture: Texture, // requires "features = [..., "unsafe_textures"]" under [dependencies.sdl2] in Cargo.toml, to avoid lifetimes
}

impl System {
    pub fn init(sdl: &sdl2::Sdl, config: &Config) -> Result<System, String> {
        let video_subsystem = sdl.video().pre_err("cannot init sdl video")?;
        video_subsystem.disable_screen_saver();

		let width = if config.width > 0 {config.width} else {video_subsystem.current_display_mode(0)?.w};
		let height = if config.height > 0 {config.height} else {video_subsystem.current_display_mode(0)?.h};

		if (width & 1) != 0 {
            return Err(format!("screen width {} is not even", width));
        }

        if (height & 1) != 0 {
            return Err(format!("screen height {} is not even", height));
        }

        let buffer: Vec<u8> = vec![0xFF; ((width as usize) * (height as usize)) << 2];

		let mut window_builder = video_subsystem.window(PROG_TITLE, width as u32, height as u32);

		if (config.width <= 0) && (config.height <= 0) {
			window_builder.fullscreen();
		}

        let window = window_builder.build().pre_err("cannot build sdl window")?;

		let mut canvas_builder = window.into_canvas();
		if config.vsync {
			canvas_builder = canvas_builder.present_vsync();
		}
        let mut sdl_screen_canvas = canvas_builder.build().pre_err("cannot build sdl canvas")?;

        sdl_screen_canvas.set_draw_color(Color::RGB(0, 0, 0));
        sdl_screen_canvas.clear();
        sdl_screen_canvas.present();

		let sdl_texture_creator = sdl_screen_canvas.texture_creator();

		let sdl_screen_texture = sdl_texture_creator.create_texture_streaming(Some(PixelFormatEnum::ARGB8888), width as u32, height as u32)
			.pre_err("cannot create sdl texture")?;

        Ok(System{width, height, buffer, sdl_screen_canvas, sdl_screen_texture})
    }

	pub fn width(&self) -> i32 {
		self.width
	}

	pub fn height(&self) -> i32 {
		self.height
	}

	// Display video buffer in window
	pub fn show(&mut self) -> Result<(), String> {
		self.sdl_screen_texture.update(None, &self.buffer, (self.width as usize) << 2)
			.pre_err("cannot update sdl texture from buffer")?;

		// self.sdl_screen_canvas.clear();
		self.sdl_screen_canvas.copy(&self.sdl_screen_texture, None, None).pre_err("cannot copy sdl texture to sdl canvas")?;
		self.sdl_screen_canvas.present();

		Ok(())
	}

	pub fn clear(&mut self) {
		self.buffer.fill(0);
	}

	pub fn screen_raw_mut(&mut self) -> &mut [u8] {
		&mut self.buffer
	}

	pub fn screen_raw_chunks_mut(&mut self, pixels_per_chunk: i32) -> ChunksMut<'_, u8> {
		self.buffer.chunks_mut((pixels_per_chunk << 2) as usize)
	}

	pub fn shut(&mut self) -> Result<(), String> {
		Ok(())
	}

}