@dayme/bunraylib 0.1.0 → 1.0.0

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 (67) hide show
  1. package/README.md +60 -11
  2. package/package.json +11 -3
  3. package/src/Raylib.ts +58 -3678
  4. package/src/c/common.h +0 -2
  5. package/src/constants.ts +2 -2
  6. package/src/index.ts +6 -6
  7. package/src/main.c +0 -1
  8. package/src/main.d.ts +1 -1
  9. package/src/modules/audio/AudioModule.ts +197 -0
  10. package/src/modules/audio/symbols.ts +70 -0
  11. package/src/{c/audio.c → modules/audio/wrapper.c} +40 -80
  12. package/src/modules/camera/CameraModule.ts +239 -0
  13. package/src/modules/camera/symbols.ts +49 -0
  14. package/src/modules/camera/wrapper.c +141 -0
  15. package/src/modules/collision/CollisionModule.ts +363 -0
  16. package/src/modules/collision/symbols.ts +149 -0
  17. package/src/modules/collision/wrapper.c +176 -0
  18. package/src/modules/color/ColorModule.ts +65 -0
  19. package/src/modules/color/symbols.ts +26 -0
  20. package/src/modules/color/wrapper.c +16 -0
  21. package/src/modules/draw3d/Draw3DModule.ts +441 -0
  22. package/src/modules/draw3d/symbols.ts +199 -0
  23. package/src/modules/draw3d/wrapper.c +202 -0
  24. package/src/modules/font/FontModule.ts +250 -0
  25. package/src/modules/font/symbols.ts +46 -0
  26. package/src/{c/font.c → modules/font/wrapper.c} +50 -70
  27. package/src/modules/image/ImageModule.ts +451 -0
  28. package/src/{symbols/image.ts → modules/image/symbols.ts} +15 -12
  29. package/src/{c/image.c → modules/image/wrapper.c} +23 -45
  30. package/src/modules/input/InputModule.ts +160 -0
  31. package/src/modules/input/symbols.ts +54 -0
  32. package/src/modules/input/wrapper.c +31 -0
  33. package/src/modules/model/ModelModule.ts +228 -0
  34. package/src/{symbols/model.ts → modules/model/symbols.ts} +17 -14
  35. package/src/{c/model.c → modules/model/wrapper.c} +30 -30
  36. package/src/modules/shader/ShaderModule.ts +78 -0
  37. package/src/{symbols/shader.ts → modules/shader/symbols.ts} +3 -1
  38. package/src/{c/shader.c → modules/shader/wrapper.c} +11 -1
  39. package/src/modules/shapes/ShapesModule.ts +687 -0
  40. package/src/modules/shapes/symbols.ts +161 -0
  41. package/src/modules/shapes/wrapper.c +183 -0
  42. package/src/modules/texture/TextureModule.ts +190 -0
  43. package/src/{symbols/texture.ts → modules/texture/symbols.ts} +15 -9
  44. package/src/{c/texture.c → modules/texture/wrapper.c} +7 -22
  45. package/src/modules/window/WindowModule.ts +248 -0
  46. package/src/modules/window/symbols.ts +85 -0
  47. package/src/modules/window/wrapper.c +39 -0
  48. package/src/symbols.ts +87 -47
  49. package/src/utils.ts +63 -15
  50. package/src/c/camera.c +0 -161
  51. package/src/c/collision.c +0 -176
  52. package/src/c/color.c +0 -100
  53. package/src/c/draw3d.c +0 -222
  54. package/src/c/filesystem.c +0 -36
  55. package/src/c/input.c +0 -85
  56. package/src/c/shapes.c +0 -283
  57. package/src/c/window.c +0 -150
  58. package/src/symbols/audio.ts +0 -64
  59. package/src/symbols/camera.ts +0 -46
  60. package/src/symbols/collision.ts +0 -116
  61. package/src/symbols/color.ts +0 -22
  62. package/src/symbols/draw3d.ts +0 -137
  63. package/src/symbols/filesystem.ts +0 -30
  64. package/src/symbols/font.ts +0 -40
  65. package/src/symbols/input.ts +0 -51
  66. package/src/symbols/shapes.ts +0 -92
  67. package/src/symbols/window.ts +0 -83
