cubik 0.1.0

OpenGL/glium-based multiplayer game engine
Documentation
mod support;

use cubik::glium::{glutin, Surface};
use cubik::draw::{ObjDrawInfo, EnvDrawInfo, basic_render, MAX_LIGHTS, Light};
use cubik::camera::perspective_matrix;
use cubik::input::{InputListener, process_input_event, center_cursor};
use cubik::skybox::Skybox;
use cubik::animation::ObjAnimation;
use cubik::player::{Player, PlayerControlType};
use cubik::peer_player::PeerPlayer;
use support::constants::APP_ID;
use cubik::audio::{buffer_sound, get_sound_stream, SoundStream};
use cubik::container::RenderContainer;
use std::collections::HashMap;
use cubik::client::ClientContainer;
use cubik::map::GameMap;
use support::msg::AppMessage;

const PORT: u16 = 27020;

fn net_update(client_container: &mut ClientContainer<AppMessage>, peer_map: &mut HashMap<u8, PeerPlayer>, player: &mut Player, sound_stream: &SoundStream, time_delta: f32) {
	let pids = client_container.pids();
	peer_map.retain(|&k, _| pids.contains(&k));

	client_container.update().unwrap();

	for msg in client_container.get_msgs() {
		if let AppMessage::PlayerChange { msg, player_id } = msg {
			if client_container.player_id.unwrap_or(0) == player_id {
				player.update(0., None, Some(sound_stream), Some(msg));
			} else {
				let peer_player = peer_map.entry(player_id)
					.or_insert(PeerPlayer::new());

				peer_player.update(Some(msg), time_delta);
			}
		}
	}

	for peer_player in peer_map.values_mut() {
		peer_player.update(None, time_delta);
	}

	if let Some(out_msg) = player.update(time_delta, None, Some(sound_stream), None) {
		client_container.send(AppMessage::PlayerChange {
			player_id: 0,
			msg: out_msg
		}).unwrap();
	}
}

fn main() {
	let event_loop = glutin::event_loop::EventLoop::new();
	let mut ctr = RenderContainer::new(&event_loop, 1280, 720, "Example", false);

	let mut map_info: ObjDrawInfo = Default::default();
	map_info.generate_matrix();

	let sound_stream = get_sound_stream().unwrap();

	let mut peer_map: HashMap<u8, PeerPlayer> = HashMap::new();

	let mut client_container: ClientContainer<AppMessage> = ClientContainer::new(format!("127.0.0.1:{}", PORT).as_str()).unwrap();
	let mut player = Player::new([0.0, 1.5, 0.0], PlayerControlType::MultiplayerClient,
		[0.0, 0.275, 0.0], [0.44, 0.275, 0.08]);

	player.walking_sound = Some(buffer_sound("./audio/running.wav", APP_ID).unwrap());
	
	let map = GameMap::load_map("models/map2", APP_ID,
		Some(&ctr.display), Some(&mut ctr.textures), false).unwrap();

	let wolf_standing = cubik::wavefront::load_obj("models/wolf_standing.obj", APP_ID, Some(&ctr.display), Some(&mut ctr.textures),
		&[1., 1., 1.], None, None, None).unwrap();
	let wolf_anim = ObjAnimation::load_wavefront("models/wolfrunning", APP_ID, &ctr.display, &mut ctr.textures, 0.041).unwrap();

	let skybox = Skybox::new(&ctr.display, "skybox1", APP_ID, 512, 50.).unwrap();

	let mut lights_arr: [Light; MAX_LIGHTS] = Default::default();
	let mut light_iter = map.lights.values();
	for i in 0..map.lights.len() { lights_arr[i] = *light_iter.next().unwrap(); }

	let mut displace = 0.0f32;

	let mut last_frame_time = std::time::Instant::now();

	let mut input_enabled = true;

	event_loop.run(move |ev, _, control_flow| {
		let listeners: Vec<&mut dyn InputListener> = vec![&mut player];
		*control_flow = glutin::event_loop::ControlFlow::Poll;
		match ev {
			glutin::event::Event::WindowEvent { event, .. } => match event {
				glutin::event::WindowEvent::CloseRequested => {
					*control_flow = glutin::event_loop::ControlFlow::Exit;
					return;
				},
				glutin::event::WindowEvent::KeyboardInput { input, .. } => {
					if let Some(keycode) = input.virtual_keycode {
						match keycode {
							glutin::event::VirtualKeyCode::Escape => {
								*control_flow = glutin::event_loop::ControlFlow::Exit;
								return;
							},
							glutin::event::VirtualKeyCode::T => {
								if input.state == glutin::event::ElementState::Released {
									input_enabled = !input_enabled;
									let gl_window = ctr.display.gl_window();
									let window = gl_window.window();
									window.set_cursor_visible(!input_enabled);
								}
								return;
							}
							_ => ()
						};
					}
					if !input_enabled { return; }
					process_input_event(event, listeners, &ctr.display);
					return;
				},
				_ => {
					if !input_enabled { return; }
					process_input_event(event, listeners, &ctr.display);
					return;
				}
			},
			glutin::event::Event::NewEvents(cause) => match cause {
				glutin::event::StartCause::ResumeTimeReached { .. } => (),
				glutin::event::StartCause::Init => {
					center_cursor(&ctr.display, false);
				},
				glutin::event::StartCause::Poll => (),
				_ => return
			},
			_ => return
		}
		
		let new_frame_time = std::time::Instant::now();
		let time_delta = new_frame_time.duration_since(last_frame_time).as_secs_f32();
		last_frame_time = new_frame_time;

		displace += time_delta;

		net_update(&mut client_container, &mut peer_map, &mut player, &sound_stream, time_delta);

		let mut target = ctr.display.draw();

		let perspective_mat = perspective_matrix(&mut target);
		let env_info = EnvDrawInfo {
			perspective_mat: perspective_mat,
			view_mat: player.camera.view_matrix(),
			lights: lights_arr,
			light_count: map.lights.len(),
			params: &ctr.params,
			textures: &ctr.textures
		};

		target.clear_color_and_depth((0.85, 0.85, 0.85, 1.0), 1.0); 

		for (key, o) in &map.objects {
			let text_displace = if key.starts_with("water") {
				Some([displace.sin() * 0.005, displace.sin() * 0.005])
			} else { None };
			basic_render(&mut target, &env_info, &map_info, &o, &ctr.main_program, text_displace);
		}

		for peer_player in peer_map.values_mut() {
			peer_player.draw(&mut target, &env_info, &ctr.main_program, &wolf_anim, &wolf_standing, wolf_anim.get_keyframe_by_index(5));
		}

		skybox.draw(&mut target, &env_info, &ctr.skybox_program);

		target.finish().unwrap();
	});
}