@matjash/pixi-native-win32-x64 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/LICENSE +21 -0
  2. package/THIRD_PARTY_NOTICES.md +83 -0
  3. package/index.cjs +25 -0
  4. package/index.d.ts +11 -0
  5. package/native/audio/binding-path.js +16 -0
  6. package/native/audio/dist/win32-x64/native_audio.node +0 -0
  7. package/native/audio/package.json +7 -0
  8. package/native/audio/src/index.d.ts +63 -0
  9. package/native/audio/src/index.js +5 -0
  10. package/native/audio/src/lib.rs +1520 -0
  11. package/native/gpu/dist/win32-x64/d3dcompiler_47.dll +0 -0
  12. package/native/gpu/dist/win32-x64/pixi_native_gpu.node +0 -0
  13. package/native/gpu/package.json +24 -0
  14. package/native/gpu/src/binding-path.js +16 -0
  15. package/native/gpu/src/index.d.ts +2847 -0
  16. package/native/gpu/src/index.js +48 -0
  17. package/native/video/dist/win32-x64/FFMPEG_BUILD_INFO.txt +46 -0
  18. package/native/video/dist/win32-x64/FFMPEG_LICENSE.txt +502 -0
  19. package/native/video/dist/win32-x64/FFMPEG_SHA256SUMS +4 -0
  20. package/native/video/dist/win32-x64/ffmpeg.exe +0 -0
  21. package/native/video/dist/win32-x64/ffprobe.exe +0 -0
  22. package/native/video/dist/win32-x64/native_video.node +0 -0
  23. package/native/video/package.json +7 -0
  24. package/native/video/src/binding-path.js +26 -0
  25. package/native/video/src/index.d.ts +36 -0
  26. package/native/video/src/index.js +61 -0
  27. package/native/video/src/lib.rs +994 -0
  28. package/native/window/binding-path.js +11 -0
  29. package/native/window/dist/win32-x64/native_window.node +0 -0
  30. package/native/window/package.json +7 -0
  31. package/native/window/src/index.d.ts +17 -0
  32. package/native/window/src/index.js +32 -0
  33. package/native/window/src/lib.rs +308 -0
  34. package/package.json +41 -0
  35. package/third_party/ffmpeg-source-8.0-140fd653ae.tar.gz +0 -0
  36. package/third_party/ffmpeg-source-8.0-140fd653ae.tar.gz.sha256 +1 -0
