extern crate kiss3d;
extern crate nalgebra as na;
use kiss3d::camera::Camera;
use kiss3d::context::Context;
use kiss3d::planar_camera::PlanarCamera;
use kiss3d::post_processing::PostProcessingEffect;
use kiss3d::renderer::Renderer;
use kiss3d::resource::{
AllocationType, BufferType, Effect, GPUVec, ShaderAttribute, ShaderUniform,
};
use kiss3d::text::Font;
use kiss3d::window::{State, Window};
use na::{Matrix4, Point2, Point3, Vector3};
struct AppState {
point_cloud_renderer: PointCloudRenderer,
}
impl State for AppState {
fn cameras_and_effect_and_renderer(
&mut self,
) -> (
Option<&mut dyn Camera>,
Option<&mut dyn PlanarCamera>,
Option<&mut dyn Renderer>,
Option<&mut dyn PostProcessingEffect>,
) {
(None, None, Some(&mut self.point_cloud_renderer), None)
}
fn step(&mut self, window: &mut Window) {
if self.point_cloud_renderer.num_points() < 1_000_000 {
for _ in 0..1_000 {
let random: Point3<f32> = rand::random();
self.point_cloud_renderer
.push((random - Vector3::repeat(0.5)) * 0.5, rand::random());
}
}
let num_points_text = format!(
"Number of points: {}",
self.point_cloud_renderer.num_points()
);
window.draw_text(
&num_points_text,
&Point2::new(0.0, 20.0),
60.0,
&Font::default(),
&Point3::new(1.0, 1.0, 1.0),
);
}
}
fn main() {
let window = Window::new("Kiss3d: persistent_point_cloud");
let app = AppState {
point_cloud_renderer: PointCloudRenderer::new(4.0),
};
window.render_loop(app)
}
struct PointCloudRenderer {
shader: Effect,
pos: ShaderAttribute<Point3<f32>>,
color: ShaderAttribute<Point3<f32>>,
proj: ShaderUniform<Matrix4<f32>>,
view: ShaderUniform<Matrix4<f32>>,
colored_points: GPUVec<Point3<f32>>,
point_size: f32,
}
impl PointCloudRenderer {
fn new(point_size: f32) -> PointCloudRenderer {
let mut shader = Effect::new_from_str(VERTEX_SHADER_SRC, FRAGMENT_SHADER_SRC);
shader.use_program();
PointCloudRenderer {
colored_points: GPUVec::new(Vec::new(), BufferType::Array, AllocationType::StreamDraw),
pos: shader.get_attrib::<Point3<f32>>("position").unwrap(),
color: shader.get_attrib::<Point3<f32>>("color").unwrap(),
proj: shader.get_uniform::<Matrix4<f32>>("proj").unwrap(),
view: shader.get_uniform::<Matrix4<f32>>("view").unwrap(),
shader,
point_size,
}
}
fn push(&mut self, point: Point3<f32>, color: Point3<f32>) {
if let Some(colored_points) = self.colored_points.data_mut() {
colored_points.push(point);
colored_points.push(color);
}
}
fn num_points(&self) -> usize {
self.colored_points.len() / 2
}
}
impl Renderer for PointCloudRenderer {
fn render(&mut self, pass: usize, camera: &mut dyn Camera) {
if self.colored_points.len() == 0 {
return;
}
self.shader.use_program();
self.pos.enable();
self.color.enable();
camera.upload(pass, &mut self.proj, &mut self.view);
self.color.bind_sub_buffer(&mut self.colored_points, 1, 1);
self.pos.bind_sub_buffer(&mut self.colored_points, 1, 0);
let ctxt = Context::get();
ctxt.point_size(self.point_size);
ctxt.draw_arrays(Context::POINTS, 0, (self.colored_points.len() / 2) as i32);
self.pos.disable();
self.color.disable();
}
}
const VERTEX_SHADER_SRC: &'static str = "#version 100
attribute vec3 position;
attribute vec3 color;
varying vec3 Color;
uniform mat4 proj;
uniform mat4 view;
void main() {
gl_Position = proj * view * vec4(position, 1.0);
Color = color;
}";
const FRAGMENT_SHADER_SRC: &'static str = "#version 100
#ifdef GL_FRAGMENT_PRECISION_HIGH
precision highp float;
#else
precision mediump float;
#endif
varying vec3 Color;
void main() {
gl_FragColor = vec4(Color, 1.0);
}";