Skip to content

Commit 3ffefd8

Browse files
authored
Merge pull request #77 from rust3ds/fix/lifetimes
Require frame-long lifetimes for borrowed items used during a frame
2 parents cd9cc35 + f0bd5b0 commit 3ffefd8

File tree

6 files changed

+515
-372
lines changed

6 files changed

+515
-372
lines changed

citro3d/examples/cube.rs

Lines changed: 30 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ use citro3d::macros::include_shader;
66
use citro3d::math::{
77
AspectRatio, ClipPlanes, CoordinateOrientation, FVec3, Matrix4, Projection, StereoDisplacement,
88
};
9-
use citro3d::render::ClearFlags;
10-
use citro3d::{attrib, buffer, render, shader, texenv};
9+
use citro3d::render::{ClearFlags, RenderPass, Target};
10+
use citro3d::{attrib, buffer, shader, texenv};
1111
use ctru::prelude::*;
1212
use ctru::services::gfx::{RawFrameBuffer, Screen, TopScreen3D};
1313

@@ -104,7 +104,7 @@ fn main() {
104104
let vertex_shader = shader.get(0).unwrap();
105105

106106
let program = shader::Program::new(vertex_shader).unwrap();
107-
instance.bind_program(&program);
107+
108108
let mut vbo_data = Vec::with_capacity_in(VERTS.len(), ctru::linear::LinearAllocator);
109109
for vert in VERTS.iter().enumerate().map(|(i, v)| Vertex {
110110
pos: Vec3 {
@@ -126,14 +126,6 @@ fn main() {
126126
let mut buf_info = buffer::Info::new();
127127
let vbo_slice = buf_info.add(&vbo_data, &attr_info).unwrap();
128128

129-
// Configure the first fragment shading substage to just pass through the vertex color
130-
// See https://www.opengl.org/sdk/docs/man2/xhtml/glTexEnv.xml for more insight
131-
let stage0 = texenv::Stage::new(0).unwrap();
132-
instance
133-
.texenv(stage0)
134-
.src(texenv::Mode::BOTH, texenv::Source::PrimaryColor, None, None)
135-
.func(texenv::Mode::BOTH, texenv::CombineFunc::Replace);
136-
137129
let projection_uniform_idx = program.get_uniform("projection").unwrap();
138130
let camera_transform = Matrix4::looking_at(
139131
FVec3::new(1.8, 1.8, 1.8),
@@ -158,31 +150,45 @@ fn main() {
158150
break;
159151
}
160152

161-
instance.render_frame_with(|instance| {
162-
let mut render_to = |target: &mut render::Target, projection| {
153+
instance.render_frame_with(|mut pass| {
154+
fn cast_lifetime_to_closure<'pass, T>(x: T) -> T
155+
where
156+
T: Fn(&mut RenderPass<'pass>, &'pass mut Target<'_>, &Matrix4),
157+
{
158+
x
159+
}
160+
161+
let render_to = cast_lifetime_to_closure(|pass, target, projection| {
163162
target.clear(ClearFlags::ALL, CLEAR_COLOR, 0);
164163

165-
instance
166-
.select_render_target(target)
164+
pass.select_render_target(target)
167165
.expect("failed to set render target");
168166

169-
instance.bind_vertex_uniform(projection_uniform_idx, projection * camera_transform);
167+
pass.bind_vertex_uniform(projection_uniform_idx, projection * camera_transform);
168+
169+
pass.set_attr_info(&attr_info);
170170

171-
instance.set_attr_info(&attr_info);
172-
unsafe {
173-
instance.draw_elements(buffer::Primitive::Triangles, vbo_slice, &index_buffer);
174-
}
175-
};
171+
pass.draw_elements(buffer::Primitive::Triangles, vbo_slice, &index_buffer);
172+
});
173+
174+
pass.bind_program(&program);
175+
176+
let stage0 = texenv::Stage::new(0).unwrap();
177+
pass.texenv(stage0)
178+
.src(texenv::Mode::BOTH, texenv::Source::PrimaryColor, None, None)
179+
.func(texenv::Mode::BOTH, texenv::CombineFunc::Replace);
176180

177181
let Projections {
178182
left_eye,
179183
right_eye,
180184
center,
181185
} = calculate_projections();
182186

183-
render_to(&mut top_left_target, &left_eye);
184-
render_to(&mut top_right_target, &right_eye);
185-
render_to(&mut bottom_target, &center);
187+
render_to(&mut pass, &mut top_left_target, &left_eye);
188+
render_to(&mut pass, &mut top_right_target, &right_eye);
189+
render_to(&mut pass, &mut bottom_target, &center);
190+
191+
pass
186192
});
187193
}
188194
}

citro3d/examples/fragment-light.rs

Lines changed: 37 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use citro3d::{
66
color::Color,
77
light::{DistanceAttenuation, LightEnv, Lut, LutId, LutInput, Material, Spotlight},
88
math::{AspectRatio, ClipPlanes, FVec3, Matrix4, Projection, StereoDisplacement},
9-
render::{self, ClearFlags},
9+
render::{ClearFlags, DepthFormat, RenderPass, Target},
1010
shader, texenv,
1111
};
1212
use citro3d_macros::include_shader;
@@ -260,22 +260,12 @@ fn main() {
260260

261261
let RawFrameBuffer { width, height, .. } = top_left.raw_framebuffer();
262262
let mut top_left_target = instance
263-
.render_target(
264-
width,
265-
height,
266-
top_left,
267-
Some(render::DepthFormat::Depth24Stencil8),
268-
)
263+
.render_target(width, height, top_left, Some(DepthFormat::Depth24Stencil8))
269264
.expect("failed to create render target");
270265

271266
let RawFrameBuffer { width, height, .. } = top_right.raw_framebuffer();
272267
let mut top_right_target = instance
273-
.render_target(
274-
width,
275-
height,
276-
top_right,
277-
Some(render::DepthFormat::Depth24Stencil8),
278-
)
268+
.render_target(width, height, top_right, Some(DepthFormat::Depth24Stencil8))
279269
.expect("failed to create render target");
280270

281271
let mut bottom_screen = gfx.bottom_screen.borrow_mut();
@@ -286,15 +276,14 @@ fn main() {
286276
width,
287277
height,
288278
bottom_screen,
289-
Some(render::DepthFormat::Depth24Stencil8),
279+
Some(DepthFormat::Depth24Stencil8),
290280
)
291281
.expect("failed to create bottom screen render target");
292282

293283
let shader = shader::Library::from_bytes(SHADER_BYTES).unwrap();
294284
let vertex_shader = shader.get(0).unwrap();
295285

296286
let program = shader::Program::new(vertex_shader).unwrap();
297-
instance.bind_program(&program);
298287

299288
let mut vbo_data = Vec::with_capacity_in(VERTICES.len(), ctru::linear::LinearAllocator);
300289
vbo_data.extend_from_slice(VERTICES);
@@ -344,25 +333,10 @@ fn main() {
344333
(1.0 / (0.5 * PI * d * d)).min(1.0) // We use a less aggressive attenuation to highlight the spotlight
345334
})));
346335

347-
// Bind the lighting environment for use
348-
instance.bind_light_env(Some(light_env));
349-
350336
// Setup the rotating view of the cube
351337
let mut view = Matrix4::identity();
352338
let model_idx = program.get_uniform("modelView").unwrap();
353339
view.translate(0.0, 0.0, -2.0);
354-
instance.bind_vertex_uniform(model_idx, view);
355-
356-
let stage0 = texenv::Stage::new(0).unwrap();
357-
instance
358-
.texenv(stage0)
359-
.src(
360-
texenv::Mode::BOTH,
361-
texenv::Source::FragmentPrimaryColor,
362-
Some(texenv::Source::FragmentSecondaryColor),
363-
None,
364-
)
365-
.func(texenv::Mode::BOTH, texenv::CombineFunc::Add);
366340

367341
let projection_uniform_idx = program.get_uniform("projection").unwrap();
368342

@@ -373,31 +347,51 @@ fn main() {
373347
break;
374348
}
375349

376-
instance.render_frame_with(|instance| {
377-
let mut render_to = |target: &mut render::Target, projection| {
378-
target.clear(ClearFlags::ALL, 0, 0);
350+
instance.render_frame_with(|mut pass| {
351+
fn cast_lifetime_to_closure<'pass, T>(x: T) -> T
352+
where
353+
T: Fn(&mut RenderPass<'pass>, &'pass mut Target<'_>, &Matrix4),
354+
{
355+
x
356+
}
379357

380-
instance
381-
.select_render_target(target)
358+
let render_to = cast_lifetime_to_closure(|pass, target, projection| {
359+
target.clear(ClearFlags::ALL, 0, 0);
360+
pass.select_render_target(target)
382361
.expect("failed to set render target");
383362

384-
instance.bind_vertex_uniform(projection_uniform_idx, projection);
385-
instance.bind_vertex_uniform(model_idx, view);
363+
pass.bind_vertex_uniform(projection_uniform_idx, projection);
364+
pass.bind_vertex_uniform(model_idx, view);
386365

387-
instance.set_attr_info(&attr_info);
366+
pass.set_attr_info(&attr_info);
388367

389-
instance.draw_arrays(buffer::Primitive::Triangles, vbo_data);
390-
};
368+
pass.draw_arrays(buffer::Primitive::Triangles, vbo_data);
369+
});
370+
371+
pass.bind_program(&program);
372+
pass.bind_light_env(Some(light_env.as_mut()));
373+
374+
let stage0 = texenv::Stage::new(0).unwrap();
375+
pass.texenv(stage0)
376+
.src(
377+
texenv::Mode::BOTH,
378+
texenv::Source::FragmentPrimaryColor,
379+
Some(texenv::Source::FragmentSecondaryColor),
380+
None,
381+
)
382+
.func(texenv::Mode::BOTH, texenv::CombineFunc::Add);
391383

392384
let Projections {
393385
left_eye,
394386
right_eye,
395387
center,
396388
} = calculate_projections();
397389

398-
render_to(&mut top_left_target, &left_eye);
399-
render_to(&mut top_right_target, &right_eye);
400-
render_to(&mut bottom_target, &center);
390+
render_to(&mut pass, &mut top_left_target, &left_eye);
391+
render_to(&mut pass, &mut top_right_target, &right_eye);
392+
render_to(&mut pass, &mut bottom_target, &center);
393+
394+
pass
401395
});
402396

403397
// Rotate the modelView

citro3d/examples/triangle.rs

Lines changed: 33 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@
55

66
use citro3d::macros::include_shader;
77
use citro3d::math::{AspectRatio, ClipPlanes, Matrix4, Projection, StereoDisplacement};
8-
use citro3d::render::ClearFlags;
8+
use citro3d::render::{ClearFlags, RenderPass, Target};
99
use citro3d::texenv;
10-
use citro3d::{attrib, buffer, render, shader};
10+
use citro3d::{attrib, buffer, shader};
1111
use ctru::prelude::*;
1212
use ctru::services::gfx::{RawFrameBuffer, Screen, TopScreen3D};
1313

@@ -85,55 +85,64 @@ fn main() {
8585
let vertex_shader = shader.get(0).unwrap();
8686

8787
let program = shader::Program::new(vertex_shader).unwrap();
88-
instance.bind_program(&program);
88+
let projection_uniform_idx = program.get_uniform("projection").unwrap();
8989

9090
let mut vbo_data = Vec::with_capacity_in(VERTICES.len(), ctru::linear::LinearAllocator);
9191
vbo_data.extend_from_slice(VERTICES);
9292

9393
let mut buf_info = buffer::Info::new();
9494
let (attr_info, vbo_data) = prepare_vbos(&mut buf_info, &vbo_data);
9595

96-
// Configure the first fragment shading substage to just pass through the vertex color
97-
// See https://www.opengl.org/sdk/docs/man2/xhtml/glTexEnv.xml for more insight
98-
let stage0 = texenv::Stage::new(0).unwrap();
99-
instance
100-
.texenv(stage0)
101-
.src(texenv::Mode::BOTH, texenv::Source::PrimaryColor, None, None)
102-
.func(texenv::Mode::BOTH, texenv::CombineFunc::Replace);
103-
104-
let projection_uniform_idx = program.get_uniform("projection").unwrap();
105-
10696
while apt.main_loop() {
10797
hid.scan_input();
10898

10999
if hid.keys_down().contains(KeyPad::START) {
110100
break;
111101
}
112102

113-
instance.render_frame_with(|instance| {
114-
let mut render_to = |target: &mut render::Target, projection| {
103+
instance.render_frame_with(|mut pass| {
104+
// Sadly closures can't have lifetime specifiers,
105+
// so we wrap `render_to` in this function to force the borrow checker rules.
106+
fn cast_lifetime_to_closure<'pass, T>(x: T) -> T
107+
where
108+
T: Fn(&mut RenderPass<'pass>, &'pass mut Target<'_>, &Matrix4),
109+
{
110+
x
111+
}
112+
113+
let render_to = cast_lifetime_to_closure(|pass, target, projection| {
115114
target.clear(ClearFlags::ALL, CLEAR_COLOR, 0);
116115

117-
instance
118-
.select_render_target(target)
116+
pass.select_render_target(target)
119117
.expect("failed to set render target");
118+
pass.bind_vertex_uniform(projection_uniform_idx, projection);
119+
120+
pass.set_attr_info(&attr_info);
120121

121-
instance.bind_vertex_uniform(projection_uniform_idx, projection);
122+
pass.draw_arrays(buffer::Primitive::Triangles, vbo_data);
123+
});
122124

123-
instance.set_attr_info(&attr_info);
125+
// We bind the vertex shader.
126+
pass.bind_program(&program);
124127

125-
instance.draw_arrays(buffer::Primitive::Triangles, vbo_data);
126-
};
128+
// Configure the first fragment shading substage to just pass through the vertex color
129+
// See https://www.opengl.org/sdk/docs/man2/xhtml/glTexEnv.xml for more insight
130+
let stage0 = texenv::Stage::new(0).unwrap();
131+
pass.texenv(stage0)
132+
.src(texenv::Mode::BOTH, texenv::Source::PrimaryColor, None, None)
133+
.func(texenv::Mode::BOTH, texenv::CombineFunc::Replace);
127134

128135
let Projections {
129136
left_eye,
130137
right_eye,
131138
center,
132139
} = calculate_projections();
133140

134-
render_to(&mut top_left_target, &left_eye);
135-
render_to(&mut top_right_target, &right_eye);
136-
render_to(&mut bottom_target, &center);
141+
render_to(&mut pass, &mut top_left_target, &left_eye);
142+
render_to(&mut pass, &mut top_right_target, &right_eye);
143+
render_to(&mut pass, &mut bottom_target, &center);
144+
145+
pass
137146
});
138147
}
139148
}

0 commit comments

Comments
 (0)