fyroxed_base 0.16.0

A scene editor for Fyrox game engine
Documentation
use fyrox::core::sstorage::ImmutableString;
use fyrox::renderer::framework::framebuffer::BlendParameters;
use fyrox::renderer::framework::geometry_buffer::{GeometryBuffer, GeometryBufferKind};
use fyrox::renderer::framework::state::{BlendFactor, BlendFunc};
use fyrox::{
    core::{algebra::Matrix4, math::Matrix4Ext},
    renderer::{
        framework::{
            error::FrameworkError,
            framebuffer::DrawParameters,
            gpu_program::{GpuProgram, UniformLocation},
            state::PipelineState,
        },
        RenderPassStatistics, SceneRenderPass, SceneRenderPassContext,
    },
    resource::texture::{CompressionOptions, Texture},
    scene::mesh::surface::SurfaceData,
};
use std::cell::RefCell;
use std::rc::Rc;

struct OverlayShader {
    program: GpuProgram,
    view_projection_matrix: UniformLocation,
    world_matrix: UniformLocation,
    camera_side_vector: UniformLocation,
    camera_up_vector: UniformLocation,
    diffuse_texture: UniformLocation,
    size: UniformLocation,
}

impl OverlayShader {
    pub fn new(state: &mut PipelineState) -> Result<Self, FrameworkError> {
        let fragment_source = include_str!("../resources/embed/shaders/overlay_fs.glsl");
        let vertex_source = include_str!("../resources/embed/shaders/overlay_vs.glsl");
        let program =
            GpuProgram::from_source(state, "OverlayShader", vertex_source, fragment_source)?;
        Ok(Self {
            view_projection_matrix: program
                .uniform_location(state, &ImmutableString::new("viewProjectionMatrix"))?,
            world_matrix: program.uniform_location(state, &ImmutableString::new("worldMatrix"))?,
            camera_side_vector: program
                .uniform_location(state, &ImmutableString::new("cameraSideVector"))?,
            camera_up_vector: program
                .uniform_location(state, &ImmutableString::new("cameraUpVector"))?,
            size: program.uniform_location(state, &ImmutableString::new("size"))?,
            diffuse_texture: program
                .uniform_location(state, &ImmutableString::new("diffuseTexture"))?,
            program,
        })
    }
}

pub struct OverlayRenderPass {
    quad: GeometryBuffer,
    shader: OverlayShader,
    sound_icon: Texture,
    light_icon: Texture,
}

impl OverlayRenderPass {
    pub fn new(state: &mut PipelineState) -> Rc<RefCell<Self>> {
        Rc::new(RefCell::new(Self {
            quad: GeometryBuffer::from_surface_data(
                &SurfaceData::make_collapsed_xy_quad(),
                GeometryBufferKind::StaticDraw,
                state,
            ),
            shader: OverlayShader::new(state).unwrap(),
            sound_icon: Texture::load_from_memory(
                include_bytes!("../resources/embed/sound_source.png"),
                CompressionOptions::NoCompression,
                false,
            )
            .unwrap(),
            light_icon: Texture::load_from_memory(
                include_bytes!("../resources/embed/light_source.png"),
                CompressionOptions::NoCompression,
                false,
            )
            .unwrap(),
        }))
    }
}

impl SceneRenderPass for OverlayRenderPass {
    fn on_hdr_render(
        &mut self,
        ctx: SceneRenderPassContext,
    ) -> Result<RenderPassStatistics, FrameworkError> {
        let view_projection = ctx.camera.view_projection_matrix();
        let shader = &self.shader;
        let inv_view = ctx.camera.inv_view_matrix().unwrap();
        let camera_up = -inv_view.up();
        let camera_side = inv_view.side();
        let sound_icon = ctx
            .texture_cache
            .get(ctx.pipeline_state, &self.sound_icon)
            .unwrap();
        let light_icon = ctx
            .texture_cache
            .get(ctx.pipeline_state, &self.light_icon)
            .unwrap();

        for node in ctx.scene.graph.linear_iter() {
            let icon =
                if node.is_directional_light() || node.is_spot_light() || node.is_point_light() {
                    light_icon.clone()
                } else if node.is_sound() {
                    sound_icon.clone()
                } else {
                    continue;
                };

            let position = node.global_position();
            let world_matrix = Matrix4::new_translation(&position);

            ctx.framebuffer.draw(
                &self.quad,
                ctx.pipeline_state,
                ctx.viewport,
                &shader.program,
                &DrawParameters {
                    cull_face: None,
                    color_write: Default::default(),
                    depth_write: false,
                    stencil_test: None,
                    depth_test: true,
                    blend: Some(BlendParameters {
                        func: BlendFunc::new(BlendFactor::SrcAlpha, BlendFactor::OneMinusSrcAlpha),
                        ..Default::default()
                    }),
                    stencil_op: Default::default(),
                },
                |mut program_binding| {
                    program_binding
                        .set_matrix4(&shader.view_projection_matrix, &view_projection)
                        .set_matrix4(&shader.world_matrix, &world_matrix)
                        .set_vector3(&shader.camera_side_vector, &camera_side)
                        .set_vector3(&shader.camera_up_vector, &camera_up)
                        .set_f32(&shader.size, 0.33)
                        .set_texture(&shader.diffuse_texture, &icon);
                },
            );
        }

        Ok(Default::default())
    }
}