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
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
// Take a look at the license at the top of the repository in the LICENSE file.

use glib::{prelude::*, translate::*};

use crate::{GLContext, GLTextureBuilder, MemoryFormat, Texture};

#[cfg(not(feature = "gl"))]
pub type GLsync = *const libc::c_void;

#[cfg(feature = "gl")]
pub use gl::types::GLsync;

impl GLTextureBuilder {
    /// Builds a new [`Texture`][crate::Texture] with the values set up in the builder.
    ///
    /// The `destroy` function gets called when the returned texture gets released;
    /// either when the texture is finalized or by an explicit call to
    /// [`GLTexture::release()`][crate::GLTexture::release()]. It should release all GL resources associated
    /// with the texture, such as the [`id`][struct@crate::GLTextureBuilder#id] and the
    /// [`sync`][struct@crate::GLTextureBuilder#sync].
    ///
    /// Note that it is a programming error to call this function if any mandatory
    /// property has not been set.
    ///
    /// It is possible to call this function multiple times to create multiple textures,
    /// possibly with changing properties in between.
    ///
    /// # Returns
    ///
    /// a newly built [`Texture`][crate::Texture]
    #[doc(alias = "gdk_gl_texture_builder_build")]
    #[must_use = "The builder must be built to be used"]
    #[allow(clippy::missing_safety_doc)]
    pub unsafe fn build(self) -> Texture {
        from_glib_full(ffi::gdk_gl_texture_builder_build(
            self.to_glib_none().0,
            None,
            std::ptr::null_mut(),
        ))
    }

