1#[path = "common/runtime.rs"]
2mod runtime;
3
4use ombre::prelude::*;
5
6struct Renderer<T> {
7 display_pipeline: gfx::PipelineId,
8 display_bind: gfx::Bindings,
9 offscreen_pipeline: gfx::PipelineId,
10 offscreen_bind: gfx::Bindings,
11 offscreen_pass: gfx::PassId,
12 rx: f32,
13 ry: f32,
14 width: f64,
15 height: f64,
16 backend: T,
17}
18
19impl<T: gfx::RenderBackend> RuntimeRenderer for Renderer<T> {
20 type Error = T::Error;
21
22 fn window_resized(&mut self, size: platform::LogicalSize) {
23 self.width = size.width;
24 self.height = size.height;
25 self.backend.window_resized(size);
26 }
27
28 fn frame(&mut self) -> Result<(), Self::Error> {
29 let (width, height) = (self.width as f32, self.height as f32);
30 let proj = Transform3D::perspective(60.0f32, width / height, 0.01, 100.);
31 let view = Transform3D::<f32>::look_at(
32 Vector3D::new(0.0, 1.5, 9.0),
33 Vector3D::new(0.0, 0.0, 0.0),
34 Vector3D::new(0.0, 1.0, 0.0),
35 );
36 let view_proj = proj * view;
37
38 self.rx += 0.01;
39 self.ry += 0.03;
40
41 let model = Transform3D::rotation(self.ry, Vector3D::new(0., 1.0, 0.))
42 * Transform3D::<f32>::rotation(self.rx, Vector3D::new(1.0, 0., 0.));
43 let vs_params = display_shader::Uniforms {
44 mvp: view_proj * model,
45 };
46 let mut frame = self.backend.frame();
47
48 frame.begin_pass(
50 self.offscreen_pass,
51 gfx::PassAction::clear(gfx::color::Rgba::WHITE),
52 );
53 frame.apply_pipeline(&self.offscreen_pipeline)?;
54 frame.apply_bindings(&self.offscreen_bind)?;
55 frame.apply_uniforms(&vs_params)?;
56 frame.draw(0, 36, 1)?;
57 frame.end_pass();
58
59 frame.begin_default_pass(gfx::PassAction::clear(gfx::color::Rgba::new(
61 0.0, 0., 0.45, 1.,
62 )));
63 frame.apply_pipeline(&self.display_pipeline)?;
64 frame.apply_bindings(&self.display_bind)?;
65 frame.apply_uniforms(&vs_params)?;
66 frame.draw(0, 36, 1)?;
67 frame.end_pass();
68 frame.commit();
69
70 Ok(())
71 }
72}
73
74impl<T: gfx::RenderBackend> Renderer<T> {
75 pub fn init(mut backend: T) -> Result<Self, Box<dyn std::error::Error>> {
76 let color_img = backend.texture(gfx::Texture {
77 data: gfx::Empty,
78 access: gfx::TextureAccess::RenderTarget,
79 size: Size::new(1024, 1024),
80 format: gfx::TextureFormat::Rgba8,
81 ..gfx::Texture::default()
82 })?;
83 let depth_img = backend.texture(gfx::Texture {
84 data: gfx::Empty,
85 size: Size::new(1024, 1024),
86 access: gfx::TextureAccess::RenderTarget,
87 format: gfx::TextureFormat::Depth,
88 ..gfx::Texture::default()
89 })?;
90 let offscreen_pass = backend.pass(gfx::PassDescriptor {
91 color_attachment: Some(color_img),
92 depth_attachment: Some(depth_img),
93 })?;
94
95 #[rustfmt::skip]
96 let vertices: &[f32] = &[
97 -1.0, -1.0, -1.0, 1.0, 0.5, 0.5, 1.0, 0.0, 0.0,
99 1.0, -1.0, -1.0, 1.0, 0.5, 0.5, 1.0, 1.0, 0.0,
100 1.0, 1.0, -1.0, 1.0, 0.5, 0.5, 1.0, 1.0, 1.0,
101 -1.0, 1.0, -1.0, 1.0, 0.5, 0.5, 1.0, 0.0, 1.0,
102
103 -1.0, -1.0, 1.0, 0.5, 1.0, 0.5, 1.0, 0.0, 0.0,
104 1.0, -1.0, 1.0, 0.5, 1.0, 0.5, 1.0, 1.0, 0.0,
105 1.0, 1.0, 1.0, 0.5, 1.0, 0.5, 1.0, 1.0, 1.0,
106 -1.0, 1.0, 1.0, 0.5, 1.0, 0.5, 1.0, 0.0, 1.0,
107
108 -1.0, -1.0, -1.0, 0.5, 0.5, 1.0, 1.0, 0.0, 0.0,
109 -1.0, 1.0, -1.0, 0.5, 0.5, 1.0, 1.0, 1.0, 0.0,
110 -1.0, 1.0, 1.0, 0.5, 0.5, 1.0, 1.0, 1.0, 1.0,
111 -1.0, -1.0, 1.0, 0.5, 0.5, 1.0, 1.0, 0.0, 1.0,
112
113 1.0, -1.0, -1.0, 1.0, 0.5, 0.0, 1.0, 0.0, 0.0,
114 1.0, 1.0, -1.0, 1.0, 0.5, 0.0, 1.0, 1.0, 0.0,
115 1.0, 1.0, 1.0, 1.0, 0.5, 0.0, 1.0, 1.0, 1.0,
116 1.0, -1.0, 1.0, 1.0, 0.5, 0.0, 1.0, 0.0, 1.0,
117
118 -1.0, -1.0, -1.0, 0.0, 0.5, 1.0, 1.0, 0.0, 0.0,
119 -1.0, -1.0, 1.0, 0.0, 0.5, 1.0, 1.0, 1.0, 0.0,
120 1.0, -1.0, 1.0, 0.0, 0.5, 1.0, 1.0, 1.0, 1.0,
121 1.0, -1.0, -1.0, 0.0, 0.5, 1.0, 1.0, 0.0, 1.0,
122
123 -1.0, 1.0, -1.0, 1.0, 0.0, 0.5, 1.0, 0.0, 0.0,
124 -1.0, 1.0, 1.0, 1.0, 0.0, 0.5, 1.0, 1.0, 0.0,
125 1.0, 1.0, 1.0, 1.0, 0.0, 0.5, 1.0, 1.0, 1.0,
126 1.0, 1.0, -1.0, 1.0, 0.0, 0.5, 1.0, 0.0, 1.0
127 ];
128
129 let vertex_buffer = backend.buffer(
130 gfx::BufferKind::Vertex,
131 gfx::BufferUsage::Immutable,
132 gfx::BufferSource::slice(vertices),
133 )?;
134
135 #[rustfmt::skip]
136 let indices: &[u8] = &[
137 0, 1, 2, 0, 2, 3,
138 6, 5, 4, 7, 6, 4,
139 8, 9, 10, 8, 10, 11,
140 14, 13, 12, 15, 14, 12,
141 16, 17, 18, 16, 18, 19,
142 22, 21, 20, 23, 22, 20
143 ];
144
145 let index_buffer = backend.buffer(
146 gfx::BufferKind::Index,
147 gfx::BufferUsage::Immutable,
148 gfx::BufferSource::slice(indices),
149 )?;
150
151 let offscreen_bind = gfx::Bindings {
152 vertex: vec![vertex_buffer],
153 index: Some(index_buffer),
154 textures: vec![],
155 };
156
157 let display_bind = gfx::Bindings {
158 vertex: vec![vertex_buffer],
159 index: Some(index_buffer),
160 textures: vec![color_img],
161 };
162
163 let source = gfx::ShaderSource {
164 vertex: display_shader::VERTEX,
165 fragment: display_shader::FRAGMENT,
166 };
167 let default_shader = backend.shader(source, display_shader::meta()).unwrap();
168
169 let display_pipeline = backend.pipeline(
170 default_shader,
171 gfx::PipelineDescriptor {
172 layout: &[gfx::BufferLayout {
173 attrs: &[
174 gfx::VertexAttribute::new("in_pos", gfx::VertexFormat::Float3),
175 gfx::VertexAttribute::new("in_color", gfx::VertexFormat::Float4),
176 gfx::VertexAttribute::new("in_uv", gfx::VertexFormat::Float2),
177 ],
178 ..gfx::BufferLayout::default()
179 }],
180 depth: Some(gfx::DepthState {
181 compare: gfx::Comparison::LessOrEqual,
182 offset: None,
183 }),
184 ..Default::default()
185 },
186 );
187
188 let source = gfx::ShaderSource {
189 vertex: offscreen_shader::VERTEX,
190 fragment: offscreen_shader::FRAGMENT,
191 };
192 let offscreen_shader = backend.shader(source, offscreen_shader::meta()).unwrap();
193 let offscreen_pipeline = backend.pipeline(
194 offscreen_shader,
195 gfx::PipelineDescriptor {
196 layout: &[gfx::BufferLayout {
197 stride: Some(36),
198 attrs: &[
199 gfx::VertexAttribute::new("in_pos", gfx::VertexFormat::Float3),
200 gfx::VertexAttribute::new("in_color", gfx::VertexFormat::Float4),
201 ],
202 ..Default::default()
203 }],
204 depth: Some(gfx::DepthState {
205 compare: gfx::Comparison::LessOrEqual,
206 offset: None,
207 }),
208 ..Default::default()
209 },
210 );
211
212 Ok(Self {
213 display_pipeline,
214 display_bind,
215 offscreen_pipeline,
216 offscreen_bind,
217 offscreen_pass,
218 height: 1.,
219 width: 1.,
220 rx: 0.,
221 ry: 0.,
222 backend,
223 })
224 }
225}
226
227fn main() -> Result<(), Box<dyn std::error::Error>> {
228 logger::init(log::Level::Debug)?;
229
230 let (mut win, events) =
231 platform::init("offscreen", 640, 480, &[], platform::GraphicsContext::Gl)?;
232 let ctx = unsafe { glow::Context::from_loader_function(|p| win.get_proc_address(p)) };
233 let backend = gfx::gl::Context::new(ctx, win.size())?;
234 let renderer = Renderer::init(backend)?;
235
236 runtime::run(win, events, renderer)?;
237
238 Ok(())
239}
240
241mod display_shader {
242 use super::*;
243
244 pub const VERTEX: &str = r#"
245 #version 100
246
247 attribute vec3 in_pos;
248 attribute vec4 in_color;
249 attribute vec2 in_uv;
250
251 varying lowp vec4 color;
252 varying lowp vec2 uv;
253
254 uniform mat4 mvp;
255
256 void main() {
257 gl_Position = mvp * vec4(in_pos, 1);
258 color = in_color;
259 uv = in_uv;
260 }
261 "#;
262
263 pub const FRAGMENT: &str = r#"
264 #version 100
265
266 varying lowp vec4 color;
267 varying lowp vec2 uv;
268
269 uniform sampler2D tex;
270
271 void main() {
272 gl_FragColor = color * texture2D(tex, uv);
273 }
274 "#;
275
276 pub fn meta() -> gfx::ShaderDescriptor {
277 gfx::ShaderDescriptor {
278 textures: vec!["tex".to_string()],
279 uniforms: gfx::UniformBlockLayout {
280 uniforms: vec![gfx::UniformDescriptor::new("mvp", gfx::UniformKind::Mat4)],
281 },
282 }
283 }
284
285 #[repr(C)]
286 pub struct Uniforms {
287 pub mvp: Transform3D,
288 }
289 unsafe impl bytes::Packed for Uniforms {}
290}
291
292mod offscreen_shader {
293 use super::*;
294
295 pub const VERTEX: &str = r#"
296 #version 100
297
298 attribute vec3 in_pos;
299 attribute vec4 in_color;
300
301 varying lowp vec4 color;
302
303 uniform mat4 mvp;
304
305 void main() {
306 gl_Position = mvp * vec4(in_pos, 1);
307 color = in_color;
308 }
309 "#;
310
311 pub const FRAGMENT: &str = r#"
312 #version 100
313
314 varying lowp vec4 color;
315
316 void main() {
317 gl_FragColor = color;
318 }
319 "#;
320
321 pub fn meta() -> gfx::ShaderDescriptor {
322 gfx::ShaderDescriptor {
323 textures: vec![],
324 uniforms: gfx::UniformBlockLayout {
325 uniforms: vec![gfx::UniformDescriptor::new("mvp", gfx::UniformKind::Mat4)],
326 },
327 }
328 }
329}