227 lines
6.7 KiB
Rust
227 lines
6.7 KiB
Rust
use std::sync::{Arc, RwLock};
|
|
|
|
use super::glsl;
|
|
use crate::gl;
|
|
use byteorder::{NativeEndian, WriteBytesExt};
|
|
use cgmath::{Matrix4, Point3};
|
|
use log::error;
|
|
|
|
pub struct Clouds {
|
|
program: gl::Program,
|
|
// Shader props
|
|
_a_position: gl::Attribute,
|
|
u_perspective_matrix: gl::Uniform,
|
|
u_camera_matrix: gl::Uniform,
|
|
u_light_level: gl::Uniform,
|
|
u_sky_offset: gl::Uniform,
|
|
u_offset: gl::Uniform,
|
|
u_texture_info: gl::Uniform,
|
|
u_atlas: gl::Uniform,
|
|
u_textures: gl::Uniform,
|
|
u_cloud_map: gl::Uniform,
|
|
u_cloud_offset: gl::Uniform,
|
|
|
|
array: gl::VertexArray,
|
|
_buffer: gl::Buffer,
|
|
|
|
textures: Arc<RwLock<super::TextureManager>>,
|
|
|
|
texture: gl::Texture,
|
|
pub heightmap_data: Vec<u8>,
|
|
pub dirty: bool,
|
|
|
|
offset: f64,
|
|
num_points: usize,
|
|
}
|
|
|
|
impl Clouds {
|
|
pub fn new(greg: &glsl::Registry, textures: Arc<RwLock<super::TextureManager>>) -> Clouds {
|
|
let program = gl::Program::new();
|
|
|
|
let vertex = greg.get("clouds_vertex");
|
|
let geo = greg.get("clouds_geo");
|
|
let fragment = greg.get("clouds_frag");
|
|
|
|
let v = gl::Shader::new(gl::VERTEX_SHADER);
|
|
v.set_source(&vertex);
|
|
v.compile();
|
|
|
|
if !v.get_shader_compile_status() {
|
|
error!("Src: {}", vertex);
|
|
panic!("Shader error: {}", v.get_info_log());
|
|
} else {
|
|
let log = v.get_info_log();
|
|
let log = log.trim().trim_matches('\u{0}');
|
|
if !log.is_empty() {
|
|
error!("{}", log);
|
|
}
|
|
}
|
|
|
|
let g = gl::Shader::new(gl::GEOMETRY_SHADER);
|
|
g.set_source(&geo);
|
|
g.compile();
|
|
|
|
if !g.get_shader_compile_status() {
|
|
error!("Src: {}", geo);
|
|
panic!("Shader error: {}", g.get_info_log());
|
|
} else {
|
|
let log = g.get_info_log();
|
|
let log = log.trim().trim_matches('\u{0}');
|
|
if !log.is_empty() {
|
|
error!("{}", log);
|
|
}
|
|
}
|
|
|
|
let f = gl::Shader::new(gl::FRAGMENT_SHADER);
|
|
f.set_source(&fragment);
|
|
f.compile();
|
|
|
|
if !f.get_shader_compile_status() {
|
|
error!("Src: {}", fragment);
|
|
panic!("Shader error: {}", f.get_info_log());
|
|
} else {
|
|
let log = f.get_info_log();
|
|
let log = log.trim().trim_matches('\u{0}');
|
|
if !log.is_empty() {
|
|
error!("{}", log);
|
|
}
|
|
}
|
|
|
|
program.attach_shader(v);
|
|
program.attach_shader(g);
|
|
program.attach_shader(f);
|
|
program.link();
|
|
program.use_program();
|
|
|
|
let a_position = program.attribute_location("aPosition").unwrap();
|
|
let u_perspective_matrix = program.uniform_location("perspectiveMatrix").unwrap();
|
|
let u_camera_matrix = program.uniform_location("cameraMatrix").unwrap();
|
|
let u_light_level = program.uniform_location("lightLevel").unwrap();
|
|
let u_sky_offset = program.uniform_location("skyOffset").unwrap();
|
|
let u_offset = program.uniform_location("offset").unwrap();
|
|
let u_texture_info = program.uniform_location("textureInfo").unwrap();
|
|
let u_atlas = program.uniform_location("atlas").unwrap();
|
|
let u_textures = program.uniform_location("textures").unwrap();
|
|
let u_cloud_map = program.uniform_location("cloudMap").unwrap();
|
|
let u_cloud_offset = program.uniform_location("cloudOffset").unwrap();
|
|
|
|
let array = gl::VertexArray::new();
|
|
array.bind();
|
|
let buffer = gl::Buffer::new();
|
|
buffer.bind(gl::ARRAY_BUFFER);
|
|
a_position.enable();
|
|
a_position.vertex_pointer(3, gl::FLOAT, false, 12, 0);
|
|
|
|
let mut data = vec![];
|
|
let mut num_points = 0;
|
|
for x in -160..160 {
|
|
for z in -160..160 {
|
|
let _ = data.write_f32::<NativeEndian>(x as f32);
|
|
let _ = data.write_f32::<NativeEndian>(128.0);
|
|
let _ = data.write_f32::<NativeEndian>(z as f32);
|
|
num_points += 1;
|
|
}
|
|
}
|
|
|
|
buffer.set_data(gl::ARRAY_BUFFER, &data, gl::STATIC_DRAW);
|
|
|
|
let heightmap_data = vec![0; 512 * 512];
|
|
|
|
let texture = gl::Texture::new();
|
|
texture.bind(gl::TEXTURE_2D);
|
|
texture.image_2d(
|
|
gl::TEXTURE_2D,
|
|
0,
|
|
512,
|
|
512,
|
|
gl::RED,
|
|
gl::UNSIGNED_BYTE,
|
|
Some(&heightmap_data),
|
|
);
|
|
texture.set_parameter(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::NEAREST);
|
|
texture.set_parameter(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::NEAREST);
|
|
|
|
Clouds {
|
|
program,
|
|
// Shader props
|
|
_a_position: a_position,
|
|
u_perspective_matrix,
|
|
u_camera_matrix,
|
|
u_light_level,
|
|
u_sky_offset,
|
|
u_offset,
|
|
u_texture_info,
|
|
u_atlas,
|
|
u_textures,
|
|
u_cloud_map,
|
|
u_cloud_offset,
|
|
|
|
array,
|
|
_buffer: buffer,
|
|
|
|
textures,
|
|
|
|
texture,
|
|
heightmap_data,
|
|
dirty: false,
|
|
|
|
offset: 0.0,
|
|
num_points,
|
|
}
|
|
}
|
|
|
|
pub fn draw(
|
|
&mut self,
|
|
camera_pos: &Point3<f64>,
|
|
perspective_matrix: &Matrix4<f32>,
|
|
camera_matrix: &Matrix4<f32>,
|
|
light_level: f32,
|
|
sky_offset: f32,
|
|
delta: f64,
|
|
) {
|
|
self.offset += delta;
|
|
|
|
let tex = super::Renderer::get_texture(&self.textures, "steven:environment/clouds");
|
|
|
|
self.program.use_program();
|
|
self.u_perspective_matrix.set_matrix4(perspective_matrix);
|
|
self.u_camera_matrix.set_matrix4(camera_matrix);
|
|
self.u_sky_offset.set_float(sky_offset);
|
|
self.u_light_level.set_float(light_level);
|
|
self.u_offset.set_float3(
|
|
camera_pos.x.floor() as f32,
|
|
0.0,
|
|
camera_pos.z.floor() as f32,
|
|
);
|
|
self.u_texture_info.set_float4(
|
|
tex.get_x() as f32,
|
|
tex.get_y() as f32,
|
|
tex.get_width() as f32,
|
|
tex.get_height() as f32,
|
|
);
|
|
self.u_atlas.set_float(tex.atlas as f32);
|
|
self.u_cloud_offset.set_float((self.offset / 60.0) as f32);
|
|
self.u_textures.set_int(0);
|
|
|
|
gl::active_texture(1);
|
|
self.texture.bind(gl::TEXTURE_2D);
|
|
if self.dirty {
|
|
self.texture.sub_image_2d(
|
|
gl::TEXTURE_2D,
|
|
0,
|
|
0,
|
|
0,
|
|
512,
|
|
512,
|
|
gl::RED,
|
|
gl::UNSIGNED_BYTE,
|
|
&self.heightmap_data,
|
|
);
|
|
self.dirty = false;
|
|
}
|
|
self.u_cloud_map.set_int(1);
|
|
self.array.bind();
|
|
gl::draw_arrays(gl::POINTS, 0, self.num_points);
|
|
}
|
|
}
|