rust_raylib/
texture.rs

1use crate::{
2    color::Color,
3    core::Raylib,
4    ffi,
5    math::{Rectangle, Vector2},
6    text::Font,
7};
8
9use std::ffi::{CStr, CString};
10
11use static_assertions::{assert_eq_align, assert_eq_size};
12
13pub use crate::ffi::{CubemapLayout, NPatchLayout, PixelFormat, TextureFilter, TextureWrap};
14
15/// Get pixel data size in bytes for certain format
16#[inline]
17pub fn get_pixel_data_size(width: u32, height: u32, format: PixelFormat) -> usize {
18    unsafe { ffi::GetPixelDataSize(width as _, height as _, format as _) as usize }
19}
20
21/// Image file format
22#[derive(Clone, Copy, Debug, PartialEq, Eq)]
23pub enum ImageFormat {
24    /// PNG
25    Png,
26    /// BMP
27    Bmp,
28    /// TGA
29    Tga,
30    /// JPEG
31    Jpg,
32    /// GIF
33    Gif,
34    /// PIC
35    Pic,
36    /// PNM
37    Pnm,
38    /// PSD
39    Psd,
40    /// HDR
41    Hdr,
42    /// QOI
43    Qoi,
44    /// DDS
45    Dds,
46    /// PKM
47    Pkm,
48    /// KTX
49    Ktx,
50    /// PVR
51    Pvr,
52    /// ASTC
53    Astc,
54}
55
56impl ImageFormat {
57    fn as_cstr(&self) -> &'static CStr {
58        use ImageFormat::*;
59
60        CStr::from_bytes_with_nul(match self {
61            Png => b".png\0",
62            Bmp => b".bmp\0",
63            Tga => b".tga\0",
64            Jpg => b".jpg\0",
65            Gif => b".gif\0",
66            Pic => b".pic\0",
67            Pnm => b".ppm\0",
68            Psd => b".psd\0",
69            Hdr => b".hdr\0",
70            Qoi => b".qoi\0",
71            Dds => b".dds\0",
72            Pkm => b".pkm\0",
73            Ktx => b".ktx\0",
74            Pvr => b".pvr\0",
75            Astc => b".astc\0",
76        })
77        .unwrap()
78    }
79}
80
81/// NPatchInfo, n-patch layout info
82#[repr(C)]
83#[derive(Clone, Debug, PartialEq)]
84pub struct NPatchInfo {
85    /// Texture source rectangle
86    pub source: Rectangle,
87    /// Left border offset
88    pub left: i32,
89    /// Top border offset
90    pub top: i32,
91    /// Right border offset
92    pub right: i32,
93    /// Bottom border offset
94    pub bottom: i32,
95    /// Layout of the n-patch: 3x3, 1x3 or 3x1
96    pub layout: NPatchLayout,
97}
98
99assert_eq_size!(NPatchInfo, ffi::NPatchInfo);
100assert_eq_align!(NPatchInfo, ffi::NPatchInfo);
101
102impl From<NPatchInfo> for ffi::NPatchInfo {
103    #[inline]
104    fn from(val: NPatchInfo) -> Self {
105        unsafe { std::mem::transmute(val) }
106    }
107}
108
109impl From<ffi::NPatchInfo> for NPatchInfo {
110    #[inline]
111    fn from(value: ffi::NPatchInfo) -> Self {
112        unsafe { std::mem::transmute(value) }
113    }
114}
115
116/// Image, pixel data stored in CPU memory (RAM)
117#[derive(Debug)]
118#[repr(transparent)]
119pub struct Image {
120    pub(crate) raw: ffi::Image,
121}
122
123impl Image {
124    /// Image base width
125    #[inline]
126    pub fn width(&self) -> u32 {
127        self.raw.width as u32
128    }
129
130    /// Image base height
131    #[inline]
132    pub fn height(&self) -> u32 {
133        self.raw.height as u32
134    }
135
136    /// Mipmap levels, 1 by default
137    #[inline]
138    pub fn mipmaps(&self) -> u32 {
139        self.raw.mipmaps as u32
140    }
141
142    /// Data format
143    #[inline]
144    pub fn format(&self) -> PixelFormat {
145        unsafe { std::mem::transmute(self.raw.format) }
146    }
147
148    /// Load image from file into CPU memory (RAM)
149    #[inline]
150    pub fn from_file(file_name: &str) -> Option<Self> {
151        let file_name = CString::new(file_name).unwrap();
152
153        let raw = unsafe { ffi::LoadImage(file_name.as_ptr()) };
154
155        if unsafe { ffi::IsImageReady(raw.clone()) } {
156            Some(Self { raw })
157        } else {
158            None
159        }
160    }
161
162    /// Load image from RAW file data
163    #[inline]
164    pub fn from_raw_file(
165        file_name: &str,
166        width: u32,
167        height: u32,
168        format: PixelFormat,
169        header_size: u32,
170    ) -> Option<Self> {
171        let file_name = CString::new(file_name).unwrap();
172
173        let raw = unsafe {
174            ffi::LoadImageRaw(
175                file_name.as_ptr(),
176                width as _,
177                height as _,
178                format as _,
179                header_size as _,
180            )
181        };
182
183        if unsafe { ffi::IsImageReady(raw.clone()) } {
184            Some(Self { raw })
185        } else {
186            None
187        }
188    }
189
190    /// Load image sequence from file (frames appended to image.data)
191    ///
192    /// Returns the amount of frames in the image.
193    #[inline]
194    pub fn from_file_anim(file_name: &str) -> Option<(Self, usize)> {
195        let file_name = CString::new(file_name).unwrap();
196        let mut frames: i32 = 0;
197
198        let image = unsafe { ffi::LoadImageAnim(file_name.as_ptr(), (&mut frames) as *mut _) };
199
200        if unsafe { ffi::IsImageReady(image.clone()) } {
201            Some((Self { raw: image }, frames as _))
202        } else {
203            None
204        }
205    }
206
207    /// Load image from memory buffer
208    ///
209    /// If `format` is None, it will make an educated guess on the ImageFormat (not all formats are supported for guessing).
210    #[inline]
211    pub fn from_memory(file_data: &[u8], format: Option<ImageFormat>) -> Option<Self> {
212        let raw = unsafe {
213            let format = if let Some(format) = format {
214                format.as_cstr().as_ptr()
215            } else {
216                CStr::from_bytes_with_nul(b".png\0").unwrap().as_ptr()
217            };
218
219            ffi::LoadImageFromMemory(format, file_data.as_ptr(), file_data.len() as _)
220        };
221
222        if unsafe { ffi::IsImageReady(raw.clone()) } {
223            Some(Self { raw })
224        } else {
225            None
226        }
227    }
228
229    /// Load image from GPU texture data
230    #[inline]
231    pub fn from_texture(texture: &Texture) -> Option<Self> {
232        let raw = unsafe { ffi::LoadImageFromTexture(texture.raw.clone()) };
233
234        if unsafe { ffi::IsImageReady(raw.clone()) } {
235            Some(Self { raw })
236        } else {
237            None
238        }
239    }
240
241    /// Load image from screen buffer and (screenshot)
242    #[inline]
243    pub fn from_screen(_raylib: &Raylib) -> Option<Self> {
244        let raw = unsafe { ffi::LoadImageFromScreen() };
245
246        if unsafe { ffi::IsImageReady(raw.clone()) } {
247            Some(Self { raw })
248        } else {
249            None
250        }
251    }
252
253    /// Export image data to file, returns true on success
254    #[inline]
255    pub fn export(&self, file_name: &str) -> bool {
256        let file_name = CString::new(file_name).unwrap();
257
258        unsafe { ffi::ExportImage(self.raw.clone(), file_name.as_ptr()) }
259    }
260
261    /// Export image as code file defining an array of bytes, returns true on success
262    #[inline]
263    pub fn export_as_code(&self, file_name: &str) -> bool {
264        let file_name = CString::new(file_name).unwrap();
265
266        unsafe { ffi::ExportImageAsCode(self.raw.clone(), file_name.as_ptr()) }
267    }
268
269    /// Generate image: plain color
270    #[inline]
271    pub fn generate_color(width: u32, height: u32, color: Color) -> Self {
272        Self {
273            raw: unsafe { ffi::GenImageColor(width as _, height as _, color.into()) },
274        }
275    }
276
277    /// Generate image: vertical gradient
278    #[inline]
279    pub fn generate_gradient_vertical(width: u32, height: u32, top: Color, bottom: Color) -> Self {
280        Self {
281            raw: unsafe {
282                ffi::GenImageGradientV(width as _, height as _, top.into(), bottom.into())
283            },
284        }
285    }
286
287    /// Generate image: horizontal gradient
288    #[inline]
289    pub fn generate_gradient_horizontal(
290        width: u32,
291        height: u32,
292        left: Color,
293        right: Color,
294    ) -> Self {
295        Self {
296            raw: unsafe {
297                ffi::GenImageGradientH(width as _, height as _, left.into(), right.into())
298            },
299        }
300    }
301
302    /// Generate image: radial gradient
303    #[inline]
304    pub fn generate_gradient_radial(
305        width: u32,
306        height: u32,
307        density: f32,
308        inner: Color,
309        outer: Color,
310    ) -> Self {
311        Self {
312            raw: unsafe {
313                ffi::GenImageGradientRadial(
314                    width as _,
315                    height as _,
316                    density,
317                    inner.into(),
318                    outer.into(),
319                )
320            },
321        }
322    }
323
324    /// Generate image: checked
325    #[inline]
326    pub fn generate_checked(
327        width: u32,
328        height: u32,
329        checks_x: u32,
330        checks_y: u32,
331        color1: Color,
332        color2: Color,
333    ) -> Self {
334        Self {
335            raw: unsafe {
336                ffi::GenImageChecked(
337                    width as _,
338                    height as _,
339                    checks_x as _,
340                    checks_y as _,
341                    color1.into(),
342                    color2.into(),
343                )
344            },
345        }
346    }
347
348    /// Generate image: white noise
349    #[inline]
350    pub fn generate_white_noise(width: u32, height: u32, factor: f32) -> Self {
351        Self {
352            raw: unsafe { ffi::GenImageWhiteNoise(width as _, height as _, factor) },
353        }
354    }
355
356    /// Generate image: perlin noise
357    #[inline]
358    pub fn generate_perlin_noise(
359        width: u32,
360        height: u32,
361        offset_x: i32,
362        offset_y: i32,
363        scale: f32,
364    ) -> Self {
365        Self {
366            raw: unsafe {
367                ffi::GenImagePerlinNoise(width as _, height as _, offset_x, offset_y, scale)
368            },
369        }
370    }
371
372    /// Generate image: cellular algorithm, bigger tileSize means bigger cells
373    #[inline]
374    pub fn generate_cellular(width: u32, height: u32, tile_size: u32) -> Self {
375        Self {
376            raw: unsafe { ffi::GenImageCellular(width as _, height as _, tile_size as _) },
377        }
378    }
379
380    /// Generate image: grayscale image from text data
381    #[inline]
382    pub fn generate_text(width: u32, height: u32, text: &str) -> Self {
383        let text = CString::new(text).unwrap();
384
385        Self {
386            raw: unsafe { ffi::GenImageText(width as _, height as _, text.as_ptr()) },
387        }
388    }
389
390    /// Create an image from another image piece
391    #[inline]
392    pub fn from_other_image(image: Self, rect: Rectangle) -> Self {
393        Self {
394            raw: unsafe { ffi::ImageFromImage(image.raw.clone(), rect.into()) },
395        }
396    }
397
398    /// Create an image from text (default font)
399    #[inline]
400    pub fn text(text: &str, font_size: u32, color: Color) -> Self {
401        let text = CString::new(text).unwrap();
402
403        Self {
404            raw: unsafe { ffi::ImageText(text.as_ptr(), font_size as _, color.into()) },
405        }
406    }
407
408    /// Create an image from text (custom sprite font)
409    #[inline]
410    pub fn text_with_font(
411        text: &str,
412        font: &Font,
413        font_size: f32,
414        spacing: f32,
415        tint: Color,
416    ) -> Self {
417        let text = CString::new(text).unwrap();
418
419        Self {
420            raw: unsafe {
421                ffi::ImageTextEx(
422                    font.raw.clone(),
423                    text.as_ptr(),
424                    font_size,
425                    spacing,
426                    tint.into(),
427                )
428            },
429        }
430    }
431
432    /// Convert image data to desired format
433    #[inline]
434    pub fn convert_to_format(&mut self, new_format: PixelFormat) {
435        unsafe { ffi::ImageFormat(self.as_mut_ptr(), new_format as _) }
436    }
437
438    /// Convert image to POT (power-of-two)
439    #[inline]
440    pub fn convert_to_power_of_two(&mut self, fill: Color) {
441        unsafe { ffi::ImageToPOT(self.as_mut_ptr(), fill.into()) }
442    }
443
444    /// Crop an image to a defined rectangle
445    #[inline]
446    pub fn crop(&mut self, rect: Rectangle) {
447        unsafe { ffi::ImageCrop(self.as_mut_ptr(), rect.into()) }
448    }
449
450    /// Crop image depending on alpha value
451    #[inline]
452    pub fn alpha_crop(&mut self, threshold: f32) {
453        unsafe { ffi::ImageAlphaCrop(self.as_mut_ptr(), threshold) }
454    }
455
456    /// Clear alpha channel to desired color
457    #[inline]
458    pub fn alpha_clear(&mut self, color: Color, threshold: f32) {
459        unsafe { ffi::ImageAlphaClear(self.as_mut_ptr(), color.into(), threshold) }
460    }
461
462    /// Apply alpha mask to image
463    #[inline]
464    pub fn alpha_mask(&mut self, alpha_mask: &Image) {
465        unsafe { ffi::ImageAlphaMask(self.as_mut_ptr(), alpha_mask.raw.clone()) }
466    }
467
468    /// Premultiply alpha channel
469    #[inline]
470    pub fn alpha_premultiply(&mut self) {
471        unsafe { ffi::ImageAlphaPremultiply(self.as_mut_ptr()) }
472    }
473
474    /// Apply Gaussian blur using a box blur approximation
475    #[inline]
476    pub fn blur_gaussian(&mut self, blur_size: u32) {
477        unsafe { ffi::ImageBlurGaussian(self.as_mut_ptr(), blur_size as _) }
478    }
479
480    /// Resize image (Bicubic scaling algorithm)
481    #[inline]
482    pub fn resize(&mut self, new_width: u32, new_height: u32) {
483        unsafe { ffi::ImageResize(self.as_mut_ptr(), new_width as _, new_height as _) }
484    }
485
486    /// Resize image (Nearest-Neighbor scaling algorithm)
487    #[inline]
488    pub fn resize_nn(&mut self, new_width: u32, new_height: u32) {
489        unsafe { ffi::ImageResizeNN(self.as_mut_ptr(), new_width as _, new_height as _) }
490    }
491
492    /// Resize canvas and fill with color
493    #[inline]
494    pub fn resize_canvas(
495        &mut self,
496        new_width: u32,
497        new_height: u32,
498        offset_x: i32,
499        offset_y: i32,
500        fill: Color,
501    ) {
502        unsafe {
503            ffi::ImageResizeCanvas(
504                self.as_mut_ptr(),
505                new_width as _,
506                new_height as _,
507                offset_x,
508                offset_y,
509                fill.into(),
510            )
511        }
512    }
513
514    /// Compute all mipmap levels for a provided image
515    #[inline]
516    pub fn compute_mipmaps(&mut self) {
517        unsafe { ffi::ImageMipmaps(self.as_mut_ptr()) }
518    }
519
520    /// Dither image data to 16bpp or lower (Floyd-Steinberg dithering)
521    #[inline]
522    pub fn dither(&mut self, r_bpp: u32, g_bpp: u32, b_bpp: u32, a_bpp: u32) {
523        unsafe {
524            ffi::ImageDither(
525                self.as_mut_ptr(),
526                r_bpp as _,
527                g_bpp as _,
528                b_bpp as _,
529                a_bpp as _,
530            )
531        }
532    }
533
534    /// Flip image vertically
535    #[inline]
536    pub fn flip_vertical(&mut self) {
537        unsafe { ffi::ImageFlipVertical(self.as_mut_ptr()) }
538    }
539
540    /// Flip image horizontally
541    #[inline]
542    pub fn flip_horizontal(&mut self) {
543        unsafe { ffi::ImageFlipHorizontal(self.as_mut_ptr()) }
544    }
545
546    /// Rotate image clockwise 90deg
547    #[inline]
548    pub fn rotate_clockwise(&mut self) {
549        unsafe { ffi::ImageRotateCW(self.as_mut_ptr()) }
550    }
551
552    /// Rotate image counter-clockwise 90deg
553    #[inline]
554    pub fn rotate_counter_clockwise(&mut self) {
555        unsafe { ffi::ImageRotateCCW(self.as_mut_ptr()) }
556    }
557
558    /// Modify image color: tint
559    #[inline]
560    pub fn color_tint(&mut self, color: Color) {
561        unsafe { ffi::ImageColorTint(self.as_mut_ptr(), color.into()) }
562    }
563
564    /// Modify image color: invert
565    #[inline]
566    pub fn color_invert(&mut self) {
567        unsafe { ffi::ImageColorInvert(self.as_mut_ptr()) }
568    }
569
570    /// Modify image color: grayscale
571    #[inline]
572    pub fn color_grayscale(&mut self) {
573        unsafe { ffi::ImageColorGrayscale(self.as_mut_ptr()) }
574    }
575
576    /// Modify image color: contrast (-100 to 100)
577    #[inline]
578    pub fn color_contrast(&mut self, contrast: f32) {
579        unsafe { ffi::ImageColorContrast(self.as_mut_ptr(), contrast) }
580    }
581
582    /// Modify image color: brightness (-255 to 255)
583    #[inline]
584    pub fn color_brightness(&mut self, brightness: i32) {
585        unsafe { ffi::ImageColorBrightness(self.as_mut_ptr(), brightness) }
586    }
587
588    /// Modify image color: replace color
589    #[inline]
590    pub fn color_replace(&mut self, color: Color, replace: Color) {
591        unsafe { ffi::ImageColorReplace(self.as_mut_ptr(), color.into(), replace.into()) }
592    }
593
594    /// Load color data from image as a Color array (RGBA - 32bit)
595    pub fn load_colors(&self) -> Vec<Color> {
596        let colors = unsafe { ffi::LoadImageColors(self.raw.clone()) };
597        let len = (self.width() * self.height()) as usize;
598
599        let mut vec = Vec::with_capacity(len);
600
601        for i in 0..len {
602            unsafe {
603                vec.push(colors.add(i).read().into());
604            }
605        }
606
607        unsafe {
608            ffi::UnloadImageColors(colors);
609        }
610
611        vec
612    }
613
614    /// Load colors palette from image as a Color array (RGBA - 32bit)
615    pub fn load_palette(&self, max_size: usize) -> Vec<Color> {
616        let mut count: i32 = 0;
617        let palette = unsafe {
618            ffi::LoadImagePalette(self.raw.clone(), max_size as _, (&mut count) as *mut _)
619        };
620
621        let mut vec = Vec::with_capacity(count as usize);
622
623        for i in 0..(count as usize) {
624            unsafe {
625                vec.push(palette.add(i).read().into());
626            }
627        }
628
629        unsafe {
630            ffi::UnloadImagePalette(palette);
631        }
632
633        vec
634    }
635
636    /// Get image alpha border rectangle
637    #[inline]
638    pub fn get_alpha_border(&self, threshold: f32) -> Rectangle {
639        unsafe { ffi::GetImageAlphaBorder(self.raw.clone(), threshold).into() }
640    }
641
642    /// Get image pixel color at (x, y) position
643    #[inline]
644    pub fn get_color(&self, x: u32, y: u32) -> Color {
645        unsafe { ffi::GetImageColor(self.raw.clone(), x as _, y as _).into() }
646    }
647
648    /// Clear image background with given color
649    #[inline]
650    pub fn clear_background(&mut self, color: Color) {
651        unsafe { ffi::ImageClearBackground(self.as_mut_ptr(), color.into()) }
652    }
653
654    /// Draw pixel within an image
655    #[inline]
656    pub fn draw_pixel(&mut self, pos: Vector2, color: Color) {
657        unsafe { ffi::ImageDrawPixelV(self.as_mut_ptr(), pos.into(), color.into()) }
658    }
659
660    /// Draw line within an image
661    #[inline]
662    pub fn draw_line(&mut self, start: Vector2, end: Vector2, color: Color) {
663        unsafe { ffi::ImageDrawLineV(self.as_mut_ptr(), start.into(), end.into(), color.into()) }
664    }
665
666    /// Draw a filled circle within an image
667    #[inline]
668    pub fn draw_circle(&mut self, center: Vector2, radius: u32, color: Color) {
669        unsafe {
670            ffi::ImageDrawCircleV(self.as_mut_ptr(), center.into(), radius as _, color.into())
671        }
672    }
673
674    /// Draw circle outline within an image
675    #[inline]
676    pub fn draw_circle_lines_v(&mut self, center: Vector2, radius: u32, color: Color) {
677        unsafe {
678            ffi::ImageDrawCircleLinesV(self.as_mut_ptr(), center.into(), radius as _, color.into())
679        }
680    }
681
682    /// Draw rectangle within an image
683    #[inline]
684    pub fn draw_rectangle(&mut self, rect: Rectangle, color: Color) {
685        unsafe { ffi::ImageDrawRectangleRec(self.as_mut_ptr(), rect.into(), color.into()) }
686    }
687
688    /// Draw rectangle lines within an image
689    #[inline]
690    pub fn draw_rectangle_lines(&mut self, rect: Rectangle, thickness: u32, color: Color) {
691        unsafe {
692            ffi::ImageDrawRectangleLines(
693                self.as_mut_ptr(),
694                rect.into(),
695                thickness as _,
696                color.into(),
697            )
698        }
699    }
700
701    /// Draw a source image within a destination image (tint applied to source)
702    #[inline]
703    pub fn draw_image(
704        &mut self,
705        source: &Image,
706        source_rect: Rectangle,
707        dest_rect: Rectangle,
708        tint: Color,
709    ) {
710        unsafe {
711            ffi::ImageDraw(
712                self.as_mut_ptr(),
713                source.raw.clone(),
714                source_rect.into(),
715                dest_rect.into(),
716                tint.into(),
717            )
718        }
719    }
720
721    /// Draw text (using default font) within an image (destination)
722    #[inline]
723    pub fn draw_text(&mut self, text: &str, position: Vector2, font_size: u32, color: Color) {
724        let text = CString::new(text).unwrap();
725
726        unsafe {
727            ffi::ImageDrawText(
728                self.as_mut_ptr(),
729                text.as_ptr(),
730                position.x as _,
731                position.y as _,
732                font_size as _,
733                color.into(),
734            )
735        }
736    }
737
738    /// Draw text (custom sprite font) within an image (destination)
739    #[inline]
740    pub fn draw_text_with_font(
741        &mut self,
742        text: &str,
743        pos: Vector2,
744        font: &Font,
745        font_size: f32,
746        spacing: f32,
747        tint: Color,
748    ) {
749        let text = CString::new(text).unwrap();
750
751        unsafe {
752            ffi::ImageDrawTextEx(
753                self.as_mut_ptr(),
754                font.raw.clone(),
755                text.as_ptr(),
756                pos.into(),
757                font_size,
758                spacing,
759                tint.into(),
760            )
761        }
762    }
763
764    /// Get pixel data size in bytes for this image
765    #[inline]
766    pub fn get_pixel_data_size(&self) -> usize {
767        unsafe { ffi::GetPixelDataSize(self.raw.width, self.raw.height, self.raw.format) as usize }
768    }
769
770    /// Returns a rectangle with x = 0, y = 0; width and height correspond to image's dimensions
771    #[inline]
772    pub fn rectangle(&self) -> Rectangle {
773        Rectangle::new(0., 0., self.raw.width as f32, self.raw.height as f32)
774    }
775
776    #[inline]
777    fn as_mut_ptr(&mut self) -> *mut ffi::Image {
778        (&mut self.raw) as *mut ffi::Image
779    }
780
781    /// Get the 'raw' ffi type
782    /// Take caution when cloning so it doesn't outlive the original
783    #[inline]
784    pub fn as_raw(&self) -> &ffi::Image {
785        &self.raw
786    }
787
788    /// Get the 'raw' ffi type
789    /// Take caution when cloning so it doesn't outlive the original
790    #[inline]
791    pub fn as_raw_mut(&mut self) -> &mut ffi::Image {
792        &mut self.raw
793    }
794
795    /// Convert a 'raw' ffi object to a safe wrapper
796    ///
797    /// # Safety
798    /// * The raw object must be correctly initialized
799    /// * The raw object should be unique. Otherwise, make sure its clones don't outlive the newly created object.
800    #[inline]
801    pub unsafe fn from_raw(raw: ffi::Image) -> Self {
802        Self { raw }
803    }
804}
805
806impl Clone for Image {
807    #[inline]
808    fn clone(&self) -> Self {
809        Self {
810            raw: unsafe { ffi::ImageCopy(self.raw.clone()) },
811        }
812    }
813}
814
815impl Drop for Image {
816    #[inline]
817    fn drop(&mut self) {
818        unsafe { ffi::UnloadImage(self.raw.clone()) }
819    }
820}
821
822/// Texture, tex data stored in GPU memory (VRAM)
823#[derive(Debug)]
824#[repr(transparent)]
825pub struct Texture {
826    pub(crate) raw: ffi::Texture,
827}
828
829impl Texture {
830    /// Texture base width
831    #[inline]
832    pub fn width(&self) -> u32 {
833        self.raw.width as u32
834    }
835
836    /// Texture base height
837    #[inline]
838    pub fn height(&self) -> u32 {
839        self.raw.height as u32
840    }
841
842    /// Mipmap levels, 1 by default
843    #[inline]
844    pub fn mipmaps(&self) -> u32 {
845        self.raw.mipmaps as u32
846    }
847
848    /// Data format
849    #[inline]
850    pub fn format(&self) -> PixelFormat {
851        unsafe { std::mem::transmute(self.raw.format) }
852    }
853
854    /// Load texture from file into GPU memory (VRAM)
855    #[inline]
856    pub fn from_file(file_name: &str) -> Option<Self> {
857        let file_name = CString::new(file_name).unwrap();
858
859        let raw = unsafe { ffi::LoadTexture(file_name.as_ptr()) };
860
861        if unsafe { ffi::IsTextureReady(raw.clone()) } {
862            Some(Self { raw })
863        } else {
864            None
865        }
866    }
867
868    /// Load texture from image data
869    #[inline]
870    pub fn from_image(image: &Image) -> Option<Self> {
871        let raw = unsafe { ffi::LoadTextureFromImage(image.raw.clone()) };
872
873        if unsafe { ffi::IsTextureReady(raw.clone()) } {
874            Some(Self { raw })
875        } else {
876            None
877        }
878    }
879
880    /// Load cubemap from image, multiple image cubemap layouts supported
881    #[inline]
882    pub fn from_cubemap(image: &Image, layout: CubemapLayout) -> Option<TextureCubemap> {
883        let raw = unsafe { ffi::LoadTextureCubemap(image.raw.clone(), layout as _) };
884
885        if unsafe { ffi::IsTextureReady(raw.clone()) } {
886            Some(Self { raw })
887        } else {
888            None
889        }
890    }
891
892    /// Update GPU texture with new data
893    ///
894    /// Returns `true` on success, `false` if `pixels` has wrong size (use [`get_pixel_data_size()`])
895    #[inline]
896    pub fn update(&mut self, pixels: &[u8]) -> bool {
897        if pixels.len() == self.get_pixel_data_size() {
898            unsafe {
899                ffi::UpdateTexture(self.raw.clone(), pixels.as_ptr() as *const _);
900            }
901            true
902        } else {
903            false
904        }
905    }
906
907    /// Update GPU texture rectangle with new data
908    ///
909    /// Returns `true` on success, `false` if `pixels` has wrong size or `rect` goes out of bounds
910    #[inline]
911    pub fn update_rect(&mut self, rect: Rectangle, pixels: &[u8]) -> bool {
912        if pixels.len() == get_pixel_data_size(rect.width as u32, rect.height as u32, self.format())
913            && rect.x >= 0.
914            && rect.y >= 0.
915            && ((rect.x + rect.width) as u32) < self.width()
916            && ((rect.y + rect.height) as u32) < self.height()
917        {
918            unsafe {
919                ffi::UpdateTextureRec(self.raw.clone(), rect.into(), pixels.as_ptr() as *const _);
920            }
921            true
922        } else {
923            false
924        }
925    }
926
927    /// Get pixel data size in bytes for this texture
928    #[inline]
929    pub fn get_pixel_data_size(&self) -> usize {
930        get_pixel_data_size(self.width(), self.height(), self.format())
931    }
932
933    /// Generate GPU mipmaps for a texture
934    #[inline]
935    pub fn generate_mipmaps(&mut self) {
936        unsafe {
937            ffi::GenTextureMipmaps(&mut self.raw as *mut _);
938        }
939    }
940
941    /// Set texture scaling filter mode
942    #[inline]
943    pub fn set_filter(&mut self, filter: TextureFilter) {
944        unsafe { ffi::SetTextureFilter(self.raw.clone(), filter as _) }
945    }
946
947    /// Set texture wrapping mode
948    #[inline]
949    pub fn set_wrap(&mut self, wrap: TextureWrap) {
950        unsafe { ffi::SetTextureWrap(self.raw.clone(), wrap as _) }
951    }
952
953    /// Get the 'raw' ffi type
954    /// Take caution when cloning so it doesn't outlive the original
955    #[inline]
956    pub fn as_raw(&self) -> &ffi::Texture {
957        &self.raw
958    }
959
960    /// Get the 'raw' ffi type
961    /// Take caution when cloning so it doesn't outlive the original
962    #[inline]
963    pub fn as_raw_mut(&mut self) -> &mut ffi::Texture {
964        &mut self.raw
965    }
966
967    /// Convert a 'raw' ffi object to a safe wrapper
968    ///
969    /// # Safety
970    /// * The raw object must be correctly initialized
971    /// * The raw object should be unique. Otherwise, make sure its clones don't outlive the newly created object.
972    #[inline]
973    pub unsafe fn from_raw(raw: ffi::Texture) -> Self {
974        Self { raw }
975    }
976}
977
978impl Drop for Texture {
979    #[inline]
980    fn drop(&mut self) {
981        unsafe { ffi::UnloadTexture(self.raw.clone()) }
982    }
983}
984
985/// RenderTexture, fbo for texture rendering
986#[derive(Debug)]
987#[repr(transparent)]
988pub struct RenderTexture {
989    pub(crate) raw: ffi::RenderTexture,
990}
991
992impl RenderTexture {
993    /// Texture base width
994    #[inline]
995    pub fn width(&self) -> u32 {
996        self.raw.texture.width as u32
997    }
998
999    /// Texture base height
1000    #[inline]
1001    pub fn height(&self) -> u32 {
1002        self.raw.texture.height as u32
1003    }
1004
1005    /// Load texture for rendering (framebuffer)
1006    #[inline]
1007    pub fn new(width: u32, height: u32) -> Option<Self> {
1008        let raw = unsafe { ffi::LoadRenderTexture(width as _, height as _) };
1009
1010        if unsafe { ffi::IsRenderTextureReady(raw.clone()) } {
1011            Some(Self { raw })
1012        } else {
1013            None
1014        }
1015    }
1016
1017    /// Get the 'raw' ffi type
1018    /// Take caution when cloning so it doesn't outlive the original
1019    #[inline]
1020    pub fn as_raw(&self) -> &ffi::RenderTexture {
1021        &self.raw
1022    }
1023
1024    /// Get the 'raw' ffi type
1025    /// Take caution when cloning so it doesn't outlive the original
1026    #[inline]
1027    pub fn as_raw_mut(&mut self) -> &mut ffi::RenderTexture {
1028        &mut self.raw
1029    }
1030
1031    /// Convert a 'raw' ffi object to a safe wrapper
1032    ///
1033    /// # Safety
1034    /// * The raw object must be correctly initialized
1035    /// * The raw object should be unique. Otherwise, make sure its clones don't outlive the newly created object.
1036    #[inline]
1037    pub unsafe fn from_raw(raw: ffi::RenderTexture) -> Self {
1038        Self { raw }
1039    }
1040}
1041
1042impl Drop for RenderTexture {
1043    #[inline]
1044    fn drop(&mut self) {
1045        unsafe { ffi::UnloadRenderTexture(self.raw.clone()) }
1046    }
1047}
1048
1049/// Texture2D, same as Texture
1050pub type Texture2D = Texture;
1051
1052/// TextureCubemap, same as Texture
1053pub type TextureCubemap = Texture;
1054
1055/// RenderTexture2D, same as RenderTexture
1056pub type RenderTexture2D = RenderTexture;