Add fancy clouds

This commit is contained in:
Thinkofname 2016-04-01 20:00:13 +01:00
parent c59aca6cd8
commit 0d9073420c
8 changed files with 468 additions and 3 deletions

View File

@ -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,

196
src/render/clouds.rs Normal file
View File

@ -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);
}
}

View File

@ -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();

View File

@ -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 {

View File

@ -0,0 +1,10 @@
in vec4 fColor;
in vec3 fLighting;
out vec4 fragColor;
void main() {
vec4 col = fColor;
col.rgb *= fLighting;
fragColor = col;
}

View File

@ -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();
}
}

View File

@ -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));
}

View File

@ -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 {