Add fancy clouds
This commit is contained in:
parent
c59aca6cd8
commit
0d9073420c
|
@ -285,6 +285,56 @@ impl Texture {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn image_2d(&self,
|
||||
target: TextureTarget,
|
||||
level: i32,
|
||||
width: u32,
|
||||
height: u32,
|
||||
format: TextureFormat,
|
||||
ty: Type,
|
||||
pix: Option<&[u8]>) {
|
||||
unsafe {
|
||||
let ptr = match pix {
|
||||
Some(val) => val.as_ptr() as *const gl::types::GLvoid,
|
||||
None => ptr::null(),
|
||||
};
|
||||
gl::TexImage2D(target,
|
||||
level,
|
||||
format as i32,
|
||||
width as i32,
|
||||
height as i32,
|
||||
0,
|
||||
format,
|
||||
ty,
|
||||
ptr
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sub_image_2d(&self,
|
||||
target: TextureTarget,
|
||||
level: i32,
|
||||
x: u32,
|
||||
y: u32,
|
||||
width: u32,
|
||||
height: u32,
|
||||
format: TextureFormat,
|
||||
ty: Type,
|
||||
pix: &[u8]) {
|
||||
unsafe {
|
||||
gl::TexSubImage2D(target,
|
||||
level,
|
||||
x as i32,
|
||||
y as i32,
|
||||
width as i32,
|
||||
height as i32,
|
||||
format,
|
||||
ty,
|
||||
pix.as_ptr() as *const _
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn image_2d_ex(&self,
|
||||
target: TextureTarget,
|
||||
level: i32,
|
||||
|
|
|
@ -0,0 +1,196 @@
|
|||
|
||||
use std::sync::{Arc, RwLock};
|
||||
|
||||
use cgmath::{Point3, Matrix4};
|
||||
use byteorder::{WriteBytesExt, NativeEndian};
|
||||
use gl;
|
||||
use super::glsl;
|
||||
|
||||
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_parameter(gl::COMPILE_STATUS) == 0 {
|
||||
println!("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() {
|
||||
println!("{}", log);
|
||||
}
|
||||
}
|
||||
|
||||
let g = gl::Shader::new(gl::GEOMETRY_SHADER);
|
||||
g.set_source(&geo);
|
||||
g.compile();
|
||||
|
||||
if g.get_parameter(gl::COMPILE_STATUS) == 0 {
|
||||
println!("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() {
|
||||
println!("{}", log);
|
||||
}
|
||||
}
|
||||
|
||||
let f = gl::Shader::new(gl::FRAGMENT_SHADER);
|
||||
f.set_source(&fragment);
|
||||
f.compile();
|
||||
|
||||
if f.get_parameter(gl::COMPILE_STATUS) == 0 {
|
||||
println!("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() {
|
||||
println!("{}", 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");
|
||||
let u_perspective_matrix = program.uniform_location("perspectiveMatrix");
|
||||
let u_camera_matrix = program.uniform_location("cameraMatrix");
|
||||
let u_light_level = program.uniform_location("lightLevel");
|
||||
let u_sky_offset = program.uniform_location("skyOffset");
|
||||
let u_offset = program.uniform_location("offset");
|
||||
let u_texture_info = program.uniform_location("textureInfo");
|
||||
let u_atlas = program.uniform_location("atlas");
|
||||
let u_textures = program.uniform_location("textures");
|
||||
let u_cloud_map = program.uniform_location("cloudMap");
|
||||
let u_cloud_offset = program.uniform_location("cloudOffset");
|
||||
|
||||
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![120; 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: program,
|
||||
// Shader props
|
||||
_a_position: a_position,
|
||||
u_perspective_matrix: u_perspective_matrix,
|
||||
u_camera_matrix: u_camera_matrix,
|
||||
u_light_level: u_light_level,
|
||||
u_sky_offset: u_sky_offset,
|
||||
u_offset: u_offset,
|
||||
u_texture_info: u_texture_info,
|
||||
u_atlas: u_atlas,
|
||||
u_textures: u_textures,
|
||||
u_cloud_map: u_cloud_map,
|
||||
u_cloud_offset: u_cloud_offset,
|
||||
|
||||
array: array,
|
||||
_buffer: buffer,
|
||||
|
||||
textures: textures,
|
||||
|
||||
texture: texture,
|
||||
heightmap_data: heightmap_data,
|
||||
dirty: false,
|
||||
|
||||
offset: 0.0,
|
||||
num_points: num_points,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn draw(&mut self, camera_pos: &Point3<f64>, perspective_matrix: &Matrix4<f32>, camera_matrix: &Matrix4<f32>, sky_offset: f32, light_level: 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);
|
||||
}
|
||||
}
|
|
@ -18,6 +18,7 @@ pub mod glsl;
|
|||
pub mod shaders;
|
||||
pub mod ui;
|
||||
pub mod model;
|
||||
pub mod clouds;
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::sync::{Arc, RwLock};
|
||||
|
@ -52,6 +53,7 @@ pub struct Renderer {
|
|||
textures: Arc<RwLock<TextureManager>>,
|
||||
pub ui: ui::UIState,
|
||||
pub model: model::Manager,
|
||||
pub clouds: clouds::Clouds,
|
||||
|
||||
gl_texture: gl::Texture,
|
||||
texture_layers: usize,
|
||||
|
@ -194,6 +196,7 @@ impl Renderer {
|
|||
Renderer {
|
||||
resource_version: version,
|
||||
model: model::Manager::new(&greg),
|
||||
clouds: clouds::Clouds::new(&greg, textures.clone()),
|
||||
textures: textures,
|
||||
ui: ui,
|
||||
resources: res,
|
||||
|
@ -318,7 +321,10 @@ impl Renderer {
|
|||
// Line rendering
|
||||
// Model rendering
|
||||
self.model.draw(&self.frustum, &self.perspective_matrix, &self.camera_matrix, self.light_level, self.sky_offset);
|
||||
// Cloud rendering
|
||||
if world.copy_cloud_heightmap(&mut self.clouds.heightmap_data) {
|
||||
self.clouds.dirty = true;
|
||||
}
|
||||
self.clouds.draw(&self.camera.pos, &self.perspective_matrix, &self.camera_matrix, self.light_level, self.sky_offset, delta);
|
||||
|
||||
// Trans chunk rendering
|
||||
self.chunk_shader_alpha.program.use_program();
|
||||
|
|
|
@ -33,6 +33,10 @@ pub fn add_shaders(reg: &mut glsl::Registry) {
|
|||
|
||||
reg.register("sun_vertex", include_str!("shaders/sun_vertex.glsl"));
|
||||
reg.register("sun_frag", include_str!("shaders/sun_frag.glsl"));
|
||||
|
||||
reg.register("clouds_vertex", include_str!("shaders/clouds_vertex.glsl"));
|
||||
reg.register("clouds_geo", include_str!("shaders/clouds_geo.glsl"));
|
||||
reg.register("clouds_frag", include_str!("shaders/clouds_frag.glsl"));
|
||||
}
|
||||
|
||||
macro_rules! get_shader {
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
in vec4 fColor;
|
||||
in vec3 fLighting;
|
||||
|
||||
out vec4 fragColor;
|
||||
|
||||
void main() {
|
||||
vec4 col = fColor;
|
||||
col.rgb *= fLighting;
|
||||
fragColor = col;
|
||||
}
|
|
@ -0,0 +1,121 @@
|
|||
layout(points) in;
|
||||
layout(triangle_strip, max_vertices = 24) out;
|
||||
|
||||
uniform mat4 perspectiveMatrix;
|
||||
uniform mat4 cameraMatrix;
|
||||
uniform vec3 offset;
|
||||
uniform float cloudOffset;
|
||||
|
||||
uniform vec4 textureInfo;
|
||||
uniform float atlas;
|
||||
uniform sampler2DArray textures;
|
||||
uniform sampler2D cloudMap;
|
||||
|
||||
in vec3 vLighting[];
|
||||
|
||||
out vec3 fLighting;
|
||||
out vec4 fColor;
|
||||
|
||||
void setVertex(vec3 base, vec3 off, float color) {
|
||||
gl_Position = perspectiveMatrix * cameraMatrix * vec4(base + off*vec3(1.0,-1.0,1.0), 1.0);
|
||||
fColor = vec4(color, color, color, 1.0);
|
||||
fLighting = vLighting[0];
|
||||
EmitVertex();
|
||||
}
|
||||
|
||||
float coffset = cloudOffset;
|
||||
const float invAtlasSize = 1.0 / 1024.0;
|
||||
vec4 atlasTexture(vec2 tPos) {
|
||||
tPos.y += floor(coffset);
|
||||
tPos = mod(tPos, textureInfo.zw);
|
||||
tPos += textureInfo.xy;
|
||||
tPos *= invAtlasSize;
|
||||
return texture(textures, vec3(tPos, atlas));
|
||||
}
|
||||
|
||||
ivec2 texP, heightP;
|
||||
|
||||
bool isSolid(ivec2 pos) {
|
||||
float height = texelFetch(cloudMap, ivec2(mod(heightP + pos, 512)), 0).r;
|
||||
if (height >= 127.0/255.0) return false;
|
||||
return atlasTexture(vec2(texP + pos)).r + height > (250.0 / 255.0);
|
||||
}
|
||||
|
||||
bool isFutureSolid(ivec2 pos) {
|
||||
// Sneak a peak into the future
|
||||
coffset += 1.0;
|
||||
bool ret = isSolid(pos);
|
||||
coffset -= 1.0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void main() {
|
||||
vec3 base = floor(offset) + gl_in[0].gl_Position.xyz;
|
||||
texP = ivec2(gl_in[0].gl_Position.xz + 160.0 + offset.xz);
|
||||
heightP = ivec2(mod(base.xz, 512));
|
||||
if (!isSolid(ivec2(0))) return;
|
||||
|
||||
float backOffset = 1.0 - fract(cloudOffset);
|
||||
float frontOffset = -fract(cloudOffset);
|
||||
if (!isFutureSolid(ivec2(0, -1))) {
|
||||
frontOffset = 0.0;
|
||||
}
|
||||
|
||||
// Top
|
||||
setVertex(base, vec3(0.0, 1.0, frontOffset), 1.0);
|
||||
setVertex(base, vec3(1.0, 1.0, frontOffset), 1.0);
|
||||
setVertex(base, vec3(0.0, 1.0, backOffset), 1.0);
|
||||
setVertex(base, vec3(1.0, 1.0, backOffset), 1.0);
|
||||
EndPrimitive();
|
||||
|
||||
// Bottom
|
||||
setVertex(base, vec3(0.0, 0.0, frontOffset), 0.7);
|
||||
setVertex(base, vec3(0.0, 0.0, backOffset), 0.7);
|
||||
setVertex(base, vec3(1.0, 0.0, frontOffset), 0.7);
|
||||
setVertex(base, vec3(1.0, 0.0, backOffset), 0.7);
|
||||
EndPrimitive();
|
||||
|
||||
if (!isSolid(ivec2(-1, 0)) || !isFutureSolid(ivec2(-1, -1))) {
|
||||
float sideOffset = backOffset;
|
||||
if (isSolid(ivec2(-1, 1)) && !isFutureSolid(ivec2(-1, 0))) {
|
||||
sideOffset = 1.0;
|
||||
}
|
||||
// -X
|
||||
setVertex(base, vec3(0.0, 0.0, frontOffset), 0.8);
|
||||
setVertex(base, vec3(0.0, 1.0, frontOffset), 0.8);
|
||||
setVertex(base, vec3(0.0, 0.0, sideOffset), 0.8);
|
||||
setVertex(base, vec3(0.0, 1.0, sideOffset), 0.8);
|
||||
EndPrimitive();
|
||||
}
|
||||
|
||||
if (!isSolid(ivec2(1, 0)) || !isFutureSolid(ivec2(1, -1))) {
|
||||
float sideOffset = backOffset;
|
||||
if (isSolid(ivec2(1, 1)) && !isFutureSolid(ivec2(1, 0))) {
|
||||
sideOffset = 1.0;
|
||||
}
|
||||
// +X
|
||||
setVertex(base, vec3(1.0, 0.0, frontOffset), 0.8);
|
||||
setVertex(base, vec3(1.0, 0.0, sideOffset), 0.8);
|
||||
setVertex(base, vec3(1.0, 1.0, frontOffset), 0.8);
|
||||
setVertex(base, vec3(1.0, 1.0, sideOffset), 0.8);
|
||||
EndPrimitive();
|
||||
}
|
||||
|
||||
if (!isSolid(ivec2(0, 1)) || !isFutureSolid(ivec2(0, 0))) {
|
||||
// -Z
|
||||
setVertex(base, vec3(0.0, 0.0, backOffset), 0.8);
|
||||
setVertex(base, vec3(0.0, 1.0, backOffset), 0.8);
|
||||
setVertex(base, vec3(1.0, 0.0, backOffset), 0.8);
|
||||
setVertex(base, vec3(1.0, 1.0, backOffset), 0.8);
|
||||
EndPrimitive();
|
||||
}
|
||||
|
||||
if (!isSolid(ivec2(0, -1)) || !isFutureSolid(ivec2(0, -2))) {
|
||||
// +Z
|
||||
setVertex(base, vec3(0.0, 0.0, frontOffset), 0.8);
|
||||
setVertex(base, vec3(1.0, 0.0, frontOffset), 0.8);
|
||||
setVertex(base, vec3(0.0, 1.0, frontOffset), 0.8);
|
||||
setVertex(base, vec3(1.0, 1.0, frontOffset), 0.8);
|
||||
EndPrimitive();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
in vec3 aPosition;
|
||||
|
||||
uniform float lightLevel;
|
||||
uniform float skyOffset;
|
||||
|
||||
out vec3 vLighting;
|
||||
|
||||
#include get_light
|
||||
|
||||
void main() {
|
||||
vec3 pos = vec3(aPosition.x, -aPosition.y, aPosition.z);
|
||||
gl_Position = vec4(pos, 1.0);
|
||||
|
||||
vLighting = getLight(vec2(0.0, 15.0));
|
||||
}
|
|
@ -96,6 +96,25 @@ impl World {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn copy_cloud_heightmap(&mut self, data: &mut [u8]) -> bool {
|
||||
let mut dirty = false;
|
||||
for (_, c) in &mut self.chunks {
|
||||
if c.heightmap_dirty {
|
||||
dirty = true;
|
||||
c.heightmap_dirty = false;
|
||||
for xx in 0 .. 16 {
|
||||
for zz in 0 .. 16 {
|
||||
data[
|
||||
(((c.position.0 << 4) as usize + xx) & 0x1FF) +
|
||||
((((c.position.1 << 4) as usize + zz) & 0x1FF) << 9)
|
||||
] = c.heightmap[(zz << 4) | xx];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
dirty
|
||||
}
|
||||
|
||||
pub fn compute_render_list(&mut self, renderer: &mut render::Renderer) {
|
||||
use chunk_builder;
|
||||
use types::Direction;
|
||||
|
@ -380,6 +399,8 @@ impl World {
|
|||
if new {
|
||||
try!(data.read_exact(&mut chunk.biomes));
|
||||
}
|
||||
|
||||
chunk.calculate_heightmap();
|
||||
}
|
||||
|
||||
for i in 0 .. 16 {
|
||||
|
@ -485,6 +506,9 @@ pub struct Chunk {
|
|||
sections: [Option<Section>; 16],
|
||||
sections_rendered_on: [u32; 16],
|
||||
biomes: [u8; 16 * 16],
|
||||
|
||||
heightmap: [u8; 16 * 16],
|
||||
heightmap_dirty: bool,
|
||||
}
|
||||
|
||||
impl Chunk {
|
||||
|
@ -499,9 +523,29 @@ impl Chunk {
|
|||
],
|
||||
sections_rendered_on: [0; 16],
|
||||
biomes: [0; 16 * 16],
|
||||
heightmap: [0; 16 * 16],
|
||||
heightmap_dirty: true,
|
||||
}
|
||||
}
|
||||
|
||||
fn calculate_heightmap(&mut self) {
|
||||
for x in 0 .. 16 {
|
||||
for z in 0 .. 16 {
|
||||
let idx = ((z<<4)|x) as usize;
|
||||
for yy in 0 .. 256 {
|
||||
let sy = 255 - yy;
|
||||
match self.get_block(x, sy, z) {
|
||||
block::Block::Air{..} => continue,
|
||||
_ => {},
|
||||
};
|
||||
self.heightmap[idx] = sy as u8;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
self.heightmap_dirty = true;
|
||||
}
|
||||
|
||||
fn set_block(&mut self, x: i32, y: i32, z: i32, b: block::Block) {
|
||||
let s_idx = y >> 4;
|
||||
if s_idx < 0 || s_idx > 15 {
|
||||
|
@ -513,8 +557,27 @@ impl Chunk {
|
|||
}
|
||||
self.sections[s_idx as usize] = Some(Section::new(self.position.0, s_idx as u8, self.position.1));
|
||||
}
|
||||
let section = self.sections[s_idx as usize].as_mut().unwrap();
|
||||
section.set_block(x, y & 0xF, z, b);
|
||||
{
|
||||
let section = self.sections[s_idx as usize].as_mut().unwrap();
|
||||
section.set_block(x, y & 0xF, z, b);
|
||||
}
|
||||
let idx = ((z<<4)|x) as usize;
|
||||
if self.heightmap[idx] < y as u8 {
|
||||
self.heightmap[idx] = y as u8;
|
||||
self.heightmap_dirty = true;
|
||||
} else if self.heightmap[idx] == y as u8 {
|
||||
// Find a new lowest
|
||||
for yy in 0 .. y {
|
||||
let sy = y - yy - 1;
|
||||
match self.get_block(x, sy, z) {
|
||||
block::Block::Air{..} => continue,
|
||||
_ => {},
|
||||
};
|
||||
self.heightmap[idx] = sy as u8;
|
||||
break;
|
||||
}
|
||||
self.heightmap_dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
fn get_block(&self, x: i32, y: i32, z: i32) -> block::Block {
|
||||
|
|
Loading…
Reference in New Issue