mirror of
https://github.com/FyroxEngine/Fyrox.git
synced 2026-10-12 02:02:20 +00:00
added shadows, graphics quality, minor refactoring
This commit is contained in:
Generated
+64
-1
@@ -7,8 +7,56 @@
|
||||
<list default="true" id="1932b2c4-d6ff-413c-9558-19959667326b" name="Default Changelist" comment="scene graph">
|
||||
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/Cargo.lock" beforeDir="false" afterPath="$PROJECT_DIR$/Cargo.lock" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/Cargo.toml" beforeDir="false" afterPath="$PROJECT_DIR$/Cargo.toml" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/rg3d.iml" beforeDir="false" afterPath="$PROJECT_DIR$/rg3d.iml" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/engine/mod.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/engine/mod.rs" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/gui/event.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/gui/event.rs" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/gui/grid.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/gui/grid.rs" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/gui/list_box.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/gui/list_box.rs" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/gui/mod.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/gui/mod.rs" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/gui/scroll_viewer.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/gui/scroll_viewer.rs" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/gui/window.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/gui/window.rs" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/lib.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/lib.rs" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/renderer/deferred_light_renderer.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/renderer/deferred_light_renderer.rs" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/renderer/error.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/renderer/error.rs" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/renderer/gbuffer.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/renderer/gbuffer.rs" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/renderer/geometry_buffer.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/renderer/geometry_buffer.rs" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/renderer/gpu_program.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/renderer/gpu_program.rs" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/renderer/mod.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/renderer/mod.rs" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/renderer/particle_system_renderer.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/renderer/particle_system_renderer.rs" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/renderer/shaders/ambient_light_fs.glsl" beforeDir="false" afterPath="$PROJECT_DIR$/src/renderer/shaders/ambient_light_fs.glsl" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/renderer/shaders/ambient_light_vs.glsl" beforeDir="false" afterPath="$PROJECT_DIR$/src/renderer/shaders/ambient_light_vs.glsl" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/renderer/shaders/deferred_light_fs.glsl" beforeDir="false" afterPath="$PROJECT_DIR$/src/renderer/shaders/deferred_light_fs.glsl" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/renderer/shaders/deferred_light_vs.glsl" beforeDir="false" afterPath="$PROJECT_DIR$/src/renderer/shaders/deferred_light_vs.glsl" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/renderer/shaders/flat_fs.glsl" beforeDir="false" afterPath="$PROJECT_DIR$/src/renderer/shaders/flat_fs.glsl" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/renderer/shaders/flat_vs.glsl" beforeDir="false" afterPath="$PROJECT_DIR$/src/renderer/shaders/flat_vs.glsl" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/renderer/shaders/gbuffer_fs.glsl" beforeDir="false" afterPath="$PROJECT_DIR$/src/renderer/shaders/gbuffer_fs.glsl" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/renderer/shaders/gbuffer_vs.glsl" beforeDir="false" afterPath="$PROJECT_DIR$/src/renderer/shaders/gbuffer_vs.glsl" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/renderer/shaders/particle_system_fs.glsl" beforeDir="false" afterPath="$PROJECT_DIR$/src/renderer/shaders/particle_system_fs.glsl" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/renderer/shaders/particle_system_vs.glsl" beforeDir="false" afterPath="$PROJECT_DIR$/src/renderer/shaders/particle_system_vs.glsl" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/renderer/shaders/point_shadow_map_fs.glsl" beforeDir="false" afterPath="$PROJECT_DIR$/src/renderer/shaders/point_shadow_map_fs.glsl" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/renderer/shaders/point_shadow_map_vs.glsl" beforeDir="false" afterPath="$PROJECT_DIR$/src/renderer/shaders/point_shadow_map_vs.glsl" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/renderer/shaders/spot_shadow_map_fs.glsl" beforeDir="false" afterPath="$PROJECT_DIR$/src/renderer/shaders/spot_shadow_map_fs.glsl" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/renderer/shaders/spot_shadow_map_vs.glsl" beforeDir="false" afterPath="$PROJECT_DIR$/src/renderer/shaders/spot_shadow_map_vs.glsl" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/renderer/shaders/sprite_fs.glsl" beforeDir="false" afterPath="$PROJECT_DIR$/src/renderer/shaders/sprite_fs.glsl" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/renderer/shaders/sprite_vs.glsl" beforeDir="false" afterPath="$PROJECT_DIR$/src/renderer/shaders/sprite_vs.glsl" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/renderer/shaders/ui_fs.glsl" beforeDir="false" afterPath="$PROJECT_DIR$/src/renderer/shaders/ui_fs.glsl" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/renderer/shaders/ui_vs.glsl" beforeDir="false" afterPath="$PROJECT_DIR$/src/renderer/shaders/ui_vs.glsl" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/renderer/shadow_map_renderer.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/renderer/shadow_map_renderer.rs" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/renderer/sprite_renderer.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/renderer/sprite_renderer.rs" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/renderer/surface.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/renderer/surface.rs" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/renderer/ui_renderer.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/renderer/ui_renderer.rs" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/resource/fbx/mod.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/resource/fbx/mod.rs" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/resource/fbx/texture.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/resource/fbx/texture.rs" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/resource/texture.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/resource/texture.rs" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/resource/ttf.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/resource/ttf.rs" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/scene/base.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/scene/base.rs" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/scene/camera.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/scene/camera.rs" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/scene/graph.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/scene/graph.rs" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/scene/light.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/scene/light.rs" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/scene/mesh.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/scene/mesh.rs" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/scene/particle_system.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/scene/particle_system.rs" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/scene/sprite.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/scene/sprite.rs" afterDir="false" />
|
||||
</list>
|
||||
<option name="EXCLUDED_CONVERTED_TO_IGNORED" value="true" />
|
||||
<option name="SHOW_DIALOG" value="false" />
|
||||
@@ -63,7 +111,7 @@
|
||||
</list>
|
||||
</option>
|
||||
</component>
|
||||
<component name="RunManager" selected="Cargo Command.Release">
|
||||
<component name="RunManager" selected="Cargo Command.Clippy">
|
||||
<configuration name="Clippy" type="CargoCommandRunConfiguration" factoryName="Cargo Command">
|
||||
<option name="channel" value="DEFAULT" />
|
||||
<option name="command" value="clippy" />
|
||||
@@ -103,6 +151,19 @@
|
||||
<option name="CARGO.BUILD_TASK_PROVIDER" enabled="true" />
|
||||
</method>
|
||||
</configuration>
|
||||
<configuration name="Run window" type="CargoCommandRunConfiguration" factoryName="Cargo Command" temporary="true">
|
||||
<option name="channel" value="DEFAULT" />
|
||||
<option name="command" value="run --package rg3d --example window" />
|
||||
<option name="allFeatures" value="false" />
|
||||
<option name="nocapture" value="false" />
|
||||
<option name="emulateTerminal" value="false" />
|
||||
<option name="backtrace" value="SHORT" />
|
||||
<option name="workingDirectory" value="file://$PROJECT_DIR$" />
|
||||
<envs />
|
||||
<method v="2">
|
||||
<option name="CARGO.BUILD_TASK_PROVIDER" enabled="true" />
|
||||
</method>
|
||||
</configuration>
|
||||
<configuration name="Test" type="CargoCommandRunConfiguration" factoryName="Cargo Command">
|
||||
<option name="channel" value="DEFAULT" />
|
||||
<option name="command" value="test" />
|
||||
@@ -121,9 +182,11 @@
|
||||
<item itemvalue="Cargo Command.Release" />
|
||||
<item itemvalue="Cargo Command.Test" />
|
||||
<item itemvalue="Cargo Command.Debug" />
|
||||
<item itemvalue="Cargo Command.Run window" />
|
||||
</list>
|
||||
<recent_temporary>
|
||||
<list>
|
||||
<item itemvalue="Cargo Command.Run window" />
|
||||
<item itemvalue="Cargo Command.Debug" />
|
||||
</list>
|
||||
</recent_temporary>
|
||||
|
||||
Generated
+5
-5
@@ -992,7 +992,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "rg3d"
|
||||
version = "0.3.1"
|
||||
version = "0.3.2"
|
||||
dependencies = [
|
||||
"byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"glutin 0.22.0-alpha3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -1001,14 +1001,14 @@ dependencies = [
|
||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lexical 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rg3d-core 0.1.9",
|
||||
"rg3d-core 0.2.0",
|
||||
"rg3d-physics 0.1.7",
|
||||
"rg3d-sound 0.2.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rg3d-core"
|
||||
version = "0.1.9"
|
||||
version = "0.2.0"
|
||||
dependencies = [
|
||||
"base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -1020,7 +1020,7 @@ name = "rg3d-physics"
|
||||
version = "0.1.7"
|
||||
dependencies = [
|
||||
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rg3d-core 0.1.9",
|
||||
"rg3d-core 0.2.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1029,7 +1029,7 @@ version = "0.2.0"
|
||||
dependencies = [
|
||||
"alsa-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rg3d-core 0.1.9",
|
||||
"rg3d-core 0.2.0",
|
||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "rg3d"
|
||||
version = "0.3.1"
|
||||
version = "0.3.2"
|
||||
authors = ["Dmitry Stepanov <[email protected]>"]
|
||||
edition = "2018"
|
||||
license = "MIT"
|
||||
@@ -16,7 +16,7 @@ opt-level = 0
|
||||
opt-level = 3
|
||||
|
||||
[dependencies]
|
||||
rg3d-core = { path = "../rg3d-core", version = "0.1.9" }
|
||||
rg3d-core = { path = "../rg3d-core", version = "0.2.0" }
|
||||
rg3d-sound = { path = "../rg3d-sound", version = "0.2.0" }
|
||||
rg3d-physics = { path = "../rg3d-physics", version = "0.1.7" }
|
||||
glutin = "0.22.0-alpha3"
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
extern crate rg3d;
|
||||
|
||||
use rg3d::{
|
||||
event::{Event, WindowEvent},
|
||||
event_loop::{EventLoop, ControlFlow},
|
||||
engine::Engine
|
||||
};
|
||||
use std::time::Instant;
|
||||
use rg3d_core::color::Color;
|
||||
|
||||
fn main() {
|
||||
let event_loop = EventLoop::new();
|
||||
|
||||
let window_builder = rg3d::window::WindowBuilder::new()
|
||||
.with_title("Example 01: Model")
|
||||
.with_resizable(true);
|
||||
|
||||
let mut engine = Engine::new(window_builder, &event_loop).unwrap();
|
||||
|
||||
engine.interface_mut().renderer.set_ambient_color(Color::opaque(100, 100, 200));
|
||||
|
||||
let clock = Instant::now();
|
||||
let fixed_timestep = 1.0 / 60.0;
|
||||
let mut elapsed_time = 0.0;
|
||||
|
||||
event_loop.run(move |event, _, control_flow| {
|
||||
match event {
|
||||
Event::EventsCleared => {
|
||||
let mut dt = clock.elapsed().as_secs_f64() - elapsed_time;
|
||||
while dt >= fixed_timestep as f64 {
|
||||
dt -= fixed_timestep as f64;
|
||||
elapsed_time += fixed_timestep as f64;
|
||||
|
||||
engine.update(fixed_timestep);
|
||||
}
|
||||
engine.get_window().request_redraw();
|
||||
}
|
||||
Event::WindowEvent { event, .. } => {
|
||||
match event {
|
||||
WindowEvent::RedrawRequested => {
|
||||
engine.render().unwrap();
|
||||
}
|
||||
WindowEvent::CloseRequested => {
|
||||
*control_flow = ControlFlow::Exit
|
||||
}
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
_ => *control_flow = ControlFlow::Poll,
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -10,7 +10,6 @@
|
||||
<sourceFolder url="file://C:/rg3d\examples" isTestSource="false" />
|
||||
<sourceFolder url="file://C:/rg3d\tests" isTestSource="true" />
|
||||
<sourceFolder url="file://C:/rg3d\benches" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/../rg3d\examples" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/../rg3d\tests" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/../rg3d\benches" isTestSource="true" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/target" />
|
||||
|
||||
@@ -68,6 +68,7 @@ impl Engine {
|
||||
let context_wrapper: WindowedContext<NotCurrent> = glutin::ContextBuilder::new()
|
||||
.with_vsync(true)
|
||||
.with_gl_profile(GlProfile::Core)
|
||||
.with_gl_debug_flag(true)
|
||||
.with_gl(GlRequest::Specific(Api::OpenGl, (3, 3)))
|
||||
.build_windowed(window_builder, events_loop)?;
|
||||
|
||||
|
||||
@@ -66,14 +66,19 @@ pub enum UIEventKind {
|
||||
new_value: f32,
|
||||
},
|
||||
|
||||
/// Generated by any widget that has max numeric value (scroll bar for example).
|
||||
MaxValueChanged(f32),
|
||||
|
||||
/// Generated by any widget that has min numeric value (scroll bar for example).
|
||||
MinValueChanged(f32),
|
||||
|
||||
/// Generated by any ItemsControl that has selection behaviour.
|
||||
SelectionChanged(Option<usize>),
|
||||
|
||||
/// Generated by opened window.
|
||||
Opened,
|
||||
|
||||
/// Generated by closed window.
|
||||
Closed,
|
||||
|
||||
/// Widget just got keyboard focus.
|
||||
@@ -82,8 +87,16 @@ pub enum UIEventKind {
|
||||
/// Widget lost keyboard focus.
|
||||
LostFocus,
|
||||
|
||||
/// Generated by window that has become minimized.
|
||||
Minimized(bool),
|
||||
|
||||
/// Generated by window that has changed its ability to minimize.
|
||||
CanMinimizeChanged(bool),
|
||||
|
||||
/// Generated by window that has changed its ability to close.
|
||||
CanCloseChanged(bool),
|
||||
|
||||
/// Generated by checkbox that has changed its checked state.
|
||||
Checked(Option<bool>),
|
||||
|
||||
/// Any kind of user-defined event.
|
||||
|
||||
+131
-109
@@ -157,117 +157,14 @@ impl Layout for Grid {
|
||||
}
|
||||
|
||||
// Step 2. Calculate width of columns and heights of rows.
|
||||
let mut preset_width = 0.0;
|
||||
let mut preset_height = 0.0;
|
||||
let preset_width = self.calculate_preset_width(ui);
|
||||
let preset_height = self.calculate_preset_height(ui);
|
||||
|
||||
// Step 2.1. Calculate size of strict-sized and auto-sized columns.
|
||||
for (i, col) in self.columns.borrow_mut().iter_mut().enumerate() {
|
||||
if col.size_mode == SizeMode::Strict {
|
||||
col.actual_width = col.desired_width;
|
||||
preset_width += col.actual_width;
|
||||
} else if col.size_mode == SizeMode::Auto {
|
||||
col.actual_width = col.desired_width;
|
||||
for child_handle in self.widget.children.iter() {
|
||||
let child = ui.nodes.borrow(*child_handle).widget();
|
||||
if child.column == i && child.visibility == Visibility::Visible && child.desired_size.get().x > col.actual_width {
|
||||
col.actual_width = child.desired_size.get().x;
|
||||
}
|
||||
}
|
||||
preset_width += col.actual_width;
|
||||
}
|
||||
}
|
||||
self.fit_stretch_sized_columns(ui, available_size, preset_width);
|
||||
self.fit_stretch_sized_rows(ui, available_size, preset_height);
|
||||
|
||||
// Step 2.2. Calculate size of strict-sized and auto-sized rows.
|
||||
for (i, row) in self.rows.borrow_mut().iter_mut().enumerate() {
|
||||
if row.size_mode == SizeMode::Strict {
|
||||
row.actual_height = row.desired_height;
|
||||
preset_height += row.actual_height;
|
||||
} else if row.size_mode == SizeMode::Auto {
|
||||
row.actual_height = row.desired_height;
|
||||
for child_handle in self.widget.children.iter() {
|
||||
let child = ui.nodes.borrow(*child_handle).widget();
|
||||
if child.row == i && child.visibility == Visibility::Visible && child.desired_size.get().y > row.actual_height {
|
||||
row.actual_height = child.desired_size.get().y;
|
||||
}
|
||||
}
|
||||
preset_height += row.actual_height;
|
||||
}
|
||||
}
|
||||
|
||||
// Step 2.3. Fit stretch-sized columns
|
||||
let mut rest_width = 0.0;
|
||||
if available_size.x.is_infinite() {
|
||||
for child_handle in self.widget.children.iter() {
|
||||
let child = ui.nodes.borrow(*child_handle).widget();
|
||||
if let Some(column) = self.columns.borrow().get(child.column) {
|
||||
if column.size_mode == SizeMode::Stretch {
|
||||
rest_width += child.desired_size.get().x;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
rest_width = available_size.x - preset_width;
|
||||
}
|
||||
|
||||
// count columns first
|
||||
let mut stretch_sized_columns = 0;
|
||||
for column in self.columns.borrow().iter() {
|
||||
if column.size_mode == SizeMode::Stretch {
|
||||
stretch_sized_columns += 1;
|
||||
}
|
||||
}
|
||||
if stretch_sized_columns > 0 {
|
||||
let width_per_col = rest_width / stretch_sized_columns as f32;
|
||||
for column in self.columns.borrow_mut().iter_mut() {
|
||||
if column.size_mode == SizeMode::Stretch {
|
||||
column.actual_width = width_per_col;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Step 2.4. Fit stretch-sized rows.
|
||||
let mut stretch_sized_rows = 0;
|
||||
let mut rest_height = 0.0;
|
||||
if available_size.y.is_infinite() {
|
||||
for child_handle in self.widget.children.iter() {
|
||||
let child = ui.nodes.borrow(*child_handle).widget();
|
||||
if let Some(row) = self.rows.borrow().get(child.row) {
|
||||
if row.size_mode == SizeMode::Stretch {
|
||||
rest_height += child.desired_size.get().y;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
rest_height = available_size.y - preset_height;
|
||||
}
|
||||
// count rows first
|
||||
for row in self.rows.borrow().iter() {
|
||||
if row.size_mode == SizeMode::Stretch {
|
||||
stretch_sized_rows += 1;
|
||||
}
|
||||
}
|
||||
if stretch_sized_rows > 0 {
|
||||
let height_per_row = rest_height / stretch_sized_rows as f32;
|
||||
for row in self.rows.borrow_mut().iter_mut() {
|
||||
if row.size_mode == SizeMode::Stretch {
|
||||
row.actual_height = height_per_row;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Step 2.5. Calculate positions of each column.
|
||||
let mut y = 0.0;
|
||||
for row in self.rows.borrow_mut().iter_mut() {
|
||||
row.y = y;
|
||||
y += row.actual_height;
|
||||
}
|
||||
|
||||
// Step 2.6. Calculate positions of each row.
|
||||
let mut x = 0.0;
|
||||
for column in self.columns.borrow_mut().iter_mut() {
|
||||
column.x = x;
|
||||
x += column.actual_width;
|
||||
}
|
||||
self.arrange_rows();
|
||||
self.arrange_columns();
|
||||
|
||||
// Step 3. Re-measure children with new constraints.
|
||||
for child_handle in self.widget.children.iter() {
|
||||
@@ -380,4 +277,129 @@ impl Grid {
|
||||
self.columns.borrow_mut().push(column);
|
||||
self
|
||||
}
|
||||
|
||||
fn calculate_preset_width(&self, ui: &UserInterface) -> f32 {
|
||||
let mut preset_width = 0.0;
|
||||
|
||||
// Calculate size of strict-sized and auto-sized columns.
|
||||
for (i, col) in self.columns.borrow_mut().iter_mut().enumerate() {
|
||||
if col.size_mode == SizeMode::Strict {
|
||||
col.actual_width = col.desired_width;
|
||||
preset_width += col.actual_width;
|
||||
} else if col.size_mode == SizeMode::Auto {
|
||||
col.actual_width = col.desired_width;
|
||||
for child_handle in self.widget.children.iter() {
|
||||
let child = ui.nodes.borrow(*child_handle).widget();
|
||||
if child.column == i && child.visibility == Visibility::Visible && child.desired_size.get().x > col.actual_width {
|
||||
col.actual_width = child.desired_size.get().x;
|
||||
}
|
||||
}
|
||||
preset_width += col.actual_width;
|
||||
}
|
||||
}
|
||||
|
||||
preset_width
|
||||
}
|
||||
|
||||
fn calculate_preset_height(&self, ui: &UserInterface) -> f32 {
|
||||
let mut preset_height = 0.0;
|
||||
|
||||
// Calculate size of strict-sized and auto-sized rows.
|
||||
for (i, row) in self.rows.borrow_mut().iter_mut().enumerate() {
|
||||
if row.size_mode == SizeMode::Strict {
|
||||
row.actual_height = row.desired_height;
|
||||
preset_height += row.actual_height;
|
||||
} else if row.size_mode == SizeMode::Auto {
|
||||
row.actual_height = row.desired_height;
|
||||
for child_handle in self.widget.children.iter() {
|
||||
let child = ui.nodes.borrow(*child_handle).widget();
|
||||
if child.row == i && child.visibility == Visibility::Visible && child.desired_size.get().y > row.actual_height {
|
||||
row.actual_height = child.desired_size.get().y;
|
||||
}
|
||||
}
|
||||
preset_height += row.actual_height;
|
||||
}
|
||||
}
|
||||
|
||||
preset_height
|
||||
}
|
||||
|
||||
fn fit_stretch_sized_columns(&self, ui: &UserInterface, available_size: Vec2, preset_width: f32) {
|
||||
let mut rest_width = 0.0;
|
||||
if available_size.x.is_infinite() {
|
||||
for child_handle in self.widget.children.iter() {
|
||||
let child = ui.nodes.borrow(*child_handle).widget();
|
||||
if let Some(column) = self.columns.borrow().get(child.column) {
|
||||
if column.size_mode == SizeMode::Stretch {
|
||||
rest_width += child.desired_size.get().x;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
rest_width = available_size.x - preset_width;
|
||||
}
|
||||
|
||||
// count columns first
|
||||
let mut stretch_sized_columns = 0;
|
||||
for column in self.columns.borrow().iter() {
|
||||
if column.size_mode == SizeMode::Stretch {
|
||||
stretch_sized_columns += 1;
|
||||
}
|
||||
}
|
||||
if stretch_sized_columns > 0 {
|
||||
let width_per_col = rest_width / stretch_sized_columns as f32;
|
||||
for column in self.columns.borrow_mut().iter_mut() {
|
||||
if column.size_mode == SizeMode::Stretch {
|
||||
column.actual_width = width_per_col;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn fit_stretch_sized_rows(&self, ui: &UserInterface, available_size: Vec2, preset_height: f32) {
|
||||
let mut stretch_sized_rows = 0;
|
||||
let mut rest_height = 0.0;
|
||||
if available_size.y.is_infinite() {
|
||||
for child_handle in self.widget.children.iter() {
|
||||
let child = ui.nodes.borrow(*child_handle).widget();
|
||||
if let Some(row) = self.rows.borrow().get(child.row) {
|
||||
if row.size_mode == SizeMode::Stretch {
|
||||
rest_height += child.desired_size.get().y;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
rest_height = available_size.y - preset_height;
|
||||
}
|
||||
// count rows first
|
||||
for row in self.rows.borrow().iter() {
|
||||
if row.size_mode == SizeMode::Stretch {
|
||||
stretch_sized_rows += 1;
|
||||
}
|
||||
}
|
||||
if stretch_sized_rows > 0 {
|
||||
let height_per_row = rest_height / stretch_sized_rows as f32;
|
||||
for row in self.rows.borrow_mut().iter_mut() {
|
||||
if row.size_mode == SizeMode::Stretch {
|
||||
row.actual_height = height_per_row;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn arrange_rows(&self) {
|
||||
let mut y = 0.0;
|
||||
for row in self.rows.borrow_mut().iter_mut() {
|
||||
row.y = y;
|
||||
y += row.actual_height;
|
||||
}
|
||||
}
|
||||
|
||||
fn arrange_columns(&self) {
|
||||
let mut x = 0.0;
|
||||
for column in self.columns.borrow_mut().iter_mut() {
|
||||
column.x = x;
|
||||
x += column.actual_width;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+4
-2
@@ -23,7 +23,6 @@ use crate::gui::{
|
||||
|
||||
pub struct ListBox {
|
||||
widget: Widget,
|
||||
panel: Handle<UINode>,
|
||||
selected_index: Option<usize>,
|
||||
items: Vec<Handle<UINode>>,
|
||||
}
|
||||
@@ -46,6 +45,10 @@ impl ListBox {
|
||||
pub fn get_selected(&self) -> Option<usize> {
|
||||
self.selected_index
|
||||
}
|
||||
|
||||
pub fn get_items(&self) -> &[Handle<UINode>] {
|
||||
&self.items
|
||||
}
|
||||
}
|
||||
|
||||
impl AsWidget for ListBox {
|
||||
@@ -162,7 +165,6 @@ impl ListBoxBuilder {
|
||||
.build(ui))
|
||||
.build(),
|
||||
selected_index: None,
|
||||
panel,
|
||||
items,
|
||||
});
|
||||
|
||||
|
||||
+6
-1
@@ -541,6 +541,12 @@ impl UserInterface {
|
||||
}
|
||||
|
||||
fn pick_node(&self, node_handle: Handle<UINode>, pt: Vec2, level: &mut i32) -> Handle<UINode> {
|
||||
let widget = self.nodes.borrow(node_handle).widget();
|
||||
|
||||
if !widget.is_hit_test_visible {
|
||||
return Handle::NONE;
|
||||
}
|
||||
|
||||
let (mut picked, mut topmost_picked_level) =
|
||||
if self.is_node_contains_point(node_handle, pt) {
|
||||
(node_handle, *level)
|
||||
@@ -548,7 +554,6 @@ impl UserInterface {
|
||||
(Handle::NONE, 0)
|
||||
};
|
||||
|
||||
let widget = self.nodes.borrow(node_handle).widget();
|
||||
for child_handle in widget.children.iter() {
|
||||
*level += 1;
|
||||
let picked_child = self.pick_node(*child_handle, pt, level);
|
||||
|
||||
@@ -108,7 +108,7 @@ impl ScrollViewerBuilder {
|
||||
|
||||
scroll_bar.set_max_value(new_value);
|
||||
|
||||
if scroll_bar.get_max_value() == scroll_bar.get_min_value() {
|
||||
if (scroll_bar.get_max_value() - scroll_bar.get_min_value()).abs() <= std::f32::EPSILON {
|
||||
scroll_bar.widget_mut().set_visibility(Visibility::Collapsed)
|
||||
} else {
|
||||
scroll_bar.widget_mut().set_visibility(Visibility::Visible)
|
||||
@@ -130,7 +130,7 @@ impl ScrollViewerBuilder {
|
||||
|
||||
scroll_bar.set_max_value(new_value);
|
||||
|
||||
if scroll_bar.get_max_value() == scroll_bar.get_min_value() {
|
||||
if (scroll_bar.get_max_value() - scroll_bar.get_min_value()).abs() <= std::f32::EPSILON {
|
||||
scroll_bar.widget_mut().set_visibility(Visibility::Collapsed)
|
||||
} else {
|
||||
scroll_bar.widget_mut().set_visibility(Visibility::Visible)
|
||||
|
||||
+71
-31
@@ -3,7 +3,16 @@ use rg3d_core::{
|
||||
pool::Handle,
|
||||
math::vec2::Vec2,
|
||||
};
|
||||
use crate::gui::{event::UIEventKind, border::BorderBuilder, node::UINode, UserInterface, grid::{GridBuilder, Column, Row}, HorizontalAlignment, text::TextBuilder, Thickness, button::ButtonBuilder, scroll_viewer::ScrollViewerBuilder, Layout, widget::{Widget, WidgetBuilder, AsWidget}, Draw, draw::DrawingContext, Update, event::UIEvent, Visibility};
|
||||
use crate::gui::{
|
||||
event::UIEventKind,
|
||||
border::BorderBuilder, node::UINode,
|
||||
UserInterface, grid::{GridBuilder, Column, Row},
|
||||
HorizontalAlignment, text::TextBuilder, Thickness,
|
||||
button::ButtonBuilder, scroll_viewer::ScrollViewerBuilder,
|
||||
Layout, widget::{Widget, WidgetBuilder, AsWidget}, Draw,
|
||||
draw::DrawingContext, Update, event::UIEvent, Visibility,
|
||||
bool_to_visibility,
|
||||
};
|
||||
|
||||
/// Represents a widget looking as window in Windows - with title, minimize and close buttons.
|
||||
/// It has scrollable region for content, content can be any desired node or even other window.
|
||||
@@ -56,6 +65,14 @@ impl Window {
|
||||
pub fn minimize(&mut self, state: bool) {
|
||||
self.widget.events.borrow_mut().push_back(UIEvent::new(UIEventKind::Minimized(state)));
|
||||
}
|
||||
|
||||
pub fn can_close(&mut self, state: bool) {
|
||||
self.widget.events.borrow_mut().push_back(UIEvent::new(UIEventKind::CanCloseChanged(state)));
|
||||
}
|
||||
|
||||
pub fn can_minimize(&mut self, state: bool) {
|
||||
self.widget.events.borrow_mut().push_back(UIEvent::new(UIEventKind::CanMinimizeChanged(state)));
|
||||
}
|
||||
}
|
||||
|
||||
impl Draw for Window {
|
||||
@@ -123,6 +140,9 @@ impl<'a> WindowBuilder<'a> {
|
||||
}
|
||||
|
||||
pub fn build(self, ui: &mut UserInterface) -> Handle<UINode> {
|
||||
let minimize_button;
|
||||
let close_button;
|
||||
|
||||
let header = BorderBuilder::new(WidgetBuilder::new()
|
||||
.with_color(Color::opaque(120, 120, 120))
|
||||
.with_horizontal_alignment(HorizontalAlignment::Stretch)
|
||||
@@ -181,38 +201,44 @@ impl<'a> WindowBuilder<'a> {
|
||||
}
|
||||
}
|
||||
})
|
||||
.with_child(ButtonBuilder::new(WidgetBuilder::new()
|
||||
.on_row(0)
|
||||
.on_column(1)
|
||||
.with_visibility(if self.can_minimize { Visibility::Visible } else { Visibility::Collapsed })
|
||||
.with_event_handler(Box::new(|ui, handle, evt| {
|
||||
if evt.source == handle {
|
||||
if let UIEventKind::Click = evt.kind {
|
||||
let window = ui.borrow_by_criteria_up_mut(handle, |node| node.is_window())
|
||||
.as_window_mut();
|
||||
window.minimize(!window.minimized);
|
||||
.with_child({
|
||||
minimize_button = ButtonBuilder::new(WidgetBuilder::new()
|
||||
.on_row(0)
|
||||
.on_column(1)
|
||||
.with_visibility(if self.can_minimize { Visibility::Visible } else { Visibility::Collapsed })
|
||||
.with_event_handler(Box::new(|ui, handle, evt| {
|
||||
if evt.source == handle {
|
||||
if let UIEventKind::Click = evt.kind {
|
||||
let window = ui.borrow_by_criteria_up_mut(handle, |node| node.is_window())
|
||||
.as_window_mut();
|
||||
window.minimize(!window.minimized);
|
||||
}
|
||||
}
|
||||
}
|
||||
}))
|
||||
.with_margin(Thickness::uniform(2.0)))
|
||||
.with_text("_")
|
||||
.build(ui))
|
||||
.with_child(ButtonBuilder::new(WidgetBuilder::new()
|
||||
.on_row(0)
|
||||
.on_column(2)
|
||||
.with_visibility(if self.can_close { Visibility::Visible } else { Visibility::Collapsed })
|
||||
.with_event_handler(Box::new(|ui, handle, evt| {
|
||||
if evt.source == handle {
|
||||
if let UIEventKind::Click = evt.kind {
|
||||
ui.borrow_by_criteria_up_mut(handle, |node| node.is_window())
|
||||
.as_window_mut()
|
||||
.close();
|
||||
}))
|
||||
.with_margin(Thickness::uniform(2.0)))
|
||||
.with_text("_")
|
||||
.build(ui);
|
||||
minimize_button
|
||||
})
|
||||
.with_child({
|
||||
close_button = ButtonBuilder::new(WidgetBuilder::new()
|
||||
.on_row(0)
|
||||
.on_column(2)
|
||||
.with_visibility(if self.can_close { Visibility::Visible } else { Visibility::Collapsed })
|
||||
.with_event_handler(Box::new(|ui, handle, evt| {
|
||||
if evt.source == handle {
|
||||
if let UIEventKind::Click = evt.kind {
|
||||
ui.borrow_by_criteria_up_mut(handle, |node| node.is_window())
|
||||
.as_window_mut()
|
||||
.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}))
|
||||
.with_margin(Thickness::uniform(2.0)))
|
||||
.with_text("X")
|
||||
.build(ui)))
|
||||
}))
|
||||
.with_margin(Thickness::uniform(2.0)))
|
||||
.with_text("X")
|
||||
.build(ui);
|
||||
close_button
|
||||
}))
|
||||
.add_column(Column::stretch())
|
||||
.add_column(Column::strict(30.0))
|
||||
.add_column(Column::strict(30.0))
|
||||
@@ -247,6 +273,20 @@ impl<'a> WindowBuilder<'a> {
|
||||
let visibility = if !minimized { Visibility::Visible } else { Visibility::Collapsed };
|
||||
scroll_viewer.widget_mut().set_visibility(visibility);
|
||||
}
|
||||
UIEventKind::CanMinimizeChanged(value) => {
|
||||
let window = ui.get_node_mut(handle).as_window_mut();
|
||||
window.can_minimize = value;
|
||||
ui.get_node_mut(minimize_button)
|
||||
.widget_mut()
|
||||
.set_visibility(bool_to_visibility(value));
|
||||
}
|
||||
UIEventKind::CanCloseChanged(value) => {
|
||||
let window = ui.get_node_mut(handle).as_window_mut();
|
||||
window.can_close = value;
|
||||
ui.get_node_mut(close_button)
|
||||
.widget_mut()
|
||||
.set_visibility(bool_to_visibility(value));
|
||||
}
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
|
||||
+48
-1
@@ -1,4 +1,51 @@
|
||||
#![allow(dead_code)]
|
||||
//! 3D Game Engine.
|
||||
//!
|
||||
//! Features:
|
||||
//! - Scene graph with pivot, camera, mesh, light, particle system, sprite nodes.
|
||||
//! - FBX Loader - both ASCII and binary. Note: Only 7100 - 7400 versions are supported!
|
||||
//! - Advanced node-based UI with these widgets:
|
||||
//! - Border
|
||||
//! - Button
|
||||
//! - Canvas (layout panel)
|
||||
//! - Grid (layout panel)
|
||||
//! - Stack panel
|
||||
//! - Scroll bar
|
||||
//! - Scroll viewer
|
||||
//! - Scroll content presenter
|
||||
//! - Text
|
||||
//! - Text box
|
||||
//! - List box
|
||||
//! - Window
|
||||
//! - Fonts - TTF Loader (compound characters are not supported yet)
|
||||
//! - Built-in save/load using object visitor - save/load state of engine in one call.
|
||||
//! - Skinning
|
||||
//! - Animation blending - allows you to blend your animations as you want to, i.e. idle animation can be blended with walk.
|
||||
//! - Animation retargetting - allows you to remap animation from one model to another.
|
||||
//! - Automatic resource management
|
||||
//! - Texture
|
||||
//! - Models
|
||||
//! - Sound buffers
|
||||
//! - Deferred shading
|
||||
//! - Point light
|
||||
//! - Spot light
|
||||
//! - Bump mapping
|
||||
//! - Particle systems with soft particles.
|
||||
//! - Sounds
|
||||
//! - Physics
|
||||
//!
|
||||
//! # Getting started
|
||||
//!
|
||||
//! ```
|
||||
//!
|
||||
//! ```
|
||||
//!
|
||||
//! # Demos
|
||||
//!
|
||||
//! For now there is one big project written using rg3d engine:
|
||||
//! https://github.com/mrDIMAS/rusty-shooter
|
||||
//!
|
||||
|
||||
//#![warn(missing_docs)]
|
||||
|
||||
extern crate image;
|
||||
extern crate glutin;
|
||||
|
||||
@@ -1,26 +1,36 @@
|
||||
use std::ffi::CString;
|
||||
use rg3d_core::{
|
||||
color::Color,
|
||||
math::{vec3::Vec3, mat4::Mat4},
|
||||
};
|
||||
use crate::{
|
||||
renderer::gpu_texture::GpuTexture,
|
||||
scene::{
|
||||
camera::Camera,
|
||||
Scene,
|
||||
node::Node,
|
||||
SceneInterface,
|
||||
light::LightKind,
|
||||
base::AsBase
|
||||
base::AsBase,
|
||||
},
|
||||
renderer::{
|
||||
surface::SurfaceSharedData,
|
||||
gpu_program::{UniformLocation, GpuProgram},
|
||||
gl, gbuffer::GBuffer,
|
||||
FlatShader, error::RendererError,
|
||||
gl,
|
||||
gbuffer::GBuffer,
|
||||
FlatShader,
|
||||
error::RendererError,
|
||||
shadow_map_renderer::SpotShadowMapRenderer,
|
||||
gpu_texture::GpuTexture,
|
||||
shadow_map_renderer::PointShadowMapRenderer,
|
||||
QualitySettings,
|
||||
},
|
||||
};
|
||||
use rg3d_core::{
|
||||
math::{
|
||||
vec2::Vec2,
|
||||
vec3::Vec3,
|
||||
mat4::Mat4,
|
||||
frustum::Frustum,
|
||||
},
|
||||
color::Color,
|
||||
};
|
||||
use crate::renderer::RenderPassStatistics;
|
||||
|
||||
struct AmbientLightShader {
|
||||
program: GpuProgram,
|
||||
@@ -144,7 +154,7 @@ impl DeferredLightingShader {
|
||||
}
|
||||
|
||||
fn set_soft_shadows_enabled(&self, enabled: bool) {
|
||||
self.program.set_int(self.soft_shadows, if enabled { 1 } else { 0 })
|
||||
self.program.set_bool(self.soft_shadows, enabled)
|
||||
}
|
||||
|
||||
fn set_shadow_map_inv_size(&self, value: f32) {
|
||||
@@ -187,29 +197,51 @@ pub struct DeferredLightRenderer {
|
||||
sphere: SurfaceSharedData,
|
||||
flat_shader: FlatShader,
|
||||
spot_shadow_map_renderer: SpotShadowMapRenderer,
|
||||
point_shadow_map_renderer: PointShadowMapRenderer,
|
||||
}
|
||||
|
||||
pub struct DeferredRendererContext<'a> {
|
||||
pub frame_size: Vec2,
|
||||
pub scene: &'a Scene,
|
||||
pub camera: &'a Camera,
|
||||
pub gbuffer: &'a GBuffer,
|
||||
pub white_dummy: &'a GpuTexture,
|
||||
pub ambient_color: Color,
|
||||
pub settings: &'a QualitySettings,
|
||||
}
|
||||
|
||||
impl DeferredLightRenderer {
|
||||
pub fn new() -> Result<Self, RendererError> {
|
||||
pub fn new(settings: &QualitySettings) -> Result<Self, RendererError> {
|
||||
Ok(Self {
|
||||
shader: DeferredLightingShader::new()?,
|
||||
ambient_light_shader: AmbientLightShader::new()?,
|
||||
quad: SurfaceSharedData::make_unit_xy_quad(),
|
||||
sphere: SurfaceSharedData::make_sphere(6, 6, 1.0),
|
||||
flat_shader: FlatShader::new()?,
|
||||
spot_shadow_map_renderer: SpotShadowMapRenderer::new(1024)?,
|
||||
spot_shadow_map_renderer: SpotShadowMapRenderer::new(settings.spot_shadow_map_size)?,
|
||||
point_shadow_map_renderer: PointShadowMapRenderer::new(settings.point_shadow_map_size)?,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn render(&mut self, frame_width: f32, frame_height: f32, scene: &Scene,
|
||||
camera: &Camera, gbuffer: &GBuffer, white_dummy: &GpuTexture, ambient_color: Color) {
|
||||
pub fn set_quality_settings(&mut self, settings: &QualitySettings) -> Result<(), RendererError> {
|
||||
self.spot_shadow_map_renderer = SpotShadowMapRenderer::new(settings.spot_shadow_map_size)?;
|
||||
self.point_shadow_map_renderer = PointShadowMapRenderer::new(settings.point_shadow_map_size)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn render(&mut self, context: DeferredRendererContext) -> RenderPassStatistics {
|
||||
let mut statistics = RenderPassStatistics::default();
|
||||
|
||||
let frustum = Frustum::from(context.camera.get_view_projection_matrix()).unwrap();
|
||||
|
||||
let frame_matrix =
|
||||
Mat4::ortho(0.0, frame_width, frame_height, 0.0, -1.0, 1.0) *
|
||||
Mat4::scale(Vec3::new(frame_width, frame_height, 0.0));
|
||||
Mat4::ortho(0.0, context.frame_size.x, context.frame_size.y, 0.0, -1.0, 1.0) *
|
||||
Mat4::scale(Vec3::new(context.frame_size.x, context.frame_size.y, 0.0));
|
||||
|
||||
unsafe {
|
||||
gl::BindFramebuffer(gl::FRAMEBUFFER, gbuffer.opt_fbo);
|
||||
gl::Viewport(0, 0, frame_width as i32, frame_height as i32);
|
||||
gl::BindFramebuffer(gl::FRAMEBUFFER, context.gbuffer.opt_fbo);
|
||||
gl::Viewport(0, 0, context.frame_size.x as i32, context.frame_size.y as i32);
|
||||
gl::Clear(gl::COLOR_BUFFER_BIT | gl::STENCIL_BUFFER_BIT);
|
||||
|
||||
gl::Disable(gl::BLEND);
|
||||
@@ -221,26 +253,26 @@ impl DeferredLightRenderer {
|
||||
// Ambient light.
|
||||
self.ambient_light_shader.bind();
|
||||
self.ambient_light_shader.set_wvp_matrix(&frame_matrix);
|
||||
self.ambient_light_shader.set_ambient_color(ambient_color);
|
||||
self.ambient_light_shader.set_ambient_color(context.ambient_color);
|
||||
self.ambient_light_shader.set_diffuse_texture(0);
|
||||
gl::ActiveTexture(gl::TEXTURE0);
|
||||
gl::BindTexture(gl::TEXTURE_2D, gbuffer.color_texture);
|
||||
gl::BindTexture(gl::TEXTURE_2D, context.gbuffer.color_texture);
|
||||
self.quad.draw();
|
||||
|
||||
// Lighting
|
||||
gl::Enable(gl::BLEND);
|
||||
gl::BlendFunc(gl::ONE, gl::ONE);
|
||||
gl::ActiveTexture(gl::TEXTURE0);
|
||||
gl::BindTexture(gl::TEXTURE_2D, gbuffer.depth_texture);
|
||||
gl::BindTexture(gl::TEXTURE_2D, context.gbuffer.depth_texture);
|
||||
gl::ActiveTexture(gl::TEXTURE1);
|
||||
gl::BindTexture(gl::TEXTURE_2D, gbuffer.color_texture);
|
||||
gl::BindTexture(gl::TEXTURE_2D, context.gbuffer.color_texture);
|
||||
gl::ActiveTexture(gl::TEXTURE2);
|
||||
gl::BindTexture(gl::TEXTURE_2D, gbuffer.normal_texture);
|
||||
gl::BindTexture(gl::TEXTURE_2D, context.gbuffer.normal_texture);
|
||||
|
||||
let view_projection = camera.get_view_projection_matrix();
|
||||
let view_projection = context.camera.get_view_projection_matrix();
|
||||
let inv_view_projection = view_projection.inverse().unwrap();
|
||||
|
||||
let SceneInterface { graph, .. } = scene.interface();
|
||||
let SceneInterface { graph, .. } = context.scene.interface();
|
||||
|
||||
for light_node in graph.linear_iter() {
|
||||
if !light_node.base().get_global_visibility() {
|
||||
@@ -258,22 +290,58 @@ impl DeferredLightRenderer {
|
||||
};
|
||||
|
||||
let light_position = light_node.base().get_global_position();
|
||||
let light_radius_scale = light_node.base().get_local_transform().get_scale().max_value();
|
||||
let light_radius_scale = light_node.base().get_local_transform().get_scale().max_value();
|
||||
let light_radius = light_radius_scale * raw_radius;
|
||||
let light_r_inflate = 1.05 * light_radius;
|
||||
let light_radius_vec = Vec3::new(light_r_inflate, light_r_inflate, light_r_inflate);
|
||||
let light_emit_direction = light_node.base().get_up_vector().normalized().unwrap_or(Vec3::UP);
|
||||
|
||||
match light.get_kind() {
|
||||
LightKind::Spot(_) => {
|
||||
self.spot_shadow_map_renderer.render(graph, &Mat4::IDENTITY, white_dummy, gbuffer.opt_fbo);
|
||||
}
|
||||
LightKind::Point(_) => {}
|
||||
if !frustum.is_intersects_sphere(light_position, light_radius) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let light_type = match light.get_kind() {
|
||||
LightKind::Spot(_) => 2,
|
||||
LightKind::Point(_) => -1, // TODO
|
||||
let distance_to_camera = (light.base().get_global_position() - context.camera.base().get_global_position()).len();
|
||||
|
||||
let mut light_view_projection = Mat4::IDENTITY;
|
||||
let apply_shadows = match light.get_kind() {
|
||||
LightKind::Spot(spot) if distance_to_camera <= context.settings.spot_shadows_distance && context.settings.spot_shadows_enabled => {
|
||||
let light_projection_matrix = Mat4::perspective(
|
||||
spot.get_cone_angle(),
|
||||
1.0,
|
||||
0.01,
|
||||
light_radius,
|
||||
);
|
||||
|
||||
let emit_direction = light.base().get_up_vector().normalized().unwrap_or(Vec3::LOOK);
|
||||
|
||||
let light_look_at = light_position - emit_direction;
|
||||
|
||||
let light_up_vec = light.base().get_look_vector().normalized().unwrap_or(Vec3::UP);
|
||||
|
||||
let light_view_matrix = Mat4::look_at(light_position, light_look_at, light_up_vec)
|
||||
.unwrap_or_default();
|
||||
|
||||
light_view_projection = light_projection_matrix * light_view_matrix;
|
||||
|
||||
statistics += self.spot_shadow_map_renderer.render(
|
||||
graph,
|
||||
&light_view_projection,
|
||||
context.white_dummy,
|
||||
);
|
||||
|
||||
true
|
||||
}
|
||||
LightKind::Point(_) if distance_to_camera <= context.settings.point_shadows_distance && context.settings.point_shadows_enabled => {
|
||||
statistics += self.point_shadow_map_renderer.render(
|
||||
graph,
|
||||
context.white_dummy,
|
||||
light_position,
|
||||
light_radius,
|
||||
);
|
||||
|
||||
true
|
||||
}
|
||||
_ => false
|
||||
};
|
||||
|
||||
// Mark lighted areas in stencil buffer to do light calculations only on them.
|
||||
@@ -290,12 +358,12 @@ impl DeferredLightRenderer {
|
||||
gl::CullFace(gl::FRONT);
|
||||
gl::StencilFunc(gl::ALWAYS, 0, 0xFF);
|
||||
gl::StencilOp(gl::KEEP, gl::INCR, gl::KEEP);
|
||||
self.sphere.draw();
|
||||
statistics.add_draw_call(self.sphere.draw());
|
||||
|
||||
gl::CullFace(gl::BACK);
|
||||
gl::StencilFunc(gl::ALWAYS, 0, 0xFF);
|
||||
gl::StencilOp(gl::KEEP, gl::DECR, gl::KEEP);
|
||||
self.sphere.draw();
|
||||
statistics.add_draw_call(self.sphere.draw());
|
||||
|
||||
gl::StencilFunc(gl::NOTEQUAL, 0, 0xFF);
|
||||
gl::StencilOp(gl::KEEP, gl::KEEP, gl::ZERO);
|
||||
@@ -311,24 +379,47 @@ impl DeferredLightRenderer {
|
||||
|
||||
// Finally render light.
|
||||
self.shader.bind();
|
||||
|
||||
match light.get_kind() {
|
||||
LightKind::Spot(_) => {
|
||||
gl::ActiveTexture(gl::TEXTURE3);
|
||||
gl::BindTexture(gl::TEXTURE_2D, self.spot_shadow_map_renderer.texture);
|
||||
self.shader.set_spot_shadow_texture(3);
|
||||
self.shader.set_light_view_proj_matrix(&light_view_projection);
|
||||
self.shader.set_soft_shadows_enabled(context.settings.spot_soft_shadows);
|
||||
}
|
||||
LightKind::Point(_) => {
|
||||
gl::ActiveTexture(gl::TEXTURE3);
|
||||
gl::BindTexture(gl::TEXTURE_CUBE_MAP, self.point_shadow_map_renderer.texture);
|
||||
self.shader.set_point_shadow_texture(3);
|
||||
self.shader.set_soft_shadows_enabled(context.settings.point_soft_shadows);
|
||||
}
|
||||
}
|
||||
|
||||
let light_type = match light.get_kind() {
|
||||
LightKind::Spot(_) if apply_shadows => 2,
|
||||
LightKind::Point(_) if apply_shadows => 0,
|
||||
_ => -1
|
||||
};
|
||||
|
||||
self.shader.set_light_position(&light_position);
|
||||
self.shader.set_light_direction(&light_emit_direction);
|
||||
self.shader.set_light_type(light_type); // Disable shadows for now
|
||||
self.shader.set_light_type(light_type);
|
||||
self.shader.set_light_radius(light_radius);
|
||||
self.shader.set_inv_view_proj_matrix(&inv_view_projection);
|
||||
self.shader.set_light_color(light.get_color());
|
||||
self.shader.set_light_cone_angle_cos(cone_angle_cos);
|
||||
self.shader.set_wvp_matrix(&frame_matrix);
|
||||
self.shader.set_shadow_map_inv_size(0.0); // TODO
|
||||
self.shader.set_camera_position(&camera.base().get_global_position());
|
||||
self.shader.set_shadow_map_inv_size(1.0 / (self.spot_shadow_map_renderer.size as f32));
|
||||
self.shader.set_camera_position(&context.camera.base().get_global_position());
|
||||
self.shader.set_depth_sampler_id(0);
|
||||
self.shader.set_color_sampler_id(1);
|
||||
self.shader.set_normal_sampler_id(2);
|
||||
|
||||
gl::ActiveTexture(gl::TEXTURE0);
|
||||
gl::BindTexture(gl::TEXTURE_2D, gbuffer.depth_texture);
|
||||
gl::BindTexture(gl::TEXTURE_2D, context.gbuffer.depth_texture);
|
||||
|
||||
self.quad.draw();
|
||||
statistics.add_draw_call(self.quad.draw());
|
||||
|
||||
gl::ActiveTexture(gl::TEXTURE3);
|
||||
gl::BindTexture(gl::TEXTURE_2D, 0);
|
||||
@@ -348,5 +439,7 @@ impl DeferredLightRenderer {
|
||||
gl::ActiveTexture(gl::TEXTURE2);
|
||||
gl::BindTexture(gl::TEXTURE_2D, 0);
|
||||
}
|
||||
|
||||
statistics
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,7 @@ pub enum RendererError {
|
||||
error_message: String,
|
||||
},
|
||||
|
||||
/// Means that shader link state failed, exact reason is inside `error_message`
|
||||
/// Means that shader link stage failed, exact reason is inside `error_message`
|
||||
ShaderLinkingFailed {
|
||||
shader_name: String,
|
||||
error_message: String,
|
||||
|
||||
+23
-9
@@ -1,17 +1,16 @@
|
||||
use std::ffi::CString;
|
||||
use rg3d_core::{
|
||||
math::{
|
||||
mat4::Mat4,
|
||||
vec2::Vec2,
|
||||
Rect,
|
||||
},
|
||||
use rg3d_core::math::{
|
||||
mat4::Mat4,
|
||||
vec2::Vec2,
|
||||
Rect,
|
||||
frustum::Frustum,
|
||||
};
|
||||
use crate::{
|
||||
scene::{
|
||||
node::Node,
|
||||
graph::Graph,
|
||||
camera::Camera,
|
||||
base::AsBase
|
||||
base::AsBase,
|
||||
},
|
||||
renderer::{
|
||||
gl::types::GLuint, gl,
|
||||
@@ -20,6 +19,7 @@ use crate::{
|
||||
gpu_texture::GpuTexture,
|
||||
},
|
||||
};
|
||||
use crate::renderer::RenderPassStatistics;
|
||||
|
||||
struct GBufferShader {
|
||||
program: GpuProgram,
|
||||
@@ -208,13 +208,19 @@ impl GBuffer {
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn fill(&mut self,
|
||||
frame_width: f32,
|
||||
frame_height: f32,
|
||||
graph: &Graph,
|
||||
camera: &Camera,
|
||||
white_dummy: &GpuTexture,
|
||||
normal_dummy: &GpuTexture) {
|
||||
normal_dummy: &GpuTexture
|
||||
) -> RenderPassStatistics {
|
||||
let mut statistics = RenderPassStatistics::default();
|
||||
|
||||
let frustum = Frustum::from(camera.get_view_projection_matrix()).unwrap();
|
||||
|
||||
unsafe {
|
||||
gl::BindFramebuffer(gl::FRAMEBUFFER, self.fbo);
|
||||
gl::ClearColor(0.0, 0.0, 0.0, 0.0);
|
||||
@@ -239,6 +245,12 @@ impl GBuffer {
|
||||
|
||||
for node in graph.linear_iter() {
|
||||
if let Node::Mesh(mesh) = node {
|
||||
let global_transform = node.base().get_global_transform();
|
||||
|
||||
if !frustum.is_intersects_aabb_transform(&mesh.get_bounding_box(), &global_transform) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if !node.base().get_global_visibility() {
|
||||
continue;
|
||||
}
|
||||
@@ -284,10 +296,12 @@ impl GBuffer {
|
||||
normal_dummy.bind(1);
|
||||
}
|
||||
|
||||
surface.get_data().lock().unwrap().draw();
|
||||
statistics.add_draw_call(surface.get_data().lock().unwrap().draw());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
statistics
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ pub struct GeometryBuffer<T> {
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
#[allow(dead_code)]
|
||||
pub enum AttributeKind {
|
||||
Float,
|
||||
Float2,
|
||||
@@ -228,7 +229,7 @@ impl<T> GeometryBuffer<T> where T: Sized {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn draw_part(&self, start_triangle: usize, triangle_count: usize) -> Result<(), RendererError> {
|
||||
pub fn draw_part(&self, start_triangle: usize, triangle_count: usize) -> Result<usize, RendererError> {
|
||||
let last_triangle_index = start_triangle + triangle_count;
|
||||
|
||||
if last_triangle_index > self.triangle_count.get() {
|
||||
@@ -243,15 +244,17 @@ impl<T> GeometryBuffer<T> where T: Sized {
|
||||
|
||||
unsafe { self.draw_internal(start_index, index_count); }
|
||||
|
||||
Ok(())
|
||||
Ok(triangle_count)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn draw(&self) {
|
||||
pub fn draw(&self) -> usize {
|
||||
let start_index = 0;
|
||||
let index_count = self.triangle_count.get() * 3;
|
||||
|
||||
unsafe { self.draw_internal(start_index, index_count) }
|
||||
|
||||
self.triangle_count.get()
|
||||
}
|
||||
|
||||
unsafe fn draw_internal(&self, start_index: usize, index_count: usize) {
|
||||
|
||||
@@ -19,7 +19,6 @@ use rg3d_core::{
|
||||
};
|
||||
|
||||
pub struct GpuProgram {
|
||||
name: String,
|
||||
id: GLuint,
|
||||
name_buf: Vec<u8>,
|
||||
}
|
||||
@@ -80,7 +79,6 @@ impl GpuProgram {
|
||||
})
|
||||
} else {
|
||||
Ok(Self {
|
||||
name: name.to_owned(),
|
||||
id: program,
|
||||
name_buf: Vec::new(),
|
||||
})
|
||||
|
||||
+240
-44
@@ -4,6 +4,10 @@ pub mod surface;
|
||||
pub mod gpu_program;
|
||||
pub mod error;
|
||||
|
||||
macro_rules! check_gl_error {
|
||||
() => (crate::renderer::check_gl_error_internal(line!(), file!()))
|
||||
}
|
||||
|
||||
mod geometry_buffer;
|
||||
mod ui_renderer;
|
||||
mod particle_system_renderer;
|
||||
@@ -14,10 +18,14 @@ mod flat_shader;
|
||||
pub mod gpu_texture;
|
||||
mod sprite_renderer;
|
||||
|
||||
use std::time;
|
||||
use std::{
|
||||
time,
|
||||
ffi::CStr,
|
||||
};
|
||||
use rg3d_core::{
|
||||
math::{vec3::Vec3, mat4::Mat4},
|
||||
color::Color,
|
||||
math::vec2::Vec2,
|
||||
};
|
||||
use glutin::PossiblyCurrent;
|
||||
use crate::{
|
||||
@@ -28,14 +36,17 @@ use crate::{
|
||||
surface::SurfaceSharedData,
|
||||
particle_system_renderer::ParticleSystemRenderer,
|
||||
gbuffer::GBuffer,
|
||||
deferred_light_renderer::DeferredLightRenderer,
|
||||
deferred_light_renderer::{
|
||||
DeferredLightRenderer,
|
||||
DeferredRendererContext
|
||||
},
|
||||
error::RendererError,
|
||||
gpu_texture::{GpuTexture, GpuTextureKind, PixelKind},
|
||||
flat_shader::FlatShader,
|
||||
sprite_renderer::SpriteRenderer,
|
||||
gl::types::{GLsizei, GLenum, GLuint, GLchar},
|
||||
},
|
||||
scene::{
|
||||
SceneInterface,
|
||||
SceneContainer,
|
||||
node::Node,
|
||||
},
|
||||
@@ -48,31 +59,10 @@ pub struct TriangleDefinition {
|
||||
pub c: u32,
|
||||
}
|
||||
|
||||
fn check_gl_error_internal(line: u32, file: &str) {
|
||||
unsafe {
|
||||
let error_code = gl::GetError();
|
||||
if error_code != gl::NO_ERROR {
|
||||
match error_code {
|
||||
gl::INVALID_ENUM => print!("GL_INVALID_ENUM"),
|
||||
gl::INVALID_VALUE => print!("GL_INVALID_VALUE"),
|
||||
gl::INVALID_OPERATION => print!("GL_INVALID_OPERATION"),
|
||||
gl::STACK_OVERFLOW => print!("GL_STACK_OVERFLOW"),
|
||||
gl::STACK_UNDERFLOW => print!("GL_STACK_UNDERFLOW"),
|
||||
gl::OUT_OF_MEMORY => print!("GL_OUT_OF_MEMORY"),
|
||||
_ => (),
|
||||
};
|
||||
|
||||
println!(" error has occurred! At line {} in file {}, stability is not guaranteed!", line, file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! check_gl_error {
|
||||
() => (check_gl_error_internal(line!(), file!()))
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Statistics {
|
||||
/// Geometry statistics.
|
||||
pub geometry: RenderPassStatistics,
|
||||
/// Real time consumed to render frame.
|
||||
pub pure_frame_time: f32,
|
||||
/// Total time renderer took to process single frame, usually includes
|
||||
@@ -85,10 +75,85 @@ pub struct Statistics {
|
||||
last_fps_commit_time: time::Instant,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct RenderPassStatistics {
|
||||
pub draw_calls: usize,
|
||||
pub triangles_rendered: usize,
|
||||
}
|
||||
|
||||
impl Default for RenderPassStatistics {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
draw_calls: 0,
|
||||
triangles_rendered: 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::AddAssign for RenderPassStatistics {
|
||||
fn add_assign(&mut self, rhs: Self) {
|
||||
self.draw_calls += rhs.draw_calls;
|
||||
self.triangles_rendered += rhs.triangles_rendered;
|
||||
}
|
||||
}
|
||||
|
||||
impl RenderPassStatistics {
|
||||
pub fn add_draw_call(&mut self, triangles_rendered: usize) {
|
||||
self.triangles_rendered += triangles_rendered;
|
||||
self.draw_calls += 1;
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::AddAssign<RenderPassStatistics> for Statistics {
|
||||
fn add_assign(&mut self, rhs: RenderPassStatistics) {
|
||||
self.geometry += rhs;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq)]
|
||||
pub struct QualitySettings {
|
||||
/// Point shadows
|
||||
/// Size of cube map face of shadow map texture in pixels.
|
||||
pub point_shadow_map_size: usize,
|
||||
/// Use or not percentage close filtering (smoothing) for point shadows.
|
||||
pub point_soft_shadows: bool,
|
||||
/// Point shadows enabled or not.
|
||||
pub point_shadows_enabled: bool,
|
||||
/// Maximum distance from camera to draw shadows.
|
||||
pub point_shadows_distance: f32,
|
||||
|
||||
/// Spot shadows
|
||||
/// Size of square shadow map texture in pixels
|
||||
pub spot_shadow_map_size: usize,
|
||||
/// Use or not percentage close filtering (smoothing) for spot shadows.
|
||||
pub spot_soft_shadows: bool,
|
||||
/// Spot shadows enabled or not.
|
||||
pub spot_shadows_enabled: bool,
|
||||
/// Maximum distance from camera to draw shadows.
|
||||
pub spot_shadows_distance: f32,
|
||||
}
|
||||
|
||||
impl Default for QualitySettings {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
point_shadow_map_size: 1024,
|
||||
point_shadows_distance: 10.0,
|
||||
point_shadows_enabled: true,
|
||||
point_soft_shadows: true,
|
||||
|
||||
spot_shadow_map_size: 1024,
|
||||
spot_shadows_distance: 10.0,
|
||||
spot_shadows_enabled: true,
|
||||
spot_soft_shadows: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Statistics {
|
||||
/// Must be called before render anything.
|
||||
fn begin_frame(&mut self) {
|
||||
self.frame_start_time = time::Instant::now();
|
||||
self.geometry = Default::default();
|
||||
}
|
||||
|
||||
/// Must be called before SwapBuffers but after all rendering is done.
|
||||
@@ -114,6 +179,7 @@ impl Statistics {
|
||||
impl Default for Statistics {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
geometry: RenderPassStatistics::default(),
|
||||
pure_frame_time: 0.0,
|
||||
capped_frame_time: 0.0,
|
||||
frames_per_second: 0,
|
||||
@@ -139,9 +205,9 @@ pub struct Renderer {
|
||||
ui_renderer: UIRenderer,
|
||||
statistics: Statistics,
|
||||
quad: SurfaceSharedData,
|
||||
last_render_time: time::Instant,
|
||||
frame_size: (u32, u32),
|
||||
ambient_color: Color,
|
||||
quality_settings: QualitySettings,
|
||||
}
|
||||
|
||||
impl Renderer {
|
||||
@@ -150,9 +216,11 @@ impl Renderer {
|
||||
gl::Enable(gl::DEPTH_TEST);
|
||||
}
|
||||
|
||||
let settings = QualitySettings::default();
|
||||
|
||||
Ok(Self {
|
||||
frame_size,
|
||||
deferred_light_renderer: DeferredLightRenderer::new()?,
|
||||
deferred_light_renderer: DeferredLightRenderer::new(&settings)?,
|
||||
flat_shader: FlatShader::new()?,
|
||||
gbuffer: GBuffer::new(frame_size)?,
|
||||
statistics: Statistics::default(),
|
||||
@@ -166,8 +234,8 @@ impl Renderer {
|
||||
quad: SurfaceSharedData::make_unit_xy_quad(),
|
||||
ui_renderer: UIRenderer::new()?,
|
||||
particle_system_renderer: ParticleSystemRenderer::new()?,
|
||||
last_render_time: time::Instant::now(), // TODO: Is this right?
|
||||
ambient_color: Color::opaque(100, 100, 100),
|
||||
quality_settings: settings,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -207,8 +275,20 @@ impl Renderer {
|
||||
self.frame_size
|
||||
}
|
||||
|
||||
pub(in crate) fn render(&mut self, scenes: &SceneContainer, drawing_context: &DrawingContext,
|
||||
context: &glutin::WindowedContext<PossiblyCurrent>) -> Result<(), RendererError> {
|
||||
pub fn set_quality_settings(&mut self, settings: &QualitySettings) -> Result<(), RendererError> {
|
||||
self.quality_settings = *settings;
|
||||
self.deferred_light_renderer.set_quality_settings(settings)
|
||||
}
|
||||
|
||||
pub fn get_quality_settings(&self) -> QualitySettings {
|
||||
self.quality_settings
|
||||
}
|
||||
|
||||
pub(in crate) fn render(&mut self,
|
||||
scenes: &SceneContainer,
|
||||
drawing_context: &DrawingContext,
|
||||
context: &glutin::WindowedContext<PossiblyCurrent>,
|
||||
) -> Result<(), RendererError> {
|
||||
self.statistics.begin_frame();
|
||||
|
||||
let frame_width = self.frame_size.0 as f32;
|
||||
@@ -219,7 +299,7 @@ impl Renderer {
|
||||
|
||||
// Render scenes into g-buffer.
|
||||
for scene in scenes.iter() {
|
||||
let SceneInterface { graph, .. } = scene.interface();
|
||||
let graph = scene.interface().graph;
|
||||
|
||||
// Prepare for render - fill lists of nodes participating in rendering.
|
||||
let camera = match graph.linear_iter().find(|node| node.is_camera()) {
|
||||
@@ -232,7 +312,7 @@ impl Renderer {
|
||||
_ => continue
|
||||
};
|
||||
|
||||
self.gbuffer.fill(
|
||||
self.statistics += self.gbuffer.fill(
|
||||
frame_width,
|
||||
frame_height,
|
||||
graph,
|
||||
@@ -241,18 +321,18 @@ impl Renderer {
|
||||
&self.normal_dummy,
|
||||
);
|
||||
|
||||
self.deferred_light_renderer.render(
|
||||
frame_width,
|
||||
frame_height,
|
||||
self.statistics += self.deferred_light_renderer.render(DeferredRendererContext {
|
||||
frame_size: Vec2::new(frame_width, frame_height),
|
||||
scene,
|
||||
camera,
|
||||
&self.gbuffer,
|
||||
&self.white_dummy,
|
||||
self.ambient_color,
|
||||
);
|
||||
gbuffer: &self.gbuffer,
|
||||
white_dummy: &self.white_dummy,
|
||||
ambient_color: self.ambient_color,
|
||||
settings: &self.quality_settings,
|
||||
});
|
||||
}
|
||||
|
||||
self.particle_system_renderer.render(
|
||||
self.statistics += self.particle_system_renderer.render(
|
||||
scenes,
|
||||
&self.white_dummy,
|
||||
frame_width,
|
||||
@@ -260,7 +340,7 @@ impl Renderer {
|
||||
&self.gbuffer,
|
||||
);
|
||||
|
||||
self.sprite_renderer.render(scenes, &self.white_dummy);
|
||||
self.statistics += self.sprite_renderer.render(scenes, &self.white_dummy);
|
||||
|
||||
unsafe {
|
||||
// Finally render everything into back buffer.
|
||||
@@ -279,9 +359,9 @@ impl Renderer {
|
||||
gl::ActiveTexture(gl::TEXTURE0);
|
||||
gl::BindTexture(gl::TEXTURE_2D, self.gbuffer.frame_texture);
|
||||
}
|
||||
self.quad.draw();
|
||||
self.statistics.geometry.add_draw_call(self.quad.draw());
|
||||
|
||||
self.ui_renderer.render(
|
||||
self.statistics += self.ui_renderer.render(
|
||||
frame_width,
|
||||
frame_height,
|
||||
drawing_context,
|
||||
@@ -300,4 +380,120 @@ impl Renderer {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn check_gl_error_internal(line: u32, file: &str) {
|
||||
unsafe {
|
||||
let error_code = gl::GetError();
|
||||
if error_code != gl::NO_ERROR {
|
||||
match error_code {
|
||||
gl::INVALID_ENUM => print!("GL_INVALID_ENUM"),
|
||||
gl::INVALID_VALUE => print!("GL_INVALID_VALUE"),
|
||||
gl::INVALID_OPERATION => print!("GL_INVALID_OPERATION"),
|
||||
gl::STACK_OVERFLOW => print!("GL_STACK_OVERFLOW"),
|
||||
gl::STACK_UNDERFLOW => print!("GL_STACK_UNDERFLOW"),
|
||||
gl::OUT_OF_MEMORY => print!("GL_OUT_OF_MEMORY"),
|
||||
_ => (),
|
||||
};
|
||||
|
||||
println!(" error has occurred! At line {} in file {}, stability is not guaranteed!", line, file);
|
||||
|
||||
if gl::GetDebugMessageLog::is_loaded() {
|
||||
let mut max_message_length = 0;
|
||||
gl::GetIntegerv(gl::MAX_DEBUG_MESSAGE_LENGTH, &mut max_message_length);
|
||||
|
||||
let mut max_logged_messages = 0;
|
||||
gl::GetIntegerv(gl::MAX_DEBUG_LOGGED_MESSAGES, &mut max_logged_messages);
|
||||
|
||||
let buffer_size = max_message_length * max_logged_messages;
|
||||
|
||||
let mut message_buffer: Vec<GLchar> = Vec::with_capacity(buffer_size as usize);
|
||||
message_buffer.set_len(buffer_size as usize);
|
||||
|
||||
let mut sources: Vec<GLenum> = Vec::with_capacity(max_logged_messages as usize);
|
||||
sources.set_len(max_logged_messages as usize);
|
||||
|
||||
let mut types: Vec<GLenum> = Vec::with_capacity(max_logged_messages as usize);
|
||||
types.set_len(max_logged_messages as usize);
|
||||
|
||||
let mut ids: Vec<GLuint> = Vec::with_capacity(max_logged_messages as usize);
|
||||
ids.set_len(max_logged_messages as usize);
|
||||
|
||||
let mut severities: Vec<GLenum> = Vec::with_capacity(max_logged_messages as usize);
|
||||
severities.set_len(max_logged_messages as usize);
|
||||
|
||||
let mut lengths: Vec<GLsizei> = Vec::with_capacity(max_logged_messages as usize);
|
||||
lengths.set_len(max_logged_messages as usize);
|
||||
|
||||
let message_count = gl::GetDebugMessageLog(
|
||||
max_logged_messages as u32,
|
||||
buffer_size,
|
||||
sources.as_mut_ptr(),
|
||||
types.as_mut_ptr(),
|
||||
ids.as_mut_ptr(),
|
||||
severities.as_mut_ptr(),
|
||||
lengths.as_mut_ptr(),
|
||||
message_buffer.as_mut_ptr(),
|
||||
);
|
||||
|
||||
if message_count == 0 {
|
||||
println!("Debug info is not available - run with OpenGL debug flag!");
|
||||
}
|
||||
|
||||
let mut message = message_buffer.as_ptr();
|
||||
|
||||
for i in 0..message_count as usize {
|
||||
let source = sources[i];
|
||||
let ty = types[i];
|
||||
let severity = severities[i];
|
||||
let id = ids[i];
|
||||
let len = lengths[i] as usize;
|
||||
|
||||
let source_str =
|
||||
match source {
|
||||
gl::DEBUG_SOURCE_API => "API",
|
||||
gl::DEBUG_SOURCE_SHADER_COMPILER => "Shader Compiler",
|
||||
gl::DEBUG_SOURCE_WINDOW_SYSTEM => "Window System",
|
||||
gl::DEBUG_SOURCE_THIRD_PARTY => "Third Party",
|
||||
gl::DEBUG_SOURCE_APPLICATION => "Application",
|
||||
gl::DEBUG_SOURCE_OTHER => "Other",
|
||||
_ => "Unknown"
|
||||
};
|
||||
|
||||
let type_str =
|
||||
match ty {
|
||||
gl::DEBUG_TYPE_ERROR => "Error",
|
||||
gl::DEBUG_TYPE_DEPRECATED_BEHAVIOR => "Deprecated Behavior",
|
||||
gl::DEBUG_TYPE_UNDEFINED_BEHAVIOR => "Undefined Behavior",
|
||||
gl::DEBUG_TYPE_PERFORMANCE => "Performance",
|
||||
gl::DEBUG_TYPE_PORTABILITY => "Portability",
|
||||
gl::DEBUG_TYPE_OTHER => "Other",
|
||||
_ => "Unknown",
|
||||
};
|
||||
|
||||
let severity_str =
|
||||
match severity {
|
||||
gl::DEBUG_SEVERITY_HIGH => "High",
|
||||
gl::DEBUG_SEVERITY_MEDIUM => "Medium",
|
||||
gl::DEBUG_SEVERITY_LOW => "Low",
|
||||
gl::DEBUG_SEVERITY_NOTIFICATION => "Notification",
|
||||
_ => "Unknown"
|
||||
};
|
||||
|
||||
let str_msg = CStr::from_ptr(message);
|
||||
|
||||
println!("OpenGL message\nSource: {}\nType: {}\nId: {}\nSeverity: {}\nMessage: {:?}\n",
|
||||
source_str,
|
||||
type_str,
|
||||
id,
|
||||
severity_str,
|
||||
str_msg);
|
||||
|
||||
message = message.add(len);
|
||||
}
|
||||
} else {
|
||||
println!("Debug info is not available - glGetDebugMessageLog is not available!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -20,6 +20,7 @@ use crate::{
|
||||
base::AsBase
|
||||
}
|
||||
};
|
||||
use crate::renderer::RenderPassStatistics;
|
||||
|
||||
struct ParticleSystemShader {
|
||||
program: GpuProgram,
|
||||
@@ -116,12 +117,16 @@ impl ParticleSystemRenderer {
|
||||
})
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn render(&mut self,
|
||||
scenes: &SceneContainer,
|
||||
white_dummy: &GpuTexture,
|
||||
frame_width: f32,
|
||||
frame_height: f32,
|
||||
gbuffer: &GBuffer) {
|
||||
gbuffer: &GBuffer
|
||||
) -> RenderPassStatistics {
|
||||
let mut statistics = RenderPassStatistics::default();
|
||||
|
||||
unsafe {
|
||||
gl::Disable(gl::CULL_FACE);
|
||||
gl::Enable(gl::BLEND);
|
||||
@@ -179,7 +184,7 @@ impl ParticleSystemRenderer {
|
||||
self.shader.set_inv_screen_size(Vec2::new(1.0 / frame_width, 1.0 / frame_height));
|
||||
self.shader.set_proj_params(camera.get_z_far(), camera.get_z_near());
|
||||
|
||||
self.geometry_buffer.draw();
|
||||
statistics.add_draw_call(self.geometry_buffer.draw());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -187,5 +192,7 @@ impl ParticleSystemRenderer {
|
||||
gl::Disable(gl::BLEND);
|
||||
gl::DepthMask(gl::TRUE);
|
||||
}
|
||||
|
||||
statistics
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,5 +8,5 @@ in vec2 texCoord;
|
||||
|
||||
void main()
|
||||
{
|
||||
FragColor = ambientColor * texture(diffuseTexture, texCoord);
|
||||
FragColor = ambientColor * texture(diffuseTexture, texCoord);
|
||||
}
|
||||
@@ -9,6 +9,6 @@ out vec2 texCoord;
|
||||
|
||||
void main()
|
||||
{
|
||||
texCoord = vertexTexCoord;
|
||||
gl_Position = worldViewProjection * vec4(vertexPosition, 1.0);
|
||||
texCoord = vertexTexCoord;
|
||||
gl_Position = worldViewProjection * vec4(vertexPosition, 1.0);
|
||||
}
|
||||
@@ -23,108 +23,108 @@ out vec4 FragColor;
|
||||
|
||||
vec3 GetProjection(vec3 worldPosition, mat4 viewProjectionMatrix)
|
||||
{
|
||||
vec4 projPos = viewProjectionMatrix * vec4(worldPosition, 1);
|
||||
projPos /= projPos.w;
|
||||
return vec3(projPos.x * 0.5 + 0.5, projPos.y * 0.5 + 0.5, projPos.z * 0.5 + 0.5);
|
||||
vec4 projPos = viewProjectionMatrix * vec4(worldPosition, 1);
|
||||
projPos /= projPos.w;
|
||||
return vec3(projPos.x * 0.5 + 0.5, projPos.y * 0.5 + 0.5, projPos.z * 0.5 + 0.5);
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 normalSpecular = texture2D(normalTexture, texCoord);
|
||||
vec3 normal = normalize(normalSpecular.xyz * 2.0 - 1.0);
|
||||
vec4 normalSpecular = texture2D(normalTexture, texCoord);
|
||||
vec3 normal = normalize(normalSpecular.xyz * 2.0 - 1.0);
|
||||
|
||||
vec4 screenPosition;
|
||||
screenPosition.x = texCoord.x * 2.0 - 1.0;
|
||||
screenPosition.y = texCoord.y * 2.0 - 1.0;
|
||||
screenPosition.z = texture2D(depthTexture, texCoord).r;
|
||||
screenPosition.w = 1.0;
|
||||
vec4 screenPosition;
|
||||
screenPosition.x = texCoord.x * 2.0 - 1.0;
|
||||
screenPosition.y = texCoord.y * 2.0 - 1.0;
|
||||
screenPosition.z = texture2D(depthTexture, texCoord).r;
|
||||
screenPosition.w = 1.0;
|
||||
|
||||
vec4 worldPosition = invViewProj * screenPosition;
|
||||
worldPosition /= worldPosition.w;
|
||||
vec4 worldPosition = invViewProj * screenPosition;
|
||||
worldPosition /= worldPosition.w;
|
||||
|
||||
vec3 lightVector = lightPos - worldPosition.xyz;
|
||||
float distanceToLight = length(lightVector);
|
||||
float d = min(distanceToLight, lightRadius);
|
||||
vec3 normLightVector = lightVector / d;
|
||||
vec3 h = normalize(lightVector + (cameraPosition - worldPosition.xyz));
|
||||
vec3 specular = normalSpecular.w * vec3(0.4 * pow(clamp(dot(normal, h), 0.0, 1.0), 80));
|
||||
float y = dot(lightDirection, normLightVector);
|
||||
float k = max(dot(normal, normLightVector), 0);
|
||||
float attenuation = 1.0 + cos((d / lightRadius) * 3.14159);
|
||||
if (y < coneAngleCos)
|
||||
{
|
||||
attenuation *= smoothstep(coneAngleCos - 0.1, coneAngleCos, y);
|
||||
}
|
||||
vec3 lightVector = lightPos - worldPosition.xyz;
|
||||
float distanceToLight = length(lightVector);
|
||||
float d = min(distanceToLight, lightRadius);
|
||||
vec3 normLightVector = lightVector / d;
|
||||
vec3 h = normalize(lightVector + (cameraPosition - worldPosition.xyz));
|
||||
vec3 specular = normalSpecular.w * vec3(0.4 * pow(clamp(dot(normal, h), 0.0, 1.0), 80));
|
||||
float y = dot(lightDirection, normLightVector);
|
||||
float k = max(dot(normal, normLightVector), 0);
|
||||
float attenuation = 1.0 + cos((d / lightRadius) * 3.14159);
|
||||
if (y < coneAngleCos)
|
||||
{
|
||||
attenuation *= smoothstep(coneAngleCos - 0.1, coneAngleCos, y);
|
||||
}
|
||||
|
||||
float shadow = 1.0;
|
||||
if (lightType == 2) /* Spot light shadows */
|
||||
{
|
||||
vec3 lightSpacePosition = GetProjection(worldPosition.xyz, lightViewProjMatrix);
|
||||
const float bias = 0.00005;
|
||||
if (softShadows)
|
||||
{
|
||||
for (float y = -1.5; y <= 1.5; y += 0.5)
|
||||
{
|
||||
for (float x = -1.5; x <= 1.5; x += 0.5)
|
||||
{
|
||||
vec2 fetchTexCoord = lightSpacePosition.xy + vec2(x, y) * shadowMapInvSize;
|
||||
if (lightSpacePosition.z - bias > texture(spotShadowTexture, fetchTexCoord).r)
|
||||
{
|
||||
shadow += 1.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
float shadow = 1.0;
|
||||
if (lightType == 2) /* Spot light shadows */
|
||||
{
|
||||
vec3 lightSpacePosition = GetProjection(worldPosition.xyz, lightViewProjMatrix);
|
||||
const float bias = 0.00005;
|
||||
if (softShadows)
|
||||
{
|
||||
for (float y = -1.5; y <= 1.5; y += 0.5)
|
||||
{
|
||||
for (float x = -1.5; x <= 1.5; x += 0.5)
|
||||
{
|
||||
vec2 fetchTexCoord = lightSpacePosition.xy + vec2(x, y) * shadowMapInvSize;
|
||||
if (lightSpacePosition.z - bias > texture(spotShadowTexture, fetchTexCoord).r)
|
||||
{
|
||||
shadow += 1.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
shadow = clamp(1.0 - shadow / 9.0, 0.0, 1.0);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (lightSpacePosition.z - bias > texture(spotShadowTexture, lightSpacePosition.xy).r)
|
||||
{
|
||||
shadow = 0.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(lightType == 0) /* Point light shadows */
|
||||
{
|
||||
const float bias = 0.01;
|
||||
if (softShadows)
|
||||
{
|
||||
const int samples = 20;
|
||||
shadow = clamp(1.0 - shadow / 9.0, 0.0, 1.0);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (lightSpacePosition.z - bias > texture(spotShadowTexture, lightSpacePosition.xy).r)
|
||||
{
|
||||
shadow = 0.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (lightType == 0) /* Point light shadows */
|
||||
{
|
||||
const float bias = 0.01;
|
||||
if (softShadows)
|
||||
{
|
||||
const int samples = 20;
|
||||
|
||||
const vec3 directions[samples] = vec3[samples] (
|
||||
vec3(1, 1, 1), vec3( 1, -1, 1), vec3(-1, -1, 1), vec3(-1, 1, 1),
|
||||
vec3(1, 1, -1), vec3( 1, -1, -1), vec3(-1, -1, -1), vec3(-1, 1, -1),
|
||||
vec3(1, 1, 0), vec3( 1, -1, 0), vec3(-1, -1, 0), vec3(-1, 1, 0),
|
||||
vec3(1, 0, 1), vec3(-1, 0, 1), vec3( 1, 0, -1), vec3(-1, 0, -1),
|
||||
vec3(0, 1, 1), vec3( 0, -1, 1), vec3( 0, -1, -1), vec3( 0, 1, -1)
|
||||
);
|
||||
const vec3 directions[samples] = vec3[samples] (
|
||||
vec3(1, 1, 1), vec3(1, -1, 1), vec3(-1, -1, 1), vec3(-1, 1, 1),
|
||||
vec3(1, 1, -1), vec3(1, -1, -1), vec3(-1, -1, -1), vec3(-1, 1, -1),
|
||||
vec3(1, 1, 0), vec3(1, -1, 0), vec3(-1, -1, 0), vec3(-1, 1, 0),
|
||||
vec3(1, 0, 1), vec3(-1, 0, 1), vec3(1, 0, -1), vec3(-1, 0, -1),
|
||||
vec3(0, 1, 1), vec3(0, -1, 1), vec3(0, -1, -1), vec3(0, 1, -1)
|
||||
);
|
||||
|
||||
const float diskRadius = 0.0025;
|
||||
const float diskRadius = 0.0025;
|
||||
|
||||
for (int i = 0; i < samples; ++i)
|
||||
{
|
||||
vec3 fetchDirection = -normLightVector + directions[i] * diskRadius;
|
||||
float shadowDistanceToLight = texture(pointShadowTexture, fetchDirection).r;
|
||||
if (distanceToLight - bias > shadowDistanceToLight)
|
||||
{
|
||||
shadow += 1.0;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < samples; ++i)
|
||||
{
|
||||
vec3 fetchDirection = -normLightVector + directions[i] * diskRadius;
|
||||
float shadowDistanceToLight = texture(pointShadowTexture, fetchDirection).r;
|
||||
if (distanceToLight - bias > shadowDistanceToLight)
|
||||
{
|
||||
shadow += 1.0;
|
||||
}
|
||||
}
|
||||
|
||||
shadow = clamp(1.0 - shadow / float(samples), 0.0, 1.0);
|
||||
}
|
||||
else
|
||||
{
|
||||
float shadowDistanceToLight = texture(pointShadowTexture, -normLightVector).r;
|
||||
if (distanceToLight - bias > shadowDistanceToLight)
|
||||
{
|
||||
shadow = 0.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
shadow = clamp(1.0 - shadow / float(samples), 0.0, 1.0);
|
||||
}
|
||||
else
|
||||
{
|
||||
float shadowDistanceToLight = texture(pointShadowTexture, -normLightVector).r;
|
||||
if (distanceToLight - bias > shadowDistanceToLight)
|
||||
{
|
||||
shadow = 0.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FragColor = texture2D(colorTexture, texCoord);
|
||||
FragColor.xyz += specular;
|
||||
FragColor *= k * shadow * attenuation * lightColor;
|
||||
FragColor = texture2D(colorTexture, texCoord);
|
||||
FragColor.xyz += specular;
|
||||
FragColor *= k * shadow * attenuation * lightColor;
|
||||
}
|
||||
@@ -9,6 +9,6 @@ out vec2 texCoord;
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_Position = worldViewProjection * vec4(vertexPosition, 1.0);
|
||||
texCoord = vertexTexCoord;
|
||||
gl_Position = worldViewProjection * vec4(vertexPosition, 1.0);
|
||||
texCoord = vertexTexCoord;
|
||||
}
|
||||
@@ -8,5 +8,5 @@ in vec2 texCoord;
|
||||
|
||||
void main()
|
||||
{
|
||||
FragColor = texture(diffuseTexture, texCoord);
|
||||
FragColor = texture(diffuseTexture, texCoord);
|
||||
}
|
||||
@@ -9,6 +9,6 @@ out vec2 texCoord;
|
||||
|
||||
void main()
|
||||
{
|
||||
texCoord = vertexTexCoord;
|
||||
gl_Position = worldViewProjection * vec4(vertexPosition, 1.0);
|
||||
texCoord = vertexTexCoord;
|
||||
gl_Position = worldViewProjection * vec4(vertexPosition, 1.0);
|
||||
}
|
||||
@@ -16,12 +16,12 @@ in vec3 binormal;
|
||||
|
||||
void main()
|
||||
{
|
||||
outDepth = position.z / position.w;
|
||||
outColor = texture2D(diffuseTexture, texCoord);
|
||||
if(outColor.a < 0.5) discard;
|
||||
outColor.a = 1;
|
||||
vec4 n = normalize(texture2D(normalTexture, texCoord) * 2.0 - 1.0);
|
||||
mat3 tangentSpace = mat3(tangent, binormal, normal);
|
||||
outNormal.xyz = normalize(tangentSpace * n.xyz) * 0.5 + 0.5;
|
||||
outNormal.w = texture2D(specularTexture, texCoord).r;
|
||||
outDepth = position.z / position.w;
|
||||
outColor = texture2D(diffuseTexture, texCoord);
|
||||
if (outColor.a < 0.5) discard;
|
||||
outColor.a = 1;
|
||||
vec4 n = normalize(texture2D(normalTexture, texCoord) * 2.0 - 1.0);
|
||||
mat3 tangentSpace = mat3(tangent, binormal, normal);
|
||||
outNormal.xyz = normalize(tangentSpace * n.xyz) * 0.5 + 0.5;
|
||||
outNormal.w = texture2D(specularTexture, texCoord).r;
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
#version 330 core
|
||||
#version 330 core
|
||||
|
||||
layout(location = 0) in vec3 vertexPosition;
|
||||
layout(location = 1) in vec2 vertexTexCoord;
|
||||
@@ -20,43 +20,43 @@ out vec3 binormal;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 localPosition = vec4(0);
|
||||
vec3 localNormal = vec3(0);
|
||||
vec3 localTangent = vec3(0);
|
||||
if(useSkeletalAnimation)
|
||||
{
|
||||
vec4 vertex = vec4(vertexPosition, 1.0);
|
||||
vec4 localPosition = vec4(0);
|
||||
vec3 localNormal = vec3(0);
|
||||
vec3 localTangent = vec3(0);
|
||||
if (useSkeletalAnimation)
|
||||
{
|
||||
vec4 vertex = vec4(vertexPosition, 1.0);
|
||||
|
||||
int i0 = int(boneIndices.x);
|
||||
int i1 = int(boneIndices.y);
|
||||
int i2 = int(boneIndices.z);
|
||||
int i3 = int(boneIndices.w);
|
||||
int i0 = int(boneIndices.x);
|
||||
int i1 = int(boneIndices.y);
|
||||
int i2 = int(boneIndices.z);
|
||||
int i3 = int(boneIndices.w);
|
||||
|
||||
localPosition += boneMatrices[i0] * vertex * boneWeights.x;
|
||||
localPosition += boneMatrices[i1] * vertex * boneWeights.y;
|
||||
localPosition += boneMatrices[i2] * vertex * boneWeights.z;
|
||||
localPosition += boneMatrices[i3] * vertex * boneWeights.w;
|
||||
localPosition += boneMatrices[i0] * vertex * boneWeights.x;
|
||||
localPosition += boneMatrices[i1] * vertex * boneWeights.y;
|
||||
localPosition += boneMatrices[i2] * vertex * boneWeights.z;
|
||||
localPosition += boneMatrices[i3] * vertex * boneWeights.w;
|
||||
|
||||
localNormal += mat3(boneMatrices[i0]) * vertexNormal * boneWeights.x;
|
||||
localNormal += mat3(boneMatrices[i1]) * vertexNormal * boneWeights.y;
|
||||
localNormal += mat3(boneMatrices[i2]) * vertexNormal * boneWeights.z;
|
||||
localNormal += mat3(boneMatrices[i3]) * vertexNormal * boneWeights.w;
|
||||
localNormal += mat3(boneMatrices[i0]) * vertexNormal * boneWeights.x;
|
||||
localNormal += mat3(boneMatrices[i1]) * vertexNormal * boneWeights.y;
|
||||
localNormal += mat3(boneMatrices[i2]) * vertexNormal * boneWeights.z;
|
||||
localNormal += mat3(boneMatrices[i3]) * vertexNormal * boneWeights.w;
|
||||
|
||||
localTangent += mat3(boneMatrices[i0]) * vertexTangent.xyz * boneWeights.x;
|
||||
localTangent += mat3(boneMatrices[i1]) * vertexTangent.xyz * boneWeights.y;
|
||||
localTangent += mat3(boneMatrices[i2]) * vertexTangent.xyz * boneWeights.z;
|
||||
localTangent += mat3(boneMatrices[i3]) * vertexTangent.xyz * boneWeights.w;
|
||||
}
|
||||
else
|
||||
{
|
||||
localPosition = vec4(vertexPosition, 1.0);
|
||||
localNormal = vertexNormal;
|
||||
localTangent = vertexTangent.xyz;
|
||||
}
|
||||
gl_Position = worldViewProjection * localPosition;
|
||||
normal = normalize(mat3(worldMatrix) * localNormal);
|
||||
tangent = normalize(mat3(worldMatrix) * localTangent);
|
||||
binormal = normalize(vertexTangent.w * cross(tangent, normal));
|
||||
texCoord = vertexTexCoord;
|
||||
position = gl_Position;
|
||||
localTangent += mat3(boneMatrices[i0]) * vertexTangent.xyz * boneWeights.x;
|
||||
localTangent += mat3(boneMatrices[i1]) * vertexTangent.xyz * boneWeights.y;
|
||||
localTangent += mat3(boneMatrices[i2]) * vertexTangent.xyz * boneWeights.z;
|
||||
localTangent += mat3(boneMatrices[i3]) * vertexTangent.xyz * boneWeights.w;
|
||||
}
|
||||
else
|
||||
{
|
||||
localPosition = vec4(vertexPosition, 1.0);
|
||||
localNormal = vertexNormal;
|
||||
localTangent = vertexTangent.xyz;
|
||||
}
|
||||
gl_Position = worldViewProjection * localPosition;
|
||||
normal = normalize(mat3(worldMatrix) * localNormal);
|
||||
tangent = normalize(mat3(worldMatrix) * localTangent);
|
||||
binormal = normalize(vertexTangent.w * cross(tangent, normal));
|
||||
texCoord = vertexTexCoord;
|
||||
position = gl_Position;
|
||||
}
|
||||
@@ -11,15 +11,15 @@ in vec4 color;
|
||||
|
||||
float toProjSpace(float z)
|
||||
{
|
||||
float far = projParams.x;
|
||||
float near = projParams.y;
|
||||
return (far * near) / (far - z * (far + near));
|
||||
float far = projParams.x;
|
||||
float near = projParams.y;
|
||||
return (far * near) / (far - z * (far + near));
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
float sceneDepth = toProjSpace(texture(depthBufferTexture, gl_FragCoord.xy * invScreenSize).r);
|
||||
float depthOpacity = clamp((sceneDepth - gl_FragCoord.z / gl_FragCoord.w) * 2.0f, 0.0, 1.0);
|
||||
FragColor = color * texture(diffuseTexture, texCoord).r;
|
||||
FragColor.a *= depthOpacity;
|
||||
float sceneDepth = toProjSpace(texture(depthBufferTexture, gl_FragCoord.xy * invScreenSize).r);
|
||||
float depthOpacity = clamp((sceneDepth - gl_FragCoord.z / gl_FragCoord.w) * 2.0f, 0.0, 1.0);
|
||||
FragColor = color * texture(diffuseTexture, texCoord).r;
|
||||
FragColor.a *= depthOpacity;
|
||||
}
|
||||
@@ -16,18 +16,18 @@ out vec4 color;
|
||||
|
||||
vec2 rotateVec2(vec2 v, float angle)
|
||||
{
|
||||
float c = cos(angle);
|
||||
float s = sin(angle);
|
||||
mat2 m = mat2(c, -s, s, c);
|
||||
return m * v;
|
||||
float c = cos(angle);
|
||||
float s = sin(angle);
|
||||
mat2 m = mat2(c, -s, s, c);
|
||||
return m * v;
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
color = vertexColor;
|
||||
texCoord = vertexTexCoord;
|
||||
vec2 vertexOffset = rotateVec2(vertexTexCoord * 2.0 - 1.0, particleRotation);
|
||||
vec4 worldPosition = worldMatrix * vec4(vertexPosition, 1.0);
|
||||
vec3 offset = (vertexOffset.x * cameraSideVector + vertexOffset.y * cameraUpVector) * particleSize;
|
||||
gl_Position = viewProjectionMatrix * (worldPosition + vec4(offset.x, offset.y, offset.z, 0.0));
|
||||
color = vertexColor;
|
||||
texCoord = vertexTexCoord;
|
||||
vec2 vertexOffset = rotateVec2(vertexTexCoord * 2.0 - 1.0, particleRotation);
|
||||
vec4 worldPosition = worldMatrix * vec4(vertexPosition, 1.0);
|
||||
vec3 offset = (vertexOffset.x * cameraSideVector + vertexOffset.y * cameraUpVector) * particleSize;
|
||||
gl_Position = viewProjectionMatrix * (worldPosition + vec4(offset.x, offset.y, offset.z, 0.0));
|
||||
}
|
||||
@@ -8,8 +8,8 @@ in vec3 worldPosition;
|
||||
|
||||
layout(location = 0) out float depth;
|
||||
|
||||
void main()
|
||||
void main()
|
||||
{
|
||||
if(texture(diffuseTexture, texCoord).a < 0.2) discard;
|
||||
depth = length(lightPosition - worldPosition);
|
||||
if (texture(diffuseTexture, texCoord).a < 0.2) discard;
|
||||
depth = length(lightPosition - worldPosition);
|
||||
}
|
||||
@@ -8,30 +8,30 @@ layout(location = 5) in vec4 boneIndices;
|
||||
uniform mat4 worldMatrix;
|
||||
uniform mat4 worldViewProjection;
|
||||
uniform bool useSkeletalAnimation;
|
||||
uniform mat4 boneMatrices[ DE_STRINGIZE(DE_RENDERER_MAX_SKINNING_MATRICES) ];
|
||||
uniform mat4 boneMatrices[80];
|
||||
|
||||
out vec2 texCoord;
|
||||
out vec3 worldPosition;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 localPosition = vec4(0);
|
||||
vec4 localPosition = vec4(0);
|
||||
|
||||
if(useSkeletalAnimation)
|
||||
{
|
||||
vec4 vertex = vec4(vertexPosition, 1.0);
|
||||
if (useSkeletalAnimation)
|
||||
{
|
||||
vec4 vertex = vec4(vertexPosition, 1.0);
|
||||
|
||||
localPosition += boneMatrices[int(boneIndices.x)] * vertex * boneWeights.x;
|
||||
localPosition += boneMatrices[int(boneIndices.y)] * vertex * boneWeights.y;
|
||||
localPosition += boneMatrices[int(boneIndices.z)] * vertex * boneWeights.z;
|
||||
localPosition += boneMatrices[int(boneIndices.w)] * vertex * boneWeights.w;
|
||||
}
|
||||
else
|
||||
{
|
||||
localPosition = vec4(vertexPosition, 1.0);
|
||||
}
|
||||
localPosition += boneMatrices[int(boneIndices.x)] * vertex * boneWeights.x;
|
||||
localPosition += boneMatrices[int(boneIndices.y)] * vertex * boneWeights.y;
|
||||
localPosition += boneMatrices[int(boneIndices.z)] * vertex * boneWeights.z;
|
||||
localPosition += boneMatrices[int(boneIndices.w)] * vertex * boneWeights.w;
|
||||
}
|
||||
else
|
||||
{
|
||||
localPosition = vec4(vertexPosition, 1.0);
|
||||
}
|
||||
|
||||
gl_Position = worldViewProjection * localPosition;
|
||||
worldPosition = (worldMatrix * localPosition).xyz;
|
||||
texCoord = vertexTexCoord;
|
||||
gl_Position = worldViewProjection * localPosition;
|
||||
worldPosition = (worldMatrix * localPosition).xyz;
|
||||
texCoord = vertexTexCoord;
|
||||
}
|
||||
@@ -6,5 +6,5 @@ in vec2 texCoord;
|
||||
|
||||
void main()
|
||||
{
|
||||
if(texture(diffuseTexture, texCoord).a < 0.2) discard;
|
||||
if (texture(diffuseTexture, texCoord).a < 0.2) discard;
|
||||
}
|
||||
@@ -13,22 +13,22 @@ out vec2 texCoord;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 localPosition = vec4(0);
|
||||
vec4 localPosition = vec4(0);
|
||||
|
||||
if(useSkeletalAnimation)
|
||||
{
|
||||
vec4 vertex = vec4(vertexPosition, 1.0);
|
||||
if (useSkeletalAnimation)
|
||||
{
|
||||
vec4 vertex = vec4(vertexPosition, 1.0);
|
||||
|
||||
localPosition += boneMatrices[int(boneIndices.x)] * vertex * boneWeights.x;
|
||||
localPosition += boneMatrices[int(boneIndices.y)] * vertex * boneWeights.y;
|
||||
localPosition += boneMatrices[int(boneIndices.z)] * vertex * boneWeights.z;
|
||||
localPosition += boneMatrices[int(boneIndices.w)] * vertex * boneWeights.w;
|
||||
}
|
||||
else
|
||||
{
|
||||
localPosition = vec4(vertexPosition, 1.0);
|
||||
}
|
||||
localPosition += boneMatrices[int(boneIndices.x)] * vertex * boneWeights.x;
|
||||
localPosition += boneMatrices[int(boneIndices.y)] * vertex * boneWeights.y;
|
||||
localPosition += boneMatrices[int(boneIndices.z)] * vertex * boneWeights.z;
|
||||
localPosition += boneMatrices[int(boneIndices.w)] * vertex * boneWeights.w;
|
||||
}
|
||||
else
|
||||
{
|
||||
localPosition = vec4(vertexPosition, 1.0);
|
||||
}
|
||||
|
||||
gl_Position = worldViewProjection * localPosition;
|
||||
texCoord = vertexTexCoord;
|
||||
gl_Position = worldViewProjection * localPosition;
|
||||
texCoord = vertexTexCoord;
|
||||
}
|
||||
@@ -9,5 +9,5 @@ in vec2 texCoord;
|
||||
|
||||
void main()
|
||||
{
|
||||
FragColor = color * texture(diffuseTexture, texCoord).r;
|
||||
FragColor = color * texture(diffuseTexture, texCoord).r;
|
||||
}
|
||||
@@ -14,17 +14,17 @@ out vec2 texCoord;
|
||||
|
||||
vec2 rotateVec2(vec2 v, float angle)
|
||||
{
|
||||
float c = cos(angle);
|
||||
float s = sin(angle);
|
||||
mat2 m = mat2(c, -s, s, c);
|
||||
return m * v;
|
||||
float c = cos(angle);
|
||||
float s = sin(angle);
|
||||
mat2 m = mat2(c, -s, s, c);
|
||||
return m * v;
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
texCoord = vertexTexCoord;
|
||||
vec2 vertexOffset = rotateVec2(vertexTexCoord * 2.0 - 1.0, rotation);
|
||||
vec4 worldPosition = worldMatrix * vec4(vertexPosition, 1.0);
|
||||
vec3 offset = (vertexOffset.x * cameraSideVector + vertexOffset.y * cameraUpVector) * size;
|
||||
gl_Position = viewProjectionMatrix * (worldPosition + vec4(offset.x, offset.y, offset.z, 0.0));
|
||||
texCoord = vertexTexCoord;
|
||||
vec2 vertexOffset = rotateVec2(vertexTexCoord * 2.0 - 1.0, rotation);
|
||||
vec4 worldPosition = worldMatrix * vec4(vertexPosition, 1.0);
|
||||
vec3 offset = (vertexOffset.x * cameraSideVector + vertexOffset.y * cameraUpVector) * size;
|
||||
gl_Position = viewProjectionMatrix * (worldPosition + vec4(offset.x, offset.y, offset.z, 0.0));
|
||||
}
|
||||
@@ -9,13 +9,13 @@ in vec4 color;
|
||||
|
||||
void main()
|
||||
{
|
||||
if (isFont)
|
||||
{
|
||||
FragColor = color;
|
||||
FragColor.a *= texture(diffuseTexture, texCoord).r;
|
||||
}
|
||||
else
|
||||
{
|
||||
FragColor = color * texture(diffuseTexture, texCoord);
|
||||
}
|
||||
if (isFont)
|
||||
{
|
||||
FragColor = color;
|
||||
FragColor.a *= texture(diffuseTexture, texCoord).r;
|
||||
}
|
||||
else
|
||||
{
|
||||
FragColor = color * texture(diffuseTexture, texCoord);
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,7 @@ out vec4 color;
|
||||
|
||||
void main()
|
||||
{
|
||||
texCoord = vertexTexCoord;
|
||||
color = vertexColor;
|
||||
gl_Position = worldViewProjection * vec4(vertexPosition, 1.0);
|
||||
texCoord = vertexTexCoord;
|
||||
color = vertexColor;
|
||||
gl_Position = worldViewProjection * vec4(vertexPosition, 1.0);
|
||||
}
|
||||
@@ -1,19 +1,24 @@
|
||||
use std::ffi::CString;
|
||||
use rg3d_core::math::mat4::Mat4;
|
||||
use rg3d_core::math::{
|
||||
mat4::Mat4,
|
||||
vec3::Vec3,
|
||||
frustum::Frustum,
|
||||
};
|
||||
use crate::{
|
||||
scene::{
|
||||
node::Node,
|
||||
graph::Graph,
|
||||
base::AsBase
|
||||
base::AsBase,
|
||||
},
|
||||
renderer::{
|
||||
gpu_texture::GpuTexture,
|
||||
gl::types::GLuint,
|
||||
gpu_program::{GpuProgram, UniformLocation},
|
||||
error::RendererError,
|
||||
gl
|
||||
gl,
|
||||
},
|
||||
};
|
||||
use crate::renderer::RenderPassStatistics;
|
||||
|
||||
pub struct SpotShadowMapShader {
|
||||
program: GpuProgram,
|
||||
@@ -41,7 +46,6 @@ impl SpotShadowMapShader {
|
||||
self.program.bind()
|
||||
}
|
||||
|
||||
|
||||
fn set_wvp_matrix(&self, mat: &Mat4) {
|
||||
self.program.set_mat4(self.world_view_projection_matrix, mat)
|
||||
}
|
||||
@@ -62,9 +66,9 @@ impl SpotShadowMapShader {
|
||||
pub struct SpotShadowMapRenderer {
|
||||
shader: SpotShadowMapShader,
|
||||
fbo: GLuint,
|
||||
texture: GLuint,
|
||||
pub texture: GLuint,
|
||||
bone_matrices: Vec<Mat4>,
|
||||
size: usize,
|
||||
pub size: usize,
|
||||
}
|
||||
|
||||
impl SpotShadowMapRenderer {
|
||||
@@ -115,32 +119,50 @@ impl SpotShadowMapRenderer {
|
||||
pub fn render(&mut self,
|
||||
graph: &Graph,
|
||||
light_view_projection: &Mat4,
|
||||
white_dummy: &GpuTexture,
|
||||
active_fbo: GLuint) {
|
||||
white_dummy: &GpuTexture
|
||||
) -> RenderPassStatistics {
|
||||
let mut statistics = RenderPassStatistics::default();
|
||||
|
||||
let mut old_fbo = 0;
|
||||
let mut old_viewport = [0; 4];
|
||||
|
||||
unsafe {
|
||||
gl::DepthMask(gl::TRUE);
|
||||
gl::Disable(gl::BLEND);
|
||||
gl::Disable(gl::STENCIL_TEST);
|
||||
gl::Enable(gl::CULL_FACE);
|
||||
|
||||
gl::GetIntegerv(gl::DRAW_FRAMEBUFFER_BINDING, &mut old_fbo);
|
||||
gl::GetIntegerv(gl::VIEWPORT, old_viewport.as_mut_ptr());
|
||||
|
||||
gl::Viewport(0, 0, self.size as i32, self.size as i32);
|
||||
gl::BindFramebuffer(gl::FRAMEBUFFER, self.fbo);
|
||||
gl::Clear(gl::DEPTH_BUFFER_BIT);
|
||||
}
|
||||
|
||||
self.shader.bind();
|
||||
|
||||
let frustum = Frustum::from(*light_view_projection).unwrap();
|
||||
|
||||
for node in graph.linear_iter() {
|
||||
if let Node::Mesh(mesh) = node {
|
||||
if !node.base().get_global_visibility() {
|
||||
continue;
|
||||
}
|
||||
|
||||
let global_transform = node.base().get_global_transform();
|
||||
|
||||
if !frustum.is_intersects_aabb_transform(&mesh.get_bounding_box(), &global_transform) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for surface in mesh.get_surfaces().iter() {
|
||||
let is_skinned = !surface.bones.is_empty();
|
||||
|
||||
let world = if is_skinned {
|
||||
Mat4::IDENTITY
|
||||
} else {
|
||||
node.base().get_global_transform()
|
||||
global_transform
|
||||
};
|
||||
let mvp = *light_view_projection * world;
|
||||
|
||||
@@ -160,20 +182,25 @@ impl SpotShadowMapRenderer {
|
||||
}
|
||||
|
||||
// Bind diffuse texture.
|
||||
self.shader.set_diffuse_texture(0);
|
||||
if let Some(texture) = surface.get_diffuse_texture() {
|
||||
texture.lock().unwrap().gpu_tex.as_ref().unwrap().bind(0);
|
||||
} else {
|
||||
white_dummy.bind(0);
|
||||
}
|
||||
|
||||
surface.get_data().lock().unwrap().draw();
|
||||
statistics.add_draw_call(surface.get_data().lock().unwrap().draw());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe {
|
||||
gl::BindFramebuffer(gl::FRAMEBUFFER, active_fbo);
|
||||
// Set previous state
|
||||
gl::BindFramebuffer(gl::FRAMEBUFFER, old_fbo as u32);
|
||||
gl::Viewport(old_viewport[0], old_viewport[1], old_viewport[2], old_viewport[3]);
|
||||
}
|
||||
|
||||
statistics
|
||||
}
|
||||
}
|
||||
|
||||
@@ -212,17 +239,86 @@ impl PointShadowMapShader
|
||||
program,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn bind(&self) {
|
||||
self.program.bind();
|
||||
}
|
||||
|
||||
fn set_wvp_matrix(&self, mat: &Mat4) {
|
||||
self.program.set_mat4(self.world_view_projection_matrix, mat)
|
||||
}
|
||||
|
||||
fn set_world_matrix(&self, mat: &Mat4) {
|
||||
self.program.set_mat4(self.world_matrix, mat)
|
||||
}
|
||||
|
||||
fn set_use_skeletal_animation(&self, value: bool) {
|
||||
self.program.set_int(self.use_skeletal_animation, if value { 1 } else { 0 })
|
||||
}
|
||||
|
||||
fn set_bone_matrices(&self, matrices: &[Mat4]) {
|
||||
self.program.set_mat4_array(self.bone_matrices, matrices);
|
||||
}
|
||||
|
||||
fn set_diffuse_texture(&self, id: i32) {
|
||||
self.program.set_int(self.diffuse_texture, id)
|
||||
}
|
||||
|
||||
fn set_light_position(&self, pos: Vec3) {
|
||||
self.program.set_vec3(self.light_position, &pos);
|
||||
}
|
||||
}
|
||||
|
||||
pub struct PointShadowMapRenderer {
|
||||
bone_matrices: Vec<Mat4>,
|
||||
shader: PointShadowMapShader,
|
||||
fbo: GLuint,
|
||||
texture: GLuint,
|
||||
pub texture: GLuint,
|
||||
depth_buffer: GLuint,
|
||||
pub size: usize,
|
||||
}
|
||||
|
||||
struct CubeMapFace {
|
||||
id: GLuint,
|
||||
look: Vec3,
|
||||
up: Vec3,
|
||||
}
|
||||
|
||||
impl PointShadowMapRenderer {
|
||||
pub fn new(size: i32) -> Result<PointShadowMapRenderer, RendererError> {
|
||||
const FACES: [CubeMapFace; 6] = [
|
||||
CubeMapFace {
|
||||
id: gl::TEXTURE_CUBE_MAP_POSITIVE_X,
|
||||
look: Vec3 { x: 1.0, y: 0.0, z: 0.0 },
|
||||
up: Vec3 { x: 0.0, y: -1.0, z: 0.0 },
|
||||
},
|
||||
CubeMapFace {
|
||||
id: gl::TEXTURE_CUBE_MAP_NEGATIVE_X,
|
||||
look: Vec3 { x: -1.0, y: 0.0, z: 0.0 },
|
||||
up: Vec3 { x: 0.0, y: -1.0, z: 0.0 },
|
||||
},
|
||||
CubeMapFace {
|
||||
id: gl::TEXTURE_CUBE_MAP_POSITIVE_Y,
|
||||
look: Vec3 { x: 0.0, y: 1.0, z: 0.0 },
|
||||
up: Vec3 { x: 0.0, y: 0.0, z: 1.0 },
|
||||
},
|
||||
CubeMapFace {
|
||||
id: gl::TEXTURE_CUBE_MAP_NEGATIVE_Y,
|
||||
look: Vec3 { x: 0.0, y: -1.0, z: 0.0 },
|
||||
up: Vec3 { x: 0.0, y: 0.0, z: -1.0 },
|
||||
},
|
||||
CubeMapFace {
|
||||
id: gl::TEXTURE_CUBE_MAP_POSITIVE_Z,
|
||||
look: Vec3 { x: 0.0, y: 0.0, z: 1.0 },
|
||||
up: Vec3 { x: 0.0, y: -1.0, z: 0.0 },
|
||||
},
|
||||
CubeMapFace {
|
||||
id: gl::TEXTURE_CUBE_MAP_NEGATIVE_Z,
|
||||
look: Vec3 { x: 0.0, y: 0.0, z: -1.0 },
|
||||
up: Vec3 { x: 0.0, y: -1.0, z: 0.0 },
|
||||
},
|
||||
];
|
||||
|
||||
pub fn new(size: usize) -> Result<PointShadowMapRenderer, RendererError> {
|
||||
unsafe {
|
||||
let mut fbo = 0;
|
||||
gl::GenFramebuffers(1, &mut fbo);
|
||||
@@ -236,8 +332,8 @@ impl PointShadowMapRenderer {
|
||||
gl::TexImage2D(gl::TEXTURE_2D,
|
||||
0,
|
||||
gl::DEPTH_COMPONENT as i32,
|
||||
size,
|
||||
size,
|
||||
size as i32,
|
||||
size as i32,
|
||||
0,
|
||||
gl::DEPTH_COMPONENT,
|
||||
gl::FLOAT,
|
||||
@@ -262,8 +358,8 @@ impl PointShadowMapRenderer {
|
||||
gl::TexImage2D(gl::TEXTURE_CUBE_MAP_POSITIVE_X + i,
|
||||
0,
|
||||
gl::R32F as i32,
|
||||
size,
|
||||
size,
|
||||
size as i32,
|
||||
size as i32,
|
||||
0,
|
||||
gl::RED,
|
||||
gl::FLOAT,
|
||||
@@ -278,12 +374,130 @@ impl PointShadowMapRenderer {
|
||||
|
||||
gl::BindFramebuffer(gl::FRAMEBUFFER, 0);
|
||||
|
||||
gl::BindTexture(gl::TEXTURE_CUBE_MAP, 0);
|
||||
|
||||
Ok(Self {
|
||||
shader: PointShadowMapShader::new()?,
|
||||
fbo,
|
||||
size,
|
||||
texture,
|
||||
depth_buffer,
|
||||
bone_matrices: Vec::new(),
|
||||
shader: PointShadowMapShader::new()?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn render(&mut self,
|
||||
graph: &Graph,
|
||||
white_dummy: &GpuTexture,
|
||||
light_pos: Vec3,
|
||||
light_radius: f32
|
||||
) -> RenderPassStatistics {
|
||||
let mut statistics = RenderPassStatistics::default();
|
||||
|
||||
unsafe {
|
||||
gl::DepthMask(gl::TRUE);
|
||||
gl::Disable(gl::BLEND);
|
||||
gl::Disable(gl::STENCIL_TEST);
|
||||
gl::Enable(gl::CULL_FACE);
|
||||
gl::CullFace(gl::BACK);
|
||||
|
||||
let mut old_fbo = 0;
|
||||
gl::GetIntegerv(gl::DRAW_FRAMEBUFFER_BINDING, &mut old_fbo);
|
||||
|
||||
let mut old_viewport = [0; 4];
|
||||
gl::GetIntegerv(gl::VIEWPORT, old_viewport.as_mut_ptr());
|
||||
|
||||
gl::Viewport(0, 0, self.size as i32, self.size as i32);
|
||||
gl::BindFramebuffer(gl::FRAMEBUFFER, self.fbo);
|
||||
|
||||
let light_projection_matrix = Mat4::perspective(std::f32::consts::FRAC_PI_2, 1.0, 0.01, light_radius);
|
||||
|
||||
self.shader.bind();
|
||||
self.shader.set_light_position(light_pos);
|
||||
|
||||
for face in Self::FACES.iter() {
|
||||
gl::FramebufferTexture2D(gl::FRAMEBUFFER, gl::COLOR_ATTACHMENT0, face.id, self.texture, 0);
|
||||
gl::DrawBuffer(gl::COLOR_ATTACHMENT0);
|
||||
gl::ClearColor(std::f32::MAX, std::f32::MAX, std::f32::MAX, std::f32::MAX);
|
||||
gl::Clear(gl::DEPTH_BUFFER_BIT | gl::COLOR_BUFFER_BIT);
|
||||
|
||||
let light_look_at = light_pos + face.look;
|
||||
let light_view_matrix = Mat4::look_at(light_pos, light_look_at, face.up).unwrap_or_default();
|
||||
let light_view_projection_matrix = light_projection_matrix * light_view_matrix;
|
||||
|
||||
let frustum = Frustum::from(light_view_projection_matrix).unwrap();
|
||||
|
||||
for node in graph.linear_iter() {
|
||||
if let Node::Mesh(mesh) = node {
|
||||
if !node.base().get_global_visibility() {
|
||||
continue;
|
||||
}
|
||||
|
||||
let global_transform = node.base().get_global_transform();
|
||||
|
||||
if !frustum.is_intersects_aabb_transform(&mesh.get_bounding_box(), &global_transform) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for surface in mesh.get_surfaces().iter() {
|
||||
let is_skinned = !surface.bones.is_empty();
|
||||
|
||||
let world = if is_skinned {
|
||||
Mat4::IDENTITY
|
||||
} else {
|
||||
global_transform
|
||||
};
|
||||
let mvp = light_view_projection_matrix * world;
|
||||
|
||||
self.shader.set_world_matrix(&world);
|
||||
self.shader.set_wvp_matrix(&mvp);
|
||||
self.shader.set_use_skeletal_animation(is_skinned);
|
||||
|
||||
if is_skinned {
|
||||
self.bone_matrices.clear();
|
||||
for bone_handle in surface.bones.iter() {
|
||||
let bone_node = graph.get(*bone_handle);
|
||||
self.bone_matrices.push(
|
||||
bone_node.base().get_global_transform() *
|
||||
bone_node.base().get_inv_bind_pose_transform());
|
||||
}
|
||||
|
||||
self.shader.set_bone_matrices(&self.bone_matrices);
|
||||
}
|
||||
|
||||
// Bind diffuse texture.
|
||||
self.shader.set_diffuse_texture(0);
|
||||
if let Some(texture) = surface.get_diffuse_texture() {
|
||||
texture.lock().unwrap().gpu_tex.as_ref().unwrap().bind(0);
|
||||
} else {
|
||||
white_dummy.bind(0);
|
||||
}
|
||||
|
||||
statistics.add_draw_call(surface.get_data().lock().unwrap().draw());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gl::DepthMask(gl::FALSE);
|
||||
gl::Enable(gl::BLEND);
|
||||
|
||||
// Set previous state
|
||||
gl::BindFramebuffer(gl::FRAMEBUFFER, old_fbo as u32);
|
||||
gl::Viewport(old_viewport[0], old_viewport[1], old_viewport[2], old_viewport[3]);
|
||||
}
|
||||
|
||||
statistics
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for PointShadowMapRenderer {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
gl::DeleteFramebuffers(1, &self.fbo);
|
||||
gl::DeleteTextures(1, &self.texture);
|
||||
gl::DeleteTextures(1, &self.depth_buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,7 @@ use crate::{
|
||||
gl, gpu_texture::GpuTexture,
|
||||
},
|
||||
};
|
||||
use crate::renderer::RenderPassStatistics;
|
||||
|
||||
pub struct SpriteShader {
|
||||
program: GpuProgram,
|
||||
@@ -101,7 +102,10 @@ impl SpriteRenderer {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn render(&mut self, scenes: &SceneContainer, white_dummy: &GpuTexture) {
|
||||
#[must_use]
|
||||
pub fn render(&mut self, scenes: &SceneContainer, white_dummy: &GpuTexture) -> RenderPassStatistics {
|
||||
let mut statistics = RenderPassStatistics::default();
|
||||
|
||||
unsafe {
|
||||
gl::Disable(gl::CULL_FACE);
|
||||
gl::Enable(gl::BLEND);
|
||||
@@ -153,7 +157,7 @@ impl SpriteRenderer {
|
||||
self.shader.set_color(sprite.get_color());
|
||||
self.shader.set_rotation(sprite.get_rotation());
|
||||
|
||||
self.surface.draw();
|
||||
statistics.add_draw_call(self.surface.draw());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -161,5 +165,7 @@ impl SpriteRenderer {
|
||||
gl::Disable(gl::BLEND);
|
||||
gl::DepthMask(gl::TRUE);
|
||||
}
|
||||
|
||||
statistics
|
||||
}
|
||||
}
|
||||
@@ -70,7 +70,8 @@ impl SurfaceSharedData {
|
||||
self.vertices.push(vertex);
|
||||
}
|
||||
|
||||
pub fn draw(&self) {
|
||||
/// Draws surface, returns amount of triangles were rendered.
|
||||
pub fn draw(&self) -> usize {
|
||||
if self.need_upload.get() {
|
||||
self.geometry_buffer.set_vertices(self.vertices.as_slice());
|
||||
|
||||
@@ -87,7 +88,7 @@ impl SurfaceSharedData {
|
||||
self.need_upload.set(false);
|
||||
}
|
||||
|
||||
self.geometry_buffer.draw();
|
||||
self.geometry_buffer.draw()
|
||||
}
|
||||
|
||||
/// Inserts vertex or its index. Performs optimizing insertion with checking if such
|
||||
|
||||
@@ -20,6 +20,7 @@ use crate::{
|
||||
},
|
||||
gui::draw::CommandTexture
|
||||
};
|
||||
use crate::renderer::RenderPassStatistics;
|
||||
|
||||
struct UIShader {
|
||||
program: GpuProgram,
|
||||
@@ -84,7 +85,9 @@ impl UIRenderer {
|
||||
frame_width: f32,
|
||||
frame_height: f32,
|
||||
drawing_context: &DrawingContext,
|
||||
white_dummy: &GpuTexture) -> Result<(), RendererError> {
|
||||
white_dummy: &GpuTexture) -> Result<RenderPassStatistics, RendererError> {
|
||||
let mut statistics = RenderPassStatistics::default();
|
||||
|
||||
unsafe {
|
||||
// Render UI on top of everything
|
||||
gl::Disable(gl::DEPTH_TEST);
|
||||
@@ -157,9 +160,10 @@ impl UIRenderer {
|
||||
}
|
||||
}
|
||||
|
||||
self.geometry_buffer.draw_part(cmd.get_start_triangle(), cmd.get_triangle_count())?;
|
||||
statistics.triangles_rendered += self.geometry_buffer.draw_part(cmd.get_start_triangle(), cmd.get_triangle_count())?;
|
||||
statistics.draw_calls += 1;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
Ok(statistics)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,184 @@
|
||||
use crate::{
|
||||
resource::fbx::{
|
||||
find_and_borrow_node,
|
||||
find_node,
|
||||
FbxContainer,
|
||||
FbxComponent,
|
||||
FbxNode,
|
||||
FbxReference,
|
||||
string_to_reference,
|
||||
string_to_mapping,
|
||||
error::FbxError,
|
||||
},
|
||||
renderer::surface::{VertexWeightSet, VertexWeight},
|
||||
};
|
||||
use rg3d_core::{
|
||||
math::{
|
||||
vec3::Vec3,
|
||||
vec2::Vec2
|
||||
},
|
||||
pool::{Pool, Handle},
|
||||
};
|
||||
|
||||
pub struct FbxGeometry {
|
||||
pub vertices: Vec<Vec3>,
|
||||
pub indices: Vec<i32>,
|
||||
pub normals: FbxContainer<Vec3>,
|
||||
pub uvs: FbxContainer<Vec2>,
|
||||
pub materials: FbxContainer<i32>,
|
||||
pub tangents: FbxContainer<Vec3>,
|
||||
pub binormals: FbxContainer<Vec3>,
|
||||
pub(in crate::resource::fbx) deformers: Vec<Handle<FbxComponent>>,
|
||||
}
|
||||
|
||||
impl FbxGeometry {
|
||||
pub(in crate::resource::fbx) fn read(geom_node_handle: Handle<FbxNode>, nodes: &Pool<FbxNode>) -> Result<FbxGeometry, String> {
|
||||
Ok(FbxGeometry {
|
||||
vertices: Self::read_vertices(geom_node_handle, nodes)?,
|
||||
indices: Self::read_indices(geom_node_handle, nodes)?,
|
||||
normals: Self::read_normals(geom_node_handle, nodes)?,
|
||||
uvs: Self::read_uvs(geom_node_handle, nodes)?,
|
||||
materials: Self::read_materials(geom_node_handle, nodes)?,
|
||||
tangents: FbxContainer::default(),
|
||||
binormals: FbxContainer::default(),
|
||||
deformers: Vec::new(),
|
||||
})
|
||||
}
|
||||
|
||||
fn read_vertices(geom_node_handle: Handle<FbxNode>, nodes: &Pool<FbxNode>) -> Result<Vec<Vec3>, String> {
|
||||
let vertices_node_handle = find_node(nodes, geom_node_handle, "Vertices")?;
|
||||
let vertices_array_node = find_and_borrow_node(nodes, vertices_node_handle, "a")?;
|
||||
let vertex_count = vertices_array_node.attrib_count() / 3;
|
||||
let mut vertices = Vec::with_capacity(vertex_count);
|
||||
for i in 0..vertex_count {
|
||||
vertices.push(vertices_array_node.get_vec3_at(i * 3)?);
|
||||
}
|
||||
Ok(vertices)
|
||||
}
|
||||
|
||||
fn read_indices(geom_node_handle: Handle<FbxNode>, nodes: &Pool<FbxNode>) -> Result<Vec<i32>, String> {
|
||||
let indices_node_handle = find_node(nodes, geom_node_handle, "PolygonVertexIndex")?;
|
||||
let indices_array_node = find_and_borrow_node(nodes, indices_node_handle, "a")?;
|
||||
let index_count = indices_array_node.attrib_count();
|
||||
let mut indices = Vec::with_capacity(index_count);
|
||||
for i in 0..index_count {
|
||||
let index = indices_array_node.get_attrib(i)?.as_i32()?;
|
||||
indices.push(index);
|
||||
}
|
||||
Ok(indices)
|
||||
}
|
||||
|
||||
fn read_normals(geom_node_handle: Handle<FbxNode>, nodes: &Pool<FbxNode>) -> Result<FbxContainer<Vec3>, String> {
|
||||
if let Ok(layer_element_normal_node_handle) = find_node(nodes, geom_node_handle, "LayerElementNormal") {
|
||||
let map_type_node = find_and_borrow_node(nodes, layer_element_normal_node_handle, "MappingInformationType")?;
|
||||
let mapping = string_to_mapping(&map_type_node.get_attrib(0)?.as_string());
|
||||
|
||||
let ref_type_node = find_and_borrow_node(nodes, layer_element_normal_node_handle, "ReferenceInformationType")?;
|
||||
let reference = string_to_reference(&ref_type_node.get_attrib(0)?.as_string());
|
||||
|
||||
let normals_node_handle = find_node(nodes, layer_element_normal_node_handle, "Normals")?;
|
||||
let normals_array_node = find_and_borrow_node(nodes, normals_node_handle, "a")?;
|
||||
let count = normals_array_node.attrib_count() / 3;
|
||||
let mut normals = Vec::with_capacity(count);
|
||||
for i in 0..count {
|
||||
normals.push(normals_array_node.get_vec3_at(i * 3)?);
|
||||
}
|
||||
|
||||
Ok(FbxContainer {
|
||||
elements: normals,
|
||||
mapping,
|
||||
reference,
|
||||
..Default::default()
|
||||
})
|
||||
} else {
|
||||
Ok(Default::default())
|
||||
}
|
||||
}
|
||||
|
||||
fn read_uvs(geom_node_handle: Handle<FbxNode>, nodes: &Pool<FbxNode>) -> Result<FbxContainer<Vec2>, String> {
|
||||
if let Ok(layer_element_uv_node_handle) = find_node(nodes, geom_node_handle, "LayerElementUV") {
|
||||
let map_type_node = find_and_borrow_node(nodes, layer_element_uv_node_handle, "MappingInformationType")?;
|
||||
let mapping = string_to_mapping(&map_type_node.get_attrib(0)?.as_string());
|
||||
|
||||
let ref_type_node = find_and_borrow_node(nodes, layer_element_uv_node_handle, "ReferenceInformationType")?;
|
||||
let reference = string_to_reference(&ref_type_node.get_attrib(0)?.as_string());
|
||||
|
||||
let uvs_node_handle = find_node(nodes, layer_element_uv_node_handle, "UV")?;
|
||||
let uvs_array_node = find_and_borrow_node(nodes, uvs_node_handle, "a")?;
|
||||
let count = uvs_array_node.attrib_count() / 2;
|
||||
let mut uvs = Vec::with_capacity(count);
|
||||
for i in 0..count {
|
||||
let uv = uvs_array_node.get_vec2_at(i * 2)?;
|
||||
uvs.push(Vec2 { x: uv.x, y: -uv.y }); // Hack FIXME
|
||||
}
|
||||
|
||||
let mut index = Vec::new();
|
||||
if reference == FbxReference::IndexToDirect {
|
||||
let uv_index_node = find_node(nodes, layer_element_uv_node_handle, "UVIndex")?;
|
||||
let uv_index_array_node = find_and_borrow_node(nodes, uv_index_node, "a")?;
|
||||
for i in 0..uv_index_array_node.attrib_count() {
|
||||
index.push(uv_index_array_node.get_attrib(i)?.as_i32()?);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(FbxContainer {
|
||||
elements: uvs,
|
||||
index,
|
||||
mapping,
|
||||
reference,
|
||||
})
|
||||
} else {
|
||||
Ok(Default::default())
|
||||
}
|
||||
}
|
||||
|
||||
fn read_materials(geom_node_handle: Handle<FbxNode>, nodes: &Pool<FbxNode>) -> Result<FbxContainer<i32>, String> {
|
||||
if let Ok(layer_element_material_node_handle) = find_node(nodes, geom_node_handle, "LayerElementMaterial") {
|
||||
let map_type_node = find_and_borrow_node(nodes, layer_element_material_node_handle, "MappingInformationType")?;
|
||||
let mapping = string_to_mapping(&map_type_node.get_attrib(0)?.as_string());
|
||||
|
||||
let ref_type_node = find_and_borrow_node(nodes, layer_element_material_node_handle, "ReferenceInformationType")?;
|
||||
let reference = string_to_reference(&ref_type_node.get_attrib(0)?.as_string());
|
||||
|
||||
let materials_node_handle = find_node(nodes, layer_element_material_node_handle, "Materials")?;
|
||||
let materials_array_node = find_and_borrow_node(nodes, materials_node_handle, "a")?;
|
||||
let count = materials_array_node.attrib_count();
|
||||
let mut materials = Vec::with_capacity(count);
|
||||
for i in 0..count {
|
||||
materials.push(materials_array_node.get_attrib(i)?.as_i32()?);
|
||||
}
|
||||
|
||||
Ok(FbxContainer {
|
||||
elements: materials,
|
||||
mapping,
|
||||
reference,
|
||||
..Default::default()
|
||||
})
|
||||
} else {
|
||||
Ok(Default::default())
|
||||
}
|
||||
}
|
||||
|
||||
pub(in crate::resource::fbx) fn get_skin_data(&self, components: &Pool<FbxComponent>) -> Result<Vec<VertexWeightSet>, FbxError> {
|
||||
let mut out = vec![VertexWeightSet::default(); self.vertices.len()];
|
||||
for deformer_handle in self.deformers.iter() {
|
||||
for sub_deformer_handle in components.borrow(*deformer_handle)
|
||||
.as_deformer()?.sub_deformers.iter() {
|
||||
let sub_deformer = components.borrow(*sub_deformer_handle)
|
||||
.as_sub_deformer()?;
|
||||
for (index, weight) in sub_deformer.weights.iter() {
|
||||
let bone_set = out.get_mut(*index as usize)
|
||||
.ok_or(FbxError::IndexOutOfBounds)?;
|
||||
if !bone_set.push(VertexWeight {
|
||||
value: *weight,
|
||||
effector: sub_deformer.model.into(),
|
||||
}) {
|
||||
// TODO: Maybe gather all weights, but then re-normalize them to 4-bones?
|
||||
println!("FBX: More than 4 bones per vertex?! Excess will be discarded");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(out)
|
||||
}
|
||||
}
|
||||
+65
-240
@@ -2,6 +2,7 @@ mod fbx_ascii;
|
||||
mod fbx_binary;
|
||||
mod texture;
|
||||
mod attribute;
|
||||
mod geometry;
|
||||
pub mod error;
|
||||
|
||||
use std::{
|
||||
@@ -10,7 +11,6 @@ use std::{
|
||||
io::{Read, Cursor},
|
||||
collections::{HashMap, HashSet},
|
||||
time::Instant,
|
||||
any::{Any, TypeId},
|
||||
};
|
||||
use rg3d_core::{
|
||||
color::Color,
|
||||
@@ -58,20 +58,15 @@ use crate::{
|
||||
renderer::{
|
||||
surface::{
|
||||
SurfaceSharedData, Surface,
|
||||
Vertex, VertexWeightSet, VertexWeight,
|
||||
Vertex, VertexWeightSet,
|
||||
}
|
||||
},
|
||||
};
|
||||
use crate::resource::fbx::geometry::FbxGeometry;
|
||||
|
||||
// https://help.autodesk.com/view/FBX/2016/ENU/?guid=__cpp_ref_class_fbx_anim_curve_html
|
||||
const FBX_TIME_UNIT: f64 = 1.0 / 46_186_158_000.0;
|
||||
|
||||
struct FbxKeyframe {
|
||||
time: f32,
|
||||
position: Vec3,
|
||||
scale: Vec3,
|
||||
rotation: Vec3,
|
||||
}
|
||||
|
||||
struct FbxTimeValuePair {
|
||||
time: f32,
|
||||
value: f32,
|
||||
@@ -327,159 +322,21 @@ impl FbxNode {
|
||||
}
|
||||
}
|
||||
|
||||
struct FbxGeometry {
|
||||
vertices: Vec<Vec3>,
|
||||
indices: Vec<i32>,
|
||||
|
||||
normals: Vec<Vec3>,
|
||||
normal_mapping: FbxMapping,
|
||||
normal_reference: FbxReference,
|
||||
|
||||
tangents: Vec<Vec3>,
|
||||
tangent_mapping: FbxMapping,
|
||||
tangent_reference: FbxReference,
|
||||
|
||||
binormals: Vec<Vec3>,
|
||||
binormal_mapping: FbxMapping,
|
||||
binormal_reference: FbxReference,
|
||||
|
||||
uvs: Vec<Vec2>,
|
||||
uv_index: Vec<i32>,
|
||||
uv_mapping: FbxMapping,
|
||||
uv_reference: FbxReference,
|
||||
|
||||
materials: Vec<i32>,
|
||||
material_mapping: FbxMapping,
|
||||
material_reference: FbxReference,
|
||||
|
||||
deformers: Vec<Handle<FbxComponent>>,
|
||||
pub struct FbxContainer<T> {
|
||||
elements: Vec<T>,
|
||||
index: Vec<i32>,
|
||||
mapping: FbxMapping,
|
||||
reference: FbxReference,
|
||||
}
|
||||
|
||||
impl FbxGeometry {
|
||||
pub fn read(geom_node_handle: Handle<FbxNode>, nodes: &Pool<FbxNode>) -> Result<FbxGeometry, String> {
|
||||
let mut geom = FbxGeometry {
|
||||
vertices: Vec::new(),
|
||||
indices: Vec::new(),
|
||||
normals: Vec::new(),
|
||||
normal_mapping: FbxMapping::Unknown,
|
||||
normal_reference: FbxReference::Unknown,
|
||||
tangents: Vec::new(),
|
||||
tangent_mapping: FbxMapping::Unknown,
|
||||
tangent_reference: FbxReference::Unknown,
|
||||
binormals: Vec::new(),
|
||||
binormal_mapping: FbxMapping::Unknown,
|
||||
binormal_reference: FbxReference::Unknown,
|
||||
uvs: Vec::new(),
|
||||
uv_index: Vec::new(),
|
||||
uv_mapping: FbxMapping::Unknown,
|
||||
uv_reference: FbxReference::Unknown,
|
||||
materials: Vec::new(),
|
||||
material_mapping: FbxMapping::Unknown,
|
||||
material_reference: FbxReference::Unknown,
|
||||
deformers: Vec::new(),
|
||||
};
|
||||
|
||||
// Read vertices
|
||||
let vertices_node_handle = find_node(nodes, geom_node_handle, "Vertices")?;
|
||||
let vertices_array_node = find_and_borrow_node(nodes, vertices_node_handle, "a")?;
|
||||
let vertex_count = vertices_array_node.attrib_count() / 3;
|
||||
geom.vertices = Vec::with_capacity(vertex_count);
|
||||
for i in 0..vertex_count {
|
||||
geom.vertices.push(vertices_array_node.get_vec3_at(i * 3)?);
|
||||
impl<T> Default for FbxContainer<T> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
index: Vec::new(),
|
||||
elements: Vec::new(),
|
||||
mapping: FbxMapping::Unknown,
|
||||
reference: FbxReference::Unknown
|
||||
}
|
||||
|
||||
// Read faces
|
||||
let indices_node_handle = find_node(nodes, geom_node_handle, "PolygonVertexIndex")?;
|
||||
let indices_array_node = find_and_borrow_node(nodes, indices_node_handle, "a")?;
|
||||
let index_count = indices_array_node.attrib_count();
|
||||
geom.indices = Vec::with_capacity(index_count);
|
||||
for i in 0..index_count {
|
||||
let index = indices_array_node.get_attrib(i)?.as_i32()?;
|
||||
geom.indices.push(index);
|
||||
}
|
||||
|
||||
// Read normals (normals can not exist)
|
||||
if let Ok(layer_element_normal_node_handle) = find_node(nodes, geom_node_handle, "LayerElementNormal") {
|
||||
let map_type_node = find_and_borrow_node(nodes, layer_element_normal_node_handle, "MappingInformationType")?;
|
||||
geom.normal_mapping = string_to_mapping(&map_type_node.get_attrib(0)?.as_string());
|
||||
|
||||
let ref_type_node = find_and_borrow_node(nodes, layer_element_normal_node_handle, "ReferenceInformationType")?;
|
||||
geom.normal_reference = string_to_reference(&ref_type_node.get_attrib(0)?.as_string());
|
||||
|
||||
let normals_node_handle = find_node(nodes, layer_element_normal_node_handle, "Normals")?;
|
||||
let normals_array_node = find_and_borrow_node(nodes, normals_node_handle, "a")?;
|
||||
let count = normals_array_node.attrib_count() / 3;
|
||||
for i in 0..count {
|
||||
geom.normals.push(normals_array_node.get_vec3_at(i * 3)?);
|
||||
}
|
||||
}
|
||||
|
||||
// todo: read tangents
|
||||
|
||||
// Read UVs
|
||||
if let Ok(layer_element_uv_node_handle) = find_node(nodes, geom_node_handle, "LayerElementUV") {
|
||||
let map_type_node = find_and_borrow_node(nodes, layer_element_uv_node_handle, "MappingInformationType")?;
|
||||
geom.uv_mapping = string_to_mapping(&map_type_node.get_attrib(0)?.as_string());
|
||||
|
||||
let ref_type_node = find_and_borrow_node(nodes, layer_element_uv_node_handle, "ReferenceInformationType")?;
|
||||
geom.uv_reference = string_to_reference(&ref_type_node.get_attrib(0)?.as_string());
|
||||
|
||||
let uvs_node_handle = find_node(nodes, layer_element_uv_node_handle, "UV")?;
|
||||
let uvs_array_node = find_and_borrow_node(nodes, uvs_node_handle, "a")?;
|
||||
let count = uvs_array_node.attrib_count() / 2;
|
||||
for i in 0..count {
|
||||
let uv = uvs_array_node.get_vec2_at(i * 2)?;
|
||||
geom.uvs.push(Vec2 { x: uv.x, y: -uv.y }); // Hack FIXME
|
||||
}
|
||||
|
||||
if geom.uv_reference == FbxReference::IndexToDirect {
|
||||
let uv_index_node = find_node(nodes, layer_element_uv_node_handle, "UVIndex")?;
|
||||
let uv_index_array_node = find_and_borrow_node(nodes, uv_index_node, "a")?;
|
||||
for i in 0..uv_index_array_node.attrib_count() {
|
||||
geom.uv_index.push(uv_index_array_node.get_attrib(i)?.as_i32()?);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Read materials
|
||||
if let Ok(layer_element_material_node_handle) = find_node(nodes, geom_node_handle, "LayerElementMaterial") {
|
||||
let map_type_node = find_and_borrow_node(nodes, layer_element_material_node_handle, "MappingInformationType")?;
|
||||
geom.material_mapping = string_to_mapping(&map_type_node.get_attrib(0)?.as_string());
|
||||
|
||||
let ref_type_node = find_and_borrow_node(nodes, layer_element_material_node_handle, "ReferenceInformationType")?;
|
||||
geom.material_reference = string_to_reference(&ref_type_node.get_attrib(0)?.as_string());
|
||||
|
||||
let materials_node_handle = find_node(nodes, layer_element_material_node_handle, "Materials")?;
|
||||
let materials_array_node = find_and_borrow_node(nodes, materials_node_handle, "a")?;
|
||||
for i in 0..materials_array_node.attrib_count() {
|
||||
geom.materials.push(materials_array_node.get_attrib(i)?.as_i32()?);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(geom)
|
||||
}
|
||||
|
||||
fn get_skin_data(&self, components: &Pool<FbxComponent>) -> Result<Vec<VertexWeightSet>, FbxError> {
|
||||
let mut out = vec![VertexWeightSet::default(); self.vertices.len()];
|
||||
for deformer_handle in self.deformers.iter() {
|
||||
for sub_deformer_handle in components.borrow(*deformer_handle)
|
||||
.as_deformer()?.sub_deformers.iter() {
|
||||
let sub_deformer = components.borrow(*sub_deformer_handle)
|
||||
.as_sub_deformer()?;
|
||||
for (index, weight) in sub_deformer.weights.iter() {
|
||||
let bone_set = out.get_mut(*index as usize)
|
||||
.ok_or(FbxError::IndexOutOfBounds)?;
|
||||
if !bone_set.push(VertexWeight {
|
||||
value: *weight,
|
||||
effector: sub_deformer.model.into(),
|
||||
}) {
|
||||
// TODO: Maybe gather all weights, but then renormalize them to 4-bones?
|
||||
println!("FBX: More than 4 bones per vertex?! Excess will be discarded");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(out)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -640,56 +497,25 @@ enum FbxComponent {
|
||||
Geometry(Box<FbxGeometry>),
|
||||
}
|
||||
|
||||
impl FbxComponent {
|
||||
fn type_id(&self) -> TypeId {
|
||||
match self {
|
||||
FbxComponent::Deformer(deformer) => deformer.type_id(),
|
||||
FbxComponent::SubDeformer(subdeformer) => subdeformer.type_id(),
|
||||
FbxComponent::Texture(texture) => texture.type_id(),
|
||||
FbxComponent::Light(light) => light.type_id(),
|
||||
FbxComponent::Model(model) => model.type_id(),
|
||||
FbxComponent::Material(material) => material.type_id(),
|
||||
FbxComponent::AnimationCurveNode(anim_curve_node) => anim_curve_node.type_id(),
|
||||
FbxComponent::AnimationCurve(anim_curve) => anim_curve.type_id(),
|
||||
FbxComponent::Geometry(geometry) => geometry.type_id()
|
||||
macro_rules! define_as {
|
||||
($self:ident, $name:ident, $ty:ty, $kind:ident) => {
|
||||
fn $name(&$self) -> Result<&$ty, FbxError> {
|
||||
if let FbxComponent::$kind(component) = $self {
|
||||
Ok(component)
|
||||
} else {
|
||||
Err(FbxError::UnexpectedType)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn as_deformer(&self) -> Result<&FbxDeformer, FbxError> {
|
||||
if let FbxComponent::Deformer(deformer) = self { Ok(deformer) } else { Err(FbxError::UnexpectedType) }
|
||||
}
|
||||
|
||||
fn as_sub_deformer(&self) -> Result<&FbxSubDeformer, FbxError> {
|
||||
if let FbxComponent::SubDeformer(sub_deformer) = self { Ok(sub_deformer) } else { Err(FbxError::UnexpectedType) }
|
||||
}
|
||||
|
||||
fn as_texture(&self) -> Result<&FbxTexture, FbxError> {
|
||||
if let FbxComponent::Texture(texture) = self { Ok(texture) } else { Err(FbxError::UnexpectedType) }
|
||||
}
|
||||
|
||||
fn as_light(&self) -> Result<&FbxLight, FbxError> {
|
||||
if let FbxComponent::Light(light) = self { Ok(light) } else { Err(FbxError::UnexpectedType) }
|
||||
}
|
||||
|
||||
fn as_model(&self) -> Result<&FbxModel, FbxError> {
|
||||
if let FbxComponent::Model(model) = self { Ok(model) } else { Err(FbxError::UnexpectedType) }
|
||||
}
|
||||
|
||||
fn as_material(&self) -> Result<&FbxMaterial, FbxError> {
|
||||
if let FbxComponent::Material(material) = self { Ok(material) } else { Err(FbxError::UnexpectedType) }
|
||||
}
|
||||
|
||||
fn as_animation_curve_node(&self) -> Result<&FbxAnimationCurveNode, FbxError> {
|
||||
if let FbxComponent::AnimationCurveNode(acn) = self { Ok(acn) } else { Err(FbxError::UnexpectedType) }
|
||||
}
|
||||
|
||||
fn as_animation_curve(&self) -> Result<&FbxAnimationCurve, FbxError> {
|
||||
if let FbxComponent::AnimationCurve(ac) = self { Ok(ac) } else { Err(FbxError::UnexpectedType) }
|
||||
}
|
||||
|
||||
fn as_geometry(&self) -> Result<&FbxGeometry, FbxError> {
|
||||
if let FbxComponent::Geometry(geom) = self { Ok(geom) } else { Err(FbxError::UnexpectedType) }
|
||||
}
|
||||
impl FbxComponent {
|
||||
define_as!(self, as_deformer, FbxDeformer, Deformer);
|
||||
define_as!(self, as_sub_deformer, FbxSubDeformer, SubDeformer);
|
||||
define_as!(self, as_texture, FbxTexture, Texture);
|
||||
define_as!(self, as_light, FbxLight, Light);
|
||||
define_as!(self, as_material, FbxMaterial, Material);
|
||||
define_as!(self, as_geometry, FbxGeometry, Geometry);
|
||||
}
|
||||
|
||||
pub struct Fbx {
|
||||
@@ -822,7 +648,7 @@ fn quat_from_euler(euler: Vec3) -> Quat {
|
||||
/// is actually index 2 but it xor'ed using -1.
|
||||
fn fix_index(index: i32) -> usize {
|
||||
if index < 0 {
|
||||
(-index - 1) as usize
|
||||
(index ^ -1) as usize
|
||||
} else {
|
||||
index as usize
|
||||
}
|
||||
@@ -833,8 +659,8 @@ fn fix_index(index: i32) -> usize {
|
||||
fn prepare_next_face(geom: &FbxGeometry,
|
||||
start: usize,
|
||||
temp_vertices: &mut Vec<Vec3>,
|
||||
out_triangles: &mut Vec<(usize, usize, usize)>,
|
||||
out_relative_triangles: &mut Vec<(usize, usize, usize)>) -> usize {
|
||||
out_triangles: &mut Vec<[usize; 3]>,
|
||||
out_relative_triangles: &mut Vec<[usize; 3]>) -> usize {
|
||||
out_triangles.clear();
|
||||
out_relative_triangles.clear();
|
||||
|
||||
@@ -856,21 +682,21 @@ fn prepare_next_face(geom: &FbxGeometry,
|
||||
// and they'll blow up loader.
|
||||
if a < geom.vertices.len() && b < geom.vertices.len() && c < geom.vertices.len() {
|
||||
// We have a triangle
|
||||
out_triangles.push((a, b, c));
|
||||
out_relative_triangles.push((0, 1, 2));
|
||||
out_triangles.push([a, b, c]);
|
||||
out_relative_triangles.push([0, 1, 2]);
|
||||
}
|
||||
} else if vertex_per_face > 3 {
|
||||
// Triangulate a polygon. Triangulate it!
|
||||
// Found arbitrary polygon, triangulate it.
|
||||
temp_vertices.clear();
|
||||
for i in 0..vertex_per_face {
|
||||
temp_vertices.push(geom.vertices[fix_index(geom.indices[start + i])]);
|
||||
}
|
||||
triangulate(&temp_vertices.as_slice(), out_relative_triangles);
|
||||
for triangle in out_relative_triangles.iter() {
|
||||
out_triangles.push((
|
||||
fix_index(geom.indices[start + triangle.0]),
|
||||
fix_index(geom.indices[start + triangle.1]),
|
||||
fix_index(geom.indices[start + triangle.2])));
|
||||
out_triangles.push([
|
||||
fix_index(geom.indices[start + triangle[0]]),
|
||||
fix_index(geom.indices[start + triangle[1]]),
|
||||
fix_index(geom.indices[start + triangle[2]])]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -881,36 +707,35 @@ fn convert_vertex(geom: &FbxGeometry,
|
||||
mesh: &mut Mesh,
|
||||
geometric_transform: &Mat4,
|
||||
material_index: usize,
|
||||
origin: usize,
|
||||
index: usize,
|
||||
relative_index: usize,
|
||||
skin_data: &[VertexWeightSet]) -> Result<(), FbxError> {
|
||||
let position = geometric_transform.transform_vector(*geom.vertices.get(index)
|
||||
.ok_or(FbxError::IndexOutOfBounds)?);
|
||||
|
||||
let normal = geometric_transform.transform_vector_normal(match geom.normal_mapping {
|
||||
FbxMapping::ByPolygonVertex => *geom.normals.get(origin + relative_index)
|
||||
let normal = geometric_transform.transform_vector_normal(match geom.normals.mapping {
|
||||
FbxMapping::ByPolygonVertex => *geom.normals.elements.get(relative_index)
|
||||
.ok_or(FbxError::IndexOutOfBounds)?,
|
||||
FbxMapping::ByVertex => *geom.normals.get(index).ok_or(FbxError::IndexOutOfBounds)?,
|
||||
FbxMapping::ByVertex => *geom.normals.elements.get(index).ok_or(FbxError::IndexOutOfBounds)?,
|
||||
_ => Vec3 { x: 0.0, y: 1.0, z: 0.0 }
|
||||
});
|
||||
|
||||
let tangent = geometric_transform.transform_vector_normal(match geom.tangent_mapping {
|
||||
FbxMapping::ByPolygonVertex => *geom.tangents.get(origin + relative_index)
|
||||
let tangent = geometric_transform.transform_vector_normal(match geom.tangents.mapping {
|
||||
FbxMapping::ByPolygonVertex => *geom.tangents.elements.get(relative_index)
|
||||
.ok_or(FbxError::IndexOutOfBounds)?,
|
||||
FbxMapping::ByVertex => *geom.tangents.get(index).ok_or(FbxError::IndexOutOfBounds)?,
|
||||
FbxMapping::ByVertex => *geom.tangents.elements.get(index).ok_or(FbxError::IndexOutOfBounds)?,
|
||||
_ => Vec3 { x: 0.0, y: 1.0, z: 0.0 }
|
||||
});
|
||||
|
||||
let uv = match geom.uv_mapping {
|
||||
let uv = match geom.uvs.mapping {
|
||||
FbxMapping::ByPolygonVertex => {
|
||||
match geom.uv_reference {
|
||||
FbxReference::Direct => *geom.uvs.get(origin + relative_index)
|
||||
match geom.uvs.reference {
|
||||
FbxReference::Direct => *geom.uvs.elements.get(relative_index)
|
||||
.ok_or(FbxError::IndexOutOfBounds)?,
|
||||
FbxReference::IndexToDirect => {
|
||||
let uv_index = *geom.uv_index.get(origin + relative_index)
|
||||
let uv_index = *geom.uvs.index.get(relative_index)
|
||||
.ok_or(FbxError::IndexOutOfBounds)? as usize;
|
||||
*geom.uvs.get(uv_index).ok_or(FbxError::IndexOutOfBounds)?
|
||||
*geom.uvs.elements.get(uv_index).ok_or(FbxError::IndexOutOfBounds)?
|
||||
}
|
||||
_ => Vec2 { x: 0.0, y: 0.0 }
|
||||
}
|
||||
@@ -918,9 +743,9 @@ fn convert_vertex(geom: &FbxGeometry,
|
||||
_ => Vec2 { x: 0.0, y: 0.0 }
|
||||
};
|
||||
|
||||
let material = match geom.material_mapping {
|
||||
FbxMapping::AllSame => *geom.materials.first().ok_or(FbxError::IndexOutOfBounds)? as usize,
|
||||
FbxMapping::ByPolygon => *geom.materials.get(material_index).ok_or(FbxError::IndexOutOfBounds)? as usize,
|
||||
let material = match geom.materials.mapping {
|
||||
FbxMapping::AllSame => *geom.materials.elements.first().ok_or(FbxError::IndexOutOfBounds)? as usize,
|
||||
FbxMapping::ByPolygon => *geom.materials.elements.get(material_index).ok_or(FbxError::IndexOutOfBounds)? as usize,
|
||||
_ => 0
|
||||
};
|
||||
|
||||
@@ -1108,8 +933,8 @@ impl Fbx {
|
||||
Mat4::scale(model.geometric_scale);
|
||||
|
||||
let mut temp_vertices: Vec<Vec3> = Vec::new();
|
||||
let mut triangles: Vec<(usize, usize, usize)> = Vec::new();
|
||||
let mut relative_triangles: Vec<(usize, usize, usize)> = Vec::new();
|
||||
let mut triangles = Vec::new();
|
||||
let mut relative_triangles = Vec::new();
|
||||
|
||||
for geom_handle in &model.geoms {
|
||||
let geom = self.component_pool.borrow(*geom_handle).as_geometry()?;
|
||||
@@ -1125,17 +950,17 @@ impl Fbx {
|
||||
for i in 0..triangles.len() {
|
||||
let triangle = &triangles[i];
|
||||
let relative_triangle = &relative_triangles[i];
|
||||
|
||||
convert_vertex(geom, &mut mesh, &geometric_transform, material_index, origin, triangle.0, relative_triangle.0, &skin_data)?;
|
||||
convert_vertex(geom, &mut mesh, &geometric_transform, material_index, origin, triangle.1, relative_triangle.1, &skin_data)?;
|
||||
convert_vertex(geom, &mut mesh, &geometric_transform, material_index, origin, triangle.2, relative_triangle.2, &skin_data)?;
|
||||
for (index, relative_index) in triangle.iter().zip(relative_triangle.iter()) {
|
||||
let relative_index = origin + *relative_index;
|
||||
convert_vertex(geom, &mut mesh, &geometric_transform, material_index, *index, relative_index, &skin_data)?;
|
||||
}
|
||||
}
|
||||
if geom.material_mapping == FbxMapping::ByPolygon {
|
||||
if geom.materials.mapping == FbxMapping::ByPolygon {
|
||||
material_index += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if geom.tangent_mapping == FbxMapping::Unknown {
|
||||
if geom.tangents.mapping == FbxMapping::Unknown {
|
||||
for surface in mesh.get_surfaces_mut() {
|
||||
surface.get_data().lock().unwrap().calculate_tangents();
|
||||
}
|
||||
@@ -1337,7 +1162,7 @@ impl Fbx {
|
||||
Ok(root)
|
||||
}
|
||||
|
||||
pub fn print(&mut self) {
|
||||
pub fn pretty_print(&mut self) {
|
||||
let mut stack: Vec<Handle<FbxNode>> = Vec::new();
|
||||
stack.push(self.root);
|
||||
while let Some(handle) = stack.pop() {
|
||||
|
||||
@@ -1,17 +1,12 @@
|
||||
use std::path::{
|
||||
PathBuf,
|
||||
Path,
|
||||
};
|
||||
use crate::{
|
||||
resource::fbx::{
|
||||
FbxNode,
|
||||
},
|
||||
resource::fbx::find_and_borrow_node
|
||||
use std::path::PathBuf;
|
||||
use crate::resource::fbx::{
|
||||
FbxNode,
|
||||
find_and_borrow_node,
|
||||
};
|
||||
use rg3d_core::{
|
||||
pool::{
|
||||
Handle,
|
||||
Pool
|
||||
Pool,
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -89,10 +89,4 @@ impl Texture {
|
||||
gpu_tex: None,
|
||||
})
|
||||
}
|
||||
|
||||
pub(in crate) fn bind(&self, sampler_index: usize) {
|
||||
if let Some(texture) = &self.gpu_tex {
|
||||
texture.bind(sampler_index)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -89,7 +89,6 @@ pub struct Font {
|
||||
glyphs: Vec<FontGlyph>,
|
||||
ascender: f32,
|
||||
descender: f32,
|
||||
line_gap: f32,
|
||||
char_map: HashMap<u32, usize>,
|
||||
atlas: Vec<u8>,
|
||||
atlas_size: i32,
|
||||
@@ -582,12 +581,6 @@ impl TrueType {
|
||||
}
|
||||
}
|
||||
|
||||
fn get_line_gap(&self) -> i16 {
|
||||
unsafe {
|
||||
get_i16(self.hhea_table.offset(8))
|
||||
}
|
||||
}
|
||||
|
||||
fn read_glyphs(&mut self) {
|
||||
unsafe {
|
||||
self.glyphs = Vec::with_capacity(self.num_glyphs as usize);
|
||||
@@ -881,7 +874,6 @@ impl Font {
|
||||
glyphs: Vec::new(),
|
||||
ascender: scale * f32::from(ttf.get_ascender()),
|
||||
descender: scale * f32::from(ttf.get_descender()),
|
||||
line_gap: scale * f32::from(ttf.get_line_gap()),
|
||||
char_map: HashMap::new(),
|
||||
texture: None,
|
||||
atlas: Vec::new(),
|
||||
|
||||
@@ -65,6 +65,11 @@ impl Base {
|
||||
&mut self.local_transform
|
||||
}
|
||||
|
||||
/// Sets new local transform of a node.
|
||||
pub fn set_local_transform(&mut self, transform: Transform) {
|
||||
self.local_transform = transform;
|
||||
}
|
||||
|
||||
/// Sets lifetime of node in seconds, lifetime is useful for temporary objects.
|
||||
/// Example - you firing a gun, it produces two particle systems for each shot:
|
||||
/// one for gunpowder fumes and one when bullet hits some surface. These particle
|
||||
|
||||
+14
-9
@@ -3,8 +3,8 @@ use rg3d_core::{
|
||||
math::{
|
||||
Rect,
|
||||
mat4::Mat4,
|
||||
vec2::Vec2
|
||||
}
|
||||
vec2::Vec2,
|
||||
},
|
||||
};
|
||||
use crate::scene::base::{Base, AsBase};
|
||||
|
||||
@@ -31,22 +31,22 @@ impl AsBase for Camera {
|
||||
|
||||
impl Default for Camera {
|
||||
fn default() -> Camera {
|
||||
let fov: f32 = 75.0;
|
||||
let z_near: f32 = 0.025;
|
||||
let z_far: f32 = 2048.0;
|
||||
let fov = 75.0f32;
|
||||
let z_near = 0.025;
|
||||
let z_far = 2048.0;
|
||||
|
||||
Camera {
|
||||
base: Base::default(),
|
||||
fov,
|
||||
z_near,
|
||||
z_far,
|
||||
view_matrix: Mat4::IDENTITY,
|
||||
z_near,
|
||||
projection_matrix: Mat4::perspective(
|
||||
fov.to_radians(),
|
||||
1.0,
|
||||
z_near,
|
||||
z_far
|
||||
z_far,
|
||||
),
|
||||
base: Base::default(),
|
||||
view_matrix: Mat4::IDENTITY,
|
||||
viewport: Rect { x: 0.0, y: 0.0, w: 1.0, h: 1.0 },
|
||||
}
|
||||
}
|
||||
@@ -94,6 +94,11 @@ impl Camera {
|
||||
self.projection_matrix * self.view_matrix
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_projection_matrix(&self) -> Mat4 {
|
||||
self.projection_matrix
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_view_matrix(&self) -> Mat4 {
|
||||
self.view_matrix
|
||||
|
||||
+6
-7
@@ -289,10 +289,9 @@ impl Graph {
|
||||
let SceneInterface { graph: resource_graph, .. } = model.get_scene().interface();
|
||||
if let Node::Mesh(resource_mesh) = resource_graph.get(resource_node_handle) {
|
||||
// Copy surfaces from resource and assign to meshes.
|
||||
let surfaces = mesh.get_surfaces_mut();
|
||||
surfaces.clear();
|
||||
mesh.clear_surfaces();
|
||||
for resource_surface in resource_mesh.get_surfaces() {
|
||||
surfaces.push(resource_surface.clone());
|
||||
mesh.add_surface(resource_surface.clone());
|
||||
}
|
||||
|
||||
// Remap bones
|
||||
@@ -393,7 +392,7 @@ impl Graph {
|
||||
///
|
||||
/// # Notes
|
||||
///
|
||||
/// This method allocated temporal array so it is not cheap! Should not be
|
||||
/// This method allocates temporal array so it is not cheap! Should not be
|
||||
/// used on each frame.
|
||||
pub fn traverse_iter(&self, from: Handle<Node>) -> GraphTraverseIterator {
|
||||
GraphTraverseIterator {
|
||||
@@ -406,7 +405,7 @@ impl Graph {
|
||||
///
|
||||
/// # Notes
|
||||
///
|
||||
/// This method allocated temporal array so it is not cheap! Should not be
|
||||
/// This method allocates temporal array so it is not cheap! Should not be
|
||||
/// used on each frame.
|
||||
pub fn traverse_handle_iter(&self, from: Handle<Node>) -> GraphHandleTraverseIterator {
|
||||
GraphHandleTraverseIterator {
|
||||
@@ -425,7 +424,7 @@ impl<'a> Iterator for GraphTraverseIterator<'a> {
|
||||
type Item = &'a Node;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
while let Some(handle) = self.stack.pop() {
|
||||
if let Some(handle) = self.stack.pop() {
|
||||
let node = self.graph.get(handle);
|
||||
|
||||
for child_handle in node.base().get_children() {
|
||||
@@ -448,7 +447,7 @@ impl<'a> Iterator for GraphHandleTraverseIterator<'a> {
|
||||
type Item = Handle<Node>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
while let Some(handle) = self.stack.pop() {
|
||||
if let Some(handle) = self.stack.pop() {
|
||||
for child_handle in self.graph.get(handle).base().get_children() {
|
||||
self.stack.push(*child_handle);
|
||||
}
|
||||
|
||||
+21
-6
@@ -39,6 +39,11 @@ impl SpotLight {
|
||||
self.cone_angle_cos
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_cone_angle(&self) -> f32 {
|
||||
self.cone_angle
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_cone_angle(&mut self, cone_angle: f32) {
|
||||
self.cone_angle = cone_angle;
|
||||
@@ -149,6 +154,7 @@ pub struct Light {
|
||||
base: Base,
|
||||
kind: LightKind,
|
||||
color: Color,
|
||||
cast_shadows: bool,
|
||||
}
|
||||
|
||||
impl AsBase for Light {
|
||||
@@ -167,6 +173,7 @@ impl Default for Light {
|
||||
base: Default::default(),
|
||||
kind: LightKind::Point(Default::default()),
|
||||
color: Color::WHITE,
|
||||
cast_shadows: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -183,6 +190,7 @@ impl Visit for Light {
|
||||
self.kind.visit("Kind", visitor)?;
|
||||
self.color.visit("Color", visitor)?;
|
||||
self.base.visit("Base", visitor)?;
|
||||
self.cast_shadows.visit("CastShadows", visitor)?;
|
||||
|
||||
visitor.leave_region()
|
||||
}
|
||||
@@ -191,9 +199,8 @@ impl Visit for Light {
|
||||
impl Light {
|
||||
pub fn new(kind: LightKind) -> Self {
|
||||
Self {
|
||||
base: Default::default(),
|
||||
kind,
|
||||
color: Color::WHITE,
|
||||
.. Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -221,7 +228,8 @@ impl Light {
|
||||
pub struct LightBuilder {
|
||||
base_builder: BaseBuilder,
|
||||
kind: LightKind,
|
||||
color: Option<Color>,
|
||||
color: Color,
|
||||
cast_shadows: bool,
|
||||
}
|
||||
|
||||
impl LightBuilder {
|
||||
@@ -229,12 +237,18 @@ impl LightBuilder {
|
||||
Self {
|
||||
base_builder,
|
||||
kind,
|
||||
color: None
|
||||
color: Color::WHITE,
|
||||
cast_shadows: true,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_color(mut self, color: Color) -> Self {
|
||||
self.color = Some(color);
|
||||
self.color = color;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn cast_shadows(mut self, cast_shadows: bool) -> Self {
|
||||
self.cast_shadows = cast_shadows;
|
||||
self
|
||||
}
|
||||
|
||||
@@ -242,7 +256,8 @@ impl LightBuilder {
|
||||
Light {
|
||||
base: self.base_builder.build(),
|
||||
kind: self.kind,
|
||||
color: self.color.unwrap_or(Color::WHITE)
|
||||
color: self.color,
|
||||
cast_shadows: self.cast_shadows
|
||||
}
|
||||
}
|
||||
}
|
||||
+34
-6
@@ -2,23 +2,31 @@ use crate::{
|
||||
renderer::surface::Surface,
|
||||
scene::base::{Base, AsBase}
|
||||
};
|
||||
use rg3d_core::visitor::{
|
||||
Visit,
|
||||
Visitor,
|
||||
VisitResult
|
||||
use rg3d_core::{
|
||||
visitor::{
|
||||
Visit,
|
||||
Visitor,
|
||||
VisitResult
|
||||
},
|
||||
math::aabb::AxisAlignedBoundingBox
|
||||
};
|
||||
use std::cell::Cell;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Mesh {
|
||||
base: Base,
|
||||
surfaces: Vec<Surface>,
|
||||
bounding_box: Cell<AxisAlignedBoundingBox>,
|
||||
dirty: Cell<bool>,
|
||||
}
|
||||
|
||||
impl Default for Mesh {
|
||||
fn default() -> Mesh {
|
||||
Mesh {
|
||||
base: Default::default(),
|
||||
surfaces: Vec::new()
|
||||
surfaces: Default::default(),
|
||||
bounding_box: Default::default(),
|
||||
dirty: Cell::new(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -51,12 +59,32 @@ impl Mesh {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_surfaces_mut(&mut self) -> &mut Vec<Surface> {
|
||||
pub fn get_surfaces_mut(&mut self) -> &mut [Surface] {
|
||||
&mut self.surfaces
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn clear_surfaces(&mut self) {
|
||||
self.surfaces.clear()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn add_surface(&mut self, surface: Surface) {
|
||||
self.surfaces.push(surface);
|
||||
}
|
||||
|
||||
pub fn get_bounding_box(&self) -> AxisAlignedBoundingBox {
|
||||
if self.dirty.get() {
|
||||
let mut bounding_box = AxisAlignedBoundingBox::default();
|
||||
for surface in self.surfaces.iter() {
|
||||
let data = surface.get_data();
|
||||
let data = data.lock().unwrap();
|
||||
for vertex in data.get_vertices() {
|
||||
bounding_box.add_point(vertex.position);
|
||||
}
|
||||
}
|
||||
self.bounding_box.set(bounding_box);
|
||||
}
|
||||
self.bounding_box.get()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -553,7 +553,7 @@ impl Emitter {
|
||||
if alive_particles < max_particles && alive_particles + particle_count > max_particles {
|
||||
particle_count = max_particles - particle_count;
|
||||
}
|
||||
if !self.resurrect_particles && self.spawned_particles > max_particles as u64 {
|
||||
if !self.resurrect_particles && self.spawned_particles > u64::from(max_particles) {
|
||||
self.particles_to_spawn = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,12 +1,12 @@
|
||||
use std::sync::{Arc, Mutex};
|
||||
use crate::{
|
||||
resource::texture::Texture,
|
||||
scene::base::{BaseBuilder, Base, AsBase}
|
||||
};
|
||||
use rg3d_core::{
|
||||
color::Color,
|
||||
visitor::{Visit, VisitResult, Visitor}
|
||||
};
|
||||
use crate::scene::base::{BaseBuilder, Base, AsBase};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Sprite {
|
||||
|
||||
Reference in New Issue
Block a user