added shadows, graphics quality, minor refactoring

This commit is contained in:
Dmitry
2019-11-07 21:50:03 +03:00
parent be86eeb97c
commit 609bc70724
54 changed files with 1614 additions and 792 deletions
+64 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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"
+52
View File
@@ -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,
}
});
}
-1
View File
@@ -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" />
+1
View File
@@ -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)?;
+13
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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);
+2 -2
View File
@@ -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
View File
@@ -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
View File
@@ -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;
+133 -40
View File
@@ -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
}
}
+1 -1
View File
@@ -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
View File
@@ -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
}
}
+6 -3
View File
@@ -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) {
-2
View File
@@ -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
View File
@@ -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!");
}
}
}
}
+9 -2
View File
@@ -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
}
}
+1 -1
View File
@@ -8,5 +8,5 @@ in vec2 texCoord;
void main()
{
FragColor = ambientColor * texture(diffuseTexture, texCoord);
FragColor = ambientColor * texture(diffuseTexture, texCoord);
}
+2 -2
View File
@@ -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);
}
+90 -90
View File
@@ -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;
}
+2 -2
View File
@@ -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;
}
+1 -1
View File
@@ -8,5 +8,5 @@ in vec2 texCoord;
void main()
{
FragColor = texture(diffuseTexture, texCoord);
FragColor = texture(diffuseTexture, texCoord);
}
+2 -2
View File
@@ -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);
}
+8 -8
View File
@@ -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;
}
+36 -36
View File
@@ -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;
}
+7 -7
View File
@@ -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;
}
+10 -10
View File
@@ -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);
}
+17 -17
View File
@@ -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;
}
+1 -1
View File
@@ -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;
}
+15 -15
View File
@@ -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;
}
+1 -1
View File
@@ -9,5 +9,5 @@ in vec2 texCoord;
void main()
{
FragColor = color * texture(diffuseTexture, texCoord).r;
FragColor = color * texture(diffuseTexture, texCoord).r;
}
+9 -9
View File
@@ -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 -9
View File
@@ -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);
}
}
+3 -3
View File
@@ -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);
}
+232 -18
View File
@@ -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);
}
}
}
+8 -2
View File
@@ -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
}
}
+3 -2
View File
@@ -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
+7 -3
View File
@@ -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)
}
}
+184
View File
@@ -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
View File
@@ -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() {
+5 -10
View File
@@ -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,
}
};
-6
View File
@@ -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)
}
}
}
-8
View File
@@ -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(),
+5
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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()
}
}
+1 -1
View File
@@ -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
View File
@@ -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 {