opengl/
opengl.rs

1use {
2    glu_sys as gl,
3    sfml::{
4        graphics::{
5            Color, Font, IntRect, RenderTarget, RenderWindow, Sprite, Text, Texture, Transformable,
6        },
7        system::Clock,
8        window::{ContextSettings, Event, Key, Style},
9        SfResult,
10    },
11    std::{ffi::c_void, mem::size_of},
12};
13
14include!("../example_common.rs");
15
16fn main() -> SfResult<()> {
17    example_ensure_right_working_dir();
18
19    let mut exit = false;
20    let mut srgb = false;
21
22    while !exit {
23        let ctx_sett = ContextSettings {
24            depth_bits: 24,
25            srgb_capable: srgb,
26            ..Default::default()
27        };
28
29        let mut window = RenderWindow::new(
30            (800, 600),
31            "SFML graphics with OpenGL",
32            Style::default(),
33            &ctx_sett,
34        )?;
35        window.set_vertical_sync_enabled(true);
36
37        let mut bg_tex = Texture::new()?;
38        bg_tex.set_srgb(srgb);
39        bg_tex.load_from_file("opengl-background.jpg", IntRect::default())?;
40        let bg_sprite = Sprite::with_texture(&bg_tex);
41
42        let font = Font::from_file("sansation.ttf")?;
43        let mut text = Text::new("SFML / OpenGL demo", &font, 32);
44        let mut srgb_instr = Text::new("Press space to toggle sRGB conversion", &font, 32);
45        let mut mipmap_instr = Text::new("Press return to toggle mipmapping", &font, 32);
46        text.set_fill_color(Color::rgba(255, 255, 255, 170));
47        srgb_instr.set_fill_color(Color::rgba(255, 255, 255, 170));
48        mipmap_instr.set_fill_color(Color::rgba(255, 255, 255, 170));
49        text.set_position((250., 450.));
50        srgb_instr.set_position((150., 500.));
51        mipmap_instr.set_position((180., 550.));
52
53        let mut texture = Texture::from_file("texture.jpg")?;
54        texture.generate_mipmap()?;
55        window.set_active(true)?;
56        unsafe {
57            gl::glEnable(gl::GL_DEPTH_TEST);
58            gl::glDepthMask(gl::GL_TRUE as _);
59            gl::glClearDepth(1.);
60            gl::glDisable(gl::GL_LIGHTING);
61            gl::glViewport(0, 0, window.size().x as _, window.size().y as _);
62            gl::glMatrixMode(gl::GL_PROJECTION);
63            gl::glLoadIdentity();
64            let ratio = (window.size().x / window.size().y) as gl::GLdouble;
65            gl::glFrustum(-ratio, ratio, -1., 1., 1., 500.);
66            gl::glEnable(gl::GL_TEXTURE_2D);
67            Texture::bind(&texture);
68        }
69
70        let cube: [f32; 180] = [
71            -20., -20., -20., 0., 0., -20., 20., -20., 1., 0., -20., -20., 20., 0., 1., -20., -20.,
72            20., 0., 1., -20., 20., -20., 1., 0., -20., 20., 20., 1., 1., 20., -20., -20., 0., 0.,
73            20., 20., -20., 1., 0., 20., -20., 20., 0., 1., 20., -20., 20., 0., 1., 20., 20., -20.,
74            1., 0., 20., 20., 20., 1., 1., -20., -20., -20., 0., 0., 20., -20., -20., 1., 0., -20.,
75            -20., 20., 0., 1., -20., -20., 20., 0., 1., 20., -20., -20., 1., 0., 20., -20., 20.,
76            1., 1., -20., 20., -20., 0., 0., 20., 20., -20., 1., 0., -20., 20., 20., 0., 1., -20.,
77            20., 20., 0., 1., 20., 20., -20., 1., 0., 20., 20., 20., 1., 1., -20., -20., -20., 0.,
78            0., 20., -20., -20., 1., 0., -20., 20., -20., 0., 1., -20., 20., -20., 0., 1., 20.,
79            -20., -20., 1., 0., 20., 20., -20., 1., 1., -20., -20., 20., 0., 0., 20., -20., 20.,
80            1., 0., -20., 20., 20., 0., 1., -20., 20., 20., 0., 1., 20., -20., 20., 1., 0., 20.,
81            20., 20., 1., 1.,
82        ];
83
84        unsafe {
85            gl::glEnableClientState(gl::GL_VERTEX_ARRAY);
86            gl::glEnableClientState(gl::GL_TEXTURE_COORD_ARRAY);
87            gl::glVertexPointer(
88                3,
89                gl::GL_FLOAT,
90                5 * size_of::<gl::GLfloat>() as i32,
91                cube.as_ptr() as *const c_void,
92            );
93            gl::glTexCoordPointer(
94                2,
95                gl::GL_FLOAT,
96                5 * size_of::<gl::GLfloat>() as i32,
97                cube.as_ptr().offset(3) as *const c_void,
98            );
99
100            // Disable normal and color vertex components
101            gl::glDisableClientState(gl::GL_NORMAL_ARRAY);
102            gl::glDisableClientState(gl::GL_COLOR_ARRAY);
103        }
104
105        window.set_active(false)?;
106        let clock = Clock::start()?;
107        let mut mipmap_enabled = true;
108
109        while window.is_open() {
110            while let Some(event) = window.poll_event() {
111                match event {
112                    Event::Closed
113                    | Event::KeyPressed {
114                        code: Key::Escape, ..
115                    } => {
116                        exit = true;
117                        window.close();
118                    }
119                    Event::KeyPressed {
120                        code: Key::Enter, ..
121                    } => {
122                        if mipmap_enabled {
123                            texture = Texture::from_file("texture.jpg")?;
124                            mipmap_enabled = false;
125                            window.set_active(true)?;
126                            Texture::bind(&texture);
127                            window.set_active(false)?;
128                        } else {
129                            texture.generate_mipmap()?;
130                            mipmap_enabled = true;
131                        }
132                    }
133                    Event::KeyPressed {
134                        code: Key::Space, ..
135                    } => {
136                        srgb = !srgb;
137                        window.close();
138                    }
139                    Event::Resized { width, height } => {
140                        window.set_active(true)?;
141                        unsafe {
142                            gl::glViewport(0, 0, width as _, height as _);
143                        }
144                        window.set_active(false)?;
145                    }
146                    _ => {}
147                }
148            }
149            window.push_gl_states();
150            window.draw(&bg_sprite);
151            window.pop_gl_states();
152
153            if let Err(e) = window.set_active(true) {
154                eprintln!("Failed to set window as active: {e}");
155            }
156
157            unsafe {
158                gl::glClear(gl::GL_DEPTH_BUFFER_BIT);
159                let x: f32 =
160                    window.mouse_position().x as f32 * 200. / window.size().x as f32 - 100.;
161                let y: f32 =
162                    -window.mouse_position().y as f32 * 200. / window.size().y as f32 + 100.;
163
164                gl::glMatrixMode(gl::GL_MODELVIEW);
165                gl::glLoadIdentity();
166                gl::glTranslatef(x, y, -100.);
167                gl::glRotatef(clock.elapsed_time().as_seconds() * 50., 1., 0., 0.);
168                gl::glRotatef(clock.elapsed_time().as_seconds() * 30., 0., 1., 0.);
169                gl::glRotatef(clock.elapsed_time().as_seconds() * 90., 0., 0., 1.);
170                gl::glDrawArrays(gl::GL_TRIANGLES, 0, 36);
171            }
172            if let Err(e) = window.set_active(false) {
173                eprintln!("Failed to set window as active: {e}");
174            }
175            window.push_gl_states();
176            window.draw(&text);
177            window.draw(&srgb_instr);
178            window.draw(&mipmap_instr);
179            window.pop_gl_states();
180            window.display();
181        }
182    }
183    Ok(())
184}