@@ -0,0 +1,248 @@
1
+ import { getSymbols } from '../../symbols';
2
+ import { bufs as b, cstr, f, i } from '../../utils';
3
+ import { CString } from 'bun:ffi';
4
+ import type { Vec2, RenderTexture2D, Image, Color } from '../../types';
5
+
6
+ const r = () => getSymbols();
7
+
8
+ export class WindowModule {
9
+ static initWindow(width: number, height: number, title: string): void {
10
+ r().symbols.InitWindow(i(width), i(height), cstr(title));
11
+ }
12
+ static closeWindow(): void {
13
+ r().symbols.CloseWindow();
14
+ }
15
+ static windowShouldClose(): boolean {
16
+ return r().symbols.WindowShouldClose();
17
+ }
18
+ static beginDrawing(): void {
19
+ r().symbols.BeginDrawing();
20
+ }
21
+ static endDrawing(): void {
22
+ r().symbols.EndDrawing();
23
+ }
24
+
25
+ static clearBackground(col: Color): void {
26
+ r().symbols.ClearBackground(i(col));
27
+ }
28
+ static setTargetFPS(fps: number): void {
29
+ r().symbols.SetTargetFPS(i(fps));
30
+ }
31
+ static getFrameTime(): number {
32
+ return r().symbols.GetFrameTime();
33
+ }
34
+ static isWindowReady(): boolean {
35
+ return r().symbols.IsWindowReady();
36
+ }
37
+ static isWindowFullscreen(): boolean {
38
+ return r().symbols.IsWindowFullscreen();
39
+ }
40
+ static isWindowHidden(): boolean {
41
+ return r().symbols.IsWindowHidden();
42
+ }
43
+ static isWindowMinimized(): boolean {
44
+ return r().symbols.IsWindowMinimized();
45
+ }
46
+ static isWindowMaximized(): boolean {
47
+ return r().symbols.IsWindowMaximized();
48
+ }
49
+ static isWindowFocused(): boolean {
50
+ return r().symbols.IsWindowFocused();
51
+ }
52
+ static isWindowResized(): boolean {
53
+ return r().symbols.IsWindowResized();
54
+ }
55
+ static isWindowState(flag: number): boolean {
56
+ return r().symbols.IsWindowState(i(flag));
57
+ }
58
+ static setWindowState(flags: number): void {
59
+ r().symbols.SetWindowState(i(flags));
60
+ }
61
+ static clearWindowState(flags: number): void {
62
+ r().symbols.ClearWindowState(i(flags));
63
+ }
64
+ static toggleFullscreen(): void {
65
+ r().symbols.ToggleFullscreen();
66
+ }
67
+ static toggleBorderlessWindowed(): void {
68
+ r().symbols.ToggleBorderlessWindowed();
69
+ }
70
+ static maximizeWindow(): void {
71
+ r().symbols.MaximizeWindow();
72
+ }
73
+ static minimizeWindow(): void {
74
+ r().symbols.MinimizeWindow();
75
+ }
76
+ static restoreWindow(): void {
77
+ r().symbols.RestoreWindow();
78
+ }
79
+ static setWindowTitle(title: string): void {
80
+ r().symbols.SetWindowTitle(cstr(title));
81
+ }
82
+ static setWindowPosition(x: number, y: number): void {
83
+ r().symbols.SetWindowPosition(i(x), i(y));
84
+ }
85
+ static setWindowMonitor(monitor: number): void {
86
+ r().symbols.SetWindowMonitor(i(monitor));
87
+ }
88
+ static setWindowMinSize(w: number, h: number): void {
89
+ r().symbols.SetWindowMinSize(i(w), i(h));
90
+ }
91
+ static setWindowMaxSize(w: number, h: number): void {
92
+ r().symbols.SetWindowMaxSize(i(w), i(h));
93
+ }
94
+ static setWindowSize(w: number, h: number): void {
95
+ r().symbols.SetWindowSize(i(w), i(h));
96
+ }
97
+ static setWindowOpacity(opacity: number): void {
98
+ r().symbols.SetWindowOpacity(f(opacity));
99
+ }
100
+ static setWindowFocused(): void {
101
+ r().symbols.SetWindowFocused();
102
+ }
103
+ static getScreenWidth(): number {
104
+ return r().symbols.GetScreenWidth();
105
+ }
106
+ static getScreenHeight(): number {
107
+ return r().symbols.GetScreenHeight();
108
+ }
109
+ static getRenderWidth(): number {
110
+ return r().symbols.GetRenderWidth();
111
+ }
112
+ static getRenderHeight(): number {
113
+ return r().symbols.GetRenderHeight();
114
+ }
115
+ static getMonitorCount(): number {
116
+ return r().symbols.GetMonitorCount();
117
+ }
118
+ static getCurrentMonitor(): number {
119
+ return r().symbols.GetCurrentMonitor();
120
+ }
121
+ static getMonitorPosition(monitor: number): Vec2 {
122
+ r().symbols.GetMonitorPositionW(b._vec2Buf, i(monitor));
123
+ return { x: b._vec2Buf[0]!, y: b._vec2Buf[1]! };
124
+ }
125
+ static getMonitorWidth(monitor: number): number {
126
+ return r().symbols.GetMonitorWidth(i(monitor));
127
+ }
128
+ static getMonitorHeight(monitor: number): number {
129
+ return r().symbols.GetMonitorHeight(i(monitor));
130
+ }
131
+ static getMonitorPhysicalWidth(monitor: number): number {
132
+ return r().symbols.GetMonitorPhysicalWidth(i(monitor));
133
+ }
134
+ static getMonitorPhysicalHeight(monitor: number): number {
135
+ return r().symbols.GetMonitorPhysicalHeight(i(monitor));
136
+ }
137
+ static getMonitorRefreshRate(monitor: number): number {
138
+ return r().symbols.GetMonitorRefreshRate(i(monitor));
139
+ }
140
+ static getWindowPosition(): Vec2 {
141
+ r().symbols.GetWindowPositionW(b._vec2Buf);
142
+ return { x: b._vec2Buf[0]!, y: b._vec2Buf[1]! };
143
+ }
144
+ static getWindowScaleDPI(): Vec2 {
145
+ r().symbols.GetWindowScaleDPIW(b._vec2Buf);
146
+ return { x: b._vec2Buf[0]!, y: b._vec2Buf[1]! };
147
+ }
148
+ static getMonitorName(monitor: number): string {
149
+ const ptr = r().symbols.GetMonitorName(i(monitor));
150
+ if (!ptr) return '';
151
+ return new CString(ptr).toString();
152
+ }
153
+ static setClipboardText(text: string): void {
154
+ r().symbols.SetClipboardText(cstr(text));
155
+ }
156
+ static getClipboardText(): string {
157
+ const ptr = r().symbols.GetClipboardText();
158
+ if (!ptr) return '';
159
+ return new CString(ptr).toString();
160
+ }
161
+ static enableEventWaiting(): void {
162
+ r().symbols.EnableEventWaiting();
163
+ }
164
+ static disableEventWaiting(): void {
165
+ r().symbols.DisableEventWaiting();
166
+ }
167
+ static showCursor(): void {
168
+ r().symbols.ShowCursor();
169
+ }
170
+ static hideCursor(): void {
171
+ r().symbols.HideCursor();
172
+ }
173
+ static isCursorHidden(): boolean {
174
+ return r().symbols.IsCursorHidden();
175
+ }
176
+ static enableCursor(): void {
177
+ r().symbols.EnableCursor();
178
+ }
179
+ static disableCursor(): void {
180
+ r().symbols.DisableCursor();
181
+ }
182
+ static isCursorOnScreen(): boolean {
183
+ return r().symbols.IsCursorOnScreen();
184
+ }
185
+ static beginTextureMode(target: RenderTexture2D): void {
186
+ r().symbols.BeginTextureModeW(i(target.id), i(target.texture.width), i(target.texture.height));
187
+ }
188
+ static endTextureMode(): void {
189
+ r().symbols.EndTextureMode();
190
+ }
191
+ static beginBlendMode(mode: number): void {
192
+ r().symbols.BeginBlendMode(i(mode));
193
+ }
194
+ static endBlendMode(): void {
195
+ r().symbols.EndBlendMode();
196
+ }
197
+ static beginScissorMode(x: number, y: number, w: number, h: number): void {
198
+ r().symbols.BeginScissorMode(i(x), i(y), i(w), i(h));
199
+ }
200
+ static endScissorMode(): void {
201
+ r().symbols.EndScissorMode();
202
+ }
203
+ static setConfigFlags(flags: number): void {
204
+ r().symbols.SetConfigFlags(i(flags));
205
+ }
206
+ static setWindowIcon(image: Image): void {
207
+ r().symbols.SetWindowIconW(i(image));
208
+ }
209
+ static getClipboardImage(): Image {
210
+ return r().symbols.GetClipboardImageW();
211
+ }
212
+ static setWindowIcons(images: number, count: number): void {
213
+ r().symbols.SetWindowIconsW(images as unknown as Buffer, i(count));
214
+ }
215
+ static getTime(): number {
216
+ return r().symbols.GetTime();
217
+ }
218
+ static getFPS(): number {
219
+ return r().symbols.GetFPS();
220
+ }
221
+ static swapScreenBuffer(): void {
222
+ r().symbols.SwapScreenBuffer();
223
+ }
224
+ static pollInputEvents(): void {
225
+ r().symbols.PollInputEvents();
226
+ }
227
+ static waitTime(seconds: number): void {
228
+ r().symbols.WaitTime(seconds);
229
+ }
230
+ static setRandomSeed(seed: number): void {
231
+ r().symbols.SetRandomSeed(i(seed));
232
+ }
233
+ static getRandomValue(min: number, max: number): number {
234
+ return r().symbols.GetRandomValue(i(min), i(max));
235
+ }
236
+ static takeScreenshot(fileName: string): void {
237
+ r().symbols.TakeScreenshot(cstr(fileName));
238
+ }
239
+ static openURL(url: string): void {
240
+ r().symbols.OpenURL(cstr(url));
241
+ }
242
+ static setTraceLogLevel(logLevel: number): void {
243
+ r().symbols.SetTraceLogLevel(i(logLevel));
244
+ }
245
+ static traceLog(logLevel: number, text: string): void {
246
+ r().symbols.TraceLogW(i(logLevel), cstr(text));
247
+ }
248
+ }
@@ -0,0 +1,85 @@
1
+ import { FFIType } from 'bun:ffi';
2
+ const { i32, cstring, bool, f32, f64, ptr } = FFIType;
3
+
4
+ export const windowDirectSymbols = {
5
+ InitWindow: { args: [i32, i32, cstring], returns: FFIType.void },
6
+ CloseWindow: { args: [], returns: FFIType.void },
7
+ WindowShouldClose: { args: [], returns: bool },
8
+ BeginDrawing: { args: [], returns: FFIType.void },
9
+ ClearBackground: { args: [i32], returns: FFIType.void },
10
+ EndDrawing: { args: [], returns: FFIType.void },
11
+ SetTargetFPS: { args: [i32], returns: FFIType.void },
12
+ GetFrameTime: { args: [], returns: f32 },
13
+ IsWindowReady: { args: [], returns: bool },
14
+ IsWindowFullscreen: { args: [], returns: bool },
15
+ IsWindowHidden: { args: [], returns: bool },
16
+ IsWindowMinimized: { args: [], returns: bool },
17
+ IsWindowMaximized: { args: [], returns: bool },
18
+ IsWindowFocused: { args: [], returns: bool },
19
+ IsWindowResized: { args: [], returns: bool },
20
+ IsWindowState: { args: [i32], returns: bool },
21
+ SetWindowState: { args: [i32], returns: FFIType.void },
22
+ ClearWindowState: { args: [i32], returns: FFIType.void },
23
+ ToggleFullscreen: { args: [], returns: FFIType.void },
24
+ ToggleBorderlessWindowed: { args: [], returns: FFIType.void },
25
+ MaximizeWindow: { args: [], returns: FFIType.void },
26
+ MinimizeWindow: { args: [], returns: FFIType.void },
27
+ RestoreWindow: { args: [], returns: FFIType.void },
28
+ SetWindowTitle: { args: [cstring], returns: FFIType.void },
29
+ SetWindowPosition: { args: [i32, i32], returns: FFIType.void },
30
+ SetWindowMonitor: { args: [i32], returns: FFIType.void },
31
+ SetWindowMinSize: { args: [i32, i32], returns: FFIType.void },
32
+ SetWindowMaxSize: { args: [i32, i32], returns: FFIType.void },
33
+ SetWindowSize: { args: [i32, i32], returns: FFIType.void },
34
+ SetWindowOpacity: { args: [f32], returns: FFIType.void },
35
+ SetWindowFocused: { args: [], returns: FFIType.void },
36
+ GetScreenWidth: { args: [], returns: i32 },
37
+ GetScreenHeight: { args: [], returns: i32 },
38
+ GetRenderWidth: { args: [], returns: i32 },
39
+ GetRenderHeight: { args: [], returns: i32 },
40
+ GetMonitorCount: { args: [], returns: i32 },
41
+ GetCurrentMonitor: { args: [], returns: i32 },
42
+ GetMonitorWidth: { args: [i32], returns: i32 },
43
+ GetMonitorHeight: { args: [i32], returns: i32 },
44
+ GetMonitorPhysicalWidth: { args: [i32], returns: i32 },
45
+ GetMonitorPhysicalHeight: { args: [i32], returns: i32 },
46
+ GetMonitorRefreshRate: { args: [i32], returns: i32 },
47
+ GetMonitorName: { args: [i32], returns: ptr },
48
+ SetClipboardText: { args: [cstring], returns: FFIType.void },
49
+ GetClipboardText: { args: [], returns: ptr },
50
+ EnableEventWaiting: { args: [], returns: FFIType.void },
51
+ DisableEventWaiting: { args: [], returns: FFIType.void },
52
+ ShowCursor: { args: [], returns: FFIType.void },
53
+ HideCursor: { args: [], returns: FFIType.void },
54
+ IsCursorHidden: { args: [], returns: bool },
55
+ EnableCursor: { args: [], returns: FFIType.void },
56
+ DisableCursor: { args: [], returns: FFIType.void },
57
+ IsCursorOnScreen: { args: [], returns: bool },
58
+ EndTextureMode: { args: [], returns: FFIType.void },
59
+ BeginBlendMode: { args: [i32], returns: FFIType.void },
60
+ EndBlendMode: { args: [], returns: FFIType.void },
61
+ BeginScissorMode: { args: [i32, i32, i32, i32], returns: FFIType.void },
62
+ EndScissorMode: { args: [], returns: FFIType.void },
63
+ GetTime: { args: [], returns: f64 },
64
+ GetFPS: { args: [], returns: i32 },
65
+ SwapScreenBuffer: { args: [], returns: FFIType.void },
66
+ PollInputEvents: { args: [], returns: FFIType.void },
67
+ WaitTime: { args: [f64], returns: FFIType.void },
68
+ SetRandomSeed: { args: [i32], returns: FFIType.void },
69
+ GetRandomValue: { args: [i32, i32], returns: i32 },
70
+ TakeScreenshot: { args: [cstring], returns: FFIType.void },
71
+ SetConfigFlags: { args: [i32], returns: FFIType.void },
72
+ OpenURL: { args: [cstring], returns: FFIType.void },
73
+ SetTraceLogLevel: { args: [i32], returns: FFIType.void },
74
+ } as const;
75
+
76
+ export const windowWrapperSymbols = {
77
+ GetMonitorPositionW: { args: [ptr, i32], returns: FFIType.void },
78
+ GetWindowPositionW: { args: [ptr], returns: FFIType.void },
79
+ GetWindowScaleDPIW: { args: [ptr], returns: FFIType.void },
80
+ BeginTextureModeW: { args: [i32, i32, i32], returns: FFIType.void },
81
+ TraceLogW: { args: [i32, cstring], returns: FFIType.void },
82
+ SetWindowIconW: { args: [i32], returns: FFIType.void },
83
+ GetClipboardImageW: { args: [], returns: i32 },
84
+ SetWindowIconsW: { args: [ptr, i32], returns: FFIType.void },
85
+ } as const;
@@ -0,0 +1,39 @@
1
+ #include "../../c/common.h"
2
+
3
+ void GetMonitorPositionW(float* out, int monitor) {
4
+ Vector2 v = GetMonitorPosition(monitor);
5
+ out[0] = v.x; out[1] = v.y;
6
+ }
7
+
8
+ void GetWindowPositionW(float* out) {
9
+ Vector2 v = GetWindowPosition();
10
+ out[0] = v.x; out[1] = v.y;
11
+ }
12
+
13
+ void GetWindowScaleDPIW(float* out) {
14
+ Vector2 v = GetWindowScaleDPI();
15
+ out[0] = v.x; out[1] = v.y;
16
+ }
17
+
18
+ void BeginTextureModeW(unsigned int id, int w, int h) {
19
+ RenderTexture2D rt = { id, {id, w, h, 1, 7}, {0, 0, 0, 0, 0} };
20
+ BeginTextureMode(rt);
21
+ }
22
+
23
+ void TraceLogW(int logLevel, const char* text) {
24
+ TraceLog(logLevel, "%s", text);
25
+ }
26
+
27
+ void SetWindowIconW(int imageId) {
28
+ if (imageId < 0 || imageId >= MAX_IMAGES || !imageUsed[imageId]) return;
29
+ SetWindowIcon(imageRegistry[imageId]);
30
+ }
31
+
32
+ int GetClipboardImageW() {
33
+ int slot = imageAlloc();
34
+ if (slot < 0) return -1;
35
+ imageRegistry[slot] = GetClipboardImage();
36
+ return slot;
37
+ }
38
+
39
+ void SetWindowIconsW(Image* images, int count) { SetWindowIcons(images, count); }
package/src/symbols.ts CHANGED
@@ -1,43 +1,54 @@
1
- import { cc } from "bun:ffi";
2
- import { writeFileSync, mkdirSync, existsSync } from "fs";
3
- import { join, dirname } from "path";
4
- import { tmpdir } from "os";
5
-
6
- import { windowSymbols } from "./symbols/window";
7
- import { shapesSymbols } from "./symbols/shapes";
8
- import { collisionSymbols } from "./symbols/collision";
9
- import { cameraSymbols } from "./symbols/camera";
10
- import { draw3dSymbols } from "./symbols/draw3d";
11
- import { textureSymbols } from "./symbols/texture";
12
- import { modelSymbols } from "./symbols/model";
13
- import { imageSymbols } from "./symbols/image";
14
- import { colorSymbols } from "./symbols/color";
15
- import { fontSymbols } from "./symbols/font";
16
- import { inputSymbols } from "./symbols/input";
17
- import { audioSymbols } from "./symbols/audio";
18
- import { shaderSymbols } from "./symbols/shader";
19
- import { filesystemSymbols } from "./symbols/filesystem";
20
-
21
- const allSymbols = {
22
- ...windowSymbols,
23
- ...shapesSymbols,
1
+ import { cc, dlopen, suffix } from 'bun:ffi';
2
+ import { writeFileSync, mkdirSync, existsSync } from 'fs';
3
+ import { join, dirname } from 'path';
4
+ import { tmpdir } from 'os';
5
+
6
+ import { windowDirectSymbols, windowWrapperSymbols } from './modules/window/symbols';
7
+ import { shapesDirectSymbols, shapesWrapperSymbols } from './modules/shapes/symbols';
8
+ import { collisionSymbols } from './modules/collision/symbols';
9
+ import { cameraWrapperSymbols, cameraDirectSymbols } from './modules/camera/symbols';
10
+ import { draw3dDirectSymbols, draw3dSymbols } from './modules/draw3d/symbols';
11
+ import { textureDirectSymbols, textureWrapperSymbols } from './modules/texture/symbols';
12
+ import { modelSymbols } from './modules/model/symbols';
13
+ import { imageSymbols } from './modules/image/symbols';
14
+ import { colorSymbols, colorDirectSymbols } from './modules/color/symbols';
15
+ import { inputDirectSymbols, inputWrapperSymbols } from './modules/input/symbols';
16
+ import { fontDirectSymbols, fontWrapperSymbols } from './modules/font/symbols';
17
+ import { audioDirectSymbols, audioWrapperSymbols } from './modules/audio/symbols';
18
+ import { shaderSymbols } from './modules/shader/symbols';
19
+
20
+ const allWrapperSymbols = {
21
+ ...windowWrapperSymbols,
22
+ ...shapesWrapperSymbols,
24
23
  ...collisionSymbols,
25
- ...cameraSymbols,
24
+ ...cameraWrapperSymbols,
26
25
  ...draw3dSymbols,
27
- ...textureSymbols,
26
+ ...textureWrapperSymbols,
28
27
  ...modelSymbols,
29
28
  ...imageSymbols,
30
29
  ...colorSymbols,
31
- ...fontSymbols,
32
- ...inputSymbols,
33
- ...audioSymbols,
30
+ ...fontWrapperSymbols,
31
+ ...inputWrapperSymbols,
32
+ ...audioWrapperSymbols,
34
33
  ...shaderSymbols,
35
- ...filesystemSymbols,
36
34
  };
37
35
 
38
- type SymbolsType = ReturnType<typeof cc<typeof allSymbols>>;
36
+ const allDirectSymbols = {
37
+ ...windowDirectSymbols,
38
+ ...shapesDirectSymbols,
39
+ ...draw3dDirectSymbols,
40
+ ...textureDirectSymbols,
41
+ ...inputDirectSymbols,
42
+ ...fontDirectSymbols,
43
+ ...audioDirectSymbols,
44
+ ...cameraDirectSymbols,
45
+ ...colorDirectSymbols,
46
+ };
47
+
48
+ type WrapperSymbolsType = ReturnType<typeof cc<typeof allWrapperSymbols>>;
49
+ type DirectSymbolsType = ReturnType<typeof dlopen<typeof allDirectSymbols>>;
39
50
 
40
- export interface RaylibConfig {
51
+ export type RaylibConfig = {
41
52
  maxModels?: number;
42
53
  maxFonts?: number;
43
54
  maxImages?: number;
@@ -49,10 +60,17 @@ export interface RaylibConfig {
49
60
  maxSounds?: number;
50
61
  maxMusic?: number;
51
62
  maxAudioStreams?: number;
63
+ /** Path or library name for raylib. Examples:
64
+ * - `"libraylib.so"` (Linux)
65
+ * - `"libraylib.dylib"` (macOS)
66
+ * - `"raylib.dll"` (Windows)
67
+ * - `"/usr/local/lib/libraylib.so"` (absolute path)
68
+ * - `"raylib"` (bare name — works for cc linking, dlopen resolves via platform default)
69
+ */
52
70
  raylibPath?: string;
53
- }
71
+ };
54
72
 
55
- const defaults: Required<Omit<RaylibConfig, "raylibPath">> = {
73
+ const defaults: Required<Omit<RaylibConfig, 'raylibPath'>> = {
56
74
  maxModels: 64,
57
75
  maxFonts: 32,
58
76
  maxImages: 128,
@@ -67,14 +85,14 @@ const defaults: Required<Omit<RaylibConfig, "raylibPath">> = {
67
85
  };
68
86
 
69
87
  let _config: RaylibConfig = {};
70
- let _r: SymbolsType | null = null;
88
+ let _r: { symbols: WrapperSymbolsType['symbols'] & DirectSymbolsType['symbols'] } | null = null;
71
89
 
72
90
  export function configure(config: RaylibConfig): void {
73
- if (_r) throw new Error("Raylib already initialized. Call configure() before any Raylib method.");
91
+ if (_r) throw new Error('Raylib already initialized. Call configure() before any Raylib method.');
74
92
  _config = config;
75
93
  }
76
94
 
77
- function generateConfigHeader(config: Required<Omit<RaylibConfig, "raylibPath">>): string {
95
+ function generateConfigHeader(config: Required<Omit<RaylibConfig, 'raylibPath'>>): string {
78
96
  return `#ifndef CONFIG_H
79
97
  #define CONFIG_H
80
98
 
@@ -94,38 +112,60 @@ function generateConfigHeader(config: Required<Omit<RaylibConfig, "raylibPath">>
94
112
  `;
95
113
  }
96
114
 
97
- function buildCC(config: RaylibConfig): SymbolsType {
115
+ function resolveDlopenPath(raylibPath?: string): string {
116
+ if (raylibPath) {
117
+ if (raylibPath.includes('/') || raylibPath.includes('\\') || raylibPath.includes('.')) {
118
+ return raylibPath;
119
+ }
120
+ }
121
+ return `libraylib.${suffix}`;
122
+ }
123
+
124
+ function buildCC(config: RaylibConfig) {
98
125
  const resolved = { ...defaults };
99
126
  for (const key of Object.keys(defaults) as (keyof typeof defaults)[]) {
100
- if (config[key] != null) (resolved as any)[key] = config[key];
127
+ if (config[key] !== null && config[key] !== undefined) {
128
+ (resolved as unknown as Record<string, number>)[key] = config[key];
129
+ }
101
130
  }
102
131
 
103
132
  const configHeader = generateConfigHeader(resolved);
104
- const cacheDir = join(tmpdir(), "rraylib");
105
- const configHash = Object.values(resolved).join("_");
133
+ const cacheDir = join(tmpdir(), 'rraylib');
134
+ const configHash = Object.values(resolved).join('_');
106
135
  const headerPath = join(cacheDir, `config_${configHash}.h`);
107
136
 
108
137
  if (!existsSync(cacheDir)) mkdirSync(cacheDir, { recursive: true });
109
138
  writeFileSync(headerPath, configHeader);
110
139
 
111
140
  const srcDir = dirname(new URL(import.meta.url).pathname);
112
- const cDir = join(srcDir, "c");
141
+ const cDir = join(srcDir, 'c');
142
+ const modulesDir = join(srcDir, 'modules');
113
143
 
114
- const wrapperSrc = `#include "${headerPath}"\n#include "${cDir}/registries.c"\n#include "${cDir}/window.c"\n#include "${cDir}/shapes.c"\n#include "${cDir}/collision.c"\n#include "${cDir}/camera.c"\n#include "${cDir}/draw3d.c"\n#include "${cDir}/texture.c"\n#include "${cDir}/model.c"\n#include "${cDir}/image.c"\n#include "${cDir}/color.c"\n#include "${cDir}/font.c"\n#include "${cDir}/input.c"\n#include "${cDir}/audio.c"\n#include "${cDir}/shader.c"\n#include "${cDir}/filesystem.c"\n`;
144
+ const wrapperSrc = `#include "${headerPath}"\n#include "${cDir}/registries.c"\n#include "${modulesDir}/window/wrapper.c"\n#include "${modulesDir}/shapes/wrapper.c"\n#include "${modulesDir}/collision/wrapper.c"\n#include "${modulesDir}/camera/wrapper.c"\n#include "${modulesDir}/draw3d/wrapper.c"\n#include "${modulesDir}/texture/wrapper.c"\n#include "${modulesDir}/model/wrapper.c"\n#include "${modulesDir}/image/wrapper.c"\n#include "${modulesDir}/color/wrapper.c"\n#include "${modulesDir}/font/wrapper.c"\n#include "${modulesDir}/input/wrapper.c"\n#include "${modulesDir}/audio/wrapper.c"\n#include "${modulesDir}/shader/wrapper.c"\n`;
115
145
 
116
146
  const wrapperPath = join(cacheDir, `main_${configHash}.c`);
117
147
  writeFileSync(wrapperPath, wrapperSrc);
118
148
 
119
- const library = config.raylibPath ? [config.raylibPath] : ["raylib"];
149
+ const ccLibrary = config.raylibPath ? [config.raylibPath] : [`libraylib.${suffix}`];
120
150
 
121
- return cc({
151
+ const wrapperHandle = cc({
122
152
  source: wrapperPath,
123
- library,
124
- symbols: allSymbols,
153
+ library: ccLibrary,
154
+ symbols: allWrapperSymbols,
125
155
  });
156
+
157
+ const dlopenPath = resolveDlopenPath(config.raylibPath);
158
+ const directHandle = dlopen(dlopenPath, allDirectSymbols);
159
+
160
+ return {
161
+ symbols: {
162
+ ...directHandle.symbols,
163
+ ...wrapperHandle.symbols,
164
+ },
165
+ };
126
166
  }
127
167
 
128
- export function getSymbols(): SymbolsType {
168
+ export function getSymbols() {
129
169
  if (!_r) _r = buildCC(_config);
130
170
  return _r;
131
171
  }
package/src/utils.ts CHANGED
@@ -1,25 +1,73 @@
1
1
  export function cstr(str: string) {
2
- return Buffer.from(str + "\0", "utf8");
2
+ return Buffer.from(str + '\0', 'utf8');
3
3
  }
4
4
 
5
- const _f2iBuf = new ArrayBuffer(4);
6
- const _f2iF32 = new Float32Array(_f2iBuf);
7
- const _f2iU32 = new Uint32Array(_f2iBuf);
8
-
9
- export function f2i(val: number): number {
10
- _f2iF32[0] = val;
11
- return _f2iU32[0]! | 0;
5
+ /**
6
+ * Force heap-allocated double: adds/subtracts a tiny epsilon
7
+ * to kill V8 SMI-encoding without changing the numeric value.
8
+ * Ensures bun:ffi passes the correct f32/f64 bit pattern to C.
9
+ */
10
+ export function f(n: number): number {
11
+ return n + 1e-300 - 1e-300;
12
12
  }
13
13
 
14
- const _i2fBuf = new ArrayBuffer(4);
15
- const _i2fU32 = new Uint32Array(_i2fBuf);
16
- const _i2fF32 = new Float32Array(_i2fBuf);
17
-
18
- export function i2f(val: number): number {
19
- _i2fU32[0] = val >>> 0;
20
- return _i2fF32[0]!;
14
+ export function i(n: number): number {
15
+ return n | 0;
21
16
  }
22
17
 
23
18
  export const color = (r: number, g: number, b: number, a: number = 255) => {
24
19
  return (a << 24) | (b << 16) | (g << 8) | r;
25
20
  };
21
+
22
+ export const bufs = {
23
+ _rcHit: new Uint8Array(1),
24
+ _rcDist: new Float32Array(1),
25
+ _rcPt: new Float32Array(3),
26
+ _rcNorm: new Float32Array(3),
27
+ _texOutId: new Uint32Array(1),
28
+ _texOutTexId: new Uint32Array(1),
29
+ _texOutW: new Int32Array(1),
30
+ _texOutH: new Int32Array(1),
31
+ _shapesTexId: new Uint32Array(1),
32
+ _shapesTexW: new Int32Array(1),
33
+ _shapesTexH: new Int32Array(1),
34
+ _rayPosBuf2: new Float32Array(3),
35
+ _rayDirBuf2: new Float32Array(3),
36
+ _animSlotStart: new Int32Array(1),
37
+ _animCount: new Int32Array(1),
38
+ _colPtBuf: new Float32Array(2),
39
+ _recBuf: new Float32Array(4),
40
+ _vec2Buf: new Float32Array(2),
41
+ _matBuf: new Float32Array(16),
42
+ _vec4Buf: new Float32Array(4),
43
+ _vec3Buf2: new Float32Array(3),
44
+ _imgAnimSlot: new Int32Array(1),
45
+ _imgAnimFrames: new Int32Array(1),
46
+ _glyphValue: new Int32Array(1),
47
+ _glyphOffsetX: new Int32Array(1),
48
+ _glyphOffsetY: new Int32Array(1),
49
+ _glyphAdvanceX: new Int32Array(1),
50
+ _glyphImageSlot: new Int32Array(1),
51
+ _cpSize: new Int32Array(1),
52
+ _textAppendPos: new Int32Array(1),
53
+ _bbMin: new Float32Array(3),
54
+ _bbMax: new Float32Array(3),
55
+ };
56
+
57
+ export function validatePoints(
58
+ name: string,
59
+ points: Float32Array,
60
+ stride: number,
61
+ minPoints: number,
62
+ ): void {
63
+ if (points.length % stride !== 0) {
64
+ throw new Error(
65
+ `${name}: points length must be a multiple of ${stride} (got ${points.length})`,
66
+ );
67
+ }
68
+ if (points.length < stride * minPoints) {
69
+ throw new Error(
70
+ `${name}: points must contain at least ${minPoints} points (got ${points.length / stride})`,
71
+ );
72
+ }
73
+ }