1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
use glutin;
use gfx_window_glutin;
use gfx_device_gl;
use gfx;
use gfx_text;
use cgmath::{Matrix4, One};
use id_tree::NodeId;
use types::*;
use RenderGroup;
use Scene;
use SceneNode;
use SceneNodeEntry;
use Camera;
use defines::{pipe, Locals, Globals};
/// Interface responsible for window creation and scene traversal for drawing.
pub struct Renderer {
pub factory: Factory,
device: Device,
encoder: Encoder,
/// Output framebuffer
main_color: OutputColor,
/// Output depth buffer
main_depth: OutputDepth,
/// Color for OpenGL clear command
clear_color: [f32; 4],
/// Width of the frame
pub width: u32,
/// Height of the frame
pub height: u32,
/// Global data for a given frame
globals: gfx::handle::Buffer<Resources, Globals>,
/// Text renderer
text: gfx_text::Renderer<Resources, gfx_device_gl::Factory>,
// All possible pipelines:
/// The pipeline for drawing with the `Simple` group
pso_simple: PipelineState<pipe::Meta>,
}
impl Renderer {
/// Create a new rendering instance. You should probably use `ValorBuilder` instead of this method.
pub(crate) fn new(
factory: Factory,
device: Device,
encoder: Encoder,
main_color: OutputColor,
main_depth: OutputDepth,
clear_color: [f32; 4],
width: u32,
height: u32,
globals: gfx::handle::Buffer<Resources, Globals>,
text: gfx_text::Renderer<Resources, gfx_device_gl::Factory>,
pso_simple: PipelineState<pipe::Meta>,
) -> Self {
Renderer {
device,
factory,
main_color,
main_depth,
clear_color,
encoder,
text,
pso_simple,
globals,
width,
height,
}
}
/// Update the output buffers based on the window width and height.
pub fn update_views(&mut self, window: &glutin::GlWindow) {
gfx_window_glutin::update_views(window, &mut self.main_color, &mut self.main_depth);
}
/// Setter for the frame dimensions.
pub fn set_dimensions(&mut self, width: u32, height: u32) {
self.width = width;
self.height = height;
}
/// Traverse the scene graph and render all the nodes from the camera's perspective.
pub fn render(&mut self, scene: &mut Scene, camera: &Camera) {
use gfx::Device;
let globals = Globals { mx_vp: camera.get_view_proj().into() };
self.encoder.update_constant_buffer(&self.globals, &globals);
// Clear background color
self.encoder.clear(&self.main_color, self.clear_color);
// Iterate over the entries in the scene graph
for node_container in scene.traverse() {
// Get the node which has the model and transform data
let node: &SceneNode = node_container.data();
let parent_id = node_container.parent();
match node.entry {
SceneNodeEntry::Model(ref model) => {
// Fetch correct PSO to draw with
let pso = match node.group {
RenderGroup::Simple => &self.pso_simple,
_ => &self.pso_simple,
};
// Update locals with transform
let transform = self.get_transform(scene, node, parent_id);
let locals = Locals { mx_world: transform.into() };
// TODO: cache locals on scene graph
// Flush updated locals into gpu buffers
let model = model.borrow_mut();
self.encoder.update_constant_buffer(
&model.gpu_data.locals,
&locals,
);
let params = pipe::Data {
vbuf: model.gpu_data.vertices.clone(),
cb_locals: model.gpu_data.locals.clone(),
cb_globals: self.globals.clone(),
out: self.main_color.clone(),
};
self.encoder.draw(&model.gpu_data.slice, pso, ¶ms);
},
SceneNodeEntry::Text(ref text) => {
let text = text.borrow_mut();
// Add some text 10 pixels down and right from the top left screen corner.
self.text.add(&text.data, text.position, text.color);
// Draw text.
self.text.draw(&mut self.encoder, &self.main_color).unwrap();
},
SceneNodeEntry::Empty => {}
};
}
self.encoder.flush(&mut self.device);
self.device.cleanup();
}
/// Get ancestor transforms for a given node
fn get_transform (&self, scene: &Scene, node: &SceneNode, parent_id: Option<&NodeId>) -> Matrix4<f32> {
let identity: Matrix4<f32> = Matrix4::one();
// Pool transforms for ancestors of the parent
let mut transforms: Vec<Matrix4<f32>> = vec![];
if let Some(id) = parent_id {
// Get ancestor transforms
transforms = scene
.graph
.ancestors(id)
.unwrap()
.map(|n| n.data().transform)
.collect();
transforms.reverse();
// Get parent transform
let parent = scene.graph.get(id).unwrap();
transforms.push(parent.data().transform);
};
transforms.push(node.transform);
let transform = transforms.iter().fold(identity, |acc, t| acc * t);
transform
}
}