Skip to main content

aviutl2\filter\binding/
video.rs

1use std::ffi::c_void;
2use windows::core::Interface;
3
4use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
5
6use super::{FilterProcError, FilterProcResult, ObjectInfo, SceneInfo};
7
8/// 画像フィルタのオブジェクト情報。
9#[derive(Debug, Clone, Copy)]
10pub struct VideoObjectInfo {
11    /// オブジェクトの現在の画像サイズの幅。
12    pub width: u32,
13    /// オブジェクトの現在の画像サイズの高さ。
14    pub height: u32,
15
16    /// 複数オブジェクト時の現在の対象番号
17    pub index: u32,
18    /// 複数オブジェクト時の対象数(None:不定、Some(1):単体)
19    pub num: Option<u32>,
20}
21
22/// オブジェクトの画像パラメータ構造体。
23#[derive(Debug, Clone, Copy)]
24#[non_exhaustive]
25pub struct ObjectImageParam {
26    /// 基準座標X。
27    pub x: f32,
28    /// 基準座標Y。
29    pub y: f32,
30    /// 基準座標Z。
31    pub z: f32,
32    /// 回転角度X。(360.0で1回転)
33    pub rx: f32,
34    /// 回転角度Y。(360.0で1回転)
35    pub ry: f32,
36    /// 回転角度Z。(360.0で1回転)
37    pub rz: f32,
38    /// 拡大率X。(1.0で等倍)
39    pub sx: f32,
40    /// 拡大率Y。(1.0で等倍)
41    pub sy: f32,
42    /// 拡大率Z。(1.0で等倍)
43    pub sz: f32,
44    /// 中心座標X。(基準座標からの相対)
45    pub cx: f32,
46    /// 中心座標Y。(基準座標からの相対)
47    pub cy: f32,
48    /// 中心座標Z。(基準座標からの相対)
49    pub cz: f32,
50    /// 不透明度。(0.0〜1.0/0.0=透明/1.0=不透明)
51    pub alpha: f32,
52}
53
54impl From<aviutl2_sys::filter2::OBJECT_IMAGE_PARAM> for ObjectImageParam {
55    fn from(value: aviutl2_sys::filter2::OBJECT_IMAGE_PARAM) -> Self {
56        (&value).into()
57    }
58}
59
60impl From<&aviutl2_sys::filter2::OBJECT_IMAGE_PARAM> for ObjectImageParam {
61    fn from(value: &aviutl2_sys::filter2::OBJECT_IMAGE_PARAM) -> Self {
62        Self {
63            x: value.x,
64            y: value.y,
65            z: value.z,
66            rx: value.rx,
67            ry: value.ry,
68            rz: value.rz,
69            sx: value.sx,
70            sy: value.sy,
71            sz: value.sz,
72            cx: value.cx,
73            cy: value.cy,
74            cz: value.cz,
75            alpha: value.alpha,
76        }
77    }
78}
79
80/// RGBAのピクセル。
81#[derive(
82    Debug, Default, Clone, Copy, PartialEq, Eq, IntoBytes, FromBytes, Immutable, KnownLayout,
83)]
84pub struct RgbaPixel {
85    /// 赤。
86    pub r: u8,
87    /// 緑。
88    pub g: u8,
89    /// 青。
90    pub b: u8,
91    /// アルファ。
92    pub a: u8,
93}
94
95impl From<(u8, u8, u8, u8)> for RgbaPixel {
96    fn from(value: (u8, u8, u8, u8)) -> Self {
97        Self {
98            r: value.0,
99            g: value.1,
100            b: value.2,
101            a: value.3,
102        }
103    }
104}
105impl From<RgbaPixel> for (u8, u8, u8, u8) {
106    fn from(value: RgbaPixel) -> Self {
107        (value.r, value.g, value.b, value.a)
108    }
109}
110
111/// 画像リソースに書き込むピクセルフォーマット。
112#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
113pub enum InputImageResourcePixelFormat {
114    /// DXGI_FORMAT_R8G8B8A8_UNORM。
115    Rgba,
116    /// DXGI_FORMAT_B8G8R8A8_UNORM。
117    Bgra,
118    /// DXGI_FORMAT_B8G8R8X8_UNORM。
119    Bgr,
120    /// DXGI_FORMAT_R16G16B16A16_UNORM。
121    Pa64,
122    /// DXGI_FORMAT_R16G16B16A16_FLOAT。
123    Hf64,
124    /// DXGI_FORMAT_YUY2。
125    Yuy2,
126    /// DXGI_FORMAT_R16G16B16A16_SNORM。
127    Yc48,
128}
129
130impl From<InputImageResourcePixelFormat> for aviutl2_sys::filter2::INPUT_PIXEL_FORMAT {
131    fn from(value: InputImageResourcePixelFormat) -> Self {
132        match value {
133            InputImageResourcePixelFormat::Rgba => Self::RGBA,
134            InputImageResourcePixelFormat::Bgra => Self::BGRA,
135            InputImageResourcePixelFormat::Bgr => Self::BGR,
136            InputImageResourcePixelFormat::Pa64 => Self::PA64,
137            InputImageResourcePixelFormat::Hf64 => Self::HF64,
138            InputImageResourcePixelFormat::Yuy2 => Self::YUY2,
139            InputImageResourcePixelFormat::Yc48 => Self::YC48,
140        }
141    }
142}
143
144/// 画像リソースから読み取るピクセルフォーマット。
145#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
146pub enum OutputImageResourcePixelFormat {
147    /// DXGI_FORMAT_R8G8B8A8_UNORM。
148    Rgba,
149    /// DXGI_FORMAT_R16G16B16A16_UNORM。
150    Pa64,
151    /// DXGI_FORMAT_R16G16B16A16_FLOAT。
152    Hf64,
153}
154
155impl From<OutputImageResourcePixelFormat> for aviutl2_sys::filter2::OUTPUT_PIXEL_FORMAT {
156    fn from(value: OutputImageResourcePixelFormat) -> Self {
157        match value {
158            OutputImageResourcePixelFormat::Rgba => Self::RGBA,
159            OutputImageResourcePixelFormat::Pa64 => Self::PA64,
160            OutputImageResourcePixelFormat::Hf64 => Self::HF64,
161        }
162    }
163}
164
165/// 画像フィルタ処理のための構造体。
166#[derive(Debug)]
167pub struct FilterProcVideo<U: super::FilterUserdata> {
168    /// シーン情報。
169    pub scene: SceneInfo,
170    /// オブジェクト情報。
171    pub object: ObjectInfo,
172    /// 画像フィルタ特有のオブジェクト情報。
173    pub video_object: VideoObjectInfo,
174
175    /// オブジェクトの画像パラメータ。
176    /// [`crate::filter::FilterPlugin::proc_video`] の終了時や [`Self::draw_image`]
177    /// などの呼び出し前に反映されます。
178    pub param: ObjectImageParam,
179
180    /// エフェクト毎に保持されるユーザーデータ。
181    pub userdata: super::FilterUserdataHandle<U>,
182
183    pub(crate) prevent_post_effect: bool,
184
185    pub(crate) read_section: crate::generic::ReadSection,
186    pub(crate) inner: *const aviutl2_sys::filter2::FILTER_PROC_VIDEO,
187}
188unsafe impl<U: super::FilterUserdata> Send for FilterProcVideo<U> {}
189unsafe impl<U: super::FilterUserdata> Sync for FilterProcVideo<U> {}
190
191/// 画像リソース。
192///
193/// APIごとに利用できるリソースの種類が異なります。各メソッドの引数説明を参照してください。
194#[derive(Debug, Clone, PartialEq, Eq)]
195pub enum ImageResource {
196    /// 現在のオブジェクト(`object`)。
197    Object,
198    /// 標準リソース(`resource:名前`)。
199    Resource(String),
200    /// フレームバッファ(`framebuffer`)。
201    Framebuffer,
202    /// 仮想バッファ(`tempbuffer`)。
203    TempBuffer,
204    /// キャッシュバッファ(`cache:名前`)。
205    CacheBuffer(String),
206    /// 画像ファイル(`image:ファイルパス`)。
207    ImageFile(std::path::PathBuf),
208    /// 乱数バッファ(`random`)。
209    Random,
210    /// レイヤー上のオブジェクト(`layer:レイヤー番号`、追加フィルタを実行する場合は末尾に`+`)。
211    Layer {
212        /// レイヤー番号。
213        layer: u32,
214        /// 追加フィルタを実行するかどうか。
215        apply_additional_effects: bool,
216    },
217    /// 直前オブジェクト(`before`)。
218    PreviousObject,
219}
220
221impl std::fmt::Display for ImageResource {
222    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
223        match self {
224            ImageResource::Object => write!(f, "object"),
225            ImageResource::Resource(name) => write!(f, "resource:{name}"),
226            ImageResource::Framebuffer => write!(f, "framebuffer"),
227            ImageResource::TempBuffer => write!(f, "tempbuffer"),
228            ImageResource::CacheBuffer(name) => write!(f, "cache:{name}"),
229            ImageResource::ImageFile(path) => write!(f, "image:{}", path.to_string_lossy()),
230            ImageResource::Random => write!(f, "random"),
231            ImageResource::Layer {
232                layer,
233                apply_additional_effects,
234            } => write!(
235                f,
236                "layer:{layer}{}",
237                if *apply_additional_effects { "+" } else { "" }
238            ),
239            ImageResource::PreviousObject => write!(f, "before"),
240        }
241    }
242}
243
244/// [FilterProcVideo::draw_image] のパラメーター。
245#[derive(Debug, Clone, Copy)]
246pub struct DrawImageParam {
247    /// 基準座標X。
248    pub x: f32,
249    /// 基準座標Y。
250    pub y: f32,
251    /// 基準座標Z。
252    pub z: f32,
253    /// 回転角度X。(360.0で1回転)
254    pub rx: f32,
255    /// 回転角度Y。(360.0で1回転)
256    pub ry: f32,
257    /// 回転角度Z。(360.0で1回転)
258    pub rz: f32,
259    /// 拡大率X。(1.0で等倍)
260    pub sx: f32,
261    /// 拡大率Y。(1.0で等倍)
262    pub sy: f32,
263    /// 拡大率Z。(1.0で等倍)
264    pub sz: f32,
265    /// 不透明度。(0.0〜1.0/0.0=透明/1.0=不透明)
266    pub alpha: f32,
267}
268
269impl Default for DrawImageParam {
270    fn default() -> Self {
271        Self {
272            x: 0.0,
273            y: 0.0,
274            z: 0.0,
275            rx: 0.0,
276            ry: 0.0,
277            rz: 0.0,
278            sx: 1.0,
279            sy: 1.0,
280            sz: 1.0,
281            alpha: 1.0,
282        }
283    }
284}
285
286/// 頂点データ構造体(描画色)
287#[derive(Debug, Clone, Copy)]
288pub struct VertexColor {
289    pub x: f32,
290    pub y: f32,
291    pub z: f32,
292    pub r: f32,
293    pub g: f32,
294    pub b: f32,
295    pub a: f32,
296}
297
298/// 頂点データ構造体(描画色、法線)
299#[derive(Debug, Clone, Copy)]
300pub struct VertexColorNorm {
301    pub x: f32,
302    pub y: f32,
303    pub z: f32,
304    pub r: f32,
305    pub g: f32,
306    pub b: f32,
307    pub a: f32,
308    pub vx: f32,
309    pub vy: f32,
310    pub vz: f32,
311}
312
313/// 頂点データ構造体(テクスチャ座標)
314#[derive(Debug, Clone, Copy)]
315pub struct VertexTexture {
316    pub x: f32,
317    pub y: f32,
318    pub z: f32,
319    pub u: f32,
320    pub v: f32,
321    pub a: f32,
322}
323
324/// 頂点データ構造体(テクスチャ座標、法線)
325#[derive(Debug, Clone, Copy)]
326pub struct VertexTextureNorm {
327    pub x: f32,
328    pub y: f32,
329    pub z: f32,
330    pub u: f32,
331    pub v: f32,
332    pub a: f32,
333    pub vx: f32,
334    pub vy: f32,
335    pub vz: f32,
336}
337
338impl From<VertexColor> for aviutl2_sys::filter2::VERTEX_COLOR {
339    fn from(value: VertexColor) -> Self {
340        Self {
341            x: value.x,
342            y: value.y,
343            z: value.z,
344            r: value.r,
345            g: value.g,
346            b: value.b,
347            a: value.a,
348        }
349    }
350}
351
352impl From<VertexColorNorm> for aviutl2_sys::filter2::VERTEX_COLOR_NORM {
353    fn from(value: VertexColorNorm) -> Self {
354        Self {
355            x: value.x,
356            y: value.y,
357            z: value.z,
358            r: value.r,
359            g: value.g,
360            b: value.b,
361            a: value.a,
362            vx: value.vx,
363            vy: value.vy,
364            vz: value.vz,
365        }
366    }
367}
368
369impl From<VertexTexture> for aviutl2_sys::filter2::VERTEX_TEXTURE {
370    fn from(value: VertexTexture) -> Self {
371        Self {
372            x: value.x,
373            y: value.y,
374            z: value.z,
375            u: value.u,
376            v: value.v,
377            a: value.a,
378        }
379    }
380}
381
382impl From<VertexTextureNorm> for aviutl2_sys::filter2::VERTEX_TEXTURE_NORM {
383    fn from(value: VertexTextureNorm) -> Self {
384        Self {
385            x: value.x,
386            y: value.y,
387            z: value.z,
388            u: value.u,
389            v: value.v,
390            a: value.a,
391            vx: value.vx,
392            vy: value.vy,
393            vz: value.vz,
394        }
395    }
396}
397
398/// 頂点リスト。
399pub enum VertexList {
400    TriangleColor(Vec<[VertexColor; 3]>),
401    TriangleColorNorm(Vec<[VertexColorNorm; 3]>),
402    TriangleTexture(Vec<[VertexTexture; 3]>),
403    TriangleTextureNorm(Vec<[VertexTextureNorm; 3]>),
404    QuadColor(Vec<[VertexColor; 4]>),
405    QuadColorNorm(Vec<[VertexColorNorm; 4]>),
406    QuadTexture(Vec<[VertexTexture; 4]>),
407    QuadTextureNorm(Vec<[VertexTextureNorm; 4]>),
408}
409
410/// 合成モード。
411#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
412pub enum BlendMode {
413    /// 通常。
414    #[default]
415    None,
416    /// 加算。
417    Add,
418    /// 減算。
419    Sub,
420    /// 乗算。
421    Mul,
422    /// スクリーン。
423    Screen,
424    /// オーバーレイ。
425    Overlay,
426    /// 比較(明)。
427    Light,
428    /// 比較(暗)。
429    Dark,
430    /// 輝度。
431    Brightness,
432    /// 色差。
433    Chroma,
434    /// 陰影。
435    Shadow,
436    /// 明暗。
437    LightDark,
438    /// 差分。
439    Diff,
440}
441
442/// サンプラーの種別。
443#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
444pub enum SamplerMode {
445    /// 領域外は透明色。
446    #[default]
447    Clip,
448    /// 領域外は一番外側の色。
449    Clamp,
450    /// 領域外はループ。
451    Loop,
452    /// 領域外は領域を反転しながらループ。
453    Mirror,
454    /// 拡大縮小補間をしない(領域外は透明色)。
455    Dot,
456}
457
458/// ビルボードの種別。
459#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
460pub enum BillboardMode {
461    /// 標準の向き(何もしない)。
462    #[default]
463    None,
464    /// 横方向のみカメラに向ける。
465    Side,
466    /// 縦横方向のみカメラに向ける。
467    Direction,
468    /// カメラに向ける。
469    Camera,
470}
471
472/// 出力ブレンドの種別。
473#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
474pub enum BlendStateMode {
475    /// 出力をそのままコピー。
476    #[default]
477    Copy,
478    /// α値のみを乗算。
479    Mask,
480    /// 出力をアルファブレンド。
481    Draw,
482    /// 出力を加算合成。
483    Add,
484}
485
486impl From<BlendMode> for aviutl2_sys::filter2::BLEND_MODE {
487    fn from(value: BlendMode) -> Self {
488        match value {
489            BlendMode::None => Self::NONE,
490            BlendMode::Add => Self::ADD,
491            BlendMode::Sub => Self::SUB,
492            BlendMode::Mul => Self::MUL,
493            BlendMode::Screen => Self::SCREEN,
494            BlendMode::Overlay => Self::OVERLAY,
495            BlendMode::Light => Self::LIGHT,
496            BlendMode::Dark => Self::DARK,
497            BlendMode::Brightness => Self::BRIGHTNESS,
498            BlendMode::Chroma => Self::CHROMA,
499            BlendMode::Shadow => Self::SHADOW,
500            BlendMode::LightDark => Self::LIGHT_DARK,
501            BlendMode::Diff => Self::DIFF,
502        }
503    }
504}
505impl From<SamplerMode> for aviutl2_sys::filter2::SAMPLER_MODE {
506    fn from(value: SamplerMode) -> Self {
507        match value {
508            SamplerMode::Clip => Self::CLIP,
509            SamplerMode::Clamp => Self::CLAMP,
510            SamplerMode::Loop => Self::LOOP,
511            SamplerMode::Mirror => Self::MIRROR,
512            SamplerMode::Dot => Self::DOT,
513        }
514    }
515}
516impl From<BillboardMode> for aviutl2_sys::filter2::BILLBOARD_MODE {
517    fn from(value: BillboardMode) -> Self {
518        match value {
519            BillboardMode::None => Self::NONE,
520            BillboardMode::Side => Self::SIDE,
521            BillboardMode::Direction => Self::DIRECTION,
522            BillboardMode::Camera => Self::CAMERA,
523        }
524    }
525}
526impl From<BlendStateMode> for aviutl2_sys::filter2::BLEND_STATE_MODE {
527    fn from(value: BlendStateMode) -> Self {
528        match value {
529            BlendStateMode::Copy => Self::COPY,
530            BlendStateMode::Mask => Self::MASK,
531            BlendStateMode::Draw => Self::DRAW,
532            BlendStateMode::Add => Self::ADD,
533        }
534    }
535}
536
537fn vertex_list_as_raw(
538    vertices: &VertexList,
539    f: impl FnOnce(aviutl2_sys::filter2::VERTEX_TYPE, *const c_void, i32) -> bool,
540) -> bool {
541    match vertices {
542        VertexList::TriangleColor(triangles) => {
543            let flattened: Vec<aviutl2_sys::filter2::VERTEX_COLOR> = triangles
544                .iter()
545                .flatten()
546                .copied()
547                .map(Into::into)
548                .collect();
549            f(
550                aviutl2_sys::filter2::VERTEX_TYPE::TRIANGLE_COLOR,
551                flattened.as_ptr() as *const c_void,
552                flattened.len() as i32,
553            )
554        }
555        VertexList::TriangleColorNorm(triangles) => {
556            let flattened: Vec<aviutl2_sys::filter2::VERTEX_COLOR_NORM> = triangles
557                .iter()
558                .flatten()
559                .copied()
560                .map(Into::into)
561                .collect();
562            f(
563                aviutl2_sys::filter2::VERTEX_TYPE::TRIANGLE_COLOR_NORM,
564                flattened.as_ptr() as *const c_void,
565                flattened.len() as i32,
566            )
567        }
568        VertexList::TriangleTexture(triangles) => {
569            let flattened: Vec<aviutl2_sys::filter2::VERTEX_TEXTURE> = triangles
570                .iter()
571                .flatten()
572                .copied()
573                .map(Into::into)
574                .collect();
575            f(
576                aviutl2_sys::filter2::VERTEX_TYPE::TRIANGLE_TEXTURE,
577                flattened.as_ptr() as *const c_void,
578                flattened.len() as i32,
579            )
580        }
581        VertexList::TriangleTextureNorm(triangles) => {
582            let flattened: Vec<aviutl2_sys::filter2::VERTEX_TEXTURE_NORM> = triangles
583                .iter()
584                .flatten()
585                .copied()
586                .map(Into::into)
587                .collect();
588            f(
589                aviutl2_sys::filter2::VERTEX_TYPE::TRIANGLE_TEXTURE_NORM,
590                flattened.as_ptr() as *const c_void,
591                flattened.len() as i32,
592            )
593        }
594        VertexList::QuadColor(quads) => {
595            let flattened: Vec<aviutl2_sys::filter2::VERTEX_COLOR> =
596                quads.iter().flatten().copied().map(Into::into).collect();
597            f(
598                aviutl2_sys::filter2::VERTEX_TYPE::QUAD_COLOR,
599                flattened.as_ptr() as *const c_void,
600                flattened.len() as i32,
601            )
602        }
603        VertexList::QuadColorNorm(quads) => {
604            let flattened: Vec<aviutl2_sys::filter2::VERTEX_COLOR_NORM> =
605                quads.iter().flatten().copied().map(Into::into).collect();
606            f(
607                aviutl2_sys::filter2::VERTEX_TYPE::QUAD_COLOR_NORM,
608                flattened.as_ptr() as *const c_void,
609                flattened.len() as i32,
610            )
611        }
612        VertexList::QuadTexture(quads) => {
613            let flattened: Vec<aviutl2_sys::filter2::VERTEX_TEXTURE> =
614                quads.iter().flatten().copied().map(Into::into).collect();
615            f(
616                aviutl2_sys::filter2::VERTEX_TYPE::QUAD_TEXTURE,
617                flattened.as_ptr() as *const c_void,
618                flattened.len() as i32,
619            )
620        }
621        VertexList::QuadTextureNorm(quads) => {
622            let flattened: Vec<aviutl2_sys::filter2::VERTEX_TEXTURE_NORM> =
623                quads.iter().flatten().copied().map(Into::into).collect();
624            f(
625                aviutl2_sys::filter2::VERTEX_TYPE::QUAD_TEXTURE_NORM,
626                flattened.as_ptr() as *const c_void,
627                flattened.len() as i32,
628            )
629        }
630    }
631}
632
633fn image_resource_ptr_list(
634    resources: &[ImageResource],
635) -> Result<
636    (
637        Vec<crate::common::CWString>,
638        Vec<aviutl2_sys::common::LPCWSTR>,
639    ),
640    FilterProcError,
641> {
642    let strings = resources
643        .iter()
644        .map(|resource| crate::common::CWString::new(&resource.to_string()))
645        .collect::<Result<Vec<_>, _>>()?;
646    let ptrs = strings.iter().map(|s| s.as_ptr()).collect();
647    Ok((strings, ptrs))
648}
649
650fn image_data_byte_len(pitch: u32, height: u32) -> FilterProcResult<usize> {
651    (pitch as usize)
652        .checked_mul(height as usize)
653        .ok_or(FilterProcError::ValueOutOfRange)
654}
655
656impl<U: super::FilterUserdata> FilterProcVideo<U> {
657    /// 可変長の汎用データ項目のサイズを変更する。
658    ///
659    /// データのread/writeガードが存在する場合は失敗します。
660    pub fn set_filter_config_data_size(
661        &self,
662        data: &mut crate::filter::VariableLengthFilterConfigDataHandle,
663        size: usize,
664    ) -> FilterProcResult<()> {
665        data.try_resize(size, |data, size| unsafe {
666            ((*self.inner).set_filter_item_data_size)(data, size);
667        })
668    }
669
670    /// 現在の画像のデータを取得する。
671    /// RGBA32bit で取得されます。
672    ///
673    /// # Panics
674    ///
675    /// `buffer` をバイト列に変換した際の長さが `width * height * 4` と一致しない場合、パニックします。
676    /// 例えば[`u8`] の場合、`buffer` の長さは `width * height * 4` と一致する必要があり、
677    /// [`RgbaPixel`] の場合、`buffer` の長さは `width * height` と一致する必要があります。
678    pub fn get_image_data<T>(&mut self, buffer: &mut [T]) -> usize
679    where
680        T: Copy + FromBytes + Immutable,
681    {
682        if self.video_object.width == 0 || self.video_object.height == 0 {
683            tracing::warn!("width or height is 0, perhaps the filter plugin is a custom object");
684            return 0;
685        }
686        assert_eq!(
687            std::mem::size_of_val(buffer),
688            (self.video_object.width * self.video_object.height * 4) as usize,
689            "buffer length as bytes does not match width * height * 4"
690        );
691        assert!(
692            std::mem::align_of::<T>() >= std::mem::align_of::<aviutl2_sys::filter2::PIXEL_RGBA>(),
693            "buffer alignment is not sufficient"
694        );
695        let width = self.video_object.width as usize;
696        let height = self.video_object.height as usize;
697        let inner = unsafe { &*self.inner };
698        unsafe {
699            (inner.get_image_data)(
700                buffer.as_mut_ptr() as *mut u8 as *mut aviutl2_sys::filter2::PIXEL_RGBA
701            )
702        };
703
704        width * height * 4
705    }
706
707    /// 現在の画像のデータを設定する。
708    ///
709    /// # Panics
710    ///
711    /// `data` をバイト列に変換した際の長さが `width * height * 4` と一致しない場合、パニックします。
712    pub fn set_image_data<T: IntoBytes + Immutable>(
713        &mut self,
714        data: &[T],
715        width: u32,
716        height: u32,
717    ) {
718        let bytes = &data.as_bytes();
719        assert_eq!(
720            bytes.len(),
721            (width * height * 4) as usize,
722            "data length does not match width * height * 4"
723        );
724        let inner = unsafe { &*self.inner };
725        unsafe {
726            (inner.set_image_data)(
727                bytes.as_ptr() as *const aviutl2_sys::filter2::PIXEL_RGBA,
728                width as i32,
729                height as i32,
730            )
731        };
732    }
733
734    /// 現在のオブジェクトの画像データのポインタをID3D11Texture2Dのポインタとして取得する。
735    ///
736    /// # Warning
737    ///
738    /// [`Self::set_image_data`] によって現在の画像が変更されるかフィルタ処理の終了まで有効です。
739    pub fn get_image_texture2d(
740        &mut self,
741    ) -> Option<windows::Win32::Graphics::Direct3D11::ID3D11Texture2D> {
742        let inner = unsafe { &*self.inner };
743        let ptr = unsafe { (inner.get_image_texture2d)() };
744        (!ptr.is_null()).then(|| unsafe {
745            windows::Win32::Graphics::Direct3D11::ID3D11Texture2D::from_raw(ptr)
746        })
747    }
748
749    /// 現在のフレームバッファの画像データのポインタをID3D11Texture2Dのポインタとして取得する。
750    ///
751    /// # Warning
752    ///
753    /// フィルタ処理の終了まで有効です。
754    pub fn get_framebuffer_texture2d(
755        &mut self,
756    ) -> Option<windows::Win32::Graphics::Direct3D11::ID3D11Texture2D> {
757        let inner = unsafe { &*self.inner };
758        let ptr = unsafe { (inner.get_framebuffer_texture2d)() };
759        (!ptr.is_null()).then(|| unsafe {
760            windows::Win32::Graphics::Direct3D11::ID3D11Texture2D::from_raw(ptr)
761        })
762    }
763
764    /// 読み取り専用の編集セクション。
765    pub fn read_section(&mut self) -> &crate::generic::ReadSection {
766        &self.read_section
767    }
768
769    /// 指定オブジェクト、または現在のオブジェクトの画像出力項目のパラメータを取得する。
770    ///
771    /// # Arguments
772    ///
773    /// - `object`:取得するオブジェクト。`None` の場合は現在のオブジェクト。
774    /// - `offset`:取得する時間のオフセット。
775    pub fn get_output_image_param(
776        &mut self,
777        object: Option<crate::generic::ObjectHandle>,
778        offset: f64,
779    ) -> FilterProcResult<ObjectImageParam> {
780        let inner = unsafe { &*self.inner };
781        let mut param = std::mem::MaybeUninit::<aviutl2_sys::filter2::OBJECT_IMAGE_PARAM>::uninit();
782        unsafe {
783            let ok = (inner.get_output_image_param)(
784                object.map_or(std::ptr::null_mut(), |o| o.internal as *mut _),
785                offset,
786                param.as_mut_ptr(),
787                std::mem::size_of::<aviutl2_sys::filter2::OBJECT_IMAGE_PARAM>() as i32,
788            );
789            if ok {
790                Ok(param.assume_init().into())
791            } else {
792                Err(FilterProcError::ApiCallFailed)
793            }
794        }
795    }
796
797    /// 指定のレイヤーにある画像オブジェクトを取得する。
798    pub fn get_image_object(
799        &mut self,
800        layer: u32,
801        offset: f64,
802    ) -> Option<crate::generic::ObjectHandle> {
803        let handle = unsafe { ((*self.inner).get_image_object)(layer as _, offset) };
804        if handle.is_null() {
805            None
806        } else {
807            Some(crate::generic::ObjectHandle { internal: handle })
808        }
809    }
810
811    /// 指定の画像リソースをフレームバッファに描画する。
812    ///
813    /// # Arguments
814    ///
815    /// - `resource`:描画する画像リソース。利用できる種類は [`ImageResource::Object`]、
816    ///   [`ImageResource::Resource`]、[`ImageResource::TempBuffer`]、
817    ///   [`ImageResource::CacheBuffer`]、[`ImageResource::ImageFile`]。
818    /// - `param`:描画パラメーター。
819    pub fn draw_image(
820        &mut self,
821        resource: &ImageResource,
822        param: DrawImageParam,
823    ) -> FilterProcResult<()> {
824        self.apply_param();
825        let resource_str = crate::common::CWString::new(&resource.to_string())?;
826        let inner = unsafe { &*self.inner };
827        let success = unsafe {
828            (inner.draw_image)(
829                resource_str.as_ptr(),
830                param.x,
831                param.y,
832                param.z,
833                param.rx,
834                param.ry,
835                param.rz,
836                param.sx,
837                param.sy,
838                param.sz,
839                param.alpha,
840            )
841        };
842        if success {
843            Ok(())
844        } else {
845            Err(FilterProcError::ApiCallFailed)
846        }
847    }
848
849    /// 指定の頂点リストをフレームバッファに描画する。
850    ///
851    /// # Arguments
852    ///
853    /// - `resource`:テクスチャ画像リソース。利用できる種類は [`ImageResource::Object`]、
854    ///   [`ImageResource::Resource`]、[`ImageResource::TempBuffer`]、
855    ///   [`ImageResource::CacheBuffer`]、[`ImageResource::ImageFile`]。
856    ///   `None` の場合は [`ImageResource::TempBuffer`] を利用します。
857    pub fn draw_poly(
858        &mut self,
859        vertices: &VertexList,
860        resource: Option<&ImageResource>,
861    ) -> FilterProcResult<()> {
862        self.apply_param();
863
864        let resource_str = crate::common::CWString::new(
865            &resource.map_or_else(|| "tempbuffer".to_string(), |r| r.to_string()),
866        )?;
867        let inner = unsafe { &*self.inner };
868        let success = vertex_list_as_raw(vertices, |vertex_type, vertex_list, vertex_num| unsafe {
869            (inner.draw_poly)(vertex_type, vertex_list, vertex_num, resource_str.as_ptr())
870        });
871        if success {
872            Ok(())
873        } else {
874            Err(FilterProcError::ApiCallFailed)
875        }
876    }
877
878    /// 標準のアンカー枠を設定する。
879    ///
880    /// 通常は自動で設定されます。
881    /// [`Self::draw_image`] などで手動で描画する場合に使います。
882    /// この関数を呼び出すとこれ以降の描画処理後のフィルタ処理が中断されます。
883    pub fn set_default_anchor(&mut self, width: u32, height: u32) {
884        let inner = unsafe { &*self.inner };
885        self.prevent_post_effect = true;
886        unsafe {
887            (inner.set_default_anchor)(width as i32, height as i32);
888        }
889    }
890
891    /// 描画時の合成モードを設定する。
892    pub fn set_blend_mode(&mut self, mode: BlendMode) {
893        let inner = unsafe { &*self.inner };
894        unsafe {
895            (inner.set_blend_mode)(mode.into());
896        }
897    }
898
899    /// 描画時の光沢度を設定する。
900    /// カメラ制御の光源設定が有効の時に利用されます。
901    pub fn set_material_shine(&mut self, shininess: f32) {
902        let inner = unsafe { &*self.inner };
903        unsafe {
904            (inner.set_material_shine)(shininess);
905        }
906    }
907
908    /// 描画時のサンプラーを設定する。
909    pub fn set_sampler_mode(&mut self, mode: SamplerMode) {
910        let inner = unsafe { &*self.inner };
911        unsafe {
912            (inner.set_sampler_mode)(mode.into());
913        }
914    }
915
916    /// 描画時に裏面を非表示にするかを設定する。
917    pub fn set_culling_state(&mut self, culling: bool) {
918        let inner = unsafe { &*self.inner };
919        unsafe {
920            (inner.set_culling_state)(culling);
921        }
922    }
923
924    /// 描画時にカメラに向けるかどうかを設定する。
925    pub fn set_billboard_mode(&mut self, mode: BillboardMode) {
926        let inner = unsafe { &*self.inner };
927        unsafe {
928            (inner.set_billboard_mode)(mode.into());
929        }
930    }
931
932    /// 画像リソースを作成する。
933    /// VRAMへデータを書き込みます。
934    ///
935    /// # Note
936    ///
937    /// - 既に同名の画像リソースが存在する場合、上書きされます。
938    ///
939    /// # Arguments
940    ///
941    /// - `resource`:作成する画像リソース。利用できる種類は [`ImageResource::Object`]、
942    ///   [`ImageResource::Resource`]、[`ImageResource::TempBuffer`]、
943    ///   [`ImageResource::CacheBuffer`]。
944    ///
945    /// # Panics
946    ///
947    /// `data` をバイト列に変換した際の長さが `width * height * 4` と一致しない場合、パニックします。
948    pub fn create_image_resource<T: IntoBytes + Immutable>(
949        &mut self,
950        resource: &ImageResource,
951        data: &[T],
952        width: u32,
953        height: u32,
954    ) -> FilterProcResult<()> {
955        let bytes = &data.as_bytes();
956        assert_eq!(
957            bytes.len(),
958            (width * height * 4) as usize,
959            "data length does not match width * height * 4"
960        );
961        let inner = unsafe { &*self.inner };
962        let name_cw = crate::common::CWString::new(&resource.to_string())?;
963        unsafe {
964            (inner.create_image_resource)(
965                name_cw.as_ptr(),
966                bytes.as_ptr() as *const aviutl2_sys::filter2::PIXEL_RGBA,
967                width as i32,
968                height as i32,
969            )
970        };
971        Ok(())
972    }
973
974    /// 指定の画像リソースのD3D画像リソースのポインタを取得する。
975    ///
976    /// # Arguments
977    ///
978    /// - `resource`:取得する画像リソース。利用できる種類は [`ImageResource::Object`]、
979    ///   [`ImageResource::Resource`]、[`ImageResource::TempBuffer`]、
980    ///   [`ImageResource::CacheBuffer`]、[`ImageResource::ImageFile`]、
981    ///   [`ImageResource::Random`]。
982    pub fn get_image_resource_texture2d(
983        &mut self,
984        resource: &ImageResource,
985    ) -> FilterProcResult<*mut c_void> {
986        let inner = unsafe { &*self.inner };
987        let resource_cw = crate::common::CWString::new(&resource.to_string())?;
988        let ptr = unsafe { (inner.get_image_resource_texture2d)(resource_cw.as_ptr()) };
989        if ptr.is_null() {
990            Err(FilterProcError::ApiCallFailed)
991        } else {
992            Ok(ptr)
993        }
994    }
995
996    /// 指定の画像リソースのサイズを取得する。
997    ///
998    /// # Arguments
999    ///
1000    /// - `resource`:取得する画像リソース。利用できる種類は [`ImageResource::Object`]、
1001    ///   [`ImageResource::Resource`]、[`ImageResource::TempBuffer`]、
1002    ///   [`ImageResource::CacheBuffer`]、[`ImageResource::ImageFile`]。
1003    pub fn get_image_resource_size(
1004        &mut self,
1005        resource: &ImageResource,
1006    ) -> FilterProcResult<(u32, u32)> {
1007        let inner = unsafe { &*self.inner };
1008        let resource_cw = crate::common::CWString::new(&resource.to_string())?;
1009        let mut width = 0;
1010        let mut height = 0;
1011        let success = unsafe {
1012            (inner.get_image_resource_size)(resource_cw.as_ptr(), &mut width, &mut height)
1013        };
1014        if success {
1015            Ok((width as u32, height as u32))
1016        } else {
1017            Err(FilterProcError::ApiCallFailed)
1018        }
1019    }
1020
1021    /// 画像リソースをコピーする。
1022    ///
1023    /// # Arguments
1024    ///
1025    /// - `src_resource`:コピー元。利用できる種類は [`ImageResource::Object`]、
1026    ///   [`ImageResource::Resource`]、[`ImageResource::Framebuffer`]、
1027    ///   [`ImageResource::TempBuffer`]、[`ImageResource::CacheBuffer`]、
1028    ///   [`ImageResource::ImageFile`]、[`ImageResource::Random`]、
1029    ///   [`ImageResource::Layer`]、[`ImageResource::PreviousObject`]。
1030    /// - `dst_resource`:コピー先。利用できる種類は [`ImageResource::Object`]、
1031    ///   [`ImageResource::Resource`]、[`ImageResource::TempBuffer`]、
1032    ///   [`ImageResource::CacheBuffer`]。
1033    pub fn copy_image_resource(
1034        &mut self,
1035        src_resource: &ImageResource,
1036        dst_resource: &ImageResource,
1037    ) -> FilterProcResult<()> {
1038        let inner = unsafe { &*self.inner };
1039        let dst_resource = crate::common::CWString::new(&dst_resource.to_string())?;
1040        let src_resource = crate::common::CWString::new(&src_resource.to_string())?;
1041        let success =
1042            unsafe { (inner.copy_image_resource)(dst_resource.as_ptr(), src_resource.as_ptr()) };
1043        if success {
1044            Ok(())
1045        } else {
1046            Err(FilterProcError::ApiCallFailed)
1047        }
1048    }
1049
1050    /// 画像リソースをクリアする。
1051    ///
1052    /// # Arguments
1053    ///
1054    /// - `resource`:クリアする画像リソース。利用できる種類は [`ImageResource::Object`]、
1055    ///   [`ImageResource::Resource`]、[`ImageResource::TempBuffer`]、
1056    ///   [`ImageResource::CacheBuffer`]。
1057    pub fn clear_image_resource(
1058        &mut self,
1059        resource: &ImageResource,
1060        color: RgbaPixel,
1061    ) -> FilterProcResult<()> {
1062        let inner = unsafe { &*self.inner };
1063        let resource = crate::common::CWString::new(&resource.to_string())?;
1064        let color = aviutl2_sys::filter2::PIXEL_RGBA {
1065            r: color.r,
1066            g: color.g,
1067            b: color.b,
1068            a: color.a,
1069        };
1070        let success = unsafe { (inner.clear_image_resource)(resource.as_ptr(), color) };
1071        if success {
1072            Ok(())
1073        } else {
1074            Err(FilterProcError::ApiCallFailed)
1075        }
1076    }
1077
1078    /// 画像リソースから指定フォーマットの画像データを取得する。
1079    ///
1080    /// `buffer` は少なくとも `pitch * height` バイト必要です。
1081    ///
1082    /// # Arguments
1083    ///
1084    /// - `resource`:読み取る画像リソース。利用できる種類は [`ImageResource::Object`]、
1085    ///   [`ImageResource::Resource`]。
1086    pub fn get_image_resource_data(
1087        &mut self,
1088        resource: &ImageResource,
1089        buffer: &mut [u8],
1090        width: u32,
1091        height: u32,
1092        pitch: u32,
1093        format: OutputImageResourcePixelFormat,
1094    ) -> FilterProcResult<()> {
1095        let min_len = image_data_byte_len(pitch, height)?;
1096        assert!(
1097            buffer.len() >= min_len,
1098            "buffer length must be at least pitch * height"
1099        );
1100        let inner = unsafe { &*self.inner };
1101        let resource = crate::common::CWString::new(&resource.to_string())?;
1102        let success = unsafe {
1103            (inner.get_image_resource_data)(
1104                resource.as_ptr(),
1105                buffer.as_mut_ptr() as *mut c_void,
1106                width as i32,
1107                height as i32,
1108                pitch as i32,
1109                format.into(),
1110            )
1111        };
1112        if success {
1113            Ok(())
1114        } else {
1115            Err(FilterProcError::ApiCallFailed)
1116        }
1117    }
1118
1119    /// 画像リソースに指定フォーマットの画像データを設定する。
1120    ///
1121    /// `data` をバイト列に変換した長さは少なくとも `pitch * height` バイト必要です。
1122    ///
1123    /// # Arguments
1124    ///
1125    /// - `resource`:書き込む画像リソース。利用できる種類は [`ImageResource::Object`]、
1126    ///   [`ImageResource::Resource`]。
1127    pub fn set_image_resource_data<T: IntoBytes + Immutable>(
1128        &mut self,
1129        resource: &ImageResource,
1130        data: &[T],
1131        width: u32,
1132        height: u32,
1133        pitch: u32,
1134        format: InputImageResourcePixelFormat,
1135    ) -> FilterProcResult<()> {
1136        let bytes = data.as_bytes();
1137        let min_len = image_data_byte_len(pitch, height)?;
1138        assert!(
1139            bytes.len() >= min_len,
1140            "data length must be at least pitch * height"
1141        );
1142        let inner = unsafe { &*self.inner };
1143        let resource = crate::common::CWString::new(&resource.to_string())?;
1144        let success = unsafe {
1145            (inner.set_image_resource_data)(
1146                resource.as_ptr(),
1147                bytes.as_ptr() as *const c_void,
1148                width as i32,
1149                height as i32,
1150                pitch as i32,
1151                format.into(),
1152            )
1153        };
1154        if success {
1155            Ok(())
1156        } else {
1157            Err(FilterProcError::ApiCallFailed)
1158        }
1159    }
1160
1161    /// 指定の画像リソースを描画先の画像リソースに描画する。
1162    ///
1163    /// # Arguments
1164    ///
1165    /// - `src_resource`:描画元。利用できる種類は [`ImageResource::Object`]、
1166    ///   [`ImageResource::Resource`]、[`ImageResource::TempBuffer`]、
1167    ///   [`ImageResource::CacheBuffer`]、[`ImageResource::ImageFile`]。
1168    /// - `dst_resource`:描画先。利用できる種類は [`ImageResource::Object`]、
1169    ///   [`ImageResource::Resource`]、[`ImageResource::TempBuffer`]、
1170    ///   [`ImageResource::CacheBuffer`]。
1171    pub fn draw_image_to_resource(
1172        &mut self,
1173        src_resource: &ImageResource,
1174        dst_resource: &ImageResource,
1175        param: DrawImageParam,
1176    ) -> FilterProcResult<()> {
1177        self.apply_param();
1178        let inner = unsafe { &*self.inner };
1179        let dst_resource = crate::common::CWString::new(&dst_resource.to_string())?;
1180        let src_resource = crate::common::CWString::new(&src_resource.to_string())?;
1181        let success = unsafe {
1182            (inner.draw_image_to_resource)(
1183                dst_resource.as_ptr(),
1184                src_resource.as_ptr(),
1185                param.x,
1186                param.y,
1187                param.z,
1188                param.rx,
1189                param.ry,
1190                param.rz,
1191                param.sx,
1192                param.sy,
1193                param.sz,
1194                param.alpha,
1195            )
1196        };
1197        if success {
1198            Ok(())
1199        } else {
1200            Err(FilterProcError::ApiCallFailed)
1201        }
1202    }
1203
1204    /// 指定の頂点リストのポリゴンを描画先の画像リソースに描画する。
1205    ///
1206    /// # Arguments
1207    ///
1208    /// - `dst_resource`:描画先。利用できる種類は [`ImageResource::Object`]、
1209    ///   [`ImageResource::Resource`]、[`ImageResource::TempBuffer`]、
1210    ///   [`ImageResource::CacheBuffer`]。
1211    /// - `src_resource`:テクスチャ画像リソース。利用できる種類は
1212    ///   [`ImageResource::Object`]、[`ImageResource::Resource`]、
1213    ///   [`ImageResource::TempBuffer`]、[`ImageResource::CacheBuffer`]、
1214    ///   [`ImageResource::ImageFile`]。`None` の場合は [`ImageResource::TempBuffer`] を利用します。
1215    pub fn draw_poly_to_resource(
1216        &mut self,
1217        dst_resource: &ImageResource,
1218        vertices: &VertexList,
1219        src_resource: Option<&ImageResource>,
1220    ) -> FilterProcResult<()> {
1221        self.apply_param();
1222        let inner = unsafe { &*self.inner };
1223        let dst_resource = crate::common::CWString::new(&dst_resource.to_string())?;
1224        let src_resource = crate::common::CWString::new(
1225            &src_resource.map_or_else(|| "tempbuffer".to_string(), |r| r.to_string()),
1226        )?;
1227        let success = vertex_list_as_raw(vertices, |vertex_type, vertex_list, vertex_num| unsafe {
1228            (inner.draw_poly_to_resource)(
1229                dst_resource.as_ptr(),
1230                vertex_type,
1231                vertex_list as *mut c_void,
1232                vertex_num,
1233                src_resource.as_ptr(),
1234            )
1235        });
1236        if success {
1237            Ok(())
1238        } else {
1239            Err(FilterProcError::ApiCallFailed)
1240        }
1241    }
1242
1243    /// ピクセルシェーダーを実行する。
1244    ///
1245    /// シェーダー側とメモリレイアウトを合わせるため、`constant` を構造体で渡す場合は `#[repr(C)]`
1246    /// を推奨します。
1247    ///
1248    /// # Arguments
1249    ///
1250    /// - `target`:出力先。利用できる種類は [`ImageResource::Object`]、
1251    ///   [`ImageResource::Resource`]、[`ImageResource::Framebuffer`]、
1252    ///   [`ImageResource::TempBuffer`]、[`ImageResource::CacheBuffer`]。
1253    /// - `resources`:参照する画像リソース。利用できる種類は [`ImageResource::Object`]、
1254    ///   [`ImageResource::Resource`]、[`ImageResource::TempBuffer`]、
1255    ///   [`ImageResource::CacheBuffer`]、[`ImageResource::ImageFile`]、
1256    ///   [`ImageResource::Random`]。
1257    pub fn exec_pixelshader<T: Copy>(
1258        &mut self,
1259        cso_file: &str,
1260        target: &ImageResource,
1261        resources: &[ImageResource],
1262        constant: T,
1263        blend_state: &windows::Win32::Graphics::Direct3D11::ID3D11BlendState,
1264        sampler_state: &windows::Win32::Graphics::Direct3D11::ID3D11SamplerState,
1265    ) -> FilterProcResult<()> {
1266        self.apply_param();
1267        let inner = unsafe { &*self.inner };
1268        let cso_file = crate::common::CWString::new(cso_file)?;
1269        let target = crate::common::CWString::new(&target.to_string())?;
1270        let (_resource_strings, mut resource_ptrs) = image_resource_ptr_list(resources)?;
1271        let constant_ptr = Box::new(constant);
1272        let success = unsafe {
1273            (inner.exec_pixelshader_file)(
1274                cso_file.as_ptr(),
1275                target.as_ptr(),
1276                if resource_ptrs.is_empty() {
1277                    std::ptr::null_mut()
1278                } else {
1279                    resource_ptrs.as_mut_ptr()
1280                },
1281                resource_ptrs.len() as i32,
1282                constant_ptr.as_ref() as *const T as *mut c_void,
1283                std::mem::size_of::<T>() as i32,
1284                blend_state.as_raw(),
1285                sampler_state.as_raw(),
1286            )
1287        };
1288        if success {
1289            Ok(())
1290        } else {
1291            Err(FilterProcError::ApiCallFailed)
1292        }
1293    }
1294
1295    /// メモリ上のコンパイル済みピクセルシェーダーを実行する。
1296    ///
1297    /// シェーダー側とメモリレイアウトを合わせるため、`constant` を構造体で渡す場合は `#[repr(C)]`
1298    /// を推奨します。
1299    ///
1300    /// # Arguments
1301    ///
1302    /// - `target`:出力先。利用できる種類は [`ImageResource::Object`]、
1303    ///   [`ImageResource::Resource`]、[`ImageResource::Framebuffer`]、
1304    ///   [`ImageResource::TempBuffer`]、[`ImageResource::CacheBuffer`]。
1305    /// - `resources`:参照する画像リソース。利用できる種類は [`ImageResource::Object`]、
1306    ///   [`ImageResource::Resource`]、[`ImageResource::TempBuffer`]、
1307    ///   [`ImageResource::CacheBuffer`]、[`ImageResource::ImageFile`]、
1308    ///   [`ImageResource::Random`]。
1309    pub fn exec_pixelshader_data<T: Copy>(
1310        &mut self,
1311        data: &[u8],
1312        target: &ImageResource,
1313        resources: &[ImageResource],
1314        constant: T,
1315        blend_state: &windows::Win32::Graphics::Direct3D11::ID3D11BlendState,
1316        sampler_state: &windows::Win32::Graphics::Direct3D11::ID3D11SamplerState,
1317    ) -> FilterProcResult<()> {
1318        self.apply_param();
1319        let inner = unsafe { &*self.inner };
1320        let data_size = i32::try_from(data.len()).map_err(|_| FilterProcError::ValueOutOfRange)?;
1321        let target = crate::common::CWString::new(&target.to_string())?;
1322        let (_resource_strings, mut resource_ptrs) = image_resource_ptr_list(resources)?;
1323        let constant_ptr = Box::new(constant);
1324        let success = unsafe {
1325            (inner.exec_pixelshader_data)(
1326                data.as_ptr(),
1327                data_size,
1328                target.as_ptr(),
1329                if resource_ptrs.is_empty() {
1330                    std::ptr::null_mut()
1331                } else {
1332                    resource_ptrs.as_mut_ptr()
1333                },
1334                resource_ptrs.len() as i32,
1335                constant_ptr.as_ref() as *const T as *mut c_void,
1336                std::mem::size_of::<T>() as i32,
1337                blend_state.as_raw(),
1338                sampler_state.as_raw(),
1339            )
1340        };
1341        if success {
1342            Ok(())
1343        } else {
1344            Err(FilterProcError::ApiCallFailed)
1345        }
1346    }
1347
1348    /// コンピュートシェーダーを実行する。
1349    ///
1350    /// シェーダー側とメモリレイアウトを合わせるため、`constant` を構造体で渡す場合は `#[repr(C)]`
1351    /// を推奨します。
1352    ///
1353    /// # Arguments
1354    ///
1355    /// - `targets`:読み書き先。利用できる種類は [`ImageResource::Object`]、
1356    ///   [`ImageResource::Resource`]、[`ImageResource::Framebuffer`]、
1357    ///   [`ImageResource::TempBuffer`]、[`ImageResource::CacheBuffer`]。
1358    /// - `resources`:参照する画像リソース。利用できる種類は [`ImageResource::Object`]、
1359    ///   [`ImageResource::Resource`]、[`ImageResource::TempBuffer`]、
1360    ///   [`ImageResource::CacheBuffer`]、[`ImageResource::ImageFile`]、
1361    ///   [`ImageResource::Random`]。
1362    pub fn exec_computeshader<T: Copy>(
1363        &mut self,
1364        cso_file: &str,
1365        targets: &[ImageResource],
1366        resources: &[ImageResource],
1367        constant: T,
1368        count: [u32; 3],
1369        sampler_state: &windows::Win32::Graphics::Direct3D11::ID3D11SamplerState,
1370    ) -> FilterProcResult<()> {
1371        self.apply_param();
1372        let inner = unsafe { &*self.inner };
1373        let cso_file = crate::common::CWString::new(cso_file)?;
1374        let (_target_strings, mut target_ptrs) = image_resource_ptr_list(targets)?;
1375        let (_resource_strings, mut resource_ptrs) = image_resource_ptr_list(resources)?;
1376        let constant_ptr = Box::new(constant);
1377        let success = unsafe {
1378            (inner.exec_computeshader_file)(
1379                cso_file.as_ptr(),
1380                if target_ptrs.is_empty() {
1381                    std::ptr::null_mut()
1382                } else {
1383                    target_ptrs.as_mut_ptr()
1384                },
1385                target_ptrs.len() as i32,
1386                if resource_ptrs.is_empty() {
1387                    std::ptr::null_mut()
1388                } else {
1389                    resource_ptrs.as_mut_ptr()
1390                },
1391                resource_ptrs.len() as i32,
1392                constant_ptr.as_ref() as *const T as *mut c_void,
1393                std::mem::size_of::<T>() as i32,
1394                count[0] as i32,
1395                count[1] as i32,
1396                count[2] as i32,
1397                sampler_state.as_raw(),
1398            )
1399        };
1400        if success {
1401            Ok(())
1402        } else {
1403            Err(FilterProcError::ApiCallFailed)
1404        }
1405    }
1406
1407    /// メモリ上のコンパイル済みコンピュートシェーダーを実行する。
1408    ///
1409    /// シェーダー側とメモリレイアウトを合わせるため、`constant` を構造体で渡す場合は `#[repr(C)]`
1410    /// を推奨します。
1411    ///
1412    /// # Arguments
1413    ///
1414    /// - `targets`:読み書き先。利用できる種類は [`ImageResource::Object`]、
1415    ///   [`ImageResource::Resource`]、[`ImageResource::Framebuffer`]、
1416    ///   [`ImageResource::TempBuffer`]、[`ImageResource::CacheBuffer`]。
1417    /// - `resources`:参照する画像リソース。利用できる種類は [`ImageResource::Object`]、
1418    ///   [`ImageResource::Resource`]、[`ImageResource::TempBuffer`]、
1419    ///   [`ImageResource::CacheBuffer`]、[`ImageResource::ImageFile`]、
1420    ///   [`ImageResource::Random`]。
1421    pub fn exec_computeshader_data<T: Copy>(
1422        &mut self,
1423        data: &[u8],
1424        targets: &[ImageResource],
1425        resources: &[ImageResource],
1426        constant: T,
1427        count: [u32; 3],
1428        sampler_state: &windows::Win32::Graphics::Direct3D11::ID3D11SamplerState,
1429    ) -> FilterProcResult<()> {
1430        self.apply_param();
1431        let inner = unsafe { &*self.inner };
1432        let data_size = i32::try_from(data.len()).map_err(|_| FilterProcError::ValueOutOfRange)?;
1433        let (_target_strings, mut target_ptrs) = image_resource_ptr_list(targets)?;
1434        let (_resource_strings, mut resource_ptrs) = image_resource_ptr_list(resources)?;
1435        let constant_ptr = Box::new(constant);
1436        let success = unsafe {
1437            (inner.exec_computeshader_data)(
1438                data.as_ptr(),
1439                data_size,
1440                if target_ptrs.is_empty() {
1441                    std::ptr::null_mut()
1442                } else {
1443                    target_ptrs.as_mut_ptr()
1444                },
1445                target_ptrs.len() as i32,
1446                if resource_ptrs.is_empty() {
1447                    std::ptr::null_mut()
1448                } else {
1449                    resource_ptrs.as_mut_ptr()
1450                },
1451                resource_ptrs.len() as i32,
1452                constant_ptr.as_ref() as *const T as *mut c_void,
1453                std::mem::size_of::<T>() as i32,
1454                count[0] as i32,
1455                count[1] as i32,
1456                count[2] as i32,
1457                sampler_state.as_raw(),
1458            )
1459        };
1460        if success {
1461            Ok(())
1462        } else {
1463            Err(FilterProcError::ApiCallFailed)
1464        }
1465    }
1466
1467    /// 画像リソースを解放する。
1468    ///
1469    /// # Arguments
1470    ///
1471    /// - `resource`:解放する画像リソース。利用できる種類は [`ImageResource::Resource`]。
1472    pub fn release_image_resource(&mut self, resource: &ImageResource) -> FilterProcResult<()> {
1473        let inner = unsafe { &*self.inner };
1474        let resource = crate::common::CWString::new(&resource.to_string())?;
1475        let success = unsafe { (inner.release_image_resource)(resource.as_ptr()) };
1476        if success {
1477            Ok(())
1478        } else {
1479            Err(FilterProcError::ApiCallFailed)
1480        }
1481    }
1482
1483    /// 指定のエフェクトを実行する。
1484    ///
1485    /// フィルタ効果、入力項目のエフェクトが実行できます。
1486    ///
1487    /// # Arguments
1488    ///
1489    /// - `effect_name`:実行するエフェクトの名前。
1490    /// - `param`:エフェクトのパラメーター。Key・Valueはどちらもエイリアスと同様のフォーマットで指定します。
1491    /// - `resource`:処理対象の画像リソース。利用できる種類は
1492    ///   [`ImageResource::Object`]、[`ImageResource::Resource`]。
1493    pub fn exec_effect<'a, C, K, V>(
1494        &mut self,
1495        effect_name: &str,
1496        param: C,
1497        resource: &ImageResource,
1498    ) -> FilterProcResult<()>
1499    where
1500        C: IntoIterator<Item = (&'a K, &'a V)>,
1501        K: AsRef<str> + 'a,
1502        V: AsRef<str> + 'a,
1503    {
1504        let inner = unsafe { &*self.inner };
1505        let effect_name = crate::common::CWString::new(effect_name)?;
1506        let resource = crate::common::CWString::new(&resource.to_string())?;
1507        let mut param_key_cwstrs = vec![];
1508        let mut param_value_cstrs = vec![];
1509        for (key, value) in param {
1510            param_key_cwstrs.push(crate::common::CWString::new(key.as_ref())?);
1511            param_value_cstrs.push(std::ffi::CString::new(value.as_ref())?);
1512        }
1513
1514        let mut params = param_key_cwstrs
1515            .iter()
1516            .zip(param_value_cstrs.iter())
1517            .map(|(key, value)| aviutl2_sys::filter2::EFFECT_ITEM_PARAM {
1518                name: key.as_ptr(),
1519                value: value.as_ptr(),
1520            })
1521            .collect::<Vec<_>>();
1522
1523        let success = unsafe {
1524            (inner.exec_effect)(
1525                effect_name.as_ptr(),
1526                if params.is_empty() {
1527                    std::ptr::null_mut()
1528                } else {
1529                    params.as_mut_ptr()
1530                },
1531                params.len() as i32,
1532                resource.as_ptr(),
1533            )
1534        };
1535        if success {
1536            Ok(())
1537        } else {
1538            Err(FilterProcError::ApiCallFailed)
1539        }
1540    }
1541
1542    /// 定義済みのD3Dの出力ブレンドのリソースのポインタを取得する。
1543    pub fn get_blend_state(
1544        &mut self,
1545        mode: BlendStateMode,
1546    ) -> Option<windows::Win32::Graphics::Direct3D11::ID3D11BlendState> {
1547        let inner = unsafe { &*self.inner };
1548        let ptr = unsafe { (inner.get_blend_state)(mode.into()) };
1549        (!ptr.is_null()).then_some(unsafe {
1550            windows::Win32::Graphics::Direct3D11::ID3D11BlendState::from_raw(ptr)
1551        })
1552    }
1553
1554    /// 定義済みのD3Dのサンプラーのリソースのポインタを取得する。
1555    pub fn get_sampler_state(
1556        &mut self,
1557        mode: SamplerMode,
1558    ) -> Option<windows::Win32::Graphics::Direct3D11::ID3D11SamplerState> {
1559        let inner = unsafe { &*self.inner };
1560        let ptr = unsafe { (inner.get_sampler_state)(mode.into()) };
1561        (!ptr.is_null()).then_some(unsafe {
1562            windows::Win32::Graphics::Direct3D11::ID3D11SamplerState::from_raw(ptr)
1563        })
1564    }
1565
1566    /// フィルタ処理後の処理を中断する。
1567    ///
1568    /// [`Self::draw_poly`] や [`Self::draw_image`] などを呼び出した後に使います。
1569    pub fn prevent_post_effect(&mut self) {
1570        self.prevent_post_effect = true;
1571    }
1572
1573    pub(crate) fn apply_param(&mut self) {
1574        let param = unsafe { &mut *((*self.inner).param) };
1575        param.x = self.param.x;
1576        param.y = self.param.y;
1577        param.z = self.param.z;
1578        param.rx = self.param.rx;
1579        param.ry = self.param.ry;
1580        param.rz = self.param.rz;
1581        param.sx = self.param.sx;
1582        param.sy = self.param.sy;
1583        param.sz = self.param.sz;
1584        param.cx = self.param.cx;
1585        param.cy = self.param.cy;
1586        param.cz = self.param.cz;
1587        param.alpha = self.param.alpha;
1588    }
1589}
1590
1591#[cfg(test)]
1592mod tests {
1593    use super::*;
1594
1595    #[test]
1596    fn formats_image_resources_for_sdk() {
1597        assert_eq!(ImageResource::Object.to_string(), "object");
1598        assert_eq!(
1599            ImageResource::Resource("name".to_string()).to_string(),
1600            "resource:name"
1601        );
1602        assert_eq!(ImageResource::Framebuffer.to_string(), "framebuffer");
1603        assert_eq!(ImageResource::TempBuffer.to_string(), "tempbuffer");
1604        assert_eq!(
1605            ImageResource::CacheBuffer("name".to_string()).to_string(),
1606            "cache:name"
1607        );
1608        assert_eq!(
1609            ImageResource::ImageFile(std::path::PathBuf::from("foo.png")).to_string(),
1610            "image:foo.png"
1611        );
1612        assert_eq!(ImageResource::Random.to_string(), "random");
1613        assert_eq!(
1614            ImageResource::Layer {
1615                layer: 3,
1616                apply_additional_effects: false,
1617            }
1618            .to_string(),
1619            "layer:3"
1620        );
1621        assert_eq!(
1622            ImageResource::Layer {
1623                layer: 3,
1624                apply_additional_effects: true,
1625            }
1626            .to_string(),
1627            "layer:3+"
1628        );
1629        assert_eq!(ImageResource::PreviousObject.to_string(), "before");
1630    }
1631
1632    #[allow(dead_code)]
1633    fn smoke_new_filter2_api(video: &mut FilterProcVideo<()>) -> FilterProcResult<()> {
1634        let writable = ImageResource::Resource("dst".to_string());
1635        let readable = ImageResource::Resource("src".to_string());
1636        let drawable = ImageResource::Resource("src".to_string());
1637        let target = ImageResource::Resource("target".to_string());
1638        let vertices = VertexList::TriangleColor(vec![[
1639            VertexColor {
1640                x: 0.0,
1641                y: 0.0,
1642                z: 0.0,
1643                r: 1.0,
1644                g: 0.0,
1645                b: 0.0,
1646                a: 1.0,
1647            },
1648            VertexColor {
1649                x: 1.0,
1650                y: 0.0,
1651                z: 0.0,
1652                r: 0.0,
1653                g: 1.0,
1654                b: 0.0,
1655                a: 1.0,
1656            },
1657            VertexColor {
1658                x: 0.0,
1659                y: 1.0,
1660                z: 0.0,
1661                r: 0.0,
1662                g: 0.0,
1663                b: 1.0,
1664                a: 1.0,
1665            },
1666        ]]);
1667        let constant = [0u8; 16];
1668
1669        video.set_culling_state(true);
1670        let _ = video.get_image_resource_texture2d(&readable)?;
1671        video.copy_image_resource(&readable, &writable)?;
1672        video.clear_image_resource(&writable, RgbaPixel::default())?;
1673        video.draw_image_to_resource(&drawable, &writable, DrawImageParam::default())?;
1674        video.draw_poly_to_resource(&writable, &vertices, Some(&drawable))?;
1675        let blend_state = video.get_blend_state(BlendStateMode::Draw).unwrap();
1676        let sampler_state = video.get_sampler_state(SamplerMode::Clamp).unwrap();
1677        video.exec_pixelshader(
1678            "shader.cso",
1679            &target,
1680            std::slice::from_ref(&readable),
1681            Some(&constant),
1682            &blend_state,
1683            &sampler_state,
1684        )?;
1685        video.exec_computeshader(
1686            "compute.cso",
1687            std::slice::from_ref(&target),
1688            std::slice::from_ref(&readable),
1689            Some(&constant),
1690            [1, 1, 1],
1691            &sampler_state,
1692        )?;
1693        Ok(())
1694    }
1695}