aboutsummaryrefslogtreecommitdiff
path: root/ctru-rs/src/gfx.rs
blob: 749a69a44a6880aa587f3eafe67f81e11d7053cb (plain) (blame)
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
//! LCD screens manipulation helper

use std::default::Default;
use std::ops::Drop;

use services::gspgpu::{self, FramebufferFormat};

/// A handle to libctru's gfx module. This module is a wrapper around the GSPGPU service that
/// provides helper functions and utilities for software rendering.
/// 
/// The service exits when this struct is dropped.
pub struct Gfx(());

/// Available screens on the 3DS
#[derive(Copy, Clone, Debug)]
pub enum Screen {
    /// The top screen
    Top,
    /// The bottom screen
    Bottom,
}

#[derive(Copy, Clone, Debug)]
/// Side of top screen framebuffer
///
/// The top screen of the 3DS can have two separate sets of framebuffers to support its 3D functionality
pub enum Side {
    /// The left framebuffer. This framebuffer is also the one used when 3D is disabled
    Left,
    /// The right framebuffer
    Right,
}

impl Gfx {
    /// Initialize the Gfx module with the chosen framebuffer formats for the top and bottom
    /// screens
    ///
    /// Use `Gfx::default()` instead of this function to initialize the module with default parameters
    pub fn new(
        top_fb_fmt: FramebufferFormat, bottom_fb_fmt: FramebufferFormat, use_vram_buffers: bool) -> Self {
        unsafe { ::libctru::gfxInit(top_fb_fmt.into(), bottom_fb_fmt.into(), use_vram_buffers); }
        Gfx(())
    }

    /// Enable or disable the 3D stereoscopic effect
    pub fn set_3d_enabled(&self, enabled: bool) {
        unsafe {
            ::libctru::gfxSet3D(enabled)
        }
    }

    /// Sets whether to use double buffering. Enabled by default.
    /// 
    /// Note that even when double buffering is disabled, one should still use the `swap_buffers`
    /// method on each frame to keep the gsp configuration up to date
    pub fn set_double_buffering(&self, screen: Screen, enabled: bool) {
        unsafe {
            ::libctru::gfxSetDoubleBuffering(screen.into(), enabled)
        }
    }

    /// Flushes the current framebuffers
    pub fn flush_buffers(&self) {
        unsafe { ::libctru::gfxFlushBuffers() };
    }

    /// Swaps the framebuffers and sets the gsp state
    /// 
    /// Use this function when working with software rendering
    pub fn swap_buffers(&self) {
        unsafe { ::libctru::gfxSwapBuffers() };
    }

    /// Swaps the framebuffers without manipulating the gsp state
    ///
    /// Use this function when working with GPU rendering
    pub fn swap_buffers_gpu(&self) {
        unsafe { ::libctru::gfxSwapBuffersGpu() };
    }

    /// Waits for the vertical blank interrupt
    /// 
    /// Use this to synchronize your application with the refresh rate of the LCD screens
    pub fn wait_for_vblank(&self) {
        gspgpu::wait_for_event(gspgpu::Event::VBlank0, true);

    }

    /// Gets the framebuffer format for a screen
    pub fn get_framebuffer_format(&self, screen: Screen) -> FramebufferFormat {
        unsafe { ::libctru::gfxGetScreenFormat(screen.into()).into() }
    }

    /// Change the framebuffer format for a screen
    pub fn set_framebuffer_format(&self, screen: Screen, fmt: FramebufferFormat) {
        unsafe { ::libctru::gfxSetScreenFormat(screen.into(), fmt.into()) }
    }

    /// Returns a tuple containing a pointer to the specifified framebuffer (as determined by the
    /// provided `Screen` and `Side`), the width of the framebuffer in pixels, and the height of
    /// the framebuffer in pixels
    ///
    /// Note that the pointer returned by this function can change after each call to this function
    /// if double buffering is enabled
    pub fn get_raw_framebuffer(&self, screen: Screen, side: Side) -> (*mut u8, u16, u16) {
        unsafe {
            let mut width: u16 = 0;
            let mut height: u16 = 0;
            let buf: *mut u8 = ::libctru::gfxGetFramebuffer(
                                                            screen.into(),
                                                            side.into(),
                                                            &mut width,
                                                            &mut height,
                                                            );
            (buf, width, height)
        }
    }
}

impl From<Screen> for ::libctru::gfxScreen_t {
    fn from(g: Screen) -> ::libctru::gfxScreen_t {
        use self::Screen::*;
        match g {
            Top => ::libctru::GFX_TOP,
            Bottom => ::libctru::GFX_BOTTOM,
        }
    }
}

impl From<Side> for ::libctru::gfx3dSide_t {
    fn from(s: Side) -> ::libctru::gfx3dSide_t {
        use self::Side::*;
        match s {
            Left => ::libctru::GFX_LEFT,
            Right => ::libctru::GFX_RIGHT,
        }
    }
}

impl Default for Gfx {
    fn default() -> Self {
        unsafe { ::libctru::gfxInitDefault() };
        Gfx(())
    }
}

impl Drop for Gfx {
    fn drop(&mut self) {
        unsafe { ::libctru::gfxExit() };
    }
}