1use crate::{Error, Result};
2use core::convert::TryFrom;
3use core::ptr::null_mut;
4use obs_sys::{
5 gs_address_mode, gs_address_mode_GS_ADDRESS_BORDER, gs_address_mode_GS_ADDRESS_CLAMP,
6 gs_address_mode_GS_ADDRESS_MIRROR, gs_address_mode_GS_ADDRESS_MIRRORONCE,
7 gs_address_mode_GS_ADDRESS_WRAP, gs_color_format, gs_color_format_GS_A8,
8 gs_color_format_GS_BGRA, gs_color_format_GS_BGRX, gs_color_format_GS_DXT1,
9 gs_color_format_GS_DXT3, gs_color_format_GS_DXT5, gs_color_format_GS_R10G10B10A2,
10 gs_color_format_GS_R16, gs_color_format_GS_R16F, gs_color_format_GS_R32F,
11 gs_color_format_GS_R8, gs_color_format_GS_R8G8, gs_color_format_GS_RG16F,
12 gs_color_format_GS_RG32F, gs_color_format_GS_RGBA, gs_color_format_GS_RGBA16,
13 gs_color_format_GS_RGBA16F, gs_color_format_GS_RGBA32F, gs_color_format_GS_UNKNOWN,
14 gs_effect_create, gs_effect_destroy, gs_effect_get_param_by_name, gs_effect_get_param_info,
15 gs_effect_param_info, gs_effect_set_next_sampler, gs_effect_set_vec2, gs_effect_t, gs_eparam_t,
16 gs_sample_filter, gs_sample_filter_GS_FILTER_ANISOTROPIC, gs_sample_filter_GS_FILTER_LINEAR,
17 gs_sample_filter_GS_FILTER_MIN_LINEAR_MAG_MIP_POINT,
18 gs_sample_filter_GS_FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR,
19 gs_sample_filter_GS_FILTER_MIN_MAG_LINEAR_MIP_POINT,
20 gs_sample_filter_GS_FILTER_MIN_MAG_POINT_MIP_LINEAR,
21 gs_sample_filter_GS_FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT,
22 gs_sample_filter_GS_FILTER_MIN_POINT_MAG_MIP_LINEAR, gs_sample_filter_GS_FILTER_POINT,
23 gs_sampler_info, gs_samplerstate_create, gs_samplerstate_destroy, gs_samplerstate_t,
24 gs_shader_param_type, gs_shader_param_type_GS_SHADER_PARAM_BOOL,
25 gs_shader_param_type_GS_SHADER_PARAM_FLOAT, gs_shader_param_type_GS_SHADER_PARAM_INT,
26 gs_shader_param_type_GS_SHADER_PARAM_INT2, gs_shader_param_type_GS_SHADER_PARAM_INT3,
27 gs_shader_param_type_GS_SHADER_PARAM_INT4, gs_shader_param_type_GS_SHADER_PARAM_MATRIX4X4,
28 gs_shader_param_type_GS_SHADER_PARAM_STRING, gs_shader_param_type_GS_SHADER_PARAM_TEXTURE,
29 gs_shader_param_type_GS_SHADER_PARAM_UNKNOWN, gs_shader_param_type_GS_SHADER_PARAM_VEC2,
30 gs_shader_param_type_GS_SHADER_PARAM_VEC3, gs_shader_param_type_GS_SHADER_PARAM_VEC4,
31 gs_texture_create, gs_texture_destroy, gs_texture_get_height, gs_texture_get_width,
32 gs_texture_map, gs_texture_set_image, gs_texture_t, gs_texture_unmap, obs_allow_direct_render,
33 obs_allow_direct_render_OBS_ALLOW_DIRECT_RENDERING,
34 obs_allow_direct_render_OBS_NO_DIRECT_RENDERING, obs_enter_graphics, obs_leave_graphics,
35 obs_source_draw, vec2, vec3, vec4, GS_DYNAMIC,
36};
37use paste::item;
38use std::{
39 ffi::{CStr, CString},
40 ptr,
41};
42use std::{os::raw::c_int, slice};
43
44use super::string::ObsString;
45
46struct GraphicsGuard;
50
51impl GraphicsGuard {
52 fn enter() -> Self {
53 unsafe {
54 obs_enter_graphics();
55 }
56 Self
57 }
58
59 pub fn with_enter<T, F: FnOnce() -> T>(f: F) -> T {
60 let _g = Self::enter();
61 f()
62 }
63}
64
65impl Drop for GraphicsGuard {
66 fn drop(&mut self) {
67 unsafe {
68 obs_leave_graphics();
69 }
70 }
71}
72
73#[derive(Clone, Copy, Debug, Eq, PartialEq)]
74pub enum ShaderParamType {
75 Unknown,
76 Bool,
77 Float,
78 Int,
79 String,
80 Vec2,
81 Vec3,
82 Vec4,
83 Int2,
84 Int3,
85 Int4,
86 Mat4,
87 Texture,
88}
89
90impl ShaderParamType {
91 pub fn as_raw(&self) -> gs_shader_param_type {
92 match self {
93 ShaderParamType::Unknown => gs_shader_param_type_GS_SHADER_PARAM_UNKNOWN,
94 ShaderParamType::Bool => gs_shader_param_type_GS_SHADER_PARAM_BOOL,
95 ShaderParamType::Float => gs_shader_param_type_GS_SHADER_PARAM_FLOAT,
96 ShaderParamType::Int => gs_shader_param_type_GS_SHADER_PARAM_INT,
97 ShaderParamType::String => gs_shader_param_type_GS_SHADER_PARAM_STRING,
98 ShaderParamType::Vec2 => gs_shader_param_type_GS_SHADER_PARAM_VEC2,
99 ShaderParamType::Vec3 => gs_shader_param_type_GS_SHADER_PARAM_VEC3,
100 ShaderParamType::Vec4 => gs_shader_param_type_GS_SHADER_PARAM_VEC4,
101 ShaderParamType::Int2 => gs_shader_param_type_GS_SHADER_PARAM_INT2,
102 ShaderParamType::Int3 => gs_shader_param_type_GS_SHADER_PARAM_INT3,
103 ShaderParamType::Int4 => gs_shader_param_type_GS_SHADER_PARAM_INT4,
104 ShaderParamType::Mat4 => gs_shader_param_type_GS_SHADER_PARAM_MATRIX4X4,
105 ShaderParamType::Texture => gs_shader_param_type_GS_SHADER_PARAM_TEXTURE,
106 }
107 }
108
109 #[allow(non_upper_case_globals)]
110 pub fn from_raw(param_type: gs_shader_param_type) -> Self {
111 match param_type {
112 gs_shader_param_type_GS_SHADER_PARAM_UNKNOWN => ShaderParamType::Unknown,
113 gs_shader_param_type_GS_SHADER_PARAM_BOOL => ShaderParamType::Bool,
114 gs_shader_param_type_GS_SHADER_PARAM_FLOAT => ShaderParamType::Float,
115 gs_shader_param_type_GS_SHADER_PARAM_INT => ShaderParamType::Int,
116 gs_shader_param_type_GS_SHADER_PARAM_STRING => ShaderParamType::String,
117 gs_shader_param_type_GS_SHADER_PARAM_VEC2 => ShaderParamType::Vec2,
118 gs_shader_param_type_GS_SHADER_PARAM_VEC3 => ShaderParamType::Vec3,
119 gs_shader_param_type_GS_SHADER_PARAM_VEC4 => ShaderParamType::Vec4,
120 gs_shader_param_type_GS_SHADER_PARAM_INT2 => ShaderParamType::Int2,
121 gs_shader_param_type_GS_SHADER_PARAM_INT3 => ShaderParamType::Int3,
122 gs_shader_param_type_GS_SHADER_PARAM_INT4 => ShaderParamType::Int4,
123 gs_shader_param_type_GS_SHADER_PARAM_MATRIX4X4 => ShaderParamType::Mat4,
124 gs_shader_param_type_GS_SHADER_PARAM_TEXTURE => ShaderParamType::Texture,
125 _ => panic!("Invalid param_type!"),
126 }
127 }
128}
129
130pub struct GraphicsEffect {
131 raw: *mut gs_effect_t,
132}
133
134impl GraphicsEffect {
135 pub fn from_effect_string(value: ObsString, name: ObsString) -> Option<Self> {
136 let raw = GraphicsGuard::with_enter(|| unsafe {
137 gs_effect_create(value.as_ptr(), name.as_ptr(), std::ptr::null_mut())
138 });
139 if raw.is_null() {
140 None
141 } else {
142 Some(Self { raw })
143 }
144 }
145
146 pub fn get_effect_param_by_name<T: TryFrom<GraphicsEffectParam>>(
147 &mut self,
148 name: ObsString,
149 ) -> Option<T> {
150 unsafe {
151 let pointer = gs_effect_get_param_by_name(self.raw, name.as_ptr());
152 if !pointer.is_null() {
153 T::try_from(GraphicsEffectParam::from_raw(pointer)).ok()
154 } else {
155 None
156 }
157 }
158 }
159
160 pub unsafe fn as_ptr(&self) -> *mut gs_effect_t {
163 self.raw
164 }
165}
166
167impl Drop for GraphicsEffect {
168 fn drop(&mut self) {
169 GraphicsGuard::with_enter(|| unsafe {
170 gs_effect_destroy(self.raw);
171 });
172 }
173}
174
175pub enum GraphicsEffectParamConversionError {
176 InvalidType,
177}
178
179pub struct GraphicsEffectParam {
180 raw: *mut gs_eparam_t,
181 name: String,
182 shader_type: ShaderParamType,
183}
184
185impl GraphicsEffectParam {
186 pub unsafe fn from_raw(raw: *mut gs_eparam_t) -> Self {
190 let mut info = gs_effect_param_info::default();
191 gs_effect_get_param_info(raw, &mut info);
192
193 let shader_type = ShaderParamType::from_raw(info.type_);
194 let name = CString::from(CStr::from_ptr(info.name))
195 .into_string()
196 .unwrap_or_else(|_| String::from("{unknown-param-name}"));
197
198 Self {
199 raw,
200 shader_type,
201 name,
202 }
203 }
204
205 pub fn get_name(&self) -> &str {
206 &self.name
207 }
208}
209
210macro_rules! impl_graphics_effects {
211 ($($t:ident)*) => {
212 $(
213 item! {
214 pub struct [<GraphicsEffect $t Param>] {
215 effect: GraphicsEffectParam,
216 }
217
218 impl TryFrom<GraphicsEffectParam> for [<GraphicsEffect $t Param>] {
219 type Error = Error;
220
221 fn try_from(effect: GraphicsEffectParam) -> Result<Self> {
222 match effect.shader_type {
223 ShaderParamType::[<$t>] => Ok([<GraphicsEffect $t Param>] { effect }),
224 _ => Err(Error),
225 }
226 }
227 }
228 }
229 )*
230 };
231}
232
233impl_graphics_effects! {
234 Vec2
235 Texture
236}
237
238impl GraphicsEffectVec2Param {
239 pub fn set_vec2(&mut self, _context: &GraphicsEffectContext, value: &Vec2) {
240 unsafe {
241 gs_effect_set_vec2(self.effect.raw, &value.raw);
242 }
243 }
244}
245
246impl GraphicsEffectTextureParam {
247 pub fn set_next_sampler(
248 &mut self,
249 _context: &GraphicsEffectContext,
250 value: &mut GraphicsSamplerState,
251 ) {
252 unsafe {
253 gs_effect_set_next_sampler(self.effect.raw, value.raw);
254 }
255 }
256}
257
258pub enum GraphicsAddressMode {
259 Clamp,
260 Wrap,
261 Mirror,
262 Border,
263 MirrorOnce,
264}
265
266impl GraphicsAddressMode {
267 pub fn as_raw(&self) -> gs_address_mode {
268 match self {
269 GraphicsAddressMode::Clamp => gs_address_mode_GS_ADDRESS_CLAMP,
270 GraphicsAddressMode::Wrap => gs_address_mode_GS_ADDRESS_WRAP,
271 GraphicsAddressMode::Mirror => gs_address_mode_GS_ADDRESS_MIRROR,
272 GraphicsAddressMode::Border => gs_address_mode_GS_ADDRESS_BORDER,
273 GraphicsAddressMode::MirrorOnce => gs_address_mode_GS_ADDRESS_MIRRORONCE,
274 }
275 }
276}
277
278pub enum GraphicsSampleFilter {
279 Point,
280 Linear,
281 Anisotropic,
282 MinMagPointMipLinear,
283 MinPointMagLinearMipPoint,
284 MinPointMagMipLinear,
285 MinLinearMapMipPoint,
286 MinLinearMagPointMipLinear,
287 MinMagLinearMipPoint,
288}
289
290impl GraphicsSampleFilter {
291 fn as_raw(&self) -> gs_sample_filter {
292 match self {
293 GraphicsSampleFilter::Point => gs_sample_filter_GS_FILTER_POINT,
294 GraphicsSampleFilter::Linear => gs_sample_filter_GS_FILTER_LINEAR,
295 GraphicsSampleFilter::Anisotropic => gs_sample_filter_GS_FILTER_ANISOTROPIC,
296 GraphicsSampleFilter::MinMagPointMipLinear => {
297 gs_sample_filter_GS_FILTER_MIN_MAG_POINT_MIP_LINEAR
298 }
299 GraphicsSampleFilter::MinPointMagLinearMipPoint => {
300 gs_sample_filter_GS_FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT
301 }
302 GraphicsSampleFilter::MinPointMagMipLinear => {
303 gs_sample_filter_GS_FILTER_MIN_POINT_MAG_MIP_LINEAR
304 }
305 GraphicsSampleFilter::MinLinearMapMipPoint => {
306 gs_sample_filter_GS_FILTER_MIN_LINEAR_MAG_MIP_POINT
307 }
308 GraphicsSampleFilter::MinLinearMagPointMipLinear => {
309 gs_sample_filter_GS_FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR
310 }
311 GraphicsSampleFilter::MinMagLinearMipPoint => {
312 gs_sample_filter_GS_FILTER_MIN_MAG_LINEAR_MIP_POINT
313 }
314 }
315 }
316}
317
318pub struct GraphicsSamplerInfo {
319 info: gs_sampler_info,
320}
321
322impl GraphicsSamplerInfo {
323 pub fn new() -> Self {
324 Self {
325 info: gs_sampler_info {
326 address_u: GraphicsAddressMode::Clamp.as_raw(),
327 address_v: GraphicsAddressMode::Clamp.as_raw(),
328 address_w: GraphicsAddressMode::Clamp.as_raw(),
329 max_anisotropy: 0,
330 border_color: 0,
331 filter: GraphicsSampleFilter::Point.as_raw(),
332 },
333 }
334 }
335
336 pub fn with_address_u(mut self, mode: GraphicsAddressMode) -> Self {
337 self.info.address_u = mode.as_raw();
338 self
339 }
340
341 pub fn with_address_v(mut self, mode: GraphicsAddressMode) -> Self {
342 self.info.address_v = mode.as_raw();
343 self
344 }
345
346 pub fn with_address_w(mut self, mode: GraphicsAddressMode) -> Self {
347 self.info.address_w = mode.as_raw();
348 self
349 }
350
351 pub fn with_filter(mut self, mode: GraphicsSampleFilter) -> Self {
352 self.info.filter = mode.as_raw();
353 self
354 }
355}
356
357impl Default for GraphicsSamplerInfo {
358 fn default() -> Self {
359 Self::new()
360 }
361}
362
363pub struct GraphicsSamplerState {
364 raw: *mut gs_samplerstate_t,
365}
366
367impl From<GraphicsSamplerInfo> for GraphicsSamplerState {
368 fn from(info: GraphicsSamplerInfo) -> GraphicsSamplerState {
369 let raw = GraphicsGuard::with_enter(|| unsafe { gs_samplerstate_create(&info.info) });
370 GraphicsSamplerState { raw }
371 }
372}
373
374impl Drop for GraphicsSamplerState {
375 fn drop(&mut self) {
376 GraphicsGuard::with_enter(|| unsafe {
377 gs_samplerstate_destroy(self.raw);
378 });
379 }
380}
381
382pub struct GraphicsEffectContext {}
383
384impl GraphicsEffectContext {
385 pub(crate) unsafe fn new() -> Self {
389 Self {}
390 }
391}
392
393#[derive(Debug, Eq, PartialEq, Clone, Copy)]
394pub enum GraphicsColorFormat {
395 UNKNOWN,
396 A8,
397 R8,
398 RGBA,
399 BGRX,
400 BGRA,
401 R10G10B10A2,
402 RGBA16,
403 R16,
404 RGBA16F,
405 RGBA32F,
406 RG16F,
407 RG32F,
408 R16F,
409 R32F,
410 DXT1,
411 DXT3,
412 DXT5,
413 R8G8,
414}
415
416impl GraphicsColorFormat {
417 pub fn as_raw(&self) -> gs_color_format {
418 match self {
419 GraphicsColorFormat::UNKNOWN => gs_color_format_GS_UNKNOWN,
420 GraphicsColorFormat::A8 => gs_color_format_GS_A8,
421 GraphicsColorFormat::R8 => gs_color_format_GS_R8,
422 GraphicsColorFormat::RGBA => gs_color_format_GS_RGBA,
423 GraphicsColorFormat::BGRX => gs_color_format_GS_BGRX,
424 GraphicsColorFormat::BGRA => gs_color_format_GS_BGRA,
425 GraphicsColorFormat::R10G10B10A2 => gs_color_format_GS_R10G10B10A2,
426 GraphicsColorFormat::RGBA16 => gs_color_format_GS_RGBA16,
427 GraphicsColorFormat::R16 => gs_color_format_GS_R16,
428 GraphicsColorFormat::RGBA16F => gs_color_format_GS_RGBA16F,
429 GraphicsColorFormat::RGBA32F => gs_color_format_GS_RGBA32F,
430 GraphicsColorFormat::RG16F => gs_color_format_GS_RG16F,
431 GraphicsColorFormat::RG32F => gs_color_format_GS_RG32F,
432 GraphicsColorFormat::R16F => gs_color_format_GS_R16F,
433 GraphicsColorFormat::R32F => gs_color_format_GS_R32F,
434 GraphicsColorFormat::DXT1 => gs_color_format_GS_DXT1,
435 GraphicsColorFormat::DXT3 => gs_color_format_GS_DXT3,
436 GraphicsColorFormat::DXT5 => gs_color_format_GS_DXT5,
437 GraphicsColorFormat::R8G8 => gs_color_format_GS_R8G8,
438 }
439 }
440}
441
442pub enum GraphicsAllowDirectRendering {
443 NoDirectRendering,
444 AllowDirectRendering,
445}
446
447impl GraphicsAllowDirectRendering {
448 pub fn as_raw(&self) -> obs_allow_direct_render {
449 match self {
450 GraphicsAllowDirectRendering::NoDirectRendering => {
451 obs_allow_direct_render_OBS_NO_DIRECT_RENDERING
452 }
453 GraphicsAllowDirectRendering::AllowDirectRendering => {
454 obs_allow_direct_render_OBS_ALLOW_DIRECT_RENDERING
455 }
456 }
457 }
458}
459
460macro_rules! vector_impls {
461 ($($rust_name: ident, $name:ident => $($component:ident)*,)*) => (
462 $(
463 #[derive(Clone)]
464 pub struct $rust_name {
465 raw: $name,
466 }
467
468 impl $rust_name {
469 pub fn new($( $component: f32, )*) -> Self {
470 let mut v = Self {
471 raw: $name::default(),
472 };
473 v.set($($component,)*);
474 v
475 }
476
477 #[inline]
478 pub fn zero(&mut self) {
479 $(
480 self.raw.__bindgen_anon_1.__bindgen_anon_1.$component = 0.;
481 )*
482 }
483
484 #[inline]
485 pub fn copy(&mut self, input: &$rust_name) {
486 self.set($(input.$component(),)*);
487 }
488
489 #[inline]
490 pub fn add(&mut self, input: &$rust_name) {
491 self.set($(self.$component() + input.$component(),)*);
492 }
493
494 #[inline]
495 pub fn sub(&mut self, input: &$rust_name) {
496 self.set($(self.$component() - input.$component(),)*);
497 }
498
499 #[inline]
500 pub fn mul(&mut self, input: &$rust_name) {
501 self.set($(self.$component() * input.$component(),)*);
502 }
503
504 #[inline]
505 pub fn div(&mut self, input: &$rust_name) {
506 self.set($(self.$component() / input.$component(),)*);
507 }
508
509 #[inline]
510 pub fn addf(&mut self, input: f32) {
511 self.set($(self.$component() + input,)*);
512 }
513
514 #[inline]
515 pub fn subf(&mut self, input: f32) {
516 self.set($(self.$component() - input,)*);
517 }
518
519 #[inline]
520 pub fn mulf(&mut self, input: f32) {
521 self.set($(self.$component() * input,)*);
522 }
523
524 #[inline]
525 pub fn divf(&mut self, input: f32) {
526 self.set($(self.$component() / input,)*);
527 }
528
529 #[inline]
530 pub fn neg(&mut self) {
531 self.set($(-self.$component(),)*);
532 }
533
534 #[inline]
535 pub fn dot(&mut self, input: &$rust_name) -> f32 {
536 $(
537 self.$component() * input.$component() +
538 )* 0.
539 }
540
541 #[inline]
542 pub fn len(&mut self) -> f32 {
543 ($( self.$component() * self.$component() + )* 0.).sqrt()
544 }
545
546 #[inline]
547 pub fn set(&mut self, $( $component: f32, )*) {
548 $(
549 self.raw.__bindgen_anon_1.__bindgen_anon_1.$component = $component;
550 )*
551 }
552
553 #[inline]
554 pub fn min(&mut self, input: &$rust_name) {
555 self.set($(self.$component().min(input.$component()),)*);
556 }
557
558 #[inline]
559 pub fn max(&mut self, input: &$rust_name) {
560 self.set($(self.$component().max(input.$component()),)*);
561 }
562
563 #[inline]
564 pub fn minf(&mut self, input: f32) {
565 self.set($(self.$component().min(input),)*);
566 }
567
568 #[inline]
569 pub fn maxf(&mut self, input: f32) {
570 self.set($(self.$component().max(input),)*);
571 }
572
573 #[inline]
574 pub fn abs(&mut self) {
575 self.set($(self.$component().abs(),)*);
576 }
577
578 #[inline]
579 pub fn ceil(&mut self) {
580 self.set($(self.$component().ceil(),)*);
581 }
582
583 #[inline]
584 pub fn floor(&mut self) {
585 self.set($(self.$component().floor(),)*);
586 }
587
588 #[inline]
589 pub fn close(&mut self, input: &$rust_name, epsilon: f32) -> bool {
590 $(
591 (self.$component() - input.$component()).abs() > epsilon &&
592 )* true
593 }
594
595 $(
596 item! {
597 #[inline]
598 pub fn [<$component>](&self) -> f32 {
599 unsafe {
600 self.raw.__bindgen_anon_1.__bindgen_anon_1.$component
601 }
602 }
603 }
604 )*
605
606 pub fn as_ptr(&mut self) -> *mut $name {
607 &mut self.raw
608 }
609 }
610
611 impl Default for $rust_name {
612 fn default() -> Self {
613 $(
614 let $component = 0.;
615 )*
616 Self::new($( $component, )*)
617 }
618 }
619 )*
620 );
621}
622
623vector_impls! {
624 Vec2, vec2 => x y,
625 Vec3, vec3 => x y z,
626 Vec4, vec4 => x y z w,
627}
628
629pub struct GraphicsTexture {
631 raw: *mut gs_texture_t,
632}
633
634impl GraphicsTexture {
635 pub fn new(width: u32, height: u32, format: GraphicsColorFormat) -> Self {
636 let raw = GraphicsGuard::with_enter(|| unsafe {
637 gs_texture_create(width, height, format.as_raw(), 1, null_mut(), GS_DYNAMIC)
638 });
639 Self { raw }
640 }
641
642 #[inline]
643 pub fn height(&self) -> u32 {
644 GraphicsGuard::with_enter(|| unsafe { gs_texture_get_height(self.raw) })
645 }
646
647 #[inline]
648 pub fn width(&self) -> u32 {
649 GraphicsGuard::with_enter(|| unsafe { gs_texture_get_width(self.raw) })
650 }
651
652 pub fn set_image(&mut self, data: &[u8], linesize: u32, invert: bool) {
653 GraphicsGuard::with_enter(|| unsafe {
654 gs_texture_set_image(self.raw, data.as_ptr(), linesize, invert);
655 });
656 }
657
658 pub fn draw(&self, x: c_int, y: c_int, cx: u32, cy: u32, flip: bool) {
659 unsafe {
660 obs_source_draw(self.raw, x, y, cx, cy, flip);
661 }
662 }
663
664 #[inline]
665 pub fn map(&mut self) -> Result<MappedTexture> {
666 MappedTexture::new(self)
667 }
668
669 pub fn as_ptr(&self) -> *mut gs_texture_t {
670 self.raw
671 }
672}
673
674impl Drop for GraphicsTexture {
675 fn drop(&mut self) {
676 GraphicsGuard::with_enter(|| unsafe {
677 gs_texture_destroy(self.raw);
678 });
679 }
680}
681
682pub struct MappedTexture<'tex> {
684 tex: &'tex mut GraphicsTexture,
685 ptr: *mut u8,
686 len: usize,
687}
688
689impl<'tex> MappedTexture<'tex> {
690 fn new(tex: &'tex mut GraphicsTexture) -> Result<Self> {
691 let mut ptr: *mut u8 = ptr::null_mut();
692 let mut linesize = 0u32;
693 let map_result = GraphicsGuard::with_enter(|| unsafe {
694 gs_texture_map(tex.as_ptr(), &mut ptr, &mut linesize)
695 });
696 if !map_result {
697 return Err(Error);
698 }
699 let len = (linesize * tex.height()) as usize;
700 Ok(Self { tex, ptr, len })
701 }
702
703 #[inline]
704 pub fn as_ptr(&self) -> *const u8 {
705 self.ptr
706 }
707
708 #[inline]
709 pub fn as_mut_ptr(&mut self) -> *mut u8 {
710 self.ptr
711 }
712
713 #[inline]
714 pub fn width(&self) -> u32 {
715 self.tex.width()
716 }
717
718 #[inline]
719 pub fn height(&self) -> u32 {
720 self.tex.height()
721 }
722}
723
724impl std::ops::Deref for MappedTexture<'_> {
725 type Target = [u8];
726
727 fn deref(&self) -> &[u8] {
728 unsafe { slice::from_raw_parts(self.as_ptr(), self.len) }
729 }
730}
731
732impl std::ops::DerefMut for MappedTexture<'_> {
733 fn deref_mut(&mut self) -> &mut [u8] {
734 unsafe { slice::from_raw_parts_mut(self.as_mut_ptr(), self.len) }
735 }
736}
737
738impl std::fmt::Debug for MappedTexture<'_> {
739 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
740 std::fmt::Debug::fmt(&**self, f)
741 }
742}
743
744impl Drop for MappedTexture<'_> {
745 fn drop(&mut self) {
746 GraphicsGuard::with_enter(|| unsafe {
747 gs_texture_unmap(self.tex.as_ptr());
748 });
749 }
750}