use rinecs::{
Read, Entity, ReadNot, Write, ResourcesCreation, EntitiesCreation, creation_system
};
use rin_math::{Vec2, vec2, Vec3};
use rin_gl as gl;
use crate::transformation::RenderPlane;
use crate::water::{self, ParametersSend, WaterMaterial};
use rin_material::AlphaType;
use crate::renderer::components::{
RenderPlane as GpuRenderPlane
};
use std140_data::Data;
use std::mem;
use super::RenderPlaneAsUniform;
use super::{Material, PropertyChanged, MaterialTransparency, ProgramSettings, Shader, ToGlinShaderPrecision};
fn create_buffers(gl: &gl::Renderer, buffer_size: Vec2<u32>, msaa_samples: u32) -> (gl::Fbo, gl::Fbo) {
let fbo_reflection;
let fbo_refraction;
if msaa_samples == 0 {
fbo_reflection = gl.new_fbo().from_color_depth(
gl.new_fbo_color_attachment()
.texture(buffer_size.x, buffer_size.y, gl::fbo::ColorFormat::RGBA16F)
.unwrap(),
gl.new_fbo_depth_attachment()
.render_buffer(buffer_size.x, buffer_size.y, gl::fbo::DepthFormat::_24)
.unwrap(),
).unwrap();
fbo_refraction = gl.new_fbo().from_color_depth(
gl.new_fbo_color_attachment()
.texture(buffer_size.x, buffer_size.y, gl::fbo::ColorFormat::RGBA16F)
.unwrap(),
gl.new_fbo_depth_attachment()
.texture(buffer_size.x, buffer_size.y, gl::fbo::DepthFormat::_24)
.unwrap(),
).unwrap();
}else{
#[cfg(not(any(feature="gles", feature="webgl")))]
{
fbo_reflection = gl.new_fbo().from_color_depth(
gl.new_fbo_color_attachment()
.texture_multisampled(buffer_size.x, buffer_size.y, msaa_samples, gl::fbo::ColorFormat::RGBA16F)
.unwrap(),
gl.new_fbo_depth_attachment()
.render_buffer_multisampled(buffer_size.x, buffer_size.y, msaa_samples, gl::fbo::DepthFormat::_24)
.unwrap(),
).unwrap();
fbo_refraction = gl.new_fbo().from_color_depth(
gl.new_fbo_color_attachment()
.texture_multisampled(buffer_size.x, buffer_size.y, msaa_samples, gl::fbo::ColorFormat::RGBA16F)
.unwrap(),
gl.new_fbo_depth_attachment()
.texture_multisampled(buffer_size.x, buffer_size.y, msaa_samples, gl::fbo::DepthFormat::_24)
.unwrap(),
).unwrap();
}
#[cfg(any(feature="webgl", feature="gles"))]
unimplemented!("WebGL / GLES don't support multisampled textures ")
}
(fbo_reflection, fbo_refraction)
}
#[creation_system(name = "water gpu upload")]
#[needs("ParametersSend", "RenderPlane")]
#[creates("GpuRenderPlane")]
pub fn upload_gpu_resources(mut entities: EntitiesCreation, resources: ResourcesCreation) {
let gl = resources.get::<gl::Renderer<'static>>().unwrap();
let to_add = entities
.iter_for::<(Entity, Read<ParametersSend>, ReadNot<RenderPlane, GpuRenderPlane>)>()
.map(|(entity, parameters, renderplanes)| {
let mut refl_render_sampler = gl.new_sampler();
refl_render_sampler.set_min_mag_filters(gl::LINEAR, gl::LINEAR);
refl_render_sampler.set_wrap_s(gl::REPEAT);
refl_render_sampler.set_wrap_t(gl::REPEAT);
let mut refr_render_sampler = gl.new_sampler();
refr_render_sampler.set_min_mag_filters(gl::LINEAR, gl::LINEAR);
refr_render_sampler.set_wrap_s(gl::REPEAT);
refr_render_sampler.set_wrap_t(gl::REPEAT);
if let [reflection, refraction] = &*renderplanes{
let (fbo_reflection, fbo_refraction) = create_buffers(&gl, parameters.buffer_size, parameters.msaa_samples);
let reflection_camera_ubo = gl.new_buffer()
.from_data_target(
&[reflection.camera_matrices().data()],
gl::STATIC_DRAW,
gl::UNIFORM_BUFFER)
.unwrap();
let refraction_camera_ubo = gl.new_buffer()
.from_data_target(
&[refraction.camera_matrices().data()],
gl::STATIC_DRAW,
gl::UNIFORM_BUFFER)
.unwrap();
let reflection = GpuRenderPlane{
fbo: fbo_reflection,
camera_ubo: reflection_camera_ubo,
render_sampler: Some(refl_render_sampler),
};
let refraction = GpuRenderPlane{
fbo: fbo_refraction,
camera_ubo: refraction_camera_ubo,
render_sampler: Some(refr_render_sampler),
};
(entity, reflection, refraction)
}else{
unreachable!()
}
}).collect::<Vec<_>>();
for (entity, reflection, refraction) in to_add {
entities.add_slice_component_to_thread_local(&entity, vec![reflection, refraction]);
}
let iter = entities.iter_for_mut::<(
Read<ParametersSend>,
Read<RenderPlane>,
Write<GpuRenderPlane>)>();
for (parameters, renderplanes, mut gpu_renderplanes) in iter {
if let [reflection, refraction] = &*renderplanes {
if let [gpu_reflection, gpu_refraction] = &mut *gpu_renderplanes {
let (w,h) = gpu_reflection.fbo.size();
let current_size = vec2(w,h);
if parameters.buffer_size != current_size {
log::trace!("Resizing renderplane gpu buffers {}x{} -> {}x{}",
gpu_reflection.fbo.width(), gpu_reflection.fbo.height(),
parameters.buffer_size.x, parameters.buffer_size.y);
let (fbo_reflection, fbo_refraction) = create_buffers(&gl, parameters.buffer_size, parameters.msaa_samples);
gpu_reflection.fbo = fbo_reflection;
gpu_refraction.fbo = fbo_refraction;
}
if reflection.has_changed() || refraction.has_changed() {
gpu_reflection.camera_ubo.update(&[reflection.camera_matrices().data()]);
gpu_refraction.camera_ubo.update(&[refraction.camera_matrices().data()]);
}
}
}
}
}
impl water::Parameters{
fn to_data(&self) -> Data{
let mut data = Data::with_capacity(16 * mem::size_of::<f32>());
let mut water_data = data.start_struct();
water_data.push(*self.frequency.get());
water_data.push(*self.wave_strength.get());
water_data.push(*self.speed.get());
water_data.push(*self.reflective_factor.get());
water_data.push(*self.normal_scale.get());
water_data.push(*self.max_visible_depth.get());
water_data.push(*self.water_density.get());
water_data.push(*self.refraction_color_mix.get());
water_data.push(*self.water_color_tint.get());
water_data.push(*self.reflection_color_mix.get());
water_data.push(*self.water_color_coefficient.get());
water_data.push(*self.highlights_factor.get());
water_data.push(*self.highlights_power.get());
water_data.finish();
data
}
}
impl Material for WaterMaterial{
fn data(&self) -> PropertyChanged<Option<Data>>{
if self.parameters_changed() {
PropertyChanged::New(Some(self.parameters.to_data()))
}else{
PropertyChanged::Old
}
}
fn render_planes(&self) -> PropertyChanged<Option<(rinecs::Entity, &[RenderPlaneAsUniform])>>{
if self.buffers_changed(){
PropertyChanged::New(Some((self.entity(), &[
RenderPlaneAsUniform{
color: Some("reflection_texture"),
depth: None,
},
RenderPlaneAsUniform{
color: Some("refraction_texture"),
depth: Some("refraction_depth_texture")
}
])))
}else{
PropertyChanged::Old
}
}
fn properties(&self) -> PropertyChanged<Vec<glin::Property>>{
PropertyChanged::Always(vec![
gl::Property::Blend(true),
gl::Property::BlendFunc(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA),
gl::Property::CullFace(Some(gl::BACK)),
gl::Property::DepthMask(false),
])
}
fn transparency(&self) -> PropertyChanged<MaterialTransparency>{
PropertyChanged::Always(MaterialTransparency{
alpha_type: AlphaType::Blending,
is_translucent: true,
is_visible: true,
priority: self.priority(),
})
}
fn shaders(&self) -> PropertyChanged<Vec<Shader>>{
PropertyChanged::Always(vec![
gl::vertex_shader!("shaders/water.vs.glsl"),
gl::fragment_shader!("shaders/water.fs.glsl")
])
}
fn program_settings(&self) -> PropertyChanged<ProgramSettings>{
if self.msaa_samples.has_changed()
|| self.lighting_parameters_changed()
|| self.shader_precision_changed()
{
PropertyChanged::New(ProgramSettings{
defines: vec![
(
"MSAA_SAMPLES".to_owned(),
self.msaa_samples.get().to_string()
),
(
"RECEIVES_SHADOWS".to_owned(),
(*self.parameters.receives_shadows.get() as u8).to_string()
),
(
"RECEIVES_GLOBAL_ILLUMINATION".to_owned(),
(*self.parameters.receives_global_illumination.get() as u8).to_string()
),
(
"NEEDS_IBL_BRDF".to_owned(),
"1".to_owned(),
)
],
precision: self.parameters.shader_precision.get()
.to_material_shader_precision()
.to_glin(),
.. Default::default()
})
}else{
PropertyChanged::Old
}
}
}