fyroxed_base 1.0.0

A scene editor for Fyrox game engine
Documentation
// Copyright (c) 2019-present Dmitry Stepanov and Fyrox Engine contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

use crate::{
    fyrox::{
        asset::untyped::ResourceKind,
        core::{algebra::Matrix4, math::Matrix4Ext, pool::Handle, sstorage::ImmutableString, Uuid},
        graphics::{
            buffer::BufferUsage, error::FrameworkError, geometry_buffer::GpuGeometryBuffer,
            server::GraphicsServer,
        },
        renderer::{
            cache::shader::{
                binding, property, PropertyGroup, RenderMaterial, RenderPassContainer,
            },
            framework::GeometryBufferExt,
            RenderPassStatistics, SceneRenderPass, SceneRenderPassContext,
        },
        resource::texture::{
            CompressionOptions, TextureImportOptions, TextureMinificationFilter, TextureResource,
            TextureResourceExtension,
        },
        scene::{mesh::surface::SurfaceData, Scene},
    },
    Editor,
};
use std::{any::TypeId, cell::RefCell, rc::Rc};

pub struct OverlayRenderPass {
    quad: GpuGeometryBuffer,
    shader: RenderPassContainer,
    sound_icon: TextureResource,
    light_icon: TextureResource,
    pub pictogram_size: f32,
    pub scene_handle: Handle<Scene>,
}

impl OverlayRenderPass {
    pub fn new(server: &dyn GraphicsServer) -> Rc<RefCell<Self>> {
        Rc::new(RefCell::new(Self {
            quad: GpuGeometryBuffer::from_surface_data(
                "Quad",
                &SurfaceData::make_collapsed_xy_quad(),
                BufferUsage::StaticDraw,
                server,
            )
            .unwrap(),
            shader: RenderPassContainer::from_str(
                server,
                include_str!("../resources/shaders/overlay.shader"),
            )
            .unwrap(),
            sound_icon: TextureResource::load_from_memory(
                Uuid::new_v4(),
                ResourceKind::Embedded,
                include_bytes!("../resources/sound_source.png"),
                TextureImportOptions::default()
                    .with_compression(CompressionOptions::NoCompression)
                    .with_minification_filter(TextureMinificationFilter::Linear),
            )
            .unwrap(),
            light_icon: TextureResource::load_from_memory(
                Uuid::new_v4(),
                ResourceKind::Embedded,
                include_bytes!("../resources/light_source.png"),
                TextureImportOptions::default()
                    .with_compression(CompressionOptions::NoCompression)
                    .with_minification_filter(TextureMinificationFilter::Linear),
            )
            .unwrap(),
            pictogram_size: 0.33,
            scene_handle: Default::default(),
        }))
    }
}

impl SceneRenderPass for OverlayRenderPass {
    fn on_hdr_render(
        &mut self,
        ctx: SceneRenderPassContext,
    ) -> Result<RenderPassStatistics, FrameworkError> {
        let mut stats = RenderPassStatistics::default();
        if ctx.scene_handle != self.scene_handle {
            return Ok(stats);
        }

        let view_projection = ctx.observer.position.view_projection_matrix;
        let inv_view = ctx.observer.position.view_matrix.try_inverse().unwrap();
        let camera_up = -inv_view.up();
        let camera_side = inv_view.side();
        let sound_icon = ctx
            .texture_cache
            .get(ctx.server, ctx.resource_manager, &self.sound_icon)
            .cloned()
            .unwrap();
        let light_icon = ctx
            .texture_cache
            .get(ctx.server, ctx.resource_manager, &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);

            let properties = PropertyGroup::from([
                property("viewProjectionMatrix", &view_projection),
                property("worldMatrix", &world_matrix),
                property("cameraSideVector", &camera_side),
                property("cameraUpVector", &camera_up),
                property("size", &self.pictogram_size),
            ]);
            let material = RenderMaterial::from([
                binding("diffuseTexture", (&icon.gpu_texture, &icon.gpu_sampler)),
                binding("properties", &properties),
            ]);

            stats += self.shader.run_pass(
                1,
                &ImmutableString::new("Primary"),
                ctx.framebuffer,
                &self.quad,
                ctx.observer.viewport,
                &material,
                ctx.uniform_buffer_cache,
                Default::default(),
                None,
            )?;
        }

        Ok(stats)
    }

    fn source_type_id(&self) -> TypeId {
        TypeId::of::<Editor>()
    }
}