    #[doc(alias = "gdk_gl_texture_builder_build")]
    #[must_use = "The builder must be built to be used"]
    #[allow(clippy::missing_safety_doc)]
    pub unsafe fn build_with_release_func<F: FnOnce() + Send + 'static>(
        self,
        release_func: F,
    ) -> Texture {
        unsafe extern "C" fn destroy_closure<F: FnOnce() + Send + 'static>(
            func: glib::ffi::gpointer,
        ) {
            let released_func = Box::<F>::from_raw(func as *mut _);
            released_func();
        }
        let released_func = Box::new(release_func);
        from_glib_full(ffi::gdk_gl_texture_builder_build(
            self.to_glib_none().0,
            Some(destroy_closure::<F>),
            Box::into_raw(released_func) as glib::ffi::gpointer,
        ))
    }

    /// Sets the context to be used for the texture. This is the context that owns
    /// the texture.
    ///
    /// The context must be set before calling [`build()`][Self::build()].
    /// ## `context`
    /// The context the texture beongs to or [`None`] to unset
    #[doc(alias = "gdk_gl_texture_builder_set_context")]
    pub fn set_context(self, context: Option<&impl IsA<GLContext>>) -> Self {
        unsafe {
            ffi::gdk_gl_texture_builder_set_context(
                self.to_glib_none().0,
                context.map(|p| p.as_ref()).to_glib_none().0,
            );
        }

        self
    }

    /// Sets the format of the texture. The default is `GDK_MEMORY_R8G8B8A8_PREMULTIPLIED`.
    ///
    /// The format is the preferred format the texture data should be downloaded to. The
    /// format must be supported by the GL version of [`context`][struct@crate::GLTextureBuilder#context].
    ///
    /// GDK's texture download code assumes that the format corresponds to the storage
    /// parameters of the GL texture in an obvious way. For example, a format of
    /// `GDK_MEMORY_R16G16B16A16_PREMULTIPLIED` is expected to be stored as `GL_RGBA16`
    /// texture, and `GDK_MEMORY_G8A8` is expected to be stored as `GL_RG8` texture.
    ///
    /// Setting the right format is particularly useful when using high bit depth textures
    /// to preserve the bit depth, to set the correct value for unpremultiplied textures
    /// and to make sure opaque textures are treated as such.
    ///
    /// Non-RGBA textures need to have swizzling parameters set up properly to be usable
    /// in GSK's shaders.
    /// ## `format`
    /// The texture's format
    #[doc(alias = "gdk_gl_texture_builder_set_format")]
    pub fn set_format(self, format: MemoryFormat) -> Self {
        unsafe {
            ffi::gdk_gl_texture_builder_set_format(self.to_glib_none().0, format.into_glib());
        }

        self
    }

    /// Sets whether the texture has a mipmap. This allows the renderer and other users of the
    /// generated texture to use a higher quality downscaling.
    ///
    /// Typically, the `glGenerateMipmap` function is used to generate a mimap.
    /// ## `has_mipmap`
    /// Whether the texture has a mipmap
    #[doc(alias = "gdk_gl_texture_builder_set_has_mipmap")]
    pub fn set_has_mipmap(self, has_mipmap: bool) -> Self {
        unsafe {
            ffi::gdk_gl_texture_builder_set_has_mipmap(
                self.to_glib_none().0,
                has_mipmap.into_glib(),
            );
        }

        self
    }

    /// Sets the height of the texture.
    ///
    /// The height must be set before calling [`build()`][Self::build()].
    /// ## `height`
    /// The texture's height or 0 to unset
    #[doc(alias = "gdk_gl_texture_builder_set_height")]
    pub fn set_height(self, height: i32) -> Self {
        unsafe {
            ffi::gdk_gl_texture_builder_set_height(self.to_glib_none().0, height);
        }

        self
    }

    /// Sets the texture id of the texture. The texture id must remain unmodified
    /// until the texture was finalized. See [`build()`][Self::build()]
    /// for a longer discussion.
    ///
    /// The id must be set before calling [`build()`][Self::build()].
    /// ## `id`
    /// The texture id to be used for creating the texture
    #[doc(alias = "gdk_gl_texture_builder_set_id")]
    pub fn set_id(self, id: u32) -> Self {
        unsafe {
            ffi::gdk_gl_texture_builder_set_id(self.to_glib_none().0, id);
        }

        self
    }

    /// Sets the region to be updated by this texture. Together with
    /// [`update-texture`][struct@crate::GLTextureBuilder#update-texture] this describes an
    /// update of a previous texture.
    ///
    /// When rendering animations of large textures, it is possible that
    /// consecutive textures are only updating contents in parts of the texture.
    /// It is then possible to describe this update via these two properties,
    /// so that GTK can avoid rerendering parts that did not change.
    ///
    /// An example would be a screen recording where only the mouse pointer moves.
    /// ## `region`
    /// the region to update
    #[doc(alias = "gdk_gl_texture_builder_set_update_region")]
    pub fn set_update_region(self, region: Option<&cairo::Region>) -> Self {
        unsafe {
            ffi::gdk_gl_texture_builder_set_update_region(
                self.to_glib_none().0,
                mut_override(region.to_glib_none().0),
            );
        }

        self
    }

    /// Sets the texture to be updated by this texture. See
    /// [`set_update_region()`][Self::set_update_region()] for an explanation.
    /// ## `texture`
    /// the texture to update
    #[doc(alias = "gdk_gl_texture_builder_set_update_texture")]
    pub fn set_update_texture(self, texture: Option<&impl IsA<Texture>>) -> Self {
        unsafe {
            ffi::gdk_gl_texture_builder_set_update_texture(
                self.to_glib_none().0,
                texture.map(|p| p.as_ref()).to_glib_none().0,
            );
        }

        self
    }

    /// Sets the width of the texture.
    ///
    /// The width must be set before calling [`build()`][Self::build()].
    /// ## `width`
    /// The texture's width or 0 to unset
    #[doc(alias = "gdk_gl_texture_builder_set_width")]
    pub fn set_width(self, width: i32) -> Self {
        unsafe {
            ffi::gdk_gl_texture_builder_set_width(self.to_glib_none().0, width);
        }

        self
    }

    /// Gets the `GLsync` previously set via gdk_gl_texture_builder_set_sync().
    ///
    /// # Returns
    ///
    /// the `GLSync`
    #[doc(alias = "gdk_gl_texture_builder_get_sync")]
    #[doc(alias = "get_sync")]
    pub fn sync(&self) -> Option<GLsync> {
        let ptr = unsafe { ffi::gdk_gl_texture_builder_get_sync(self.to_glib_none().0) };
        if ptr.is_null() {
            None
        } else {
            Some(ptr as _)
        }
    }

    /// Sets the GLSync object to use for the texture.
    ///
    /// GTK will wait on this object before using the created [`Texture`][crate::Texture].
    ///
    /// The `destroy` function that is passed to [`build()`][Self::build()]
    /// is responsible for freeing the sync object when it is no longer needed.
    /// The texture builder does not destroy it and it is the callers
    /// responsibility to make sure it doesn't leak.
    /// ## `sync`
    /// the GLSync object
    #[doc(alias = "gdk_gl_texture_builder_set_sync")]
    pub fn set_sync(self, sync: Option<GLsync>) -> Self {
        let ptr = sync.unwrap_or(std::ptr::null());
        unsafe {
            ffi::gdk_gl_texture_builder_set_sync(self.to_glib_none().0, ptr as _);
        }

        self
    }
}