bug fixes, api improvements

This commit is contained in:
Dmitry
2019-10-27 20:14:19 +03:00
parent 372d237591
commit ac4f576435
21 changed files with 395 additions and 104 deletions
+12 -14
View File
@@ -8,26 +8,24 @@
<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$/src/engine/mod.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/engine/mod.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/gui/border.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/gui/border.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/gui/button.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/gui/button.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/gui/canvas.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/gui/canvas.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/gui/draw.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/gui/draw.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$/README.md" beforeDir="false" afterPath="$PROJECT_DIR$/README.md" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/gui/formatted_text.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/gui/formatted_text.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/image.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/gui/image.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/node.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/gui/node.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/gui/scroll_bar.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/gui/scroll_bar.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/gui/scroll_content_presenter.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/gui/scroll_content_presenter.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/stack_panel.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/gui/stack_panel.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/gui/text.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/gui/text.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/gui/text_box.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/gui/text_box.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/gui/widget.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/gui/widget.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/renderer/deferred_light_renderer.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/renderer/deferred_light_renderer.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/shaders/ui_fs.glsl" beforeDir="false" afterPath="$PROJECT_DIR$/src/renderer/shaders/ui_fs.glsl" 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/ttf.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/resource/ttf.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/scene/animation.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/scene/animation.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/graph.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/scene/graph.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/scene/mod.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/scene/mod.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/utils/mod.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/utils/mod.rs" afterDir="false" />
</list>
<option name="EXCLUDED_CONVERTED_TO_IGNORED" value="true" />
<option name="SHOW_DIALOG" value="false" />
Generated
+7 -7
View File
@@ -883,7 +883,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "rg3d"
version = "0.2.2"
version = "0.2.3"
dependencies = [
"byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"glutin 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -892,14 +892,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.6",
"rg3d-physics 0.1.6",
"rg3d-core 0.1.8",
"rg3d-physics 0.1.7",
"rg3d-sound 0.1.3",
]
[[package]]
name = "rg3d-core"
version = "0.1.6"
version = "0.1.8"
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)",
@@ -908,10 +908,10 @@ dependencies = [
[[package]]
name = "rg3d-physics"
version = "0.1.6"
version = "0.1.7"
dependencies = [
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rg3d-core 0.1.6",
"rg3d-core 0.1.8",
]
[[package]]
@@ -919,7 +919,7 @@ name = "rg3d-sound"
version = "0.1.3"
dependencies = [
"byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"rg3d-core 0.1.6",
"rg3d-core 0.1.8",
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "rg3d"
version = "0.2.2"
version = "0.2.3"
authors = ["Dmitry Stepanov <[email protected]>"]
edition = "2018"
license = "MIT"
+12 -3
View File
@@ -1,6 +1,6 @@
# RG3D
3d game engine written in Rust. This project ports many features from [DmitrysEngine](https://github.com/mrDIMAS/DmitrysEngine) (written in C).
3D game engine written in Rust.
WARNING: Some places are semi-complete or just does not implemented yet, this engine is not in production-ready state yet.
@@ -25,16 +25,19 @@ These screenshots are from [rusty-shooter](https://github.com/mrDIMAS/rusty-shoo
- 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
- Animation retargetting - allows you to remap animation from one model to another.
- Automatic resource management
- Texture
- Models
@@ -45,12 +48,18 @@ These screenshots are from [rusty-shooter](https://github.com/mrDIMAS/rusty-shoo
- Bump mapping
- Particle systems with soft particles.
- Sounds - using [rg3d-sound](https://github.com/mrDIMAS/rg3d-sound) crate.
- Physics - using [rg3d-physics](https://github.com/mrDIMAS/rg3d-physics crate.
- Physics - using [rg3d-physics](https://github.com/mrDIMAS/rg3d-physics) crate.
### What will be added soon?
- Shadows
### Plans
- Optimization - some places of engine lacks optimization - there is still no culling, space partitioning for physics, etc.
- Simple editor - would be so nice to have, but until UI is not stabilized enough there is no point to try to write editor.
- Documentation - it is still incomplete because engine contstantly changing its API.
## Dependencies
- glutin - window and OpenGL initialization
+10
View File
@@ -67,6 +67,10 @@ impl TextLine {
pub fn len(&self) -> usize {
self.end - self.begin
}
pub fn is_empty(&self) -> bool {
self.end == self.begin
}
}
pub struct FormattedText {
@@ -270,6 +274,12 @@ pub struct FormattedTextBuilder {
horizontal_alignment: HorizontalAlignment,
}
impl Default for FormattedTextBuilder {
fn default() -> Self {
Self::new()
}
}
impl FormattedTextBuilder {
/// Creates new formatted text builder with default parameters.
pub fn new() -> FormattedTextBuilder {
+42 -4
View File
@@ -7,14 +7,17 @@ use crate::{
widget::{Widget, AsWidget},
Layout,
UserInterface,
Update
}
Update,
},
};
use rg3d_core::math::vec2::Vec2;
use crate::gui::node::UINode;
use rg3d_core::pool::Handle;
use crate::gui::widget::WidgetBuilder;
pub struct Image {
widget: Widget,
texture: Arc<Mutex<Texture>>,
texture: Option<Arc<Mutex<Texture>>>,
}
impl AsWidget for Image {
@@ -31,7 +34,9 @@ impl Draw for Image {
fn draw(&mut self, drawing_context: &mut DrawingContext) {
let bounds = self.widget.get_screen_bounds();
drawing_context.push_rect_filled(&bounds, None, self.widget.color);
drawing_context.commit(CommandKind::Geometry, CommandTexture::Texture(self.texture.clone()))
let texture = self.texture.as_ref().map_or(CommandTexture::None,
|t| { CommandTexture::Texture(t.clone()) });
drawing_context.commit(CommandKind::Geometry, texture);
}
}
@@ -49,4 +54,37 @@ impl Update for Image {
fn update(&mut self, dt: f32) {
self.widget.update(dt)
}
}
pub struct ImageBuilder {
widget_builder: WidgetBuilder,
texture: Option<Arc<Mutex<Texture>>>,
}
impl ImageBuilder {
pub fn new(widget_builder: WidgetBuilder) -> Self {
Self {
widget_builder,
texture: None,
}
}
pub fn with_texture(mut self, texture: Arc<Mutex<Texture>>) -> Self {
self.texture = Some(texture);
self
}
pub fn with_opt_texture(mut self, texture: Option<Arc<Mutex<Texture>>>) -> Self {
self.texture = texture;
self
}
pub fn build(self, ui: &mut UserInterface) -> Handle<UINode> {
let image = UINode::Image(Image {
widget: self.widget_builder.build(),
texture: self.texture,
});
ui.add_node(image)
}
}
+41 -32
View File
@@ -31,8 +31,8 @@ use crate::{
event::{
UIEvent,
UIEventKind,
UIEventHandler
}
UIEventHandler,
},
},
resource::{ttf::Font},
utils::UnsafeCollectionView,
@@ -71,22 +71,28 @@ pub struct Thickness {
}
impl Thickness {
pub fn zero() -> Thickness {
Thickness {
left: 0.0,
top: 0.0,
right: 0.0,
bottom: 0.0,
}
pub fn zero() -> Self {
Self { left: 0.0, top: 0.0, right: 0.0, bottom: 0.0 }
}
pub fn uniform(v: f32) -> Thickness {
Thickness {
left: v,
top: v,
right: v,
bottom: v,
}
pub fn uniform(v: f32) -> Self {
Self { left: v, top: v, right: v, bottom: v }
}
pub fn bottom(v: f32) -> Self {
Self { left: 0.0, top: 0.0, right: 0.0, bottom: v }
}
pub fn top(v: f32) -> Self {
Self { left: 0.0, top: v, right: 0.0, bottom: 0.0 }
}
pub fn left(v: f32) -> Self {
Self { left: v, top: 0.0, right: 0.0, bottom: 0.0 }
}
pub fn right(v: f32) -> Self {
Self { left: 0.0, top: 0.0, right: v, bottom: 0.0 }
}
}
@@ -149,7 +155,7 @@ fn minf(a: f32, b: f32) -> f32 {
impl UserInterface {
pub(in crate) fn new() -> UserInterface {
let font_bytes = std::include_bytes!("../built_in_font.ttf").to_vec();
let font = Font::from_memory(font_bytes, 20.0, (0..255).collect()).unwrap();
let font = Font::from_memory(font_bytes, 20.0, Font::default_char_set()).unwrap();
let font = Rc::new(RefCell::new(font));
let mut ui = UserInterface {
events: VecDeque::new(),
@@ -400,28 +406,31 @@ impl UserInterface {
widget.arrange_valid.set(true);
}
fn update_transform(&mut self, node_handle: Handle<UINode>) {
let screen_position;
fn update_node(&mut self, node_handle: Handle<UINode>) {
let widget = self.nodes.borrow(node_handle).widget();
let children = UnsafeCollectionView::from_slice(&widget.children);
if widget.parent.is_some() {
screen_position = widget.actual_local_position.get() + self.nodes.borrow(widget.parent).widget().screen_position;
} else {
screen_position = widget.actual_local_position.get();
}
let (screen_position, parent_visibility) =
if widget.parent.is_some() {
let parent_widget = self.nodes.borrow(widget.parent).widget();
(widget.actual_local_position.get() + parent_widget.screen_position, parent_widget.global_visibility)
} else {
(widget.actual_local_position.get(), true)
};
self.nodes.borrow_mut(node_handle).widget_mut().screen_position = screen_position;
let widget = self.nodes.borrow_mut(node_handle).widget_mut();
widget.screen_position = screen_position;
widget.global_visibility = widget.visibility == Visibility::Visible && parent_visibility;
// Continue on children
for child_handle in children.iter() {
self.update_transform(*child_handle);
self.update_node(*child_handle);
}
}
pub fn update(&mut self, screen_size: Vec2, dt: f32) {
self.measure(self.root_canvas, screen_size);
self.arrange(self.root_canvas, &Rect::new(0.0, 0.0, screen_size.x, screen_size.y));
self.update_transform(self.root_canvas);
self.update_node(self.root_canvas);
for node in self.nodes.iter_mut() {
node.update(dt)
}
@@ -432,7 +441,7 @@ impl UserInterface {
let node = self.nodes.borrow_mut(node_handle);
let bounds = node.widget().get_screen_bounds();
if node.widget_mut().visibility != Visibility::Visible {
if !node.widget_mut().global_visibility {
return;
}
@@ -491,7 +500,7 @@ impl UserInterface {
let mut clipped = true;
let widget = self.nodes.borrow(node_handle).widget();
if widget.visibility != Visibility::Visible {
if !widget.global_visibility {
return clipped;
}
@@ -515,7 +524,7 @@ impl UserInterface {
fn is_node_contains_point(&self, node_handle: Handle<UINode>, pt: Vec2) -> bool {
let widget = self.nodes.borrow(node_handle).widget();
if widget.visibility != Visibility::Visible {
if !widget.global_visibility {
return false;
}
@@ -847,7 +856,7 @@ impl UserInterface {
event_processed = true;
}
}
},
}
WindowEvent::ReceivedCharacter(unicode) => {
if self.keyboard_focus_node.is_some() {
let event = UIEvent {
@@ -856,7 +865,7 @@ impl UserInterface {
symbol: *unicode
},
target: Handle::NONE,
source: self.keyboard_focus_node
source: self.keyboard_focus_node,
};
self.events.push_back(event);
+5 -7
View File
@@ -12,7 +12,7 @@ use crate::gui::{
draw::DrawingContext,
Visibility,
event::UIEvent,
Update
Update,
};
use rg3d_core::{
pool::Handle,
@@ -163,12 +163,10 @@ impl ScrollViewerBuilder {
}
}
UIEventKind::MouseWheel { amount, .. } => {
if !event.handled {
if event.source == handle || ui.is_node_child_of(event.source, handle) {
let v_scroll_bar = ui.get_node_mut(v_scroll_bar).as_scroll_bar_mut();
v_scroll_bar.scroll(-amount * 10.0);
event.handled = true;
}
if !event.handled && (event.source == handle || ui.is_node_child_of(event.source, handle)) {
let v_scroll_bar = ui.get_node_mut(v_scroll_bar).as_scroll_bar_mut();
v_scroll_bar.scroll(-amount * 10.0);
event.handled = true;
}
}
_ => {}
+11 -15
View File
@@ -93,28 +93,24 @@ impl TextBox {
HorizontalDirection::Left => {
if self.caret_offset > 0 {
self.caret_offset -= 1
} else if self.caret_line > 0 {
self.caret_line -= 1;
self.caret_offset = lines[self.caret_line].len();
} else {
if self.caret_line > 0 {
self.caret_line -= 1;
self.caret_offset = lines[self.caret_line].len();
} else {
self.caret_offset = 0;
break;
}
self.caret_offset = 0;
break;
}
}
HorizontalDirection::Right => {
let line = lines.get(self.caret_line).unwrap();
if self.caret_offset < line.len() {
self.caret_offset += 1;
} else if self.caret_line < lines.len() - 1 {
self.caret_line += 1;
self.caret_offset = 0;
} else {
if self.caret_line < lines.len() - 1 {
self.caret_line += 1;
self.caret_offset = 0;
} else {
self.caret_offset = line.len();
break;
}
self.caret_offset = line.len();
break;
}
}
}
@@ -456,7 +452,7 @@ impl TextBoxBuilder {
blink_interval: 0.5,
formatted_text: FormattedTextBuilder::new()
.with_text(self.text)
.with_font(self.font.unwrap_or(ui.get_default_font()))
.with_font(self.font.unwrap_or_else(||ui.get_default_font()))
.build(),
selection_range: None,
selecting: false,
+19 -1
View File
@@ -62,6 +62,7 @@ pub struct Widget {
pub(in crate::gui) margin: Thickness,
/// Current visibility state
pub(in crate::gui) visibility: Visibility,
pub(in crate::gui) global_visibility: bool,
pub(in crate::gui) children: Vec<Handle<UINode>>,
pub(in crate::gui) parent: Handle<UINode>,
/// Indices of commands in command buffer emitted by the node.
@@ -71,6 +72,7 @@ pub struct Widget {
pub(in crate::gui) arrange_valid: Cell<bool>,
pub(in crate::gui) event_handlers: Vec<Box<UIEventHandler>>,
pub(in crate::gui) events: RefCell<VecDeque<UIEvent>>,
pub(in crate::gui) is_hit_test_visible: bool,
}
impl Default for Widget {
@@ -194,6 +196,8 @@ pub struct WidgetBuilder {
margin: Option<Thickness>,
children: Vec<Handle<UINode>>,
event_handlers: Vec<Box<UIEventHandler>>,
is_hit_test_visible: bool,
visibility: Visibility,
}
impl Default for WidgetBuilder {
@@ -219,6 +223,8 @@ impl WidgetBuilder {
desired_position: None,
children: Vec::new(),
event_handlers: Vec::new(),
is_hit_test_visible: true,
visibility: Visibility::Visible
}
}
@@ -301,6 +307,16 @@ impl WidgetBuilder {
self
}
pub fn with_hit_test_visibility(mut self, state: bool) -> Self {
self.is_hit_test_visible = state;
self
}
pub fn with_visibility(mut self, visibility: Visibility) -> Self {
self.visibility = visibility;
self
}
pub fn build(self) -> Widget {
Widget {
name: self.name.unwrap_or_default(),
@@ -319,7 +335,8 @@ impl WidgetBuilder {
vertical_alignment: self.vertical_alignment.unwrap_or(VerticalAlignment::Stretch),
horizontal_alignment: self.horizontal_alignment.unwrap_or(HorizontalAlignment::Stretch),
margin: self.margin.unwrap_or_else(Thickness::zero),
visibility: Visibility::Visible,
visibility: self.visibility,
global_visibility: true,
children: self.children,
parent: Handle::NONE,
command_indices: Vec::new(),
@@ -328,6 +345,7 @@ impl WidgetBuilder {
arrange_valid: Cell::new(false),
event_handlers: self.event_handlers,
events: RefCell::new(VecDeque::new()),
is_hit_test_visible: self.is_hit_test_visible,
}
}
}
+2 -2
View File
@@ -202,7 +202,7 @@ impl DeferredLightRenderer {
}
pub fn render(&mut self, frame_width: f32, frame_height: f32, scene: &Scene,
camera: &Camera, gbuffer: &GBuffer, white_dummy: &GpuTexture) {
camera: &Camera, gbuffer: &GBuffer, white_dummy: &GpuTexture, ambient_color: Color) {
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));
@@ -221,7 +221,7 @@ 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(Color::opaque(100, 100, 100));
self.ambient_light_shader.set_ambient_color(ambient_color);
self.ambient_light_shader.set_diffuse_texture(0);
gl::ActiveTexture(gl::TEXTURE0);
gl::BindTexture(gl::TEXTURE_2D, gbuffer.color_texture);
+4
View File
@@ -134,6 +134,10 @@ impl GpuProgram {
}
}
pub fn set_bool(&self, location: UniformLocation, value: bool) {
self.set_int(location, i32::from(if value { gl::TRUE } else { gl::FALSE }))
}
pub fn set_float(&self, location: UniformLocation, value: f32) {
unsafe {
gl::Uniform1f(location.id, value)
+49 -7
View File
@@ -15,7 +15,10 @@ pub mod gpu_texture;
mod sprite_renderer;
use std::time;
use rg3d_core::math::{vec3::Vec3, mat4::Mat4};
use rg3d_core::{
math::{vec3::Vec3, mat4::Mat4},
color::Color
};
use glutin::PossiblyCurrent;
use crate::{
engine::resource_manager::ResourceManager,
@@ -31,9 +34,12 @@ use crate::{
flat_shader::FlatShader,
sprite_renderer::SpriteRenderer
},
scene::{SceneInterface, SceneContainer},
scene::{
SceneInterface,
SceneContainer,
node::Node
}
};
use crate::scene::node::Node;
#[repr(C)]
pub struct TriangleDefinition {
@@ -141,6 +147,7 @@ pub struct Renderer {
quad: SurfaceSharedData,
last_render_time: time::Instant,
frame_size: (u32, u32),
ambient_color: Color,
}
impl Renderer {
@@ -165,10 +172,19 @@ impl Renderer {
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)
})
}
}
pub fn set_ambient_color(&mut self, color: Color) {
self.ambient_color = color;
}
pub fn get_ambient_color(&self) -> Color {
self.ambient_color
}
pub fn get_statistics(&self) -> Statistics {
self.statistics
}
@@ -223,12 +239,33 @@ impl Renderer {
_ => continue
};
self.gbuffer.fill(frame_width, frame_height, graph, camera, &self.white_dummy, &self.normal_dummy);
self.gbuffer.fill(
frame_width,
frame_height,
graph,
camera,
&self.white_dummy,
&self.normal_dummy
);
self.deferred_light_renderer.render(frame_width, frame_height, scene, camera, &self.gbuffer, &self.white_dummy);
self.deferred_light_renderer.render(
frame_width,
frame_height,
scene,
camera,
&self.gbuffer,
&self.white_dummy,
self.ambient_color
);
}
self.particle_system_renderer.render(scenes, &self.white_dummy, frame_width, frame_height, &self.gbuffer);
self.particle_system_renderer.render(
scenes,
&self.white_dummy,
frame_width,
frame_height,
&self.gbuffer
);
self.sprite_renderer.render(scenes, &self.white_dummy);
@@ -247,7 +284,12 @@ impl Renderer {
gl::BindTexture(gl::TEXTURE_2D, self.gbuffer.frame_texture);
self.quad.draw();
self.ui_renderer.render(frame_width, frame_height, drawing_context, &self.white_dummy)?;
self.ui_renderer.render(
frame_width,
frame_height,
drawing_context,
&self.white_dummy
)?;
}
self.statistics.end_frame();
+10 -2
View File
@@ -1,6 +1,7 @@
#version 330 core
uniform sampler2D diffuseTexture;
uniform bool isFont;
out vec4 FragColor;
in vec2 texCoord;
@@ -8,6 +9,13 @@ in vec4 color;
void main()
{
FragColor = color;
FragColor.a *= texture(diffuseTexture, texCoord).r;
if (isFont)
{
FragColor = color;
FragColor.a *= texture(diffuseTexture, texCoord).r;
}
else
{
FragColor = color * texture(diffuseTexture, texCoord);
}
}
+9 -1
View File
@@ -25,6 +25,7 @@ struct UIShader {
program: GpuProgram,
wvp_matrix: UniformLocation,
diffuse_texture: UniformLocation,
is_font: UniformLocation,
}
impl UIShader {
@@ -35,6 +36,7 @@ impl UIShader {
Ok(Self {
wvp_matrix: program.get_uniform_location("worldViewProjection")?,
diffuse_texture: program.get_uniform_location("diffuseTexture")?,
is_font: program.get_uniform_location("isFont")?,
program,
})
}
@@ -47,6 +49,10 @@ impl UIShader {
self.program.set_mat4(self.wvp_matrix, mat)
}
pub fn set_is_font(&self, value: bool) {
self.program.set_bool(self.is_font, value)
}
pub fn set_diffuse_texture_sampler_id(&self, id: i32) {
self.program.set_int(self.diffuse_texture, id)
}
@@ -134,13 +140,15 @@ impl UIRenderer {
false).unwrap()
);
}
font.texture.as_ref().unwrap().bind(0)
font.texture.as_ref().unwrap().bind(0);
self.shader.set_is_font(true);
},
CommandTexture::Texture(texture) => {
let texture = texture.lock().unwrap();
if let Some(texture) = &texture.gpu_tex {
texture.bind(0)
}
self.shader.set_is_font(false);
}
}
+13 -6
View File
@@ -15,6 +15,7 @@ use std::{
io::Read,
};
use crate::renderer::gpu_texture::GpuTexture;
use std::ops::Range;
const ON_CURVE_POINT: u8 = 1;
const REPEAT_FLAG: u8 = 8;
@@ -866,7 +867,11 @@ impl TtfGlyph {
}
impl Font {
pub fn from_memory(data: Vec<u8>, height: f32, char_set: Vec<u32>) -> Result<Self, ()> {
pub fn default_char_set() -> &'static [Range<u32>] {
&[0x0020..0x00FF] // Basic Latin + Latin Supplement
}
pub fn from_memory(data: Vec<u8>, height: f32, char_set: &[Range<u32>]) -> Result<Self, ()> {
let ttf = TrueType::new(data);
let scale = ttf.em_to_pixels(height);
@@ -889,15 +894,17 @@ impl Font {
font.pack();
for unicode in char_set {
let index = ttf.unicode_to_glyph_index(unicode);
font.char_map.insert(unicode, index);
for range in char_set {
for unicode in range.start..range.end {
let index = ttf.unicode_to_glyph_index(unicode);
font.char_map.insert(unicode, index);
}
}
Ok(font)
}
pub fn from_file(path: &Path, height: f32, char_set: Vec<u32>) -> Result<Self, ()> {
pub fn from_file(path: &Path, height: f32, char_set: &[Range<u32>]) -> Result<Self, ()> {
if let Ok(ref mut file) = File::open(path) {
let mut file_content: Vec<u8> = Vec::with_capacity(file.metadata().unwrap().len() as usize);
file.read_to_end(&mut file_content).unwrap();
@@ -947,7 +954,7 @@ impl Font {
for glyph in self.glyphs.iter() {
area += glyph.bitmap_height * glyph.bitmap_width;
}
(1.05 * area.sqrt()) as i32
(1.15 * area.sqrt()) as i32
}
#[inline]
+16
View File
@@ -28,6 +28,7 @@ use crate::{
},
resource::model::Model,
};
use rg3d_core::pool::{PoolPairIterator, PoolPairIteratorMut};
#[derive(Copy, Clone)]
pub struct KeyFrame {
@@ -421,6 +422,16 @@ impl AnimationContainer {
self.pool.iter()
}
#[inline]
pub fn pair_iter(&self) -> PoolPairIterator<Animation> {
self.pool.pair_iter()
}
#[inline]
pub fn pair_iter_mut(&mut self) -> PoolPairIteratorMut<Animation> {
self.pool.pair_iter_mut()
}
#[inline]
pub fn iter_mut(&mut self) -> PoolIteratorMut<Animation> {
self.pool.iter_mut()
@@ -451,6 +462,11 @@ impl AnimationContainer {
self.pool.borrow_mut(handle)
}
#[inline]
pub fn retain<P>(&mut self, pred: P) where P: FnMut(&Animation) -> bool {
self.pool.retain(pred)
}
pub fn resolve(&mut self, graph: &Graph) {
println!("Resolving animations...");
for animation in self.pool.iter_mut() {
+1 -1
View File
@@ -81,7 +81,7 @@ impl Base {
/// Returns current lifetime of a node. Will be None if node has undefined lifetime.
/// For more info about lifetimes see [`set_lifetime`].
pub fn get_lifetime(&self) -> Option<f32> {
self.lifetime.clone()
self.lifetime
}
/// Returns handle of parent node.
+69
View File
@@ -388,6 +388,75 @@ impl Graph {
pub fn pair_iter(&self) -> PoolPairIterator<Node> {
self.pool.pair_iter()
}
/// Create graph depth traversal iterator.
///
/// # Notes
///
/// This method allocated temporal array so it is not cheap! Should not be
/// used on each frame.
pub fn traverse_iter(&self, from: Handle<Node>) -> GraphTraverseIterator {
GraphTraverseIterator {
graph: self,
stack: vec![from]
}
}
/// Create graph depth traversal iterator which will emit *handles* to nodes.
///
/// # Notes
///
/// This method allocated 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 {
graph: self,
stack: vec![from]
}
}
}
pub struct GraphTraverseIterator<'a> {
graph: &'a Graph,
stack: Vec<Handle<Node>>
}
impl<'a> Iterator for GraphTraverseIterator<'a> {
type Item = &'a Node;
fn next(&mut self) -> Option<Self::Item> {
while let Some(handle) = self.stack.pop() {
let node = self.graph.get(handle);
for child_handle in node.base().get_children() {
self.stack.push(*child_handle);
}
return Some(node)
}
None
}
}
pub struct GraphHandleTraverseIterator<'a> {
graph: &'a Graph,
stack: Vec<Handle<Node>>
}
impl<'a> Iterator for GraphHandleTraverseIterator<'a> {
type Item = Handle<Node>;
fn next(&mut self) -> Option<Self::Item> {
while let Some(handle) = self.stack.pop() {
for child_handle in self.graph.get(handle).base().get_children() {
self.stack.push(*child_handle);
}
return Some(handle)
}
None
}
}
impl Visit for Graph {
+22 -1
View File
@@ -89,7 +89,7 @@ impl Scene {
}
}
pub fn update_physics(&mut self, dt: f32) {
fn update_physics(&mut self, dt: f32) {
self.physics.step(dt);
// Sync node positions with assigned physics bodies
@@ -104,6 +104,27 @@ impl Scene {
}
}
/// Removes node from scene with all associated entities, like animations etc.
///
/// # Panics
///
/// Panics if handle is invalid.
pub fn remove_node(&mut self, handle: Handle<Node>) {
for descendant in self.graph.traverse_handle_iter(handle) {
// Remove all associated animations.
self.animations.retain(|animation| {
for track in animation.get_tracks() {
if track.get_node() == descendant {
return false;
}
}
true
});
}
self.graph.remove_node(handle)
}
pub fn resolve(&mut self) {
println!("Starting resolve...");
self.graph.resolve();
+40
View File
@@ -1,4 +1,7 @@
use std::marker::PhantomData;
use crate::scene::mesh::Mesh;
use rg3d_physics::static_geometry::{StaticGeometry, StaticTriangle};
use crate::scene::base::AsBase;
pub struct UnsafeCollectionView<T> {
items: *const T,
@@ -51,4 +54,41 @@ impl<'a, T> Iterator for UnsafeCollectionViewIterator<'a, T> {
}
}
}
}
/// Small helper that creates static physics geometry from given mesh.
///
/// # Notes
///
/// This method *bakes* global transform of given mesh into static geometry
/// data. So if given mesh was at some position with any rotation and scale
/// resulting static geometry will have vertices that exactly matches given
/// mesh.
pub fn mesh_to_static_geometry(mesh: &Mesh) -> StaticGeometry {
let mut static_geometry = StaticGeometry::new();
let global_transform = mesh.base().get_global_transform();
for surface in mesh.get_surfaces() {
let data_rc = surface.get_data();
let shared_data = data_rc.lock().unwrap();
let vertices = shared_data.get_vertices();
let indices = shared_data.get_indices();
let last = indices.len() - indices.len() % 3;
let mut i: usize = 0;
while i < last {
let a = global_transform.transform_vector(vertices[indices[i] as usize].position);
let b = global_transform.transform_vector(vertices[indices[i + 1] as usize].position);
let c = global_transform.transform_vector(vertices[indices[i + 2] as usize].position);
if let Some(triangle) = StaticTriangle::from_points(&a, &b, &c) {
static_geometry.add_triangle(triangle);
} else {
println!("degenerated triangle!");
}
i += 3;
}
}
static_geometry
}