@@ -0,0 +1,11 @@
1
+ const Path = require("path");
2
+
3
+ const getBindingPath = () =>
4
+ Path.join(
5
+ __dirname,
6
+ "dist",
7
+ `${process.platform}-${process.arch}`,
8
+ "native_window.node",
9
+ );
10
+
11
+ module.exports = { getBindingPath };
@@ -0,0 +1,7 @@
1
+ {
2
+ "name": "@pixi-native/native-window",
3
+ "version": "0.1.0",
4
+ "private": true,
5
+ "main": "./src/index.js",
6
+ "types": "./src/index.d.ts"
7
+ }
@@ -0,0 +1,17 @@
1
+ export interface NativeWindowApi {
2
+ setTransparent(nativeData: Uint8Array, transparent: boolean): void;
3
+ waitForCompositorFrame(timeoutMs?: number): Promise<boolean>;
4
+ create(
5
+ nativeData: Uint8Array,
6
+ onFrame: () => void,
7
+ onState: (active: boolean) => void,
8
+ ): ModalFrameController;
9
+ }
10
+
11
+ export interface ModalFrameController {
12
+ attach(): void;
13
+ detach(): void;
14
+ }
15
+
16
+ declare const nativeWindow: NativeWindowApi;
17
+ export = nativeWindow;
@@ -0,0 +1,32 @@
1
+ const Fs = require("fs");
2
+ const { createRequire } = require("node:module");
3
+ const { getBindingPath } = require("../binding-path.js");
4
+
5
+ const requireNative = createRequire(__filename);
6
+ const bindingPath = getBindingPath();
7
+ if (!Fs.existsSync(bindingPath)) {
8
+ throw new Error(
9
+ `Native window addon not found for ${process.platform}-${process.arch}. Run pnpm native:window:build.`,
10
+ );
11
+ }
12
+
13
+ const binding = requireNative(bindingPath);
14
+
15
+ const setTransparent = (nativeData, transparent) => {
16
+ binding.setTransparent(nativeData, transparent);
17
+ };
18
+
19
+ const waitForCompositorFrame = (timeoutMs) =>
20
+ binding.waitForCompositorFrame(timeoutMs);
21
+
22
+ const create = (nativeData, onFrame, onState) => {
23
+ const controller = new binding.ModalFrameController(
24
+ nativeData,
25
+ onFrame,
26
+ onState,
27
+ );
28
+ controller.attach();
29
+ return controller;
30
+ };
31
+
32
+ module.exports = { create, setTransparent, waitForCompositorFrame };
@@ -0,0 +1,308 @@
1
+ use napi::bindgen_prelude::FunctionRef;
2
+ use napi::bindgen_prelude::*;
3
+ use napi_derive::napi;
4
+
5
+ #[cfg(windows)]
6
+ use windows_sys::Win32::Foundation::FreeLibrary;
7
+ #[cfg(windows)]
8
+ use windows_sys::Win32::Foundation::{HANDLE, HWND, LPARAM, LRESULT, WPARAM};
9
+ #[cfg(windows)]
10
+ use windows_sys::Win32::Graphics::Dwm::{
11
+ DwmEnableBlurBehindWindow, DWM_BB_BLURREGION, DWM_BB_ENABLE, DWM_BLURBEHIND,
12
+ };
13
+ #[cfg(windows)]
14
+ use windows_sys::Win32::Graphics::Gdi::{CreateRectRgn, DeleteObject};
15
+ #[cfg(windows)]
16
+ use windows_sys::Win32::System::LibraryLoader::{GetProcAddress, LoadLibraryW};
17
+ #[cfg(windows)]
18
+ use windows_sys::Win32::UI::WindowsAndMessaging::{
19
+ CallWindowProcW, DefWindowProcW, GetWindowLongPtrW, KillTimer, SetTimer, SetWindowLongPtrW,
20
+ GWLP_USERDATA, GWLP_WNDPROC, WM_ENTERMENULOOP, WM_ENTERSIZEMOVE, WM_EXITMENULOOP,
21
+ WM_EXITSIZEMOVE, WM_TIMER, WNDPROC,
22
+ };
23
+
24
+ #[cfg(windows)]
25
+ fn hwnd_from_native_data(native_data: &[u8]) -> Result<HWND> {
26
+ if native_data.len() < std::mem::size_of::<usize>() {
27
+ return Err(Error::from_reason("native window data is invalid"));
28
+ }
29
+ let hwnd = unsafe { *(native_data.as_ptr() as *const usize) as HWND };
30
+ if hwnd.is_null() {
31
+ return Err(Error::from_reason("native window handle is null"));
32
+ }
33
+ Ok(hwnd)
34
+ }
35
+
36
+ const DEFAULT_COMPOSITOR_WAIT_MS: u32 = 1_000;
37
+
38
+ pub struct CompositorFrameTask {
39
+ timeout_ms: u32,
40
+ }
41
+
42
+ impl Task for CompositorFrameTask {
43
+ type Output = bool;
44
+ type JsValue = bool;
45
+
46
+ fn compute(&mut self) -> Result<Self::Output> {
47
+ #[cfg(windows)]
48
+ {
49
+ return Ok(wait_for_windows_compositor(self.timeout_ms));
50
+ }
51
+
52
+ #[cfg(not(windows))]
53
+ {
54
+ Ok(false)
55
+ }
56
+ }
57
+
58
+ fn resolve(&mut self, _env: Env, signaled: Self::Output) -> Result<Self::JsValue> {
59
+ Ok(signaled)
60
+ }
61
+ }
62
+
63
+ /// Waits off the JavaScript thread for the next Windows compositor clock tick.
64
+ #[napi]
65
+ pub fn wait_for_compositor_frame(timeout_ms: Option<u32>) -> AsyncTask<CompositorFrameTask> {
66
+ AsyncTask::new(CompositorFrameTask {
67
+ timeout_ms: timeout_ms.unwrap_or(DEFAULT_COMPOSITOR_WAIT_MS).max(1),
68
+ })
69
+ }
70
+
71
+ #[cfg(windows)]
72
+ fn wait_for_windows_compositor(timeout_ms: u32) -> bool {
73
+ type WaitForCompositorClock = unsafe extern "system" fn(u32, *const HANDLE, u32) -> u32;
74
+
75
+ let library_name: Vec<u16> = "dcomp.dll\0".encode_utf16().collect();
76
+ let module = unsafe { LoadLibraryW(library_name.as_ptr()) };
77
+ if module.is_null() {
78
+ return false;
79
+ }
80
+
81
+ let procedure =
82
+ unsafe { GetProcAddress(module, b"DCompositionWaitForCompositorClock\0".as_ptr()) };
83
+ let signaled = match procedure {
84
+ Some(procedure) => {
85
+ let wait = unsafe {
86
+ std::mem::transmute::<unsafe extern "system" fn() -> isize, WaitForCompositorClock>(
87
+ procedure,
88
+ )
89
+ };
90
+ unsafe { wait(0, std::ptr::null(), timeout_ms) == 0 }
91
+ }
92
+ None => false,
93
+ };
94
+ unsafe {
95
+ FreeLibrary(module);
96
+ }
97
+ signaled
98
+ }
99
+
100
+ #[napi]
101
+ pub fn set_transparent(native_data: Buffer, transparent: bool) -> Result<()> {
102
+ #[cfg(windows)]
103
+ {
104
+ let hwnd = hwnd_from_native_data(&native_data)?;
105
+ configure_dwm_transparency(hwnd, transparent)?;
106
+ }
107
+
108
+ #[cfg(not(windows))]
109
+ {
110
+ let _ = (native_data, transparent);
111
+ return Err(Error::from_reason(
112
+ "transparent native windows are supported only on Windows 11",
113
+ ));
114
+ }
115
+
116
+ Ok(())
117
+ }
118
+
119
+ #[cfg(windows)]
120
+ fn configure_dwm_transparency(hwnd: HWND, transparent: bool) -> Result<()> {
121
+ let region = if transparent {
122
+ unsafe { CreateRectRgn(0, 0, -1, -1) }
123
+ } else {
124
+ std::ptr::null_mut()
125
+ };
126
+ if transparent && region.is_null() {
127
+ return Err(Error::from_reason(
128
+ "could not create DWM transparency region",
129
+ ));
130
+ }
131
+
132
+ let blur = DWM_BLURBEHIND {
133
+ dwFlags: if transparent {
134
+ DWM_BB_ENABLE | DWM_BB_BLURREGION
135
+ } else {
136
+ DWM_BB_ENABLE
137
+ },
138
+ fEnable: i32::from(transparent),
139
+ hRgnBlur: region,
140
+ fTransitionOnMaximized: 0,
141
+ };
142
+ let result = unsafe { DwmEnableBlurBehindWindow(hwnd, &blur) };
143
+ if !region.is_null() {
144
+ unsafe {
145
+ DeleteObject(region as _);
146
+ }
147
+ }
148
+ if result < 0 {
149
+ return Err(Error::from_reason(format!(
150
+ "DwmEnableBlurBehindWindow failed with HRESULT 0x{:08x}",
151
+ result as u32,
152
+ )));
153
+ }
154
+ Ok(())
155
+ }
156
+
157
+ #[napi]
158
+ pub struct ModalFrameController {
159
+ env: Env,
160
+ frame_callback: FunctionRef<(), ()>,
161
+ state_callback: FunctionRef<(bool,), ()>,
162
+ #[cfg(windows)]
163
+ hwnd: HWND,
164
+ #[cfg(windows)]
165
+ previous_proc: isize,
166
+ #[cfg(windows)]
167
+ previous_userdata: isize,
168
+ #[cfg(windows)]
169
+ attached: bool,
170
+ #[cfg(windows)]
171
+ invoking: bool,
172
+ }
173
+
174
+ #[napi]
175
+ impl ModalFrameController {
176
+ #[napi(constructor)]
177
+ pub fn new(
178
+ env: Env,
179
+ native_data: Buffer,
180
+ frame_callback: FunctionRef<(), ()>,
181
+ state_callback: FunctionRef<(bool,), ()>,
182
+ ) -> Result<Self> {
183
+ #[cfg(windows)]
184
+ let hwnd = hwnd_from_native_data(&native_data)?;
185
+
186
+ #[cfg(not(windows))]
187
+ let _ = native_data;
188
+
189
+ Ok(Self {
190
+ env,
191
+ frame_callback,
192
+ state_callback,
193
+ #[cfg(windows)]
194
+ hwnd,
195
+ #[cfg(windows)]
196
+ previous_proc: 0,
197
+ #[cfg(windows)]
198
+ previous_userdata: 0,
199
+ #[cfg(windows)]
200
+ attached: false,
201
+ #[cfg(windows)]
202
+ invoking: false,
203
+ })
204
+ }
205
+
206
+ #[napi]
207
+ pub fn attach(&mut self) -> Result<()> {
208
+ #[cfg(windows)]
209
+ {
210
+ if self.hwnd.is_null() || self.attached {
211
+ return Ok(());
212
+ }
213
+ self.previous_userdata = unsafe { GetWindowLongPtrW(self.hwnd, GWLP_USERDATA) };
214
+ let self_pointer = self as *mut Self as isize;
215
+ let previous_proc =
216
+ unsafe { SetWindowLongPtrW(self.hwnd, GWLP_USERDATA, self_pointer) };
217
+ self.previous_proc = unsafe {
218
+ SetWindowLongPtrW(self.hwnd, GWLP_WNDPROC, modal_window_proc as usize as isize)
219
+ };
220
+ if self.previous_proc == 0 {
221
+ unsafe {
222
+ SetWindowLongPtrW(self.hwnd, GWLP_USERDATA, self.previous_userdata);
223
+ }
224
+ return Err(Error::from_reason(
225
+ "could not install Windows modal window hook",
226
+ ));
227
+ }
228
+ let _ = previous_proc;
229
+ self.attached = true;
230
+ }
231
+ Ok(())
232
+ }
233
+
234
+ #[napi]
235
+ pub fn detach(&mut self) {
236
+ #[cfg(windows)]
237
+ if self.attached {
238
+ unsafe {
239
+ KillTimer(self.hwnd, MODAL_TIMER_ID);
240
+ SetWindowLongPtrW(self.hwnd, GWLP_WNDPROC, self.previous_proc);
241
+ SetWindowLongPtrW(self.hwnd, GWLP_USERDATA, self.previous_userdata);
242
+ }
243
+ self.attached = false;
244
+ }
245
+ }
246
+
247
+ #[cfg(windows)]
248
+ fn invoke_frame(&mut self) {
249
+ if self.invoking {
250
+ return;
251
+ }
252
+ self.invoking = true;
253
+ if let Ok(callback) = self.frame_callback.borrow_back(&self.env) {
254
+ let _ = callback.call(());
255
+ }
256
+ self.invoking = false;
257
+ }
258
+
259
+ #[cfg(windows)]
260
+ fn invoke_state(&self, active: bool) {
261
+ if let Ok(callback) = self.state_callback.borrow_back(&self.env) {
262
+ let _ = callback.call((active,));
263
+ }
264
+ }
265
+ }
266
+
267
+ impl Drop for ModalFrameController {
268
+ fn drop(&mut self) {
269
+ self.detach();
270
+ }
271
+ }
272
+
273
+ #[cfg(windows)]
274
+ const MODAL_TIMER_ID: usize = 0x5049_5849;
275
+
276
+ #[cfg(windows)]
277
+ unsafe extern "system" fn modal_window_proc(
278
+ hwnd: HWND,
279
+ message: u32,
280
+ wparam: WPARAM,
281
+ lparam: LPARAM,
282
+ ) -> LRESULT {
283
+ let controller = GetWindowLongPtrW(hwnd, GWLP_USERDATA) as *mut ModalFrameController;
284
+ if !controller.is_null() {
285
+ let controller = &mut *controller;
286
+ match message {
287
+ WM_ENTERSIZEMOVE | WM_ENTERMENULOOP => {
288
+ controller.invoke_state(true);
289
+ SetTimer(hwnd, MODAL_TIMER_ID, 16, None);
290
+ }
291
+ WM_TIMER if wparam == MODAL_TIMER_ID => {
292
+ controller.invoke_frame();
293
+ return 0;
294
+ }
295
+ WM_EXITSIZEMOVE | WM_EXITMENULOOP => {
296
+ KillTimer(hwnd, MODAL_TIMER_ID);
297
+ controller.invoke_state(false);
298
+ }
299
+ _ => {}
300
+ }
301
+ let previous = std::mem::transmute::<isize, WNDPROC>(controller.previous_proc);
302
+ return match previous {
303
+ Some(proc) => CallWindowProcW(Some(proc), hwnd, message, wparam, lparam),
304
+ None => DefWindowProcW(hwnd, message, wparam, lparam),
305
+ };
306
+ }
307
+ DefWindowProcW(hwnd, message, wparam, lparam)
308
+ }
package/package.json ADDED
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "@matjash/pixi-native-win32-x64",
3
+ "version": "0.1.2",
4
+ "type": "commonjs",
5
+ "description": "Windows x64 native binaries for @matjash/pixi-native",
6
+ "license": "MIT",
7
+ "os": [
8
+ "win32"
9
+ ],
10
+ "cpu": [
11
+ "x64"
12
+ ],
13
+ "files": [
14
+ "index.cjs",
15
+ "index.d.ts",
16
+ "native",
17
+ "THIRD_PARTY_NOTICES.md",
18
+ "third_party"
19
+ ],
20
+ "main": "./index.cjs",
21
+ "types": "./index.d.ts",
22
+ "exports": {
23
+ ".": {
24
+ "types": "./index.d.ts",
25
+ "default": "./index.cjs"
26
+ }
27
+ },
28
+ "repository": {
29
+ "type": "git",
30
+ "url": "git+https://github.com/matjazPrijatelj/pixi-native.git",
31
+ "directory": "packages/native-win32-x64"
32
+ },
33
+ "homepage": "https://github.com/matjazPrijatelj/pixi-native#readme",
34
+ "bugs": {
35
+ "url": "https://github.com/matjazPrijatelj/pixi-native/issues"
36
+ },
37
+ "publishConfig": {
38
+ "registry": "https://registry.npmjs.org",
39
+ "access": "public"
40
+ }
41
+ }
@@ -0,0 +1 @@
1
+ 083d0987eb7a1827187a6d4c6e5d37d71293a68eaecd7e0a03dccb38cc249b89 ffmpeg-source-8.0-140fd653ae.tar.gz