Commit0f08a874Recorded15 Jan 2026Repositorysigil-studio

refactor: Split sigil-studio into sigil-app, sigil-graphics, sigil-audio

Message

Split the monolithic sigil-studio package into three focused packages:

- sigil-app: Window management, input handling, application lifecycle (sokolapp, sokoltime, sokollog) - sigil-graphics: 2D rendering, images, fonts (sokolgfx, sokolgp, sokolglue, stbimage, stbtruetype) - sigil-audio: Audio playback and streaming (sokolaudio, stbvorbis)

Module names raised from (sigil studio X) to (sigil X) namespace.

sigil-studio is now a thin entrypoint package that bundles sigil-cli with the multimedia libraries.

Build system changes: - Add link-flags field to library struct for platform-specific libs - Add collect-native-link-flags to gather link flags from dependencies - Export host-os/host-arch from (sigil build) for package conditionals - Rename sokol.c files to sokol-{app,graphics,audio}.c to avoid object file collisions

Platform link flags: - Linux: -lX11 -lXi -lXcursor -lGL -lasound - macOS: Cocoa, QuartzCore, OpenGL, Metal, AudioToolbox frameworks

Changed
 examples/hello-window.sgl     |     8 +-
 examples/solitaire.sgl        |    12 +-
 package.sgl                   |   181 +-
 src/c/app.c                   |   526 ----
 src/c/audio.c                 |   641 ----
 src/c/font.c                  |   513 ----
 src/c/graphics.c              |   909 ------
 src/c/image.c                 |   236 --
 src/c/sokol.c                 |    18 -
 src/c/stb_impl.c              |    12 -
 src/c/studio-internal.h       |    58 -
 src/sigil/studio/app.sgl      |    91 -
 src/sigil/studio/audio.sgl    |    33 -
 src/sigil/studio/font.sgl     |    22 -
 src/sigil/studio/graphics.sgl |    59 -
 src/sigil/studio/image.sgl    |    29 -
 test/test-audio.sgl           |     8 +-
 test/test-draw-texture.sgl    |     4 +-
 test/test-font.sgl            |     6 +-
 test/test-image.sgl           |     4 +-
 test/test-transforms.sgl      |     6 +-
 vendor/sokol/sokol_app.h      | 14047 ------------------------------------------------------------------------------------
 vendor/sokol/sokol_audio.h    |  2663 ----------------
 vendor/sokol/sokol_gfx.h      | 26612 ----------------------------------------------------------------------------------------------------------------------------------------------------------------
 vendor/sokol/sokol_glue.h     |   206 --
 vendor/sokol/sokol_gp.h       |  3112 -------------------
 vendor/sokol/sokol_log.h      |   334 --
 vendor/sokol/sokol_time.h     |   319 --
 vendor/stb/stb_image.h        |  7988 ------------------------------------------------
 vendor/stb/stb_truetype.h     |  5079 -------------------------------
 vendor/stb/stb_vorbis.c       |  5584 ----------------------------------
 31 files changed, 49 insertions(+), 69271 deletions(-)
Diff
examples/hello-window.sglmodified
@@ -3,8 +3,9 @@
3
;;; Opens a window and clears it to a cycling color.
4
;;; Demonstrates the coroutine-based game loop where Scheme owns the main loop.
5
6
(import (sigil studio app)
7
(sigil studio graphics))
+6
(import (sigil app)
+7
(sigil graphics)
+8
(sigil math))
9
10
;; Simple color cycling using sine waves
11
(define (get-color t)
@@ -28,8 +29,9 @@
29
;; Update time
30
(let ((new-time (+ time dt)))
31
;; Get cycling color and render
+32
(begin-frame)
33
(let ((color (get-color new-time)))
32
(clear (car color) (cadr color) (caddr color)))
+34
(clear-screen (car color) (cadr color) (caddr color)))
35
(end-frame)
36
37
;; Continue unless quit requested
examples/solitaire.sglmodified
@@ -12,9 +12,10 @@
12
;;; n - New game
13
14
(import (sigil core)
15
(sigil studio app)
16
(sigil studio graphics)
17
(sigil studio font))
+15
(sigil math)
+16
(sigil app)
+17
(sigil graphics)
+18
(sigil font))
19
20
;; ============================================================
21
;; CONSTANTS
@@ -569,12 +570,13 @@
570
;; ============================================================
571
572
(define (on-init)
+573
(gfx-setup)
574
(set-viewport SCREEN-WIDTH SCREEN-HEIGHT)
575
(set-letterbox-color 0.02 0.02 0.05)
576
577
;; Load font (use test font for now)
576
(set! *font* (load-font "test/Saucer.ttf" 24))
577
(set! *font-small* (load-font "test/Saucer.ttf" 16))
+578
(set! *font* (load-font "packages/sigil-studio/test/Saucer.ttf" 24))
+579
(set! *font-small* (load-font "packages/sigil-studio/test/Saucer.ttf" 16))
580
581
(init-game))
582
package.sglmodified
@@ -1,168 +1,33 @@
1
;;; package.sgl - Sigil Studio Package Definition
+1
;;; sigil-studio - Multimedia development environment for Sigil
2
;;;
3
;;; Multimedia libraries for games and creative applications.
4
;;; Built on Sokol for cross-platform graphics, audio, and windowing.
+3
;;; A "thick" CLI variant that includes windowing, graphics, and audio
+4
;;; support for building games and creative applications.
5
;;;
6
;;; Build with:
7
;;; cd packages/sigil-studio
8
;;; ../../run-sigil build # Build native lib + Scheme modules
9
;;; ../../run-sigil run build:test # Build and run test binary
+6
;;; This is the same as the standard `sigil` CLI but with multimedia
+7
;;; modules available:
+8
;;; - (sigil app): Windowing, input handling, application lifecycle
+9
;;; - (sigil graphics): 2D rendering, images, textures
+10
;;; - (sigil image): CPU-side image loading
+11
;;; - (sigil font): Font loading and text rendering
+12
;;; - (sigil audio): Sound effects and music streaming
13
14
(package
15
name: "sigil-studio"
16
version: "0.4.0"
14
description: "Multimedia libraries for Sigil"
+17
description: "Multimedia development environment for Sigil"
+18
url: "https://codeberg.org/sigil/sigil"
19
license: "BSD-3-Clause"
+20
authors: (list "David Wilson <[email protected]>")
21
17
configs: (list
18
(config
19
name: 'dev
20
output-dir: "build/dev"
21
debug?: #t
22
optimize: 0
23
c-flags: '("-Wall" "-Wextra" "-g" "-O0")
24
features: '(debug dev))
+22
;; Reuse the CLI as entry point - same commands, just with more modules
+23
entry: '(sigil cli)
+24
bundle-name: "sigil-studio"
25
26
(config
27
name: 'release
28
output-dir: "build/release"
29
debug?: #f
30
optimize: 2
31
c-flags: '("-Wall" "-O2")
32
features: '(release)))
+26
dependencies: (list
+27
;; Core CLI (brings in sigil-run, sigil-stdlib, and all CLI deps)
+28
(from-workspace name: "sigil-cli")
29
34
default-config: 'dev
35
36
libraries: (list
37
(library
38
name: 'sigil-studio
39
c-sources: '("src/c/sokol.c"
40
"src/c/stb_impl.c"
41
"src/c/app.c"
42
"src/c/image.c"
43
"src/c/graphics.c"
44
"src/c/font.c"
45
"src/c/audio.c")
46
sigil-sources: '("src/sigil/studio/app.sgl"
47
"src/sigil/studio/image.sgl"
48
"src/sigil/studio/graphics.sgl"
49
"src/sigil/studio/font.sgl"
50
"src/sigil/studio/audio.sgl")))
51
52
tasks: (list
53
;;; --------------------------------------------------------
54
;;; Native Library Build
55
;;; --------------------------------------------------------
56
57
(task
58
name: 'build:native
59
description: "Build sigil-studio native library"
60
steps: (list
61
(ensure-dirs dirs: '("obj" "lib"))
62
63
;; Compile Sokol, STB, and wrapper sources
64
;; Note: Platform-specific flags are handled by the build system
65
(compile-c-sources
66
sources: '("src/c/sokol.c"
67
"src/c/stb_impl.c"
68
"src/c/app.c"
69
"src/c/image.c"
70
"src/c/graphics.c"
71
"src/c/font.c"
72
"src/c/audio.c")
73
output-dir: (config-output-subdir "obj")
74
flags: '("-Ivendor/sokol"
75
"-Ivendor/stb"
76
"-I../../components/libsigil/include"
77
"-I../../components/libsigil/src"
78
"-DSOKOL_NO_ENTRY"
79
"-DSOKOL_GLCORE"
80
"-D_GNU_SOURCE"))
81
82
(create-static-library
83
name: "sigil-studio"
84
output-dir: (config-output-subdir "lib"))))
85
86
;;; --------------------------------------------------------
87
;;; Scheme Module Build
88
;;; --------------------------------------------------------
89
90
(task
91
name: 'build:scheme
92
description: "Compile Scheme modules"
93
steps: (list
94
(ensure-dirs dirs: '("lib/sigil/studio"))
95
96
(compile-sigil-module
97
source: "src/sigil/studio/app.sgl"
98
output: (config-output-subdir "lib/sigil/studio/app.sgb"))
99
100
(compile-sigil-module
101
source: "src/sigil/studio/image.sgl"
102
output: (config-output-subdir "lib/sigil/studio/image.sgb"))
103
104
(compile-sigil-module
105
source: "src/sigil/studio/graphics.sgl"
106
output: (config-output-subdir "lib/sigil/studio/graphics.sgb"))
107
108
(compile-sigil-module
109
source: "src/sigil/studio/font.sgl"
110
output: (config-output-subdir "lib/sigil/studio/font.sgb"))
111
112
(compile-sigil-module
113
source: "src/sigil/studio/audio.sgl"
114
output: (config-output-subdir "lib/sigil/studio/audio.sgb"))))
115
116
;;; --------------------------------------------------------
117
;;; Combined Build
118
;;; --------------------------------------------------------
119
120
(task
121
name: 'build
122
description: "Build everything"
123
depends: '(build:native build:scheme)
124
steps: '())
125
126
;;; --------------------------------------------------------
127
;;; Test Binary
128
;;; --------------------------------------------------------
129
130
(task
131
name: 'build:test
132
description: "Build test binary"
133
depends: '(build)
134
steps: (list
135
(ensure-dirs dirs: '("bin"))
136
137
;; Compile test harness
138
(compile-c-sources
139
sources: '("test/main.c")
140
output-dir: (config-output-subdir "obj/test")
141
flags: '("-I../../components/libsigil/include"))
142
143
;; Link test binary
144
;; NOTE: Custom linking is required because we need to link against
145
;; the parent project's bootstrap build (../../build/boot/).
146
;; Once proper package dependencies are implemented, this can use
147
;; the standard link-executable action.
148
(lambda (ctx)
149
(let* ((cfg (context-config ctx))
150
(out-dir (config-output-dir cfg))
151
(test-obj (path-join out-dir "obj/test/main.o"))
152
(studio-lib (path-join out-dir "lib/libsigil-studio.a"))
153
(bin-path (path-join out-dir "bin/sigil-studio-test")))
154
155
;; Collect libsigil object files from bootstrap build
156
(let ((sigil-objs (glob "../../build/boot/obj/libsigil/*.o"))
157
(miniz-objs (glob "../../build/boot/obj/miniz/*.o")))
158
159
;; Link everything together
160
(display " LINK ")
161
(display bin-path)
162
(newline)
163
164
(apply run-process ctx "gcc" "-o" bin-path test-obj studio-lib
165
(append sigil-objs miniz-objs
166
'("-lGL" "-lX11" "-lXi" "-lXcursor" "-lasound"
167
"-lm" "-lpthread" "-ldl"))))
168
ctx))))))
+30
;; Multimedia packages
+31
(from-workspace name: "sigil-app")
+32
(from-workspace name: "sigil-graphics")
+33
(from-workspace name: "sigil-audio")))
src/c/app.cdeleted
@@ -1,526 +0,0 @@
1
/*
2
* app.c - Sigil Studio Application Module
3
*
4
* Wraps sokol_app.h to provide windowing, input, and application lifecycle.
5
*/
6
7
#include "studio-internal.h"
8
#include "sigil-internal.h"
9
10
/* Sokol headers (implementation is in sokol.c) */
11
#include "sokol_app.h"
12
#include "sokol_gfx.h"
13
#include "sokol_glue.h"
14
#include "sokol_gp.h"
15
#include "sokol_time.h"
16
#include "sokol_log.h"
17
18
#include <stdio.h>
19
#include <stdlib.h>
20
#include <string.h>
21
22
/* Global studio state */
23
StudioState *g_studio = NULL;
24
25
/*
26
* Initialize studio state
27
*/
28
void studio_state_init(SigilVM *vm)
29
{
30
if (g_studio) return;
31
32
g_studio = calloc(1, sizeof(StudioState));
33
g_studio->vm = vm;
34
g_studio->init_callback = SIGIL_FALSE;
35
g_studio->frame_callback = SIGIL_FALSE;
36
g_studio->cleanup_callback = SIGIL_FALSE;
37
}
38
39
void studio_state_shutdown(void)
40
{
41
if (g_studio) {
42
free(g_studio);
43
g_studio = NULL;
44
}
45
}
46
47
/*
48
* Clear per-frame input state
49
*/
50
void studio_clear_frame_input(void)
51
{
52
if (!g_studio) return;
53
memset(g_studio->keys_pressed, 0, sizeof(g_studio->keys_pressed));
54
memset(g_studio->keys_released, 0, sizeof(g_studio->keys_released));
55
memset(g_studio->mouse_pressed, 0, sizeof(g_studio->mouse_pressed));
56
memset(g_studio->mouse_released, 0, sizeof(g_studio->mouse_released));
57
}
58
59
/*
60
* Convert Scheme key symbol to Sokol keycode
61
*/
62
int studio_key_code_from_symbol(SigilVM *vm, Value sym)
63
{
64
(void)vm;
65
if (!sigil_is_symbol(sym)) return SAPP_KEYCODE_INVALID;
66
67
SigilSymbol *s = (SigilSymbol *)sigil_as_ptr(sym);
68
const char *name = s->name;
69
70
/* Letters */
71
if (s->length == 1 && name[0] >= 'a' && name[0] <= 'z') {
72
return SAPP_KEYCODE_A + (name[0] - 'a');
73
}
74
75
/* Numbers */
76
if (s->length == 1 && name[0] >= '0' && name[0] <= '9') {
77
return SAPP_KEYCODE_0 + (name[0] - '0');
78
}
79
80
/* Special keys */
81
if (strcmp(name, "space") == 0) return SAPP_KEYCODE_SPACE;
82
if (strcmp(name, "return") == 0 || strcmp(name, "enter") == 0) return SAPP_KEYCODE_ENTER;
83
if (strcmp(name, "escape") == 0 || strcmp(name, "esc") == 0) return SAPP_KEYCODE_ESCAPE;
84
if (strcmp(name, "tab") == 0) return SAPP_KEYCODE_TAB;
85
if (strcmp(name, "backspace") == 0) return SAPP_KEYCODE_BACKSPACE;
86
87
/* Arrow keys */
88
if (strcmp(name, "left") == 0) return SAPP_KEYCODE_LEFT;
89
if (strcmp(name, "right") == 0) return SAPP_KEYCODE_RIGHT;
90
if (strcmp(name, "up") == 0) return SAPP_KEYCODE_UP;
91
if (strcmp(name, "down") == 0) return SAPP_KEYCODE_DOWN;
92
93
/* Modifiers */
94
if (strcmp(name, "shift") == 0) return SAPP_KEYCODE_LEFT_SHIFT;
95
if (strcmp(name, "ctrl") == 0 || strcmp(name, "control") == 0) return SAPP_KEYCODE_LEFT_CONTROL;
96
if (strcmp(name, "alt") == 0) return SAPP_KEYCODE_LEFT_ALT;
97
98
return SAPP_KEYCODE_INVALID;
99
}
100
101
/*
102
* Convert mouse button symbol to index
103
*/
104
static int mouse_button_from_symbol(SigilVM *vm, Value sym)
105
{
106
(void)vm;
107
if (!sigil_is_symbol(sym)) return -1;
108
109
SigilSymbol *s = (SigilSymbol *)sigil_as_ptr(sym);
110
const char *name = s->name;
111
112
if (strcmp(name, "left") == 0) return 0;
113
if (strcmp(name, "right") == 0) return 1;
114
if (strcmp(name, "middle") == 0) return 2;
115
116
return -1;
117
}
118
119
/* ============================================================
120
* SOKOL CALLBACKS
121
* ============================================================ */
122
123
static uint64_t last_time = 0;
124
125
/* Check for VM errors and print them */
126
static void check_vm_error(const char *context)
127
{
128
if (!g_studio) return;
129
const char *err = sigil_error_message(g_studio->vm);
130
if (err) {
131
fprintf(stderr, "Scheme error in %s: %s\n", context, err);
132
sigil_error_clear(g_studio->vm);
133
sapp_request_quit();
134
}
135
}
136
137
static void app_init(void)
138
{
139
stm_setup();
140
last_time = stm_now();
141
142
/* Initialize graphics subsystem */
143
if (g_studio && !g_studio->gfx_initialized) {
144
sg_desc desc = {
145
.environment = sglue_environment(),
146
};
147
sg_setup(&desc);
148
149
/* Initialize sokol_gp for 2D rendering */
150
sgp_desc sgpdesc = {0};
151
sgp_setup(&sgpdesc);
152
if (!sgp_is_valid()) {
153
fprintf(stderr, "Failed to initialize sokol_gp\n");
154
}
155
156
g_studio->gfx_initialized = true;
157
}
158
159
if (g_studio && !sigil_is_false(g_studio->init_callback)) {
160
sigil_apply0(g_studio->vm, g_studio->init_callback);
161
check_vm_error("init");
162
}
163
}
164
165
static void app_frame(void)
166
{
167
/* Calculate frame time */
168
uint64_t now = stm_now();
169
g_studio->frame_time = stm_sec(stm_diff(now, last_time));
170
g_studio->time_elapsed += g_studio->frame_time;
171
last_time = now;
172
173
/* Call Scheme frame callback with delta time */
174
if (g_studio && !sigil_is_false(g_studio->frame_callback)) {
175
Value dt = sigil_flonum(g_studio->frame_time);
176
sigil_apply1(g_studio->vm, g_studio->frame_callback, dt);
177
check_vm_error("frame");
178
}
179
180
/* Clear per-frame input state for next frame */
181
studio_clear_frame_input();
182
}
183
184
static void app_cleanup(void)
185
{
186
if (g_studio && !sigil_is_false(g_studio->cleanup_callback)) {
187
sigil_apply0(g_studio->vm, g_studio->cleanup_callback);
188
check_vm_error("cleanup");
189
}
190
191
/* Shutdown graphics subsystem */
192
if (g_studio && g_studio->gfx_initialized) {
193
sgp_shutdown();
194
sg_shutdown();
195
g_studio->gfx_initialized = false;
196
}
197
}
198
199
static void app_event(const sapp_event *ev)
200
{
201
if (!g_studio) return;
202
203
switch (ev->type) {
204
case SAPP_EVENTTYPE_KEY_DOWN:
205
if (ev->key_code < 512) {
206
if (!g_studio->keys_down[ev->key_code]) {
207
g_studio->keys_pressed[ev->key_code] = true;
208
}
209
g_studio->keys_down[ev->key_code] = true;
210
}
211
break;
212
213
case SAPP_EVENTTYPE_KEY_UP:
214
if (ev->key_code < 512) {
215
g_studio->keys_down[ev->key_code] = false;
216
g_studio->keys_released[ev->key_code] = true;
217
}
218
break;
219
220
case SAPP_EVENTTYPE_MOUSE_DOWN:
221
if (ev->mouse_button < 3) {
222
if (!g_studio->mouse_buttons[ev->mouse_button]) {
223
g_studio->mouse_pressed[ev->mouse_button] = true;
224
}
225
g_studio->mouse_buttons[ev->mouse_button] = true;
226
}
227
break;
228
229
case SAPP_EVENTTYPE_MOUSE_UP:
230
if (ev->mouse_button < 3) {
231
g_studio->mouse_buttons[ev->mouse_button] = false;
232
g_studio->mouse_released[ev->mouse_button] = true;
233
}
234
break;
235
236
case SAPP_EVENTTYPE_MOUSE_MOVE:
237
g_studio->mouse_x = ev->mouse_x;
238
g_studio->mouse_y = ev->mouse_y;
239
break;
240
241
case SAPP_EVENTTYPE_QUIT_REQUESTED:
242
g_studio->quit_requested = true;
243
break;
244
245
default:
246
break;
247
}
248
}
249
250
/* ============================================================
251
* NATIVE FUNCTIONS
252
* ============================================================ */
253
254
/*
255
* (app-run init-proc frame-proc cleanup-proc [title] [width] [height])
256
*
257
* Run the application main loop.
258
* init-proc: called once at startup
259
* frame-proc: called each frame with delta-time argument
260
* cleanup-proc: called before shutdown
261
*/
262
static Value native_app_run(SigilVM *vm, int argc, Value *args)
263
{
264
if (argc < 3) {
265
sigil__vm_error(vm, SIGIL_ERR_ARITY, "app-run: requires init, frame, and cleanup procedures");
266
return SIGIL_UNDEFINED;
267
}
268
269
/* Initialize studio state */
270
studio_state_init(vm);
271
272
/* Store callbacks */
273
g_studio->init_callback = args[0];
274
g_studio->frame_callback = args[1];
275
g_studio->cleanup_callback = args[2];
276
277
/* Parse optional arguments */
278
const char *title = "Sigil App";
279
int width = 800;
280
int height = 600;
281
282
if (argc > 3 && sigil_is_string(args[3])) {
283
SigilString *s = (SigilString *)sigil_as_ptr(args[3]);
284
title = s->data;
285
}
286
if (argc > 4 && sigil_is_fixnum(args[4])) {
287
width = (int)sigil_as_fixnum(args[4]);
288
}
289
if (argc > 5 && sigil_is_fixnum(args[5])) {
290
height = (int)sigil_as_fixnum(args[5]);
291
}
292
293
/* Configure and run Sokol app */
294
sapp_desc desc = {
295
.init_cb = app_init,
296
.frame_cb = app_frame,
297
.cleanup_cb = app_cleanup,
298
.event_cb = app_event,
299
.width = width,
300
.height = height,
301
.window_title = title,
302
.icon.sokol_default = true,
303
.logger.func = slog_func,
304
};
305
306
sapp_run(&desc);
307
308
/* Cleanup */
309
studio_state_shutdown();
310
311
return SIGIL_NIL;
312
}
313
314
/*
315
* (frame-width) -> integer
316
*/
317
static Value native_frame_width(SigilVM *vm, int argc, Value *args)
318
{
319
(void)vm; (void)argc; (void)args;
320
return sigil_fixnum(sapp_width());
321
}
322
323
/*
324
* (frame-height) -> integer
325
*/
326
static Value native_frame_height(SigilVM *vm, int argc, Value *args)
327
{
328
(void)vm; (void)argc; (void)args;
329
return sigil_fixnum(sapp_height());
330
}
331
332
/*
333
* (frame-time) -> float (seconds since last frame)
334
*/
335
static Value native_frame_time(SigilVM *vm, int argc, Value *args)
336
{
337
(void)vm; (void)argc; (void)args;
338
if (!g_studio) return sigil_flonum(0.0);
339
return sigil_flonum(g_studio->frame_time);
340
}
341
342
/*
343
* (time-elapsed) -> float (seconds since app start)
344
*/
345
static Value native_time_elapsed(SigilVM *vm, int argc, Value *args)
346
{
347
(void)vm; (void)argc; (void)args;
348
if (!g_studio) return sigil_flonum(0.0);
349
return sigil_flonum(g_studio->time_elapsed);
350
}
351
352
/*
353
* (mouse-x) -> float
354
*/
355
static Value native_mouse_x(SigilVM *vm, int argc, Value *args)
356
{
357
(void)vm; (void)argc; (void)args;
358
if (!g_studio) return sigil_flonum(0.0);
359
return sigil_flonum(g_studio->mouse_x);
360
}
361
362
/*
363
* (mouse-y) -> float
364
*/
365
static Value native_mouse_y(SigilVM *vm, int argc, Value *args)
366
{
367
(void)vm; (void)argc; (void)args;
368
if (!g_studio) return sigil_flonum(0.0);
369
return sigil_flonum(g_studio->mouse_y);
370
}
371
372
/*
373
* (mouse-down? button) -> boolean
374
*/
375
static Value native_mouse_down(SigilVM *vm, int argc, Value *args)
376
{
377
if (argc < 1) return SIGIL_FALSE;
378
int btn = mouse_button_from_symbol(vm, args[0]);
379
if (btn < 0 || !g_studio) return SIGIL_FALSE;
380
return g_studio->mouse_buttons[btn] ? SIGIL_TRUE : SIGIL_FALSE;
381
}
382
383
/*
384
* (mouse-pressed? button) -> boolean
385
*/
386
static Value native_mouse_pressed(SigilVM *vm, int argc, Value *args)
387
{
388
if (argc < 1) return SIGIL_FALSE;
389
int btn = mouse_button_from_symbol(vm, args[0]);
390
if (btn < 0 || !g_studio) return SIGIL_FALSE;
391
return g_studio->mouse_pressed[btn] ? SIGIL_TRUE : SIGIL_FALSE;
392
}
393
394
/*
395
* (mouse-released? button) -> boolean
396
*/
397
static Value native_mouse_released(SigilVM *vm, int argc, Value *args)
398
{
399
if (argc < 1) return SIGIL_FALSE;
400
int btn = mouse_button_from_symbol(vm, args[0]);
401
if (btn < 0 || !g_studio) return SIGIL_FALSE;
402
return g_studio->mouse_released[btn] ? SIGIL_TRUE : SIGIL_FALSE;
403
}
404
405
/*
406
* (key-down? key) -> boolean
407
*/
408
static Value native_key_down(SigilVM *vm, int argc, Value *args)
409
{
410
if (argc < 1) return SIGIL_FALSE;
411
int key = studio_key_code_from_symbol(vm, args[0]);
412
if (key == SAPP_KEYCODE_INVALID || !g_studio) return SIGIL_FALSE;
413
return g_studio->keys_down[key] ? SIGIL_TRUE : SIGIL_FALSE;
414
}
415
416
/*
417
* (key-pressed? key) -> boolean
418
*/
419
static Value native_key_pressed(SigilVM *vm, int argc, Value *args)
420
{
421
if (argc < 1) return SIGIL_FALSE;
422
int key = studio_key_code_from_symbol(vm, args[0]);
423
if (key == SAPP_KEYCODE_INVALID || !g_studio) return SIGIL_FALSE;
424
return g_studio->keys_pressed[key] ? SIGIL_TRUE : SIGIL_FALSE;
425
}
426
427
/*
428
* (key-released? key) -> boolean
429
*/
430
static Value native_key_released(SigilVM *vm, int argc, Value *args)
431
{
432
if (argc < 1) return SIGIL_FALSE;
433
int key = studio_key_code_from_symbol(vm, args[0]);
434
if (key == SAPP_KEYCODE_INVALID || !g_studio) return SIGIL_FALSE;
435
return g_studio->keys_released[key] ? SIGIL_TRUE : SIGIL_FALSE;
436
}
437
438
/*
439
* (quit-requested?) -> boolean
440
*/
441
static Value native_quit_requested(SigilVM *vm, int argc, Value *args)
442
{
443
(void)vm; (void)argc; (void)args;
444
if (!g_studio) return SIGIL_FALSE;
445
return g_studio->quit_requested ? SIGIL_TRUE : SIGIL_FALSE;
446
}
447
448
/*
449
* (request-quit)
450
*/
451
static Value native_request_quit(SigilVM *vm, int argc, Value *args)
452
{
453
(void)vm; (void)argc; (void)args;
454
sapp_request_quit();
455
return SIGIL_NIL;
456
}
457
458
/* ============================================================
459
* MODULE INITIALIZATION
460
* ============================================================ */
461
462
void sigil__init_sigil_studio_app_module(SigilVM *vm)
463
{
464
SigilModule *module = sigil_begin_module(vm, "(sigil studio app)");
465
if (!module) return;
466
467
/* Application lifecycle */
468
sigil_module_register_native(vm, "app-run", native_app_run,
469
SIGIL_ARITY_RANGE(3, 6),
470
"Run application with init/frame/cleanup callbacks");
471
472
/* Frame info */
473
sigil_module_register_native(vm, "frame-width", native_frame_width,
474
SIGIL_ARITY_EXACT(0), "Get frame buffer width");
475
sigil_module_register_native(vm, "frame-height", native_frame_height,
476
SIGIL_ARITY_EXACT(0), "Get frame buffer height");
477
sigil_module_register_native(vm, "frame-time", native_frame_time,
478
SIGIL_ARITY_EXACT(0), "Seconds since last frame");
479
sigil_module_register_native(vm, "time-elapsed", native_time_elapsed,
480
SIGIL_ARITY_EXACT(0), "Seconds since app start");
481
482
/* Mouse input */
483
sigil_module_register_native(vm, "mouse-x", native_mouse_x,
484
SIGIL_ARITY_EXACT(0), "Mouse X position");
485
sigil_module_register_native(vm, "mouse-y", native_mouse_y,
486
SIGIL_ARITY_EXACT(0), "Mouse Y position");
487
sigil_module_register_native(vm, "mouse-down?", native_mouse_down,
488
SIGIL_ARITY_EXACT(1), "Is mouse button held?");
489
sigil_module_register_native(vm, "mouse-pressed?", native_mouse_pressed,
490
SIGIL_ARITY_EXACT(1), "Was mouse button just pressed?");
491
sigil_module_register_native(vm, "mouse-released?", native_mouse_released,
492
SIGIL_ARITY_EXACT(1), "Was mouse button just released?");
493
494
/* Keyboard input */
495
sigil_module_register_native(vm, "key-down?", native_key_down,
496
SIGIL_ARITY_EXACT(1), "Is key held?");
497
sigil_module_register_native(vm, "key-pressed?", native_key_pressed,
498
SIGIL_ARITY_EXACT(1), "Was key just pressed?");
499
sigil_module_register_native(vm, "key-released?", native_key_released,

Showing the first 500 of 527 diff lines for this file. This diff is INCOMPLETE; read the file or clone the repository for the rest.

src/c/audio.cdeleted
@@ -1,641 +0,0 @@
1
/*
2
* audio.c - Sigil Studio Audio Module
3
*
4
* Wraps sokol_audio.h to provide audio playback capabilities.
5
* Uses stb_vorbis for OGG decoding.
6
*
7
* Sound effects are loaded entirely into memory.
8
* Music is streamed from disk via stb_vorbis.
9
*/
10
11
#include "studio-internal.h"
12
#include "sigil-internal.h"
13
14
#include <stdio.h>
15
#include <stdlib.h>
16
#include <string.h>
17
#include <math.h>
18
19
/* Sokol headers (implementation is in sokol.c) */
20
#include "sokol_audio.h"
21
22
/* stb_vorbis for OGG decoding (implementation in stb_impl.c) */
23
#include "stb_vorbis.c"
24
25
/* ============================================================
26
* CONSTANTS
27
* ============================================================ */
28
29
#define MAX_SOUNDS 64
30
#define MAX_PLAYING_SOUNDS 16
31
#define STREAM_BUFFER_SAMPLES 4096
32
33
/* ============================================================
34
* DATA STRUCTURES
35
* ============================================================ */
36
37
/* Sound effect - fully loaded into memory */
38
typedef struct {
39
float *samples; /* Interleaved stereo samples */
40
int num_samples; /* Total samples (frames * channels) */
41
int sample_rate;
42
int channels;
43
} StudioSound;
44
45
/* Playing sound instance */
46
typedef struct {
47
StudioSound *sound;
48
int position; /* Current playback position */
49
float volume;
50
float pan; /* -1.0 left, 0.0 center, 1.0 right */
51
bool playing;
52
bool loop;
53
} PlayingSound;
54
55
/* Music stream - decoded on the fly */
56
typedef struct {
57
stb_vorbis *vorbis;
58
char *filepath; /* For reopening if looping */
59
float volume;
60
bool playing;
61
bool loop;
62
bool paused;
63
} MusicStream;
64
65
/* ============================================================
66
* GLOBAL STATE
67
* ============================================================ */
68
69
static PlayingSound g_playing_sounds[MAX_PLAYING_SOUNDS];
70
static MusicStream g_music = {0};
71
static float g_master_volume = 1.0f;
72
static bool g_muted = false;
73
74
/* Type tags for foreign objects */
75
static Value sound_type_tag = SIGIL_UNDEFINED;
76
77
/* ============================================================
78
* AUDIO CALLBACK
79
* ============================================================ */
80
81
static void audio_callback(float *buffer, int num_frames, int num_channels)
82
{
83
/* Clear buffer */
84
memset(buffer, 0, num_frames * num_channels * sizeof(float));
85
86
if (g_muted) return;
87
88
float master = g_master_volume;
89
90
/* Mix playing sounds */
91
for (int i = 0; i < MAX_PLAYING_SOUNDS; i++) {
92
PlayingSound *ps = &g_playing_sounds[i];
93
if (!ps->playing || !ps->sound) continue;
94
95
StudioSound *snd = ps->sound;
96
float vol = ps->volume * master;
97
98
/* Calculate pan gains */
99
float pan = ps->pan;
100
float left_gain = vol * (pan <= 0 ? 1.0f : 1.0f - pan);
101
float right_gain = vol * (pan >= 0 ? 1.0f : 1.0f + pan);
102
103
for (int f = 0; f < num_frames; f++) {
104
if (ps->position >= snd->num_samples / snd->channels) {
105
if (ps->loop) {
106
ps->position = 0;
107
} else {
108
ps->playing = false;
109
break;
110
}
111
}
112
113
float left, right;
114
if (snd->channels == 1) {
115
/* Mono */
116
left = right = snd->samples[ps->position];
117
} else {
118
/* Stereo */
119
left = snd->samples[ps->position * 2];
120
right = snd->samples[ps->position * 2 + 1];
121
}
122
123
if (num_channels >= 2) {
124
buffer[f * num_channels] += left * left_gain;
125
buffer[f * num_channels + 1] += right * right_gain;
126
} else {
127
buffer[f] += (left + right) * 0.5f * vol;
128
}
129
130
ps->position++;
131
}
132
}
133
134
/* Mix music stream */
135
if (g_music.playing && !g_music.paused && g_music.vorbis) {
136
float vol = g_music.volume * master;
137
float temp[STREAM_BUFFER_SAMPLES * 2];
138
int samples_needed = num_frames;
139
int offset = 0;
140
141
while (samples_needed > 0) {
142
int to_decode = samples_needed < STREAM_BUFFER_SAMPLES ?
143
samples_needed : STREAM_BUFFER_SAMPLES;
144
145
int decoded = stb_vorbis_get_samples_float_interleaved(
146
g_music.vorbis, 2, temp, to_decode * 2);
147
148
if (decoded == 0) {
149
/* End of file */
150
if (g_music.loop && g_music.filepath) {
151
/* Reopen and continue */
152
stb_vorbis_close(g_music.vorbis);
153
int error;
154
g_music.vorbis = stb_vorbis_open_filename(
155
g_music.filepath, &error, NULL);
156
if (!g_music.vorbis) {
157
g_music.playing = false;
158
break;
159
}
160
continue;
161
} else {
162
g_music.playing = false;
163
break;
164
}
165
}
166
167
/* Mix decoded samples */
168
for (int f = 0; f < decoded; f++) {
169
int buf_idx = (offset + f) * num_channels;
170
if (num_channels >= 2) {
171
buffer[buf_idx] += temp[f * 2] * vol;
172
buffer[buf_idx + 1] += temp[f * 2 + 1] * vol;
173
} else {
174
buffer[buf_idx] += (temp[f * 2] + temp[f * 2 + 1]) * 0.5f * vol;
175
}
176
}
177
178
samples_needed -= decoded;
179
offset += decoded;
180
}
181
}
182
183
/* Clamp output */
184
for (int i = 0; i < num_frames * num_channels; i++) {
185
if (buffer[i] > 1.0f) buffer[i] = 1.0f;
186
if (buffer[i] < -1.0f) buffer[i] = -1.0f;
187
}
188
}
189
190
/* ============================================================
191
* HELPER FUNCTIONS
192
* ============================================================ */
193
194
static void ensure_sound_type(SigilVM *vm)
195
{
196
if (sigil_is_undefined(sound_type_tag)) {
197
sound_type_tag = sigil_intern_symbol(vm, "sigil-studio-sound", 18);
198
}
199
}
200
201
static StudioSound *get_sound(SigilVM *vm, Value v)
202
{
203
if (!sigil_is_foreign(v)) return NULL;
204
ensure_sound_type(vm);
205
if (sigil_foreign_type(v) != sound_type_tag) return NULL;
206
return (StudioSound *)sigil_foreign_data(v);
207
}
208
209
static void sound_destructor(void *data)
210
{
211
StudioSound *snd = (StudioSound *)data;
212
if (snd) {
213
free(snd->samples);
214
free(snd);
215
}
216
}
217
218
static PlayingSound *find_free_slot(void)
219
{
220
for (int i = 0; i < MAX_PLAYING_SOUNDS; i++) {
221
if (!g_playing_sounds[i].playing) {
222
return &g_playing_sounds[i];
223
}
224
}
225
return NULL;
226
}
227
228
/* ============================================================
229
* NATIVE FUNCTIONS - SETUP
230
* ============================================================ */
231
232
/*
233
* (audio-setup) - Initialize audio subsystem
234
*/
235
static Value native_audio_setup(SigilVM *vm, int argc, Value *args)
236
{
237
(void)vm; (void)argc; (void)args;
238
239
if (g_studio && g_studio->audio_initialized) {
240
return SIGIL_NIL;
241
}
242
243
saudio_desc desc = {
244
.stream_cb = audio_callback,
245
.num_channels = 2,
246
.sample_rate = 44100,
247
.buffer_frames = 2048
248
};
249
saudio_setup(&desc);
250
251
/* Clear playing sounds */
252
memset(g_playing_sounds, 0, sizeof(g_playing_sounds));
253
254
/* Clear music */
255
memset(&g_music, 0, sizeof(g_music));
256
g_music.volume = 1.0f;
257
258
g_master_volume = 1.0f;
259
g_muted = false;
260
261
if (g_studio) {
262
g_studio->audio_initialized = true;
263
}
264
265
return SIGIL_NIL;
266
}
267
268
/*
269
* (audio-shutdown) - Shutdown audio subsystem
270
*/
271
static Value native_audio_shutdown(SigilVM *vm, int argc, Value *args)
272
{
273
(void)vm; (void)argc; (void)args;
274
275
if (g_studio && g_studio->audio_initialized) {
276
/* Stop music */
277
if (g_music.vorbis) {
278
stb_vorbis_close(g_music.vorbis);
279
g_music.vorbis = NULL;
280
}
281
free(g_music.filepath);
282
g_music.filepath = NULL;
283
284
saudio_shutdown();
285
g_studio->audio_initialized = false;
286
}
287
288
return SIGIL_NIL;
289
}
290
291
/*
292
* (audio-initialized?) -> boolean
293
*/
294
static Value native_audio_initialized(SigilVM *vm, int argc, Value *args)
295
{
296
(void)vm; (void)argc; (void)args;
297
if (!g_studio) return SIGIL_FALSE;
298
return g_studio->audio_initialized ? SIGIL_TRUE : SIGIL_FALSE;
299
}
300
301
/* ============================================================
302
* NATIVE FUNCTIONS - SOUNDS
303
* ============================================================ */
304
305
/*
306
* (load-sound path) -> <sound> or #f
307
*
308
* Load an OGG file entirely into memory.
309
*/
310
static Value native_load_sound(SigilVM *vm, int argc, Value *args)
311
{
312
if (argc < 1 || !sigil_is_string(args[0])) {
313
sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "load-sound: expected string path");
314
return SIGIL_FALSE;
315
}
316
317
SigilString *path_str = (SigilString *)sigil_as_ptr(args[0]);
318
const char *path = path_str->data;
319
320
int channels, sample_rate;
321
short *raw_samples;
322
int num_samples = stb_vorbis_decode_filename(path, &channels, &sample_rate,
323
&raw_samples);
324
if (num_samples < 0) {
325
return SIGIL_FALSE;
326
}
327
328
/* Convert to float */
329
int total_samples = num_samples * channels;
330
float *samples = malloc(total_samples * sizeof(float));
331
if (!samples) {
332
free(raw_samples);
333
return SIGIL_FALSE;
334
}
335
336
for (int i = 0; i < total_samples; i++) {
337
samples[i] = raw_samples[i] / 32768.0f;
338
}
339
free(raw_samples);
340
341
StudioSound *snd = malloc(sizeof(StudioSound));
342
if (!snd) {
343
free(samples);
344
return SIGIL_FALSE;
345
}
346
347
snd->samples = samples;
348
snd->num_samples = total_samples;
349
snd->sample_rate = sample_rate;
350
snd->channels = channels;
351
352
ensure_sound_type(vm);
353
return sigil_make_foreign(vm, sound_type_tag, snd, sound_destructor,
354
sizeof(StudioSound) + total_samples * sizeof(float));
355
}
356
357
/*
358
* (sound? obj) -> boolean
359
*/
360
static Value native_sound_p(SigilVM *vm, int argc, Value *args)
361
{
362
(void)argc;
363
return get_sound(vm, args[0]) ? SIGIL_TRUE : SIGIL_FALSE;
364
}
365
366
/*
367
* (play-sound sound [volume] [pan] [loop?]) -> boolean
368
*
369
* Play a sound effect. Returns #t if started, #f if no slots available.
370
*/
371
static Value native_play_sound(SigilVM *vm, int argc, Value *args)
372
{
373
if (argc < 1) {
374
sigil__vm_set_error(vm, SIGIL_ERR_ARITY, "play-sound: requires sound argument");
375
return SIGIL_FALSE;
376
}
377
378
StudioSound *snd = get_sound(vm, args[0]);
379
if (!snd) {
380
sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "play-sound: expected sound");
381
return SIGIL_FALSE;
382
}
383
384
PlayingSound *ps = find_free_slot();
385
if (!ps) {
386
return SIGIL_FALSE; /* No slots available */
387
}
388
389
ps->sound = snd;
390
ps->position = 0;
391
ps->volume = argc > 1 ? (float)sigil_as_flonum(args[1]) : 1.0f;
392
ps->pan = argc > 2 ? (float)sigil_as_flonum(args[2]) : 0.0f;
393
ps->loop = argc > 3 ? sigil_is_true(args[3]) : false;
394
ps->playing = true;
395
396
return SIGIL_TRUE;
397
}
398
399
/*
400
* (stop-all-sounds) - Stop all playing sound effects
401
*/
402
static Value native_stop_all_sounds(SigilVM *vm, int argc, Value *args)
403
{
404
(void)vm; (void)argc; (void)args;
405
406
for (int i = 0; i < MAX_PLAYING_SOUNDS; i++) {
407
g_playing_sounds[i].playing = false;
408
}
409
410
return SIGIL_NIL;
411
}
412
413
/* ============================================================
414
* NATIVE FUNCTIONS - MUSIC
415
* ============================================================ */
416
417
/*
418
* (play-music path [loop?]) -> boolean
419
*
420
* Start streaming music from an OGG file.
421
*/
422
static Value native_play_music(SigilVM *vm, int argc, Value *args)
423
{
424
if (argc < 1 || !sigil_is_string(args[0])) {
425
sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "play-music: expected string path");
426
return SIGIL_FALSE;
427
}
428
429
/* Stop any existing music */
430
if (g_music.vorbis) {
431
stb_vorbis_close(g_music.vorbis);
432
g_music.vorbis = NULL;
433
}
434
free(g_music.filepath);
435
g_music.filepath = NULL;
436
437
SigilString *path_str = (SigilString *)sigil_as_ptr(args[0]);
438
const char *path = path_str->data;
439
440
int error;
441
g_music.vorbis = stb_vorbis_open_filename(path, &error, NULL);
442
if (!g_music.vorbis) {
443
return SIGIL_FALSE;
444
}
445
446
g_music.filepath = strdup(path);
447
g_music.loop = argc > 1 ? sigil_is_true(args[1]) : true;
448
g_music.playing = true;
449
g_music.paused = false;
450
451
return SIGIL_TRUE;
452
}
453
454
/*
455
* (stop-music) - Stop music playback
456
*/
457
static Value native_stop_music(SigilVM *vm, int argc, Value *args)
458
{
459
(void)vm; (void)argc; (void)args;
460
461
if (g_music.vorbis) {
462
stb_vorbis_close(g_music.vorbis);
463
g_music.vorbis = NULL;
464
}
465
free(g_music.filepath);
466
g_music.filepath = NULL;
467
g_music.playing = false;
468
469
return SIGIL_NIL;
470
}
471
472
/*
473
* (pause-music) - Pause music playback
474
*/
475
static Value native_pause_music(SigilVM *vm, int argc, Value *args)
476
{
477
(void)vm; (void)argc; (void)args;
478
g_music.paused = true;
479
return SIGIL_NIL;
480
}
481
482
/*
483
* (resume-music) - Resume music playback
484
*/
485
static Value native_resume_music(SigilVM *vm, int argc, Value *args)
486
{
487
(void)vm; (void)argc; (void)args;
488
g_music.paused = false;
489
return SIGIL_NIL;
490
}
491
492
/*
493
* (music-playing?) -> boolean
494
*/
495
static Value native_music_playing(SigilVM *vm, int argc, Value *args)
496
{
497
(void)vm; (void)argc; (void)args;
498
return (g_music.playing && !g_music.paused) ? SIGIL_TRUE : SIGIL_FALSE;
499
}

Showing the first 500 of 642 diff lines for this file. This diff is INCOMPLETE; read the file or clone the repository for the rest.

src/c/font.cdeleted
@@ -1,513 +0,0 @@
1
/*
2
* font.c - Font loading and text rendering for Sigil Studio
3
*
4
* Provides TrueType font loading via stb_truetype and text rendering.
5
* Fonts are rasterized to an atlas texture at a specified size.
6
*/
7
8
#include "studio-internal.h"
9
#include "sigil-internal.h"
10
11
#include "sokol_gfx.h"
12
#include "sokol_gp.h"
13
#include "stb_truetype.h"
14
15
#include <stdio.h>
16
#include <stdlib.h>
17
#include <string.h>
18
19
/* Font type tag */
20
static Value font_type_tag = SIGIL_UNDEFINED;
21
22
/* ASCII printable range */
23
#define FIRST_CHAR 32 /* space */
24
#define LAST_CHAR 126 /* tilde */
25
#define NUM_CHARS (LAST_CHAR - FIRST_CHAR + 1)
26
27
/* Font structure */
28
typedef struct {
29
sg_image atlas;
30
sg_view atlas_view;
31
sg_sampler sampler;
32
int atlas_width;
33
int atlas_height;
34
float font_size;
35
float ascent;
36
float descent;
37
float line_gap;
38
stbtt_bakedchar char_data[NUM_CHARS];
39
} StudioFont;
40
41
/* Initialize font type tag */
42
static void ensure_font_type(SigilVM *vm)
43
{
44
if (sigil_is_undefined(font_type_tag)) {
45
font_type_tag = sigil_intern_symbol(vm, "sigil-studio-font", 17);
46
}
47
}
48
49
/* Get font from Value */
50
static StudioFont *get_font(SigilVM *vm, Value v)
51
{
52
if (!sigil_is_foreign(v)) return NULL;
53
ensure_font_type(vm);
54
if (sigil_foreign_type(v) != font_type_tag) return NULL;
55
return (StudioFont *)sigil_foreign_data(v);
56
}
57
58
/* Font destructor */
59
static void font_destructor(void *data)
60
{
61
StudioFont *font = (StudioFont *)data;
62
if (font) {
63
if (font->atlas_view.id != SG_INVALID_ID) {
64
sg_destroy_view(font->atlas_view);
65
}
66
if (font->atlas.id != SG_INVALID_ID) {
67
sg_destroy_image(font->atlas);
68
}
69
if (font->sampler.id != SG_INVALID_ID) {
70
sg_destroy_sampler(font->sampler);
71
}
72
free(font);
73
}
74
}
75
76
/* Helper to read entire file */
77
static unsigned char *read_file(const char *path, size_t *size_out)
78
{
79
FILE *f = fopen(path, "rb");
80
if (!f) return NULL;
81
82
fseek(f, 0, SEEK_END);
83
size_t size = (size_t)ftell(f);
84
fseek(f, 0, SEEK_SET);
85
86
unsigned char *data = malloc(size);
87
if (!data) {
88
fclose(f);
89
return NULL;
90
}
91
92
if (fread(data, 1, size, f) != size) {
93
free(data);
94
fclose(f);
95
return NULL;
96
}
97
98
fclose(f);
99
if (size_out) *size_out = size;
100
return data;
101
}
102
103
/* Helper to extract float from fixnum or flonum */
104
static float value_to_float(Value v)
105
{
106
if (sigil_is_fixnum(v)) {
107
return (float)sigil_as_fixnum(v);
108
} else if (sigil_is_flonum(v)) {
109
return (float)sigil_as_flonum(v);
110
}
111
return 0.0f;
112
}
113
114
/*
115
* (load-font path size) -> <font> or #f
116
*
117
* Load a TrueType font and rasterize it at the given pixel size.
118
*/
119
static Value native_load_font(SigilVM *vm, int argc, Value *args)
120
{
121
if (argc < 2) {
122
sigil__vm_error(vm, SIGIL_ERR_ARITY, "load-font: requires path and size");
123
return SIGIL_UNDEFINED;
124
}
125
126
if (!sigil_is_string(args[0])) {
127
sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "load-font: expected string path");
128
return SIGIL_FALSE;
129
}
130
131
SigilString *path_str = (SigilString *)sigil_as_ptr(args[0]);
132
const char *path = path_str->data;
133
float font_size = value_to_float(args[1]);
134
135
if (font_size < 1.0f) font_size = 16.0f;
136
137
/* Read font file */
138
size_t font_data_size;
139
unsigned char *font_data = read_file(path, &font_data_size);
140
if (!font_data) {
141
return SIGIL_FALSE;
142
}
143
144
/* Calculate atlas size based on font size */
145
int atlas_width = 512;
146
int atlas_height = 512;
147
if (font_size > 32) {
148
atlas_width = 1024;
149
atlas_height = 1024;
150
}
151
152
/* Allocate atlas bitmap */
153
unsigned char *atlas_bitmap = calloc(1, (size_t)(atlas_width * atlas_height));
154
if (!atlas_bitmap) {
155
free(font_data);
156
sigil__vm_set_error(vm, SIGIL_ERR_MEMORY, "load-font: out of memory");
157
return SIGIL_FALSE;
158
}
159
160
/* Create font structure */
161
StudioFont *font = calloc(1, sizeof(StudioFont));
162
if (!font) {
163
free(atlas_bitmap);
164
free(font_data);
165
sigil__vm_set_error(vm, SIGIL_ERR_MEMORY, "load-font: out of memory");
166
return SIGIL_FALSE;
167
}
168
169
/* Bake font to atlas */
170
int result = stbtt_BakeFontBitmap(font_data, 0, font_size,
171
atlas_bitmap, atlas_width, atlas_height,
172
FIRST_CHAR, NUM_CHARS, font->char_data);
173
if (result <= 0) {
174
free(font);
175
free(atlas_bitmap);
176
free(font_data);
177
sigil__vm_set_error(vm, SIGIL_ERR_RUNTIME, "load-font: failed to bake font");
178
return SIGIL_FALSE;
179
}
180
181
/* Get font metrics */
182
stbtt_fontinfo info;
183
if (stbtt_InitFont(&info, font_data, 0)) {
184
float scale = stbtt_ScaleForPixelHeight(&info, font_size);
185
int ascent, descent, line_gap;
186
stbtt_GetFontVMetrics(&info, &ascent, &descent, &line_gap);
187
font->ascent = (float)ascent * scale;
188
font->descent = (float)descent * scale;
189
font->line_gap = (float)line_gap * scale;
190
}
191
192
free(font_data);
193
194
/* Convert 8-bit bitmap to RGBA for GPU */
195
unsigned char *rgba = malloc((size_t)(atlas_width * atlas_height * 4));
196
if (!rgba) {
197
free(font);
198
free(atlas_bitmap);
199
sigil__vm_set_error(vm, SIGIL_ERR_MEMORY, "load-font: out of memory");
200
return SIGIL_FALSE;
201
}
202
203
for (int i = 0; i < atlas_width * atlas_height; i++) {
204
rgba[i * 4 + 0] = 255; /* R */
205
rgba[i * 4 + 1] = 255; /* G */
206
rgba[i * 4 + 2] = 255; /* B */
207
rgba[i * 4 + 3] = atlas_bitmap[i]; /* A from grayscale */
208
}
209
free(atlas_bitmap);
210
211
/* Create GPU texture */
212
sg_image_desc img_desc = {
213
.width = atlas_width,
214
.height = atlas_height,
215
.pixel_format = SG_PIXELFORMAT_RGBA8,
216
.data.mip_levels[0] = {
217
.ptr = rgba,
218
.size = (size_t)(atlas_width * atlas_height * 4)
219
}
220
};
221
font->atlas = sg_make_image(&img_desc);
222
free(rgba);
223
224
if (font->atlas.id == SG_INVALID_ID) {
225
free(font);
226
sigil__vm_set_error(vm, SIGIL_ERR_RUNTIME, "load-font: failed to create atlas texture");
227
return SIGIL_FALSE;
228
}
229
230
/* Create view for sokol_gp */
231
font->atlas_view = sgp_make_texture_view_from_image(font->atlas, "font-atlas");
232
if (font->atlas_view.id == SG_INVALID_ID) {
233
sg_destroy_image(font->atlas);
234
free(font);
235
sigil__vm_set_error(vm, SIGIL_ERR_RUNTIME, "load-font: failed to create texture view");
236
return SIGIL_FALSE;
237
}
238
239
/* Create sampler (linear filtering for smooth text) */
240
sg_sampler_desc smp_desc = {
241
.min_filter = SG_FILTER_LINEAR,
242
.mag_filter = SG_FILTER_LINEAR,
243
.wrap_u = SG_WRAP_CLAMP_TO_EDGE,
244
.wrap_v = SG_WRAP_CLAMP_TO_EDGE
245
};
246
font->sampler = sg_make_sampler(&smp_desc);
247
248
font->atlas_width = atlas_width;
249
font->atlas_height = atlas_height;
250
font->font_size = font_size;
251
252
ensure_font_type(vm);
253
return sigil_make_foreign(vm, font_type_tag, font, font_destructor,
254
sizeof(StudioFont));
255
}
256
257
/*
258
* (font? obj) -> boolean
259
*/
260
static Value native_font_p(SigilVM *vm, int argc, Value *args)
261
{
262
(void)argc;
263
return get_font(vm, args[0]) ? SIGIL_TRUE : SIGIL_FALSE;
264
}
265
266
/*
267
* (font-size font) -> number
268
*/
269
static Value native_font_size(SigilVM *vm, int argc, Value *args)
270
{
271
(void)argc;
272
StudioFont *font = get_font(vm, args[0]);
273
if (!font) {
274
sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "font-size: expected font");
275
return SIGIL_UNDEFINED;
276
}
277
return sigil_flonum(font->font_size);
278
}
279
280
/*
281
* (font-line-height font) -> number
282
*
283
* Returns the recommended line height (ascent - descent + line_gap).
284
*/
285
static Value native_font_line_height(SigilVM *vm, int argc, Value *args)
286
{
287
(void)argc;
288
StudioFont *font = get_font(vm, args[0]);
289
if (!font) {
290
sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "font-line-height: expected font");
291
return SIGIL_UNDEFINED;
292
}
293
float line_height = font->ascent - font->descent + font->line_gap;
294
return sigil_flonum(line_height);
295
}
296
297
/*
298
* (draw-text-char font char x y) -> number (advance width)
299
*
300
* Draw a single character at position. Returns the advance width for spacing.
301
* This is useful for custom text effects like wavy text.
302
*/
303
static Value native_draw_text_char(SigilVM *vm, int argc, Value *args)
304
{
305
if (argc < 4) {
306
sigil__vm_error(vm, SIGIL_ERR_ARITY, "draw-text-char: requires font, char, x, y");
307
return SIGIL_UNDEFINED;
308
}
309
310
StudioFont *font = get_font(vm, args[0]);
311
if (!font) {
312
sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "draw-text-char: expected font");
313
return SIGIL_UNDEFINED;
314
}
315
316
/* Get character - accept either a char or single-char string */
317
int c;
318
if (sigil_is_char(args[1])) {
319
c = (unsigned char)sigil_as_char(args[1]);
320
} else if (sigil_is_string(args[1])) {
321
SigilString *s = (SigilString *)sigil_as_ptr(args[1]);
322
if (s->byte_length == 0) return sigil_flonum(0.0);
323
c = (unsigned char)s->data[0];
324
} else {
325
sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "draw-text-char: expected char or string");
326
return SIGIL_UNDEFINED;
327
}
328
329
float x = value_to_float(args[2]);
330
float y = value_to_float(args[3]);
331
332
/* Handle characters outside our range */
333
if (c < FIRST_CHAR || c > LAST_CHAR) {
334
return sigil_flonum(0.0);
335
}
336
337
stbtt_bakedchar *bc = &font->char_data[c - FIRST_CHAR];
338
339
/* Bind font atlas */
340
sgp_set_view(0, font->atlas_view);
341
sgp_set_sampler(0, font->sampler);
342
sgp_set_blend_mode(SGP_BLENDMODE_BLEND);
343
344
/* Destination rectangle */
345
float dx = x + bc->xoff;
346
float dy = y + bc->yoff;
347
float dw = bc->x1 - bc->x0;
348
float dh = bc->y1 - bc->y0;
349
350
/* Source rectangle in atlas */
351
float sx = (float)bc->x0;
352
float sy = (float)bc->y0;
353
float sw = (float)(bc->x1 - bc->x0);
354
float sh = (float)(bc->y1 - bc->y0);
355
356
sgp_rect dest = {dx, dy, dw, dh};
357
sgp_rect src = {sx, sy, sw, sh};
358
sgp_draw_textured_rect(0, dest, src);
359
360
/* Reset state */
361
sgp_reset_view(0);
362
sgp_reset_sampler(0);
363
364
return sigil_flonum(bc->xadvance);
365
}
366
367
/*
368
* (draw-text font text x y) -> void
369
*
370
* Draw text at the given position. x,y is the baseline start position.
371
*/
372
static Value native_draw_text(SigilVM *vm, int argc, Value *args)
373
{
374
if (argc < 4) {
375
sigil__vm_error(vm, SIGIL_ERR_ARITY, "draw-text: requires font, text, x, y");
376
return SIGIL_UNDEFINED;
377
}
378
379
StudioFont *font = get_font(vm, args[0]);
380
if (!font) {
381
sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "draw-text: expected font");
382
return SIGIL_UNDEFINED;
383
}
384
385
if (!sigil_is_string(args[1])) {
386
sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "draw-text: expected string");
387
return SIGIL_UNDEFINED;
388
}
389
390
SigilString *text_str = (SigilString *)sigil_as_ptr(args[1]);
391
const char *text = text_str->data;
392
float x = value_to_float(args[2]);
393
float y = value_to_float(args[3]);
394
395
/* Bind font atlas */
396
sgp_set_view(0, font->atlas_view);
397
sgp_set_sampler(0, font->sampler);
398
399
/* Enable blending for text */
400
sgp_set_blend_mode(SGP_BLENDMODE_BLEND);
401
402
/* Draw each character */
403
float cursor_x = x;
404
for (const char *p = text; *p; p++) {
405
int c = (unsigned char)*p;
406
407
/* Skip characters outside our range */
408
if (c < FIRST_CHAR || c > LAST_CHAR) {
409
if (c == '\n') {
410
cursor_x = x;
411
y += font->ascent - font->descent + font->line_gap;
412
}
413
continue;
414
}
415
416
stbtt_bakedchar *bc = &font->char_data[c - FIRST_CHAR];
417
418
/* Destination rectangle */
419
float dx = cursor_x + bc->xoff;
420
float dy = y + bc->yoff;
421
float dw = bc->x1 - bc->x0;
422
float dh = bc->y1 - bc->y0;
423
424
/* Source rectangle in atlas (in pixels) */
425
float sx = (float)bc->x0;
426
float sy = (float)bc->y0;
427
float sw = (float)(bc->x1 - bc->x0);
428
float sh = (float)(bc->y1 - bc->y0);
429
430
sgp_rect dest = {dx, dy, dw, dh};
431
sgp_rect src = {sx, sy, sw, sh};
432
sgp_draw_textured_rect(0, dest, src);
433
434
cursor_x += bc->xadvance;
435
}
436
437
/* Reset state */
438
sgp_reset_view(0);
439
sgp_reset_sampler(0);
440
441
return SIGIL_NIL;
442
}
443
444
/*
445
* (text-width font text) -> number
446
*
447
* Calculate the width of text in pixels.
448
*/
449
static Value native_text_width(SigilVM *vm, int argc, Value *args)
450
{
451
if (argc < 2) {
452
sigil__vm_error(vm, SIGIL_ERR_ARITY, "text-width: requires font and text");
453
return SIGIL_UNDEFINED;
454
}
455
456
StudioFont *font = get_font(vm, args[0]);
457
if (!font) {
458
sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "text-width: expected font");
459
return SIGIL_UNDEFINED;
460
}
461
462
if (!sigil_is_string(args[1])) {
463
sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "text-width: expected string");
464
return SIGIL_UNDEFINED;
465
}
466
467
SigilString *text_str = (SigilString *)sigil_as_ptr(args[1]);
468
const char *text = text_str->data;
469
470
float width = 0.0f;
471
for (const char *p = text; *p; p++) {
472
int c = (unsigned char)*p;
473
if (c >= FIRST_CHAR && c <= LAST_CHAR) {
474
width += font->char_data[c - FIRST_CHAR].xadvance;
475
}
476
}
477
478
return sigil_flonum(width);
479
}
480
481
/*
482
* Module initialization
483
*/
484
void sigil__init_sigil_studio_font_module(SigilVM *vm)
485
{
486
SigilModule *module = sigil_begin_module(vm, "(sigil studio font)");
487
if (!module) return;
488
489
sigil_module_register_native(vm, "load-font", native_load_font,
490
SIGIL_ARITY_EXACT(2), "Load TrueType font at size");
491
sigil_module_register_native(vm, "font?", native_font_p,
492
SIGIL_ARITY_EXACT(1), "Check if object is a font");
493
sigil_module_register_native(vm, "font-size", native_font_size,
494
SIGIL_ARITY_EXACT(1), "Get font pixel size");
495
sigil_module_register_native(vm, "font-line-height", native_font_line_height,
496
SIGIL_ARITY_EXACT(1), "Get recommended line height");
497
sigil_module_register_native(vm, "draw-text", native_draw_text,
498
SIGIL_ARITY_EXACT(4), "Draw text at position");
499
sigil_module_register_native(vm, "draw-text-char", native_draw_text_char,

Showing the first 500 of 514 diff lines for this file. This diff is INCOMPLETE; read the file or clone the repository for the rest.

src/c/graphics.cdeleted
@@ -1,909 +0,0 @@
1
/*
2
* graphics.c - Sigil Studio Graphics Module
3
*
4
* Wraps sokol_gfx.h to provide 2D/3D rendering capabilities.
5
*/
6
7
#include "studio-internal.h"
8
#include "sigil-internal.h"
9
10
/* Sokol headers (implementation is in sokol.c) */
11
#include "sokol_app.h"
12
#include "sokol_gfx.h"
13
#include "sokol_glue.h"
14
#include "sokol_gp.h"
15
16
#include <stdio.h>
17
#include <stdlib.h>
18
19
/* External: get pixel data from image (defined in image.c) */
20
extern unsigned char *sigil_studio_image_pixels(SigilVM *vm, Value img_val, int *width, int *height);
21
22
/* Texture type tag (initialized at module init) */
23
static Value texture_type_tag = SIGIL_UNDEFINED;
24
25
/* Texture structure */
26
typedef struct {
27
sg_image handle;
28
sg_sampler sampler;
29
sg_view view;
30
int width;
31
int height;
32
} StudioTexture;
33
34
/* Current draw color */
35
static float draw_color[4] = {1.0f, 1.0f, 1.0f, 1.0f};
36
37
/* Clear color (set by clear, used in end-frame) */
38
static float clear_color[4] = {0.0f, 0.0f, 0.0f, 1.0f};
39
40
/* SGP initialized flag */
41
static bool sgp_initialized = false;
42
43
/* Virtual viewport state */
44
static bool virtual_viewport_enabled = false;
45
static int virtual_width = 0;
46
static int virtual_height = 0;
47
48
/* Letterbox color (bars outside viewport) */
49
static float letterbox_color[4] = {0.0f, 0.0f, 0.0f, 1.0f};
50
51
/* Helper to extract float from fixnum or flonum */
52
static float value_to_float(Value v)
53
{
54
if (sigil_is_fixnum(v)) {
55
return (float)sigil_as_fixnum(v);
56
} else if (sigil_is_flonum(v)) {
57
return (float)sigil_as_flonum(v);
58
}
59
return 0.0f;
60
}
61
62
/* ============================================================
63
* NATIVE FUNCTIONS
64
* ============================================================ */
65
66
/*
67
* (gfx-setup) - Initialize graphics subsystem
68
* Called automatically by app-run, but can be called manually.
69
*/
70
static Value native_gfx_setup(SigilVM *vm, int argc, Value *args)
71
{
72
(void)vm; (void)argc; (void)args;
73
74
if (g_studio && g_studio->gfx_initialized) {
75
return SIGIL_NIL;
76
}
77
78
/* Initialize sokol_gfx */
79
sg_desc desc = {
80
.environment = sglue_environment(),
81
};
82
sg_setup(&desc);
83
84
/* Initialize sokol_gp for 2D rendering */
85
sgp_desc sgpdesc = {0};
86
sgp_setup(&sgpdesc);
87
if (!sgp_is_valid()) {
88
fprintf(stderr, "Failed to initialize sokol_gp\n");
89
sg_shutdown();
90
return SIGIL_FALSE;
91
}
92
sgp_initialized = true;
93
94
if (g_studio) {
95
g_studio->gfx_initialized = true;
96
}
97
98
return SIGIL_NIL;
99
}
100
101
/*
102
* (gfx-shutdown) - Shutdown graphics subsystem
103
*/
104
static Value native_gfx_shutdown(SigilVM *vm, int argc, Value *args)
105
{
106
(void)vm; (void)argc; (void)args;
107
108
if (g_studio && g_studio->gfx_initialized) {
109
if (sgp_initialized) {
110
sgp_shutdown();
111
sgp_initialized = false;
112
}
113
sg_shutdown();
114
g_studio->gfx_initialized = false;
115
}
116
117
return SIGIL_NIL;
118
}
119
120
/*
121
* (set-letterbox-color r g b [a]) - Set the color for letterbox bars
122
*
123
* Default is black. Only visible when using a virtual viewport.
124
*/
125
static Value native_set_letterbox_color(SigilVM *vm, int argc, Value *args)
126
{
127
if (argc < 3) {
128
sigil__vm_error(vm, SIGIL_ERR_ARITY, "set-letterbox-color: requires r, g, b arguments");
129
return SIGIL_UNDEFINED;
130
}
131
132
letterbox_color[0] = value_to_float(args[0]);
133
letterbox_color[1] = value_to_float(args[1]);
134
letterbox_color[2] = value_to_float(args[2]);
135
letterbox_color[3] = argc > 3 ? value_to_float(args[3]) : 1.0f;
136
137
return SIGIL_NIL;
138
}
139
140
/*
141
* (set-viewport width height) - Set virtual viewport with letterboxing
142
*
143
* Creates a fixed coordinate space that maintains aspect ratio.
144
* Black bars are added as needed to fill the window.
145
* Call with #f to disable and use window coordinates.
146
*/
147
static Value native_set_viewport(SigilVM *vm, int argc, Value *args)
148
{
149
(void)vm;
150
151
if (argc == 1 && sigil_is_false(args[0])) {
152
/* Disable virtual viewport */
153
virtual_viewport_enabled = false;
154
return SIGIL_NIL;
155
}
156
157
if (argc < 2) {
158
sigil__vm_error(vm, SIGIL_ERR_ARITY, "set-viewport: requires width, height");
159
return SIGIL_UNDEFINED;
160
}
161
162
virtual_viewport_enabled = true;
163
virtual_width = (int)value_to_float(args[0]);
164
virtual_height = (int)value_to_float(args[1]);
165
166
return SIGIL_NIL;
167
}
168
169
/*
170
* (begin-frame) - Begin a new frame
171
*/
172
static Value native_begin_frame(SigilVM *vm, int argc, Value *args)
173
{
174
(void)vm; (void)argc; (void)args;
175
176
int window_w = sapp_width();
177
int window_h = sapp_height();
178
179
/* Begin sokol_gp frame with full window size */
180
sgp_begin(window_w, window_h);
181
182
if (virtual_viewport_enabled && virtual_width > 0 && virtual_height > 0) {
183
/* Calculate letterbox viewport */
184
float scale_x = (float)window_w / (float)virtual_width;
185
float scale_y = (float)window_h / (float)virtual_height;
186
float scale = (scale_x < scale_y) ? scale_x : scale_y;
187
188
int viewport_w = (int)(virtual_width * scale);
189
int viewport_h = (int)(virtual_height * scale);
190
int viewport_x = (window_w - viewport_w) / 2;
191
int viewport_y = (window_h - viewport_h) / 2;
192
193
sgp_viewport(viewport_x, viewport_y, viewport_w, viewport_h);
194
sgp_project(0, (float)virtual_width, 0, (float)virtual_height);
195
} else {
196
/* Default: use window coordinates */
197
sgp_viewport(0, 0, window_w, window_h);
198
sgp_project(0, (float)window_w, 0, (float)window_h);
199
}
200
201
/* Reset to white draw color */
202
sgp_set_color(1.0f, 1.0f, 1.0f, 1.0f);
203
204
return SIGIL_NIL;
205
}
206
207
/*
208
* (end-frame) - End the current frame
209
*/
210
static Value native_end_frame(SigilVM *vm, int argc, Value *args)
211
{
212
(void)vm; (void)argc; (void)args;
213
214
/* Begin render pass - clear to letterbox color */
215
sg_pass_action pass_action = {
216
.colors[0] = {
217
.load_action = SG_LOADACTION_CLEAR,
218
.clear_value = {letterbox_color[0], letterbox_color[1],
219
letterbox_color[2], letterbox_color[3]}
220
}
221
};
222
sg_pass pass = {
223
.action = pass_action,
224
.swapchain = sglue_swapchain()
225
};
226
sg_begin_pass(&pass);
227
228
/* Flush sokol_gp commands to GPU */
229
sgp_flush();
230
sgp_end();
231
232
sg_end_pass();
233
sg_commit();
234
235
return SIGIL_NIL;
236
}
237
238
/*
239
* (clear-screen r g b [a]) - Clear the viewport with a color
240
*
241
* When using a virtual viewport, this fills the viewport area.
242
* The letterbox bars remain the pass clear color (black).
243
*/
244
static Value native_clear_screen(SigilVM *vm, int argc, Value *args)
245
{
246
if (argc < 3) {
247
sigil__vm_error(vm, SIGIL_ERR_ARITY, "clear-screen: requires r, g, b arguments");
248
return SIGIL_UNDEFINED;
249
}
250
251
float r = value_to_float(args[0]);
252
float g = value_to_float(args[1]);
253
float b = value_to_float(args[2]);
254
float a = argc > 3 ? value_to_float(args[3]) : 1.0f;
255
256
/* Draw a filled rectangle covering the entire viewport/projection area */
257
sgp_set_color(r, g, b, a);
258
if (virtual_viewport_enabled && virtual_width > 0 && virtual_height > 0) {
259
sgp_draw_filled_rect(0, 0, (float)virtual_width, (float)virtual_height);
260
} else {
261
sgp_draw_filled_rect(0, 0, (float)sapp_width(), (float)sapp_height());
262
}
263
264
/* Reset to white for subsequent drawing */
265
sgp_set_color(1.0f, 1.0f, 1.0f, 1.0f);
266
267
return SIGIL_NIL;
268
}
269
270
/*
271
* (set-color r g b [a]) - Set current draw color
272
*/
273
static Value native_set_color(SigilVM *vm, int argc, Value *args)
274
{
275
if (argc < 3) {
276
sigil__vm_error(vm, SIGIL_ERR_ARITY, "set-color: requires r, g, b arguments");
277
return SIGIL_UNDEFINED;
278
}
279
280
draw_color[0] = value_to_float(args[0]);
281
draw_color[1] = value_to_float(args[1]);
282
draw_color[2] = value_to_float(args[2]);
283
draw_color[3] = argc > 3 ? value_to_float(args[3]) : 1.0f;
284
285
/* Set sokol_gp color */
286
sgp_set_color(draw_color[0], draw_color[1], draw_color[2], draw_color[3]);
287
288
return SIGIL_NIL;
289
}
290
291
/*
292
* (draw-filled-rect x y w h) - Draw a filled rectangle
293
*/
294
static Value native_draw_filled_rect(SigilVM *vm, int argc, Value *args)
295
{
296
if (argc < 4) {
297
sigil__vm_error(vm, SIGIL_ERR_ARITY, "draw-filled-rect: requires x, y, w, h arguments");
298
return SIGIL_UNDEFINED;
299
}
300
301
float x = value_to_float(args[0]);
302
float y = value_to_float(args[1]);
303
float w = value_to_float(args[2]);
304
float h = value_to_float(args[3]);
305
306
sgp_draw_filled_rect(x, y, w, h);
307
308
return SIGIL_NIL;
309
}
310
311
/*
312
* (draw-rect x y w h) - Draw a rectangle outline
313
*/
314
static Value native_draw_rect(SigilVM *vm, int argc, Value *args)
315
{
316
if (argc < 4) {
317
sigil__vm_error(vm, SIGIL_ERR_ARITY, "draw-rect: requires x, y, w, h arguments");
318
return SIGIL_UNDEFINED;
319
}
320
321
float x = value_to_float(args[0]);
322
float y = value_to_float(args[1]);
323
float w = value_to_float(args[2]);
324
float h = value_to_float(args[3]);
325
326
/* Draw rectangle outline using 4 lines */
327
sgp_line lines[4] = {
328
{{x, y}, {x + w, y}}, /* top */
329
{{x + w, y}, {x + w, y + h}}, /* right */
330
{{x + w, y + h}, {x, y + h}}, /* bottom */
331
{{x, y + h}, {x, y}} /* left */
332
};
333
sgp_draw_lines(lines, 4);
334
335
return SIGIL_NIL;
336
}
337
338
/*
339
* (draw-line x1 y1 x2 y2) - Draw a line
340
*/
341
static Value native_draw_line(SigilVM *vm, int argc, Value *args)
342
{
343
if (argc < 4) {
344
sigil__vm_error(vm, SIGIL_ERR_ARITY, "draw-line: requires x1, y1, x2, y2 arguments");
345
return SIGIL_UNDEFINED;
346
}
347
348
float x1 = value_to_float(args[0]);
349
float y1 = value_to_float(args[1]);
350
float x2 = value_to_float(args[2]);
351
float y2 = value_to_float(args[3]);
352
353
sgp_line line = {{x1, y1}, {x2, y2}};
354
sgp_draw_lines(&line, 1);
355
356
return SIGIL_NIL;
357
}
358
359
/*
360
* (draw-point x y) - Draw a single point
361
*/
362
static Value native_draw_point(SigilVM *vm, int argc, Value *args)
363
{
364
if (argc < 2) {
365
sigil__vm_error(vm, SIGIL_ERR_ARITY, "draw-point: requires x, y arguments");
366
return SIGIL_UNDEFINED;
367
}
368
369
float x = value_to_float(args[0]);
370
float y = value_to_float(args[1]);
371
372
sgp_point pt = {x, y};
373
sgp_draw_points(&pt, 1);
374
375
return SIGIL_NIL;
376
}
377
378
/*
379
* (draw-triangle x1 y1 x2 y2 x3 y3) - Draw a triangle outline
380
*/
381
static Value native_draw_triangle(SigilVM *vm, int argc, Value *args)
382
{
383
if (argc < 6) {
384
sigil__vm_error(vm, SIGIL_ERR_ARITY, "draw-triangle: requires x1, y1, x2, y2, x3, y3");
385
return SIGIL_UNDEFINED;
386
}
387
388
float x1 = value_to_float(args[0]);
389
float y1 = value_to_float(args[1]);
390
float x2 = value_to_float(args[2]);
391
float y2 = value_to_float(args[3]);
392
float x3 = value_to_float(args[4]);
393
float y3 = value_to_float(args[5]);
394
395
sgp_line lines[3] = {
396
{{x1, y1}, {x2, y2}},
397
{{x2, y2}, {x3, y3}},
398
{{x3, y3}, {x1, y1}}
399
};
400
sgp_draw_lines(lines, 3);
401
402
return SIGIL_NIL;
403
}
404
405
/*
406
* (fill-triangle x1 y1 x2 y2 x3 y3) - Draw a filled triangle
407
*/
408
static Value native_fill_triangle(SigilVM *vm, int argc, Value *args)
409
{
410
if (argc < 6) {
411
sigil__vm_error(vm, SIGIL_ERR_ARITY, "fill-triangle: requires x1, y1, x2, y2, x3, y3");
412
return SIGIL_UNDEFINED;
413
}
414
415
float x1 = value_to_float(args[0]);
416
float y1 = value_to_float(args[1]);
417
float x2 = value_to_float(args[2]);
418
float y2 = value_to_float(args[3]);
419
float x3 = value_to_float(args[4]);
420
float y3 = value_to_float(args[5]);
421
422
sgp_triangle tri = {{x1, y1}, {x2, y2}, {x3, y3}};
423
sgp_draw_filled_triangles(&tri, 1);
424
425
return SIGIL_NIL;
426
}
427
428
/* ============================================================
429
* TRANSFORM STACK
430
* ============================================================ */
431
432
/*
433
* (push-transform) - Save current transform state
434
*/
435
static Value native_push_transform(SigilVM *vm, int argc, Value *args)
436
{
437
(void)vm; (void)argc; (void)args;
438
sgp_push_transform();
439
return SIGIL_NIL;
440
}
441
442
/*
443
* (pop-transform) - Restore previous transform state
444
*/
445
static Value native_pop_transform(SigilVM *vm, int argc, Value *args)
446
{
447
(void)vm; (void)argc; (void)args;
448
sgp_pop_transform();
449
return SIGIL_NIL;
450
}
451
452
/*
453
* (reset-transform) - Reset to identity transform
454
*/
455
static Value native_reset_transform(SigilVM *vm, int argc, Value *args)
456
{
457
(void)vm; (void)argc; (void)args;
458
sgp_reset_transform();
459
return SIGIL_NIL;
460
}
461
462
/*
463
* (translate x y) - Translate by (x, y)
464
*/
465
static Value native_translate(SigilVM *vm, int argc, Value *args)
466
{
467
if (argc < 2) {
468
sigil__vm_error(vm, SIGIL_ERR_ARITY, "translate: requires x, y arguments");
469
return SIGIL_UNDEFINED;
470
}
471
472
float x = value_to_float(args[0]);
473
float y = value_to_float(args[1]);
474
475
sgp_translate(x, y);
476
477
return SIGIL_NIL;
478
}
479
480
/*
481
* (rotate angle) - Rotate by angle (in radians)
482
*/
483
static Value native_rotate(SigilVM *vm, int argc, Value *args)
484
{
485
if (argc < 1) {
486
sigil__vm_error(vm, SIGIL_ERR_ARITY, "rotate: requires angle argument");
487
return SIGIL_UNDEFINED;
488
}
489
490
float angle = value_to_float(args[0]);
491
sgp_rotate(angle);
492
493
return SIGIL_NIL;
494
}
495
496
/*
497
* (rotate-at angle x y) - Rotate around point (x, y)
498
*/
499
static Value native_rotate_at(SigilVM *vm, int argc, Value *args)

Showing the first 500 of 910 diff lines for this file. This diff is INCOMPLETE; read the file or clone the repository for the rest.

src/c/image.cdeleted
@@ -1,236 +0,0 @@
1
/*
2
* image.c - CPU-side image loading for Sigil Studio
3
*
4
* Provides image loading using stb_image. Images are loaded into CPU memory
5
* and can be inspected or converted to GPU textures via (sigil studio graphics).
6
*/
7
8
#include "sigil-internal.h"
9
#include <stdio.h>
10
#include <stdlib.h>
11
#include <string.h>
12
13
#include "stb_image.h"
14
15
/* Image type tag (initialized at module init) */
16
static Value image_type_tag = SIGIL_UNDEFINED;
17
18
/* Image structure stored as foreign object */
19
typedef struct {
20
unsigned char *pixels; /* RGBA pixel data */
21
int width;
22
int height;
23
int channels; /* Always 4 (RGBA) after loading */
24
} StudioImage;
25
26
/* Initialize image type tag */
27
static void ensure_image_type(SigilVM *vm)
28
{
29
if (sigil_is_undefined(image_type_tag)) {
30
image_type_tag = sigil_intern_symbol(vm, "sigil-studio-image", 18);
31
}
32
}
33
34
/* Get image from Value, returns NULL if not an image */
35
static StudioImage *get_image(SigilVM *vm, Value v)
36
{
37
if (!sigil_is_foreign(v)) return NULL;
38
ensure_image_type(vm);
39
if (sigil_foreign_type(v) != image_type_tag) return NULL;
40
return (StudioImage *)sigil_foreign_data(v);
41
}
42
43
/* Destructor for image foreign object */
44
static void image_destructor(void *data)
45
{
46
StudioImage *img = (StudioImage *)data;
47
if (img) {
48
if (img->pixels) {
49
stbi_image_free(img->pixels);
50
}
51
free(img);
52
}
53
}
54
55
/*
56
* (load-image path) -> <image> or #f
57
*
58
* Load an image file from disk. Returns an image object or #f on failure.
59
* Supported formats: PNG, JPEG, BMP, TGA, GIF, HDR, PSD, PIC, PNM
60
*/
61
static Value native_load_image(SigilVM *vm, int argc, Value *args)
62
{
63
(void)argc;
64
65
if (!sigil_is_string(args[0])) {
66
sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "load-image: expected string path");
67
return SIGIL_FALSE;
68
}
69
70
SigilString *path_str = (SigilString *)sigil_as_ptr(args[0]);
71
const char *path = path_str->data;
72
73
int width, height, channels;
74
/* Always request 4 channels (RGBA) for consistency */
75
unsigned char *pixels = stbi_load(path, &width, &height, &channels, 4);
76
77
if (!pixels) {
78
/* Return #f on failure - don't set error, let caller handle it */
79
return SIGIL_FALSE;
80
}
81
82
/* Create image structure */
83
StudioImage *img = malloc(sizeof(StudioImage));
84
if (!img) {
85
stbi_image_free(pixels);
86
sigil__vm_set_error(vm, SIGIL_ERR_MEMORY, "load-image: out of memory");
87
return SIGIL_FALSE;
88
}
89
90
img->pixels = pixels;
91
img->width = width;
92
img->height = height;
93
img->channels = 4; /* We always load as RGBA */
94
95
/* Wrap in foreign object */
96
ensure_image_type(vm);
97
return sigil_make_foreign(vm, image_type_tag, img, image_destructor,
98
sizeof(StudioImage) + (size_t)(width * height * 4));
99
}
100
101
/*
102
* (image? obj) -> boolean
103
*
104
* Check if object is an image.
105
*/
106
static Value native_image_p(SigilVM *vm, int argc, Value *args)
107
{
108
(void)argc;
109
return get_image(vm, args[0]) ? SIGIL_TRUE : SIGIL_FALSE;
110
}
111
112
/*
113
* (image-width img) -> integer
114
*
115
* Get image width in pixels.
116
*/
117
static Value native_image_width(SigilVM *vm, int argc, Value *args)
118
{
119
(void)argc;
120
121
StudioImage *img = get_image(vm, args[0]);
122
if (!img) {
123
sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "image-width: expected image");
124
return SIGIL_UNDEFINED;
125
}
126
127
return sigil_fixnum(img->width);
128
}
129
130
/*
131
* (image-height img) -> integer
132
*
133
* Get image height in pixels.
134
*/
135
static Value native_image_height(SigilVM *vm, int argc, Value *args)
136
{
137
(void)argc;
138
139
StudioImage *img = get_image(vm, args[0]);
140
if (!img) {
141
sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "image-height: expected image");
142
return SIGIL_UNDEFINED;
143
}
144
145
return sigil_fixnum(img->height);
146
}
147
148
/*
149
* (image-channels img) -> integer
150
*
151
* Get number of channels (always 4 for RGBA).
152
*/
153
static Value native_image_channels(SigilVM *vm, int argc, Value *args)
154
{
155
(void)argc;
156
157
StudioImage *img = get_image(vm, args[0]);
158
if (!img) {
159
sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "image-channels: expected image");
160
return SIGIL_UNDEFINED;
161
}
162
163
return sigil_fixnum(img->channels);
164
}
165
166
/*
167
* (image-free! img) -> void
168
*
169
* Free the CPU-side pixel data. The image object becomes invalid.
170
* This is optional - GC will clean up automatically, but this allows
171
* explicit memory management for large images.
172
*/
173
static Value native_image_free(SigilVM *vm, int argc, Value *args)
174
{
175
(void)argc;
176
177
StudioImage *img = get_image(vm, args[0]);
178
if (!img) {
179
sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "image-free!: expected image");
180
return SIGIL_UNDEFINED;
181
}
182
183
if (img->pixels) {
184
stbi_image_free(img->pixels);
185
img->pixels = NULL;
186
img->width = 0;
187
img->height = 0;
188
}
189
190
return SIGIL_NIL;
191
}
192
193
/*
194
* Internal: Get pixel data pointer for use by graphics module.
195
* Returns NULL if image is invalid or freed.
196
*/
197
unsigned char *sigil_studio_image_pixels(SigilVM *vm, Value img_val, int *width, int *height)
198
{
199
StudioImage *img = get_image(vm, img_val);
200
if (!img || !img->pixels) return NULL;
201
202
if (width) *width = img->width;
203
if (height) *height = img->height;
204
return img->pixels;
205
}
206
207
/*
208
* Module initialization
209
*/
210
void sigil__init_sigil_studio_image_module(SigilVM *vm)
211
{
212
SigilModule *module = sigil_begin_module(vm, "(sigil studio image)");
213
if (!module) return;
214
215
sigil_module_register_native(vm, "load-image", native_load_image,
216
SIGIL_ARITY_EXACT(1), "Load image from file path");
217
sigil_module_register_native(vm, "image?", native_image_p,
218
SIGIL_ARITY_EXACT(1), "Check if object is an image");
219
sigil_module_register_native(vm, "image-width", native_image_width,
220
SIGIL_ARITY_EXACT(1), "Get image width");
221
sigil_module_register_native(vm, "image-height", native_image_height,
222
SIGIL_ARITY_EXACT(1), "Get image height");
223
sigil_module_register_native(vm, "image-channels", native_image_channels,
224
SIGIL_ARITY_EXACT(1), "Get number of channels");
225
sigil_module_register_native(vm, "image-free!", native_image_free,
226
SIGIL_ARITY_EXACT(1), "Free image pixel data");
227
228
sigil_module_export(vm, "load-image");
229
sigil_module_export(vm, "image?");
230
sigil_module_export(vm, "image-width");
231
sigil_module_export(vm, "image-height");
232
sigil_module_export(vm, "image-channels");
233
sigil_module_export(vm, "image-free!");
234
235
sigil_end_module(vm);
236
}
src/c/sokol.cdeleted
@@ -1,18 +0,0 @@
1
/*
2
* sokol.c - Sokol Implementation File
3
*
4
* All Sokol implementations must be in a single translation unit.
5
* This file includes all Sokol headers with SOKOL_IMPL defined.
6
*/
7
8
#define SOKOL_IMPL
9
/* SOKOL_GLCORE is defined via compiler flags */
10
11
/* Order matters: gfx before glue */
12
#include "sokol_app.h"
13
#include "sokol_gfx.h"
14
#include "sokol_glue.h"
15
#include "sokol_gp.h"
16
#include "sokol_audio.h"
17
#include "sokol_time.h"
18
#include "sokol_log.h"
src/c/stb_impl.cdeleted
@@ -1,12 +0,0 @@
1
/*
2
* stb_impl.c - STB library implementations
3
*
4
* This file contains the implementations of STB single-header libraries.
5
* Compile this once and link with other modules.
6
*/
7
8
#define STB_IMAGE_IMPLEMENTATION
9
#include "stb_image.h"
10
11
#define STB_TRUETYPE_IMPLEMENTATION
12
#include "stb_truetype.h"
src/c/studio-internal.hdeleted
@@ -1,58 +0,0 @@
1
/*
2
* studio-internal.h - Internal header for Sigil Studio native code
3
*
4
* Shared state and utilities for app, graphics, and audio modules.
5
*/
6
7
#ifndef SIGIL_STUDIO_INTERNAL_H
8
#define SIGIL_STUDIO_INTERNAL_H
9
10
#include <sigil/sigil.h>
11
#include <stdbool.h>
12
13
/*
14
* Application state - shared between modules
15
*/
16
typedef struct {
17
SigilVM *vm;
18
19
/* Callbacks from Scheme */
20
Value init_callback;
21
Value frame_callback;
22
Value cleanup_callback;
23
24
/* Frame timing */
25
double frame_time; /* Seconds since last frame */
26
double time_elapsed; /* Seconds since app start */
27
28
/* Input state - current frame */
29
bool keys_down[512];
30
bool keys_pressed[512];
31
bool keys_released[512];
32
33
bool mouse_buttons[3];
34
bool mouse_pressed[3];
35
bool mouse_released[3];
36
float mouse_x;
37
float mouse_y;
38
39
/* Quit handling */
40
bool quit_requested;
41
42
/* Initialization flags */
43
bool gfx_initialized;
44
bool audio_initialized;
45
} StudioState;
46
47
/* Global state - initialized by app module */
48
extern StudioState *g_studio;
49
50
/* Initialize/shutdown studio state */
51
void studio_state_init(SigilVM *vm);
52
void studio_state_shutdown(void);
53
54
/* Input handling helpers */
55
void studio_clear_frame_input(void);
56
int studio_key_code_from_symbol(SigilVM *vm, Value sym);
57
58
#endif /* SIGIL_STUDIO_INTERNAL_H */
src/sigil/studio/app.sgldeleted
@@ -1,91 +0,0 @@
1
;;; (sigil studio app) - Application Framework
2
;;;
3
;;; Provides windowing, input handling, and application lifecycle management.
4
;;; Native functions are registered by app.c, this module provides re-exports
5
;;; and higher-level utilities.
6
;;;
7
;;; The frame-loop macro provides a coroutine-based game loop where Scheme
8
;;; appears to own the main loop while C (Sokol) actually controls execution.
9
10
(define-library (sigil studio app)
11
(import (sigil core)
12
(sigil coroutines))
13
14
(export
15
;; Native functions (re-exported)
16
app-run
17
frame-width frame-height
18
frame-time time-elapsed
19
mouse-x mouse-y
20
mouse-down? mouse-pressed? mouse-released?
21
key-down? key-pressed? key-released?
22
quit-requested? request-quit
23
24
;; Cooperative frame scheduling
25
run-game
26
wait-frame)
27
28
(begin
29
;; Native functions are automatically available after native module init.
30
31
;; ========== Cooperative Frame Scheduler ==========
32
;;;
33
;;; The frame-loop pattern inverts control so Scheme code reads naturally:
34
;;;
35
;;; (run-game "My Game" 800 600
36
;;; (lambda ()
37
;;; ;; init code here
38
;;; (let loop ()
39
;;; (let ((dt (wait-frame)))
40
;;; ;; frame code here using dt
41
;;; (unless (quit-requested?)
42
;;; (loop))))))
43
;;;
44
;;; Behind the scenes, (wait-frame) yields to C, which resumes the
45
;;; coroutine on the next frame with the delta time.
46
47
;; Global coroutine for the current game loop
48
(define *game-coroutine* #f)
49
50
;; Yield point - returns delta time when resumed
51
(define (wait-frame)
52
(send 'frame-complete))
53
54
;; Internal frame callback - resumes the game coroutine
55
(define (frame-tick dt)
56
(when *game-coroutine*
57
(if (coroutine-done? *game-coroutine*)
58
(request-quit)
59
(coroutine-send *game-coroutine* dt))))
60
61
;; Stored game thunk - will be converted to coroutine in init callback
62
(define *game-thunk* #f)
63
64
;; Internal init callback - creates and starts the game coroutine
65
(define (game-init)
66
(when *game-thunk*
67
;; Create the game coroutine now that Sokol is initialized
68
(set! *game-coroutine*
69
(coroutine
70
;; Call the user's game thunk
71
(*game-thunk*)
72
;; When thunk returns, game is done
73
'game-finished))
74
;; Run init code up to first (wait-frame)
75
(when (not (coroutine-done? *game-coroutine*))
76
(coroutine-send *game-coroutine* 0.0))))
77
78
;; Run a game with the coroutine-based loop
79
;; game-thunk is called inside a coroutine and can use (wait-frame)
80
(define (run-game title width height game-thunk)
81
;; Store the thunk for the init callback
82
(set! *game-thunk* game-thunk)
83
84
;; Run the app - init callback will start the coroutine
85
(app-run
86
game-init ; init - creates and starts coroutine
87
frame-tick ; frame - resumes coroutine
88
(lambda () ; cleanup
89
(set! *game-coroutine* #f)
90
(set! *game-thunk* #f))
91
title width height))))
src/sigil/studio/audio.sgldeleted
@@ -1,33 +0,0 @@
1
;;; (sigil studio audio) - Audio Module
2
;;;
3
;;; Provides audio playback capabilities via sokol_audio.
4
;;; Uses stb_vorbis for OGG audio decoding.
5
;;;
6
;;; Sound effects are loaded entirely into memory for low-latency playback.
7
;;; Music is streamed from disk for memory efficiency.
8
;;;
9
;;; Native functions are registered by audio.c.
10
11
(define-library (sigil studio audio)
12
(import (sigil core))
13
14
(export
15
;; Setup/shutdown
16
audio-setup audio-shutdown audio-initialized?
17
18
;; Sound effects (loaded into memory)
19
load-sound sound?
20
play-sound stop-all-sounds
21
22
;; Music streaming
23
play-music stop-music
24
pause-music resume-music
25
music-playing? set-music-volume
26
27
;; Global control
28
set-master-volume
29
mute-audio unmute-audio audio-muted?)
30
31
(begin
32
;; Native functions are automatically available after native module init.
33
))
src/sigil/studio/font.sgldeleted
@@ -1,22 +0,0 @@
1
;;; (sigil studio font) - Font Loading and Text Rendering
2
;;;
3
;;; Provides TrueType font loading and text rendering via stb_truetype.
4
;;; Native functions are registered by font.c.
5
6
(define-library (sigil studio font)
7
(import (sigil core))
8
9
(export
10
;; Font loading
11
load-font
12
font? font-size font-line-height
13
14
;; Text rendering
15
draw-text draw-text-char text-width
16
draw-text-centered)
17
18
(begin
19
;; Draw text centered on position x, y
20
(define (draw-text-centered font text x y)
21
(let ((w (text-width font text)))
22
(draw-text font text (- x (/ w 2)) y)))))
src/sigil/studio/graphics.sgldeleted
@@ -1,59 +0,0 @@
1
;;; (sigil studio graphics) - Graphics Module
2
;;;
3
;;; Provides 2D/3D rendering capabilities via sokol_gfx.
4
;;; Native functions are registered by graphics.c.
5
;;;
6
;;; For image loading and textures:
7
;;; - Use (sigil studio image) for CPU-side image loading
8
;;; - Use load-texture to convert images to GPU textures
9
10
(define-library (sigil studio graphics)
11
(import (sigil core)
12
(sigil studio image))
13
14
(export
15
;; Setup/shutdown
16
gfx-setup gfx-shutdown gfx-initialized?
17
18
;; Viewport
19
set-viewport
20
set-letterbox-color
21
22
;; Frame management
23
begin-frame end-frame
24
25
;; Drawing
26
clear-screen set-color
27
draw-filled-rect draw-rect
28
draw-line draw-point
29
draw-triangle fill-triangle
30
31
;; Transform stack
32
push-transform pop-transform reset-transform
33
translate rotate rotate-at
34
scale scale-at
35
36
;; Textures
37
load-texture
38
texture? texture-width texture-height
39
draw-texture draw-texture-region
40
41
;; Re-export image functions for convenience
42
load-image
43
image? image-width image-height image-channels
44
image-free!
45
46
;; High-level frame helper
47
with-frame)
48
49
(begin
50
;; Native functions are automatically available after native module init.
51
52
;; Convenience macro for frame management
53
(define-syntax with-frame
54
(syntax-rules ()
55
((_ body ...)
56
(begin
57
(begin-frame)
58
body ...
59
(end-frame)))))))
src/sigil/studio/image.sgldeleted
@@ -1,29 +0,0 @@
1
;;; (sigil studio image) - CPU-side Image Loading
2
;;;
3
;;; Provides image loading from files using stb_image.
4
;;; Images are loaded into CPU memory and can be:
5
;;; - Inspected (width, height, channels)
6
;;; - Converted to GPU textures via (sigil studio graphics)
7
;;;
8
;;; Supported formats: PNG, JPEG, BMP, TGA, GIF, HDR, PSD, PIC, PNM
9
10
(define-library (sigil studio image)
11
(import (sigil core))
12
13
(export
14
;; Image loading
15
load-image
16
17
;; Image predicates and properties
18
image?
19
image-width
20
image-height
21
image-channels
22
23
;; Memory management
24
image-free!)
25
26
(begin
27
;; Native functions are registered by image.c
28
;; This module provides re-exports and documentation.
29
))
test/test-audio.sglmodified
@@ -1,10 +1,10 @@
1
;;; test-audio.sgl - Test audio playback
2
3
(import (sigil core)
4
(sigil studio app)
5
(sigil studio graphics)
6
(sigil studio audio)
7
(sigil studio font))
+4
(sigil app)
+5
(sigil graphics)
+6
(sigil audio)
+7
(sigil font))
8
9
(define *font* #f)
10
(define *music-playing* #f)
test/test-draw-texture.sglmodified
@@ -3,8 +3,8 @@
3
;;; Opens a window and draws a test image to the screen.
4
5
(import (sigil core)
6
(sigil studio app)
7
(sigil studio graphics))
+6
(sigil app)
+7
(sigil graphics))
8
9
(display "Loading test image...\n")
10
test/test-font.sglmodified
@@ -1,9 +1,9 @@
1
;;; test-font.sgl - Test font loading and text rendering
2
3
(import (sigil core)
4
(sigil studio app)
5
(sigil studio graphics)
6
(sigil studio font))
+4
(sigil app)
+5
(sigil graphics)
+6
(sigil font))
7
8
(display "Loading font...\n")
9
test/test-image.sglmodified
@@ -1,9 +1,9 @@
1
;;; test-image.sgl - Test image loading
2
;;;
3
;;; This test verifies that (sigil studio image) can load images.
+3
;;; This test verifies that (sigil image) can load images.
4
5
(import (sigil core)
6
(sigil studio image))
+6
(sigil image))
7
8
(display "Testing image loading...\n")
9
test/test-transforms.sglmodified
@@ -1,9 +1,9 @@
1
;;; test-transforms.sgl - Demo of transform stack
2
3
(import (sigil core)
4
(sigil studio app)
5
(sigil studio graphics)
6
(sigil studio font))
+4
(sigil app)
+5
(sigil graphics)
+6
(sigil font))
7
8
(define (label text x y)
9
(set-color 0.7 0.7 0.7)
vendor/sokol/sokol_app.hdeleted
@@ -1,14047 +0,0 @@
1
#if defined(SOKOL_IMPL) && !defined(SOKOL_APP_IMPL)
2
#define SOKOL_APP_IMPL
3
#endif
4
#ifndef SOKOL_APP_INCLUDED
5
/*
6
sokol_app.h -- cross-platform application wrapper
7
8
Project URL: https://github.com/floooh/sokol
9
10
Do this:
11
#define SOKOL_IMPL or
12
#define SOKOL_APP_IMPL
13
before you include this file in *one* C or C++ file to create the
14
implementation.
15
16
In the same place define one of the following to select the 3D-API
17
which should be initialized by sokol_app.h (this must also match
18
the backend selected for sokol_gfx.h if both are used in the same
19
project):
20
21
#define SOKOL_GLCORE
22
#define SOKOL_GLES3
23
#define SOKOL_D3D11
24
#define SOKOL_METAL
25
#define SOKOL_WGPU
26
#define SOKOL_NOAPI
27
28
Optionally provide the following defines with your own implementations:
29
30
SOKOL_ASSERT(c) - your own assert macro (default: assert(c))
31
SOKOL_UNREACHABLE() - a guard macro for unreachable code (default: assert(false))
32
SOKOL_WIN32_FORCE_MAIN - define this on Win32 to add a main() entry point
33
SOKOL_WIN32_FORCE_WINMAIN - define this on Win32 to add a WinMain() entry point (enabled by default unless
34
SOKOL_WIN32_FORCE_MAIN or SOKOL_NO_ENTRY is defined)
35
SOKOL_NO_ENTRY - define this if sokol_app.h shouldn't "hijack" the main() function
36
SOKOL_APP_API_DECL - public function declaration prefix (default: extern)
37
SOKOL_API_DECL - same as SOKOL_APP_API_DECL
38
SOKOL_API_IMPL - public function implementation prefix (default: -)
39
40
Optionally define the following to force debug checks and validations
41
even in release mode:
42
43
SOKOL_DEBUG - by default this is defined if NDEBUG is not defined
44
45
If sokol_app.h is compiled as a DLL, define the following before
46
including the declaration or implementation:
47
48
SOKOL_DLL
49
50
On Windows, SOKOL_DLL will define SOKOL_APP_API_DECL as __declspec(dllexport)
51
or __declspec(dllimport) as needed.
52
53
if SOKOL_WIN32_FORCE_MAIN and SOKOL_WIN32_FORCE_WINMAIN are both defined,
54
it is up to the developer to define the desired subsystem.
55
56
On Linux, SOKOL_GLCORE can use either GLX or EGL.
57
GLX is default, set SOKOL_FORCE_EGL to override.
58
59
For example code, see https://github.com/floooh/sokol-samples/tree/master/sapp
60
61
Portions of the Windows and Linux GL initialization, event-, icon- etc... code
62
have been taken from GLFW (http://www.glfw.org/).
63
64
iOS onscreen keyboard support 'inspired' by libgdx.
65
66
Link with the following system libraries:
67
68
- on macOS:
69
- all backends: Foundation, Cocoa, QuartzCore
70
- with SOKOL_METAL: Metal, MetalKit
71
- with SOKOL_GLCORE: OpenGL
72
- with SOKOL_WGPU: a WebGPU implementation library (tested with webgpu_dawn)
73
- on iOS:
74
- all backends: Foundation, UIKit
75
- with SOKOL_METAL: Metal, MetalKit
76
- with SOKOL_GLES3: OpenGLES, GLKit
77
- on Linux:
78
- all backends: X11, Xi, Xcursor, dl, pthread, m
79
- with SOKOL_GLCORE: GL
80
- with SOKOL_GLES3: GLESv2
81
- with SOKOL_WGPU: a WebGPU implementation library (tested with webgpu_dawn)
82
- with EGL: EGL
83
- on Android: GLESv3, EGL, log, android
84
- on Windows:
85
- with MSVC or Clang: library dependencies are defined via `#pragma comment`
86
- with SOKOL_WGPU: a WebGPU implementation library (tested with webgpu_dawn)
87
- with MINGW/MSYS2 gcc:
88
- compile with '-mwin32' so that _WIN32 is defined
89
- link with the following libs: -lkernel32 -luser32 -lshell32
90
- additionally with the GL backend: -lgdi32
91
- additionally with the D3D11 backend: -ld3d11 -ldxgi
92
93
On Linux, you also need to use the -pthread compiler and linker option, otherwise weird
94
things will happen, see here for details: https://github.com/floooh/sokol/issues/376
95
96
On macOS and iOS, the implementation must be compiled as Objective-C.
97
98
On Emscripten:
99
- for WebGL2: add the linker option `-s USE_WEBGL2=1`
100
- for WebGPU: compile and link with `--use-port=emdawnwebgpu`
101
(for more exotic situations read: https://dawn.googlesource.com/dawn/+/refs/heads/main/src/emdawnwebgpu/pkg/README.md)
102
103
FEATURE OVERVIEW
104
================
105
sokol_app.h provides a minimalistic cross-platform API which
106
implements the 'application-wrapper' parts of a 3D application:
107
108
- a common application entry function
109
- creates a window and 3D-API context/device with a swapchain
110
surface, depth-stencil-buffer surface and optionally MSAA surface
111
- makes the rendered frame visible
112
- provides keyboard-, mouse- and low-level touch-events
113
- platforms: MacOS, iOS, HTML5, Win32, Linux/RaspberryPi, Android
114
- 3D-APIs: Metal, D3D11, GL4.1, GL4.3, GLES3, WebGL2, WebGPU, NOAPI
115
116
FEATURE/PLATFORM MATRIX
117
=======================
118
| Windows | macOS | Linux | iOS | Android | HTML5
119
--------------------+---------+-------+-------+-------+---------+--------
120
gl 4.x | YES | YES | YES | --- | --- | ---
121
gles3/webgl2 | --- | --- | YES(2)| YES | YES | YES
122
metal | --- | YES | --- | YES | --- | ---
123
d3d11 | YES | --- | --- | --- | --- | ---
124
webgpu | YES(4) | YES(4)| YES(4)| NO | NO | YES
125
noapi | YES | TODO | TODO | --- | TODO | ---
126
KEY_DOWN | YES | YES | YES | SOME | TODO | YES
127
KEY_UP | YES | YES | YES | SOME | TODO | YES
128
CHAR | YES | YES | YES | YES | TODO | YES
129
MOUSE_DOWN | YES | YES | YES | --- | --- | YES
130
MOUSE_UP | YES | YES | YES | --- | --- | YES
131
MOUSE_SCROLL | YES | YES | YES | --- | --- | YES
132
MOUSE_MOVE | YES | YES | YES | --- | --- | YES
133
MOUSE_ENTER | YES | YES | YES | --- | --- | YES
134
MOUSE_LEAVE | YES | YES | YES | --- | --- | YES
135
TOUCHES_BEGAN | --- | --- | --- | YES | YES | YES
136
TOUCHES_MOVED | --- | --- | --- | YES | YES | YES
137
TOUCHES_ENDED | --- | --- | --- | YES | YES | YES
138
TOUCHES_CANCELLED | --- | --- | --- | YES | YES | YES
139
RESIZED | YES | YES | YES | YES | YES | YES
140
ICONIFIED | YES | YES | YES | --- | --- | ---
141
RESTORED | YES | YES | YES | --- | --- | ---
142
FOCUSED | YES | YES | YES | --- | --- | YES
143
UNFOCUSED | YES | YES | YES | --- | --- | YES
144
SUSPENDED | --- | --- | --- | YES | YES | TODO
145
RESUMED | --- | --- | --- | YES | YES | TODO
146
QUIT_REQUESTED | YES | YES | YES | --- | --- | YES
147
IME | TODO | TODO? | TODO | ??? | TODO | ???
148
key repeat flag | YES | YES | YES | --- | --- | YES
149
windowed | YES | YES | YES | --- | --- | YES
150
fullscreen | YES | YES | YES | YES | YES | YES(3)
151
mouse hide | YES | YES | YES | --- | --- | YES
152
mouse lock | YES | YES | YES | --- | --- | YES
153
set cursor type | YES | YES | YES | --- | --- | YES
154
screen keyboard | --- | --- | --- | YES | TODO | YES
155
swap interval | YES | YES | YES | YES | TODO | YES
156
high-dpi | YES | YES | TODO | YES | YES | YES
157
clipboard | YES | YES | YES | --- | --- | YES
158
MSAA | YES | YES | YES | YES | YES | YES
159
drag'n'drop | YES | YES | YES | --- | --- | YES
160
window icon | YES | YES(1)| YES | --- | --- | YES
161
162
(1) macOS has no regular window icons, instead the dock icon is changed
163
(2) supported with EGL only (not GLX)
164
(3) fullscreen in the browser not supported on iphones
165
(4) WebGPU on native desktop platforms should be considered experimental
166
and mainly useful for debugging and benchmarking
167
168
STEP BY STEP
169
============
170
--- Add a sokol_main() function to your code which returns a sapp_desc structure
171
with initialization parameters and callback function pointers. This
172
function is called very early, usually at the start of the
173
platform's entry function (e.g. main or WinMain). You should do as
174
little as possible here, since the rest of your code might be called
175
from another thread (this depends on the platform):
176
177
sapp_desc sokol_main(int argc, char* argv[]) {
178
return (sapp_desc) {
179
.width = 640,
180
.height = 480,
181
.init_cb = my_init_func,
182
.frame_cb = my_frame_func,
183
.cleanup_cb = my_cleanup_func,
184
.event_cb = my_event_func,
185
...
186
};
187
}
188
189
To get any logging output in case of errors you need to provide a log
190
callback. The easiest way is via sokol_log.h:
191
192
#include "sokol_log.h"
193
194
sapp_desc sokol_main(int argc, char* argv[]) {
195
return (sapp_desc) {
196
...
197
.logger.func = slog_func,
198
};
199
}
200
201
There are many more setup parameters, but these are the most important.
202
For a complete list search for the sapp_desc structure declaration
203
below.
204
205
DO NOT call any sokol-app function from inside sokol_main(), since
206
sokol-app will not be initialized at this point.
207
208
The .width and .height parameters are the preferred size of the 3D
209
rendering canvas. The actual size may differ from this depending on
210
platform and other circumstances. Also the canvas size may change at
211
any time (for instance when the user resizes the application window,
212
or rotates the mobile device). You can just keep .width and .height
213
zero-initialized to open a default-sized window (what "default-size"
214
exactly means is platform-specific, but usually it's a size that covers
215
most of, but not all, of the display).
216
217
All provided function callbacks will be called from the same thread,
218
but this may be different from the thread where sokol_main() was called.
219
220
.init_cb (void (*)(void))
221
This function is called once after the application window,
222
3D rendering context and swap chain have been created. The
223
function takes no arguments and has no return value.
224
.frame_cb (void (*)(void))
225
This is the per-frame callback, which is usually called 60
226
times per second. This is where your application would update
227
most of its state and perform all rendering.
228
.cleanup_cb (void (*)(void))
229
The cleanup callback is called once right before the application
230
quits.
231
.event_cb (void (*)(const sapp_event* event))
232
The event callback is mainly for input handling, but is also
233
used to communicate other types of events to the application. Keep the
234
event_cb struct member zero-initialized if your application doesn't require
235
event handling.
236
237
As you can see, those 'standard callbacks' don't have a user_data
238
argument, so any data that needs to be preserved between callbacks
239
must live in global variables. If keeping state in global variables
240
is not an option, there's an alternative set of callbacks with
241
an additional user_data pointer argument:
242
243
.user_data (void*)
244
The user-data argument for the callbacks below
245
.init_userdata_cb (void (*)(void* user_data))
246
.frame_userdata_cb (void (*)(void* user_data))
247
.cleanup_userdata_cb (void (*)(void* user_data))
248
.event_userdata_cb (void(*)(const sapp_event* event, void* user_data))
249
250
The function sapp_userdata() can be used to query the user_data
251
pointer provided in the sapp_desc struct.
252
253
You can also call sapp_query_desc() to get a copy of the
254
original sapp_desc structure.
255
256
NOTE that there's also an alternative compile mode where sokol_app.h
257
doesn't "hijack" the main() function. Search below for SOKOL_NO_ENTRY.
258
259
--- Implement the initialization callback function (init_cb), this is called
260
once after the rendering surface, 3D API and swap chain have been
261
initialized by sokol_app. All sokol-app functions can be called
262
from inside the initialization callback, the most useful functions
263
at this point are:
264
265
int sapp_width(void)
266
int sapp_height(void)
267
Returns the current width and height of the default framebuffer in pixels,
268
this may change from one frame to the next, and it may be different
269
from the initial size provided in the sapp_desc struct.
270
271
float sapp_widthf(void)
272
float sapp_heightf(void)
273
These are alternatives to sapp_width() and sapp_height() which return
274
the default framebuffer size as float values instead of integer. This
275
may help to prevent casting back and forth between int and float
276
in more strongly typed languages than C and C++.
277
278
double sapp_frame_duration(void)
279
Returns the frame duration in seconds averaged over a number of
280
frames to smooth out any jittering spikes.
281
282
int sapp_color_format(void)
283
int sapp_depth_format(void)
284
The color and depth-stencil pixelformats of the default framebuffer,
285
as integer values which are compatible with sokol-gfx's
286
sg_pixel_format enum (so that they can be plugged directly in places
287
where sg_pixel_format is expected). Possible values are:
288
289
23 == SG_PIXELFORMAT_RGBA8
290
28 == SG_PIXELFORMAT_BGRA8
291
42 == SG_PIXELFORMAT_DEPTH
292
43 == SG_PIXELFORMAT_DEPTH_STENCIL
293
294
int sapp_sample_count(void)
295
Return the MSAA sample count of the default framebuffer.
296
297
const void* sapp_metal_get_device(void)
298
const void* sapp_metal_get_current_drawable(void)
299
const void* sapp_metal_get_depth_stencil_texture(void)
300
const void* sapp_metal_get_msaa_color_texture(void)
301
If the Metal backend has been selected, these functions return pointers
302
to various Metal API objects required for rendering, otherwise
303
they return a null pointer. These void pointers are actually
304
Objective-C ids converted with a (ARC) __bridge cast so that
305
the ids can be tunneled through C code. Also note that the returned
306
pointers may change from one frame to the next, only the Metal device
307
object is guaranteed to stay the same.
308
309
const void* sapp_macos_get_window(void)
310
On macOS, get the NSWindow object pointer, otherwise a null pointer.
311
Before being used as Objective-C object, the void* must be converted
312
back with a (ARC) __bridge cast.
313
314
const void* sapp_ios_get_window(void)
315
On iOS, get the UIWindow object pointer, otherwise a null pointer.
316
Before being used as Objective-C object, the void* must be converted
317
back with a (ARC) __bridge cast.
318
319
const void* sapp_d3d11_get_device(void)
320
const void* sapp_d3d11_get_device_context(void)
321
const void* sapp_d3d11_get_render_view(void)
322
const void* sapp_d3d11_get_resolve_view(void);
323
const void* sapp_d3d11_get_depth_stencil_view(void)
324
Similar to the sapp_metal_* functions, the sapp_d3d11_* functions
325
return pointers to D3D11 API objects required for rendering,
326
only if the D3D11 backend has been selected. Otherwise they
327
return a null pointer. Note that the returned pointers to the
328
render-target-view and depth-stencil-view may change from one
329
frame to the next!
330
331
const void* sapp_win32_get_hwnd(void)
332
On Windows, get the window's HWND, otherwise a null pointer. The
333
HWND has been cast to a void pointer in order to be tunneled
334
through code which doesn't include Windows.h.
335
336
const void* sapp_x11_get_window(void)
337
On Linux, get the X11 Window, otherwise a null pointer. The
338
Window has been cast to a void pointer in order to be tunneled
339
through code which doesn't include X11/Xlib.h.
340
341
const void* sapp_x11_get_display(void)
342
On Linux, get the X11 Display, otherwise a null pointer. The
343
Display has been cast to a void pointer in order to be tunneled
344
through code which doesn't include X11/Xlib.h.
345
346
const void* sapp_wgpu_get_device(void)
347
const void* sapp_wgpu_get_render_view(void)
348
const void* sapp_wgpu_get_resolve_view(void)
349
const void* sapp_wgpu_get_depth_stencil_view(void)
350
These are the WebGPU-specific functions to get the WebGPU
351
objects and values required for rendering. If sokol_app.h
352
is not compiled with SOKOL_WGPU, these functions return null.
353
354
uint32_t sapp_gl_get_framebuffer(void)
355
This returns the 'default framebuffer' of the GL context.
356
Typically this will be zero.
357
358
int sapp_gl_get_major_version(void)
359
int sapp_gl_get_minor_version(void)
360
bool sapp_gl_is_gles(void)
361
Returns the major and minor version of the GL context and
362
whether the GL context is a GLES context
363
364
const void* sapp_android_get_native_activity(void);
365
On Android, get the native activity ANativeActivity pointer, otherwise
366
a null pointer.
367
368
--- Implement the frame-callback function, this function will be called
369
on the same thread as the init callback, but might be on a different
370
thread than the sokol_main() function. Note that the size of
371
the rendering framebuffer might have changed since the frame callback
372
was called last. Call the functions sapp_width() and sapp_height()
373
each frame to get the current size.
374
375
--- Optionally implement the event-callback to handle input events.
376
sokol-app provides the following type of input events:
377
- a 'virtual key' was pressed down or released
378
- a single text character was entered (provided as UTF-32 encoded
379
UNICODE code point)
380
- a mouse button was pressed down or released (left, right, middle)
381
- mouse-wheel or 2D scrolling events
382
- the mouse was moved
383
- the mouse has entered or left the application window boundaries
384
- low-level, portable multi-touch events (began, moved, ended, cancelled)
385
- the application window was resized, iconified or restored
386
- the application was suspended or restored (on mobile platforms)
387
- the user or application code has asked to quit the application
388
- a string was pasted to the system clipboard
389
- one or more files have been dropped onto the application window
390
391
To explicitly 'consume' an event and prevent that the event is
392
forwarded for further handling to the operating system, call
393
sapp_consume_event() from inside the event handler (NOTE that
394
this behaviour is currently only implemented for some HTML5
395
events, support for other platforms and event types will
396
be added as needed, please open a GitHub ticket and/or provide
397
a PR if needed).
398
399
NOTE: Do *not* call any 3D API rendering functions in the event
400
callback function, since the 3D API context may not be active when the
401
event callback is called (it may work on some platforms and 3D APIs,
402
but not others, and the exact behaviour may change between
403
sokol-app versions).
404
405
--- Implement the cleanup-callback function, this is called once
406
after the user quits the application (see the section
407
"APPLICATION QUIT" for detailed information on quitting
408
behaviour, and how to intercept a pending quit - for instance to show a
409
"Really Quit?" dialog box). Note that the cleanup-callback isn't
410
guaranteed to be called on the web and mobile platforms.
411
412
MOUSE CURSOR TYPE AND VISIBILITY
413
================================
414
You can show and hide the mouse cursor with
415
416
void sapp_show_mouse(bool show)
417
418
And to get the current shown status:
419
420
bool sapp_mouse_shown(void)
421
422
NOTE that hiding the mouse cursor is different and independent from
423
the MOUSE/POINTER LOCK feature which will also hide the mouse pointer when
424
active (MOUSE LOCK is described below).
425
426
To change the mouse cursor to one of several predefined types, call
427
the function:
428
429
void sapp_set_mouse_cursor(sapp_mouse_cursor cursor)
430
431
Setting the default mouse cursor SAPP_MOUSECURSOR_DEFAULT will restore
432
the standard look.
433
434
To get the currently active mouse cursor type, call:
435
436
sapp_mouse_cursor sapp_get_mouse_cursor(void)
437
438
MOUSE LOCK (AKA POINTER LOCK, AKA MOUSE CAPTURE)
439
================================================
440
In normal mouse mode, no mouse movement events are reported when the
441
mouse leaves the windows client area or hits the screen border (whether
442
it's one or the other depends on the platform), and the mouse move events
443
(SAPP_EVENTTYPE_MOUSE_MOVE) contain absolute mouse positions in
444
framebuffer pixels in the sapp_event items mouse_x and mouse_y, and
445
relative movement in framebuffer pixels in the sapp_event items mouse_dx
446
and mouse_dy.
447
448
To get continuous mouse movement (also when the mouse leaves the window
449
client area or hits the screen border), activate mouse-lock mode
450
by calling:
451
452
sapp_lock_mouse(true)
453
454
When mouse lock is activated, the mouse pointer is hidden, the
455
reported absolute mouse position (sapp_event.mouse_x/y) appears
456
frozen, and the relative mouse movement in sapp_event.mouse_dx/dy
457
no longer has a direct relation to framebuffer pixels but instead
458
uses "raw mouse input" (what "raw mouse input" exactly means also
459
differs by platform).
460
461
To deactivate mouse lock and return to normal mouse mode, call
462
463
sapp_lock_mouse(false)
464
465
And finally, to check if mouse lock is currently active, call
466
467
if (sapp_mouse_locked()) { ... }
468
469
Note that mouse-lock state may not change immediately after sapp_lock_mouse(true/false)
470
is called, instead on some platforms the actual state switch may be delayed
471
to the end of the current frame or even to a later frame.
472
473
The mouse may also be unlocked automatically without calling sapp_lock_mouse(false),
474
most notably when the application window becomes inactive.
475
476
On the web platform there are further restrictions to be aware of, caused
477
by the limitations of the HTML5 Pointer Lock API:
478
479
- sapp_lock_mouse(true) can be called at any time, but it will
480
only take effect in a 'short-lived input event handler of a specific
481
type', meaning when one of the following events happens:
482
- SAPP_EVENTTYPE_MOUSE_DOWN
483
- SAPP_EVENTTYPE_MOUSE_UP
484
- SAPP_EVENTTYPE_MOUSE_SCROLL
485
- SAPP_EVENTTYPE_KEY_UP
486
- SAPP_EVENTTYPE_KEY_DOWN
487
- The mouse lock/unlock action on the web platform is asynchronous,
488
this means that sapp_mouse_locked() won't immediately return
489
the new status after calling sapp_lock_mouse(), instead the
490
reported status will only change when the pointer lock has actually
491
been activated or deactivated in the browser.
492
- On the web, mouse lock can be deactivated by the user at any time
493
by pressing the Esc key. When this happens, sokol_app.h behaves
494
the same as if sapp_lock_mouse(false) is called.
495
496
For things like camera manipulation it's most straightforward to lock
497
and unlock the mouse right from the sokol_app.h event handler, for
498
instance the following code enters and leaves mouse lock when the
499
left mouse button is pressed and released, and then uses the relative

Showing the first 500 of 14048 diff lines for this file. This diff is INCOMPLETE; read the file or clone the repository for the rest.

vendor/sokol/sokol_audio.hdeleted
@@ -1,2663 +0,0 @@
1
#if defined(SOKOL_IMPL) && !defined(SOKOL_AUDIO_IMPL)
2
#define SOKOL_AUDIO_IMPL
3
#endif
4
#ifndef SOKOL_AUDIO_INCLUDED
5
/*
6
sokol_audio.h -- cross-platform audio-streaming API
7
8
Project URL: https://github.com/floooh/sokol
9
10
Do this:
11
#define SOKOL_IMPL or
12
#define SOKOL_AUDIO_IMPL
13
before you include this file in *one* C or C++ file to create the
14
implementation.
15
16
Optionally provide the following defines with your own implementations:
17
18
SOKOL_DUMMY_BACKEND - use a dummy backend
19
SOKOL_ASSERT(c) - your own assert macro (default: assert(c))
20
SOKOL_AUDIO_API_DECL- public function declaration prefix (default: extern)
21
SOKOL_API_DECL - same as SOKOL_AUDIO_API_DECL
22
SOKOL_API_IMPL - public function implementation prefix (default: -)
23
24
SAUDIO_RING_MAX_SLOTS - max number of slots in the push-audio ring buffer (default 1024)
25
SAUDIO_OSX_USE_SYSTEM_HEADERS - define this to force inclusion of system headers on
26
macOS instead of using embedded CoreAudio declarations
27
28
If sokol_audio.h is compiled as a DLL, define the following before
29
including the declaration or implementation:
30
31
SOKOL_DLL
32
33
On Windows, SOKOL_DLL will define SOKOL_AUDIO_API_DECL as __declspec(dllexport)
34
or __declspec(dllimport) as needed.
35
36
Link with the following libraries:
37
38
- on macOS: AudioToolbox
39
- on iOS: AudioToolbox, AVFoundation
40
- on FreeBSD: asound
41
- on Linux: asound
42
- on Android: aaudio
43
- on Windows with MSVC or Clang toolchain: no action needed, libs are defined in-source via pragma-comment-lib
44
- on Windows with MINGW/MSYS2 gcc: compile with '-mwin32' and link with -lole32
45
- on Vita: SceAudio
46
- on 3DS: NDSP (libctru)
47
48
FEATURE OVERVIEW
49
================
50
You provide a mono- or stereo-stream of 32-bit float samples, which
51
Sokol Audio feeds into platform-specific audio backends:
52
53
- Windows: WASAPI
54
- Linux: ALSA
55
- FreeBSD: ALSA
56
- macOS: CoreAudio
57
- iOS: CoreAudio+AVAudioSession
58
- emscripten: WebAudio with ScriptProcessorNode
59
- Android: AAudio
60
- Vita: SceAudio
61
- 3DS: NDSP (libctru)
62
63
Sokol Audio will not do any buffer mixing or volume control, if you have
64
multiple independent input streams of sample data you need to perform the
65
mixing yourself before forwarding the data to Sokol Audio.
66
67
There are two mutually exclusive ways to provide the sample data:
68
69
1. Callback model: You provide a callback function, which will be called
70
when Sokol Audio needs new samples. On all platforms except emscripten,
71
this function is called from a separate thread.
72
2. Push model: Your code pushes small blocks of sample data from your
73
main loop or a thread you created. The pushed data is stored in
74
a ring buffer where it is pulled by the backend code when
75
needed.
76
77
The callback model is preferred because it is the most direct way to
78
feed sample data into the audio backends and also has less moving parts
79
(there is no ring buffer between your code and the audio backend).
80
81
Sometimes it is not possible to generate the audio stream directly in a
82
callback function running in a separate thread, for such cases Sokol Audio
83
provides the push-model as a convenience.
84
85
SOKOL AUDIO, SOLOUD AND MINIAUDIO
86
=================================
87
The WASAPI, ALSA and CoreAudio backend code has been taken from the
88
SoLoud library (with some modifications, so any bugs in there are most
89
likely my fault). If you need a more fully-featured audio solution, check
90
out SoLoud, it's excellent:
91
92
https://github.com/jarikomppa/soloud
93
94
Another alternative which feature-wise is somewhere inbetween SoLoud and
95
sokol-audio might be MiniAudio:
96
97
https://github.com/mackron/miniaudio
98
99
GLOSSARY
100
========
101
- stream buffer:
102
The internal audio data buffer, usually provided by the backend API. The
103
size of the stream buffer defines the base latency, smaller buffers have
104
lower latency but may cause audio glitches. Bigger buffers reduce or
105
eliminate glitches, but have a higher base latency.
106
107
- stream callback:
108
Optional callback function which is called by Sokol Audio when it
109
needs new samples. On Windows, macOS/iOS and Linux, this is called in
110
a separate thread, on WebAudio, this is called per-frame in the
111
browser thread.
112
113
- channel:
114
A discrete track of audio data, currently 1-channel (mono) and
115
2-channel (stereo) is supported and tested.
116
117
- sample:
118
The magnitude of an audio signal on one channel at a given time. In
119
Sokol Audio, samples are 32-bit float numbers in the range -1.0 to
120
+1.0.
121
122
- frame:
123
The tightly packed set of samples for all channels at a given time.
124
For mono 1 frame is 1 sample. For stereo, 1 frame is 2 samples.
125
126
- packet:
127
In Sokol Audio, a small chunk of audio data that is moved from the
128
main thread to the audio streaming thread in order to decouple the
129
rate at which the main thread provides new audio data, and the
130
streaming thread consuming audio data.
131
132
WORKING WITH SOKOL AUDIO
133
========================
134
First call saudio_setup() with your preferred audio playback options.
135
In most cases you can stick with the default values, these provide
136
a good balance between low-latency and glitch-free playback
137
on all audio backends.
138
139
You should always provide a logging callback to be aware of any
140
warnings and errors. The easiest way is to use sokol_log.h for this:
141
142
#include "sokol_log.h"
143
// ...
144
saudio_setup(&(saudio_desc){
145
.logger = {
146
.func = slog_func,
147
}
148
});
149
150
If you want to use the callback-model, you need to provide a stream
151
callback function either in saudio_desc.stream_cb or saudio_desc.stream_userdata_cb,
152
otherwise keep both function pointers zero-initialized.
153
154
Use push model and default playback parameters:
155
156
saudio_setup(&(saudio_desc){ .logger.func = slog_func });
157
158
Use stream callback model and default playback parameters:
159
160
saudio_setup(&(saudio_desc){
161
.stream_cb = my_stream_callback
162
.logger.func = slog_func,
163
});
164
165
The standard stream callback doesn't have a user data argument, if you want
166
that, use the alternative stream_userdata_cb and also set the user_data pointer:
167
168
saudio_setup(&(saudio_desc){
169
.stream_userdata_cb = my_stream_callback,
170
.user_data = &my_data
171
.logger.func = slog_func,
172
});
173
174
The following playback parameters can be provided through the
175
saudio_desc struct:
176
177
General parameters (both for stream-callback and push-model):
178
179
int sample_rate -- the sample rate in Hz, default: 44100
180
int num_channels -- number of channels, default: 1 (mono)
181
int buffer_frames -- number of frames in streaming buffer, default: 2048
182
183
The stream callback prototype (either with or without userdata):
184
185
void (*stream_cb)(float* buffer, int num_frames, int num_channels)
186
void (*stream_userdata_cb)(float* buffer, int num_frames, int num_channels, void* user_data)
187
Function pointer to the user-provide stream callback.
188
189
Push-model parameters:
190
191
int packet_frames -- number of frames in a packet, default: 128
192
int num_packets -- number of packets in ring buffer, default: 64
193
194
The sample_rate and num_channels parameters are only hints for the audio
195
backend, it isn't guaranteed that those are the values used for actual
196
playback.
197
198
To get the actual parameters, call the following functions after
199
saudio_setup():
200
201
int saudio_sample_rate(void)
202
int saudio_channels(void);
203
204
It's unlikely that the number of channels will be different than requested,
205
but a different sample rate isn't uncommon.
206
207
(NOTE: there's an yet unsolved issue when an audio backend might switch
208
to a different sample rate when switching output devices, for instance
209
plugging in a bluetooth headset, this case is currently not handled in
210
Sokol Audio).
211
212
You can check if audio initialization was successful with
213
saudio_isvalid(). If backend initialization failed for some reason
214
(for instance when there's no audio device in the machine), this
215
will return false. Not checking for success won't do any harm, all
216
Sokol Audio function will silently fail when called after initialization
217
has failed, so apart from missing audio output, nothing bad will happen.
218
219
Before your application exits, you should call
220
221
saudio_shutdown();
222
223
This stops the audio thread (on Linux, Windows and macOS/iOS) and
224
properly shuts down the audio backend.
225
226
THE STREAM CALLBACK MODEL
227
=========================
228
To use Sokol Audio in stream-callback-mode, provide a callback function
229
like this in the saudio_desc struct when calling saudio_setup():
230
231
void stream_cb(float* buffer, int num_frames, int num_channels) {
232
...
233
}
234
235
Or the alternative version with a user-data argument:
236
237
void stream_userdata_cb(float* buffer, int num_frames, int num_channels, void* user_data) {
238
my_data_t* my_data = (my_data_t*) user_data;
239
...
240
}
241
242
The job of the callback function is to fill the *buffer* with 32-bit
243
float sample values.
244
245
To output silence, fill the buffer with zeros:
246
247
void stream_cb(float* buffer, int num_frames, int num_channels) {
248
const int num_samples = num_frames * num_channels;
249
for (int i = 0; i < num_samples; i++) {
250
buffer[i] = 0.0f;
251
}
252
}
253
254
For stereo output (num_channels == 2), the samples for the left
255
and right channel are interleaved:
256
257
void stream_cb(float* buffer, int num_frames, int num_channels) {
258
assert(2 == num_channels);
259
for (int i = 0; i < num_frames; i++) {
260
buffer[2*i + 0] = ...; // left channel
261
buffer[2*i + 1] = ...; // right channel
262
}
263
}
264
265
Please keep in mind that the stream callback function is running in a
266
separate thread, if you need to share data with the main thread you need
267
to take care yourself to make the access to the shared data thread-safe!
268
269
THE PUSH MODEL
270
==============
271
To use the push-model for providing audio data, simply don't set (keep
272
zero-initialized) the stream_cb field in the saudio_desc struct when
273
calling saudio_setup().
274
275
To provide sample data with the push model, call the saudio_push()
276
function at regular intervals (for instance once per frame). You can
277
call the saudio_expect() function to ask Sokol Audio how much room is
278
in the ring buffer, but if you provide a continuous stream of data
279
at the right sample rate, saudio_expect() isn't required (it's a simple
280
way to sync/throttle your sample generation code with the playback
281
rate though).
282
283
With saudio_push() you may need to maintain your own intermediate sample
284
buffer, since pushing individual sample values isn't very efficient.
285
The following example is from the MOD player sample in
286
sokol-samples (https://github.com/floooh/sokol-samples):
287
288
const int num_frames = saudio_expect();
289
if (num_frames > 0) {
290
const int num_samples = num_frames * saudio_channels();
291
read_samples(flt_buf, num_samples);
292
saudio_push(flt_buf, num_frames);
293
}
294
295
Another option is to ignore saudio_expect(), and just push samples as they
296
are generated in small batches. In this case you *need* to generate the
297
samples at the right sample rate:
298
299
The following example is taken from the Tiny Emulators project
300
(https://github.com/floooh/chips-test), this is for mono playback,
301
so (num_samples == num_frames):
302
303
// tick the sound generator
304
if (ay38910_tick(&sys->psg)) {
305
// new sample is ready
306
sys->sample_buffer[sys->sample_pos++] = sys->psg.sample;
307
if (sys->sample_pos == sys->num_samples) {
308
// new sample packet is ready
309
saudio_push(sys->sample_buffer, sys->num_samples);
310
sys->sample_pos = 0;
311
}
312
}
313
314
THE WEBAUDIO BACKEND
315
====================
316
The WebAudio backend is currently using a ScriptProcessorNode callback to
317
feed the sample data into WebAudio. ScriptProcessorNode has been
318
deprecated for a while because it is running from the main thread, with
319
the default initialization parameters it works 'pretty well' though.
320
Ultimately Sokol Audio will use Audio Worklets, but this requires a few
321
more things to fall into place (Audio Worklets implemented everywhere,
322
SharedArrayBuffers enabled again, and I need to figure out a 'low-cost'
323
solution in terms of implementation effort, since Audio Worklets are
324
a lot more complex than ScriptProcessorNode if the audio data needs to come
325
from the main thread).
326
327
The WebAudio backend is automatically selected when compiling for
328
emscripten (__EMSCRIPTEN__ define exists).
329
330
https://developers.google.com/web/updates/2017/12/audio-worklet
331
https://developers.google.com/web/updates/2018/06/audio-worklet-design-pattern
332
333
"Blob URLs": https://www.html5rocks.com/en/tutorials/workers/basics/
334
335
Also see: https://blog.paul.cx/post/a-wait-free-spsc-ringbuffer-for-the-web/
336
337
THE COREAUDIO BACKEND
338
=====================
339
The CoreAudio backend is selected on macOS and iOS (__APPLE__ is defined).
340
Since the CoreAudio API is implemented in C (not Objective-C) on macOS the
341
implementation part of Sokol Audio can be included into a C source file.
342
343
However on iOS, Sokol Audio must be compiled as Objective-C due to it's
344
reliance on the AVAudioSession object. The iOS code path support both
345
being compiled with or without ARC (Automatic Reference Counting).
346
347
For thread synchronisation, the CoreAudio backend will use the
348
pthread_mutex_* functions.
349
350
The incoming floating point samples will be directly forwarded to
351
CoreAudio without further conversion.
352
353
macOS and iOS applications that use Sokol Audio need to link with
354
the AudioToolbox framework.
355
356
THE WASAPI BACKEND
357
==================
358
The WASAPI backend is automatically selected when compiling on Windows
359
(_WIN32 is defined).
360
361
For thread synchronisation a Win32 critical section is used.
362
363
WASAPI may use a different size for its own streaming buffer then requested,
364
so the base latency may be slightly bigger. The current backend implementation
365
converts the incoming floating point sample values to signed 16-bit
366
integers.
367
368
The required Windows system DLLs are linked with #pragma comment(lib, ...),
369
so you shouldn't need to add additional linker libs in the build process
370
(otherwise this is a bug which should be fixed in sokol_audio.h).
371
372
THE ALSA BACKEND
373
================
374
The ALSA backend is automatically selected when compiling on Linux
375
('linux' is defined).
376
377
For thread synchronisation, the pthread_mutex_* functions are used.
378
379
Samples are directly forwarded to ALSA in 32-bit float format, no
380
further conversion is taking place.
381
382
You need to link with the 'asound' library, and the <alsa/asoundlib.h>
383
header must be present (usually both are installed with some sort
384
of ALSA development package).
385
386
THE VITA BACKEND
387
================
388
The VITA backend is automatically selected when compiling with vitasdk
389
('PSP2_SDK_VERSION' is defined).
390
391
For thread synchronisation, the pthread_mutex_* functions are used.
392
393
Samples are converted from float to short (uint16_t) to maintain
394
all the same interface/api as other platforms.
395
396
You may use any supported sample rate you wish, but all audio MUST
397
match the same sample rate you choose.
398
399
This uses the "BGM" port to allow selecting the sample rate ("Main"
400
port is restricted to 48000 only).
401
402
You need to link with the 'SceAudio' library, and the <psp2/audioout.h>
403
header must be present (usually both are installed with the vitasdk).
404
405
THE 3DS BACKEND
406
================
407
The 3DS backend is automatically selected when compiling with libctru
408
('__3DS__' is defined).
409
410
Running a separate thread on the older 3ds is not a good idea and I
411
was not able to get it working without slowing down the main thread
412
too much (it has a single core available with cooperative threads).
413
414
The NDSP seems to work better by using its ndspSetCallback method.
415
416
You may use any supported sample rate you wish, but all audio MUST
417
match the same sample rate you choose or it will sound slowed down
418
or sped up.
419
420
The queue size and other NDSP specific parameters can be chosen by
421
the provided 'saudio_n3ds_desc' type. Defaults will be used if
422
nothing is provided.
423
424
There is a known issue of a noticeable delay when starting a new
425
sound on emulators. I was not able to improve this to my liking
426
and ~300ms can be expected. This can be improved by using a lower
427
buffer size than the 2048 default but I would not suggest under
428
1536. It may crash under 1408, and they must be in multiples of 128.
429
Note: I was NOT able to reproduce this issue on a real device and
430
the audio worked perfectly.
431
432
433
MEMORY ALLOCATION OVERRIDE
434
==========================
435
You can override the memory allocation functions at initialization time
436
like this:
437
438
void* my_alloc(size_t size, void* user_data) {
439
return malloc(size);
440
}
441
442
void my_free(void* ptr, void* user_data) {
443
free(ptr);
444
}
445
446
...
447
saudio_setup(&(saudio_desc){
448
// ...
449
.allocator = {
450
.alloc_fn = my_alloc,
451
.free_fn = my_free,
452
.user_data = ...,
453
}
454
});
455
...
456
457
If no overrides are provided, malloc and free will be used.
458
459
This only affects memory allocation calls done by sokol_audio.h
460
itself though, not any allocations in OS libraries.
461
462
Memory allocation will only happen on the same thread where saudio_setup()
463
was called, so you don't need to worry about thread-safety.
464
465
466
ERROR REPORTING AND LOGGING
467
===========================
468
To get any logging information at all you need to provide a logging callback in the setup call
469
the easiest way is to use sokol_log.h:
470
471
#include "sokol_log.h"
472
473
saudio_setup(&(saudio_desc){ .logger.func = slog_func });
474
475
To override logging with your own callback, first write a logging function like this:
476
477
void my_log(const char* tag, // e.g. 'saudio'
478
uint32_t log_level, // 0=panic, 1=error, 2=warn, 3=info
479
uint32_t log_item_id, // SAUDIO_LOGITEM_*
480
const char* message_or_null, // a message string, may be nullptr in release mode
481
uint32_t line_nr, // line number in sokol_audio.h
482
const char* filename_or_null, // source filename, may be nullptr in release mode
483
void* user_data)
484
{
485
...
486
}
487
488
...and then setup sokol-audio like this:
489
490
saudio_setup(&(saudio_desc){
491
.logger = {
492
.func = my_log,
493
.user_data = my_user_data,
494
}
495
});
496
497
The provided logging function must be reentrant (e.g. be callable from
498
different threads).
499

Showing the first 500 of 2664 diff lines for this file. This diff is INCOMPLETE; read the file or clone the repository for the rest.

vendor/sokol/sokol_gfx.hdeleted
@@ -1,26612 +0,0 @@
1
#if defined(SOKOL_IMPL) && !defined(SOKOL_GFX_IMPL)
2
#define SOKOL_GFX_IMPL
3
#endif
4
#ifndef SOKOL_GFX_INCLUDED
5
/*
6
sokol_gfx.h -- simple 3D API wrapper
7
8
Project URL: https://github.com/floooh/sokol
9
10
Example code: https://github.com/floooh/sokol-samples
11
12
Do this:
13
#define SOKOL_IMPL or
14
#define SOKOL_GFX_IMPL
15
before you include this file in *one* C or C++ file to create the
16
implementation.
17
18
In the same place define one of the following to select the rendering
19
backend:
20
#define SOKOL_GLCORE
21
#define SOKOL_GLES3
22
#define SOKOL_D3D11
23
#define SOKOL_METAL
24
#define SOKOL_WGPU
25
#define SOKOL_VULKAN
26
#define SOKOL_DUMMY_BACKEND
27
28
I.e. for the desktop GL it should look like this:
29
30
#include ...
31
#include ...
32
#define SOKOL_IMPL
33
#define SOKOL_GLCORE
34
#include "sokol_gfx.h"
35
36
The dummy backend replaces the platform-specific backend code with empty
37
stub functions. This is useful for writing tests that need to run on the
38
command line.
39
40
Optionally provide the following defines with your own implementations:
41
42
SOKOL_ASSERT(c) - your own assert macro (default: assert(c))
43
SOKOL_UNREACHABLE() - a guard macro for unreachable code (default: assert(false))
44
SOKOL_GFX_API_DECL - public function declaration prefix (default: extern)
45
SOKOL_API_DECL - same as SOKOL_GFX_API_DECL
46
SOKOL_API_IMPL - public function implementation prefix (default: -)
47
SOKOL_TRACE_HOOKS - enable trace hook callbacks (search below for TRACE HOOKS)
48
SOKOL_EXTERNAL_GL_LOADER - indicates that you're using your own GL loader, in this case
49
sokol_gfx.h will not include any platform GL headers and disable
50
the integrated Win32 GL loader
51
52
If sokol_gfx.h is compiled as a DLL, define the following before
53
including the declaration or implementation:
54
55
SOKOL_DLL
56
57
On Windows, SOKOL_DLL will define SOKOL_GFX_API_DECL as __declspec(dllexport)
58
or __declspec(dllimport) as needed.
59
60
Optionally define the following to force debug checks and validations
61
even in release mode:
62
63
SOKOL_DEBUG - by default this is defined if NDEBUG is not defined
64
65
Link with the following system libraries (note that sokol_app.h has
66
additional linker requirements):
67
68
- on macOS/iOS with Metal: Metal
69
- on macOS with GL: OpenGL
70
- on iOS with GL: OpenGLES
71
- on Linux with EGL: GL or GLESv2
72
- on Linux with GLX: GL
73
- on Android: GLESv3, log, android
74
- on Windows with the MSVC or Clang toolchains: no action needed, libs are defined in-source via pragma-comment-lib
75
- on Windows with MINGW/MSYS2 gcc: compile with '-mwin32' so that _WIN32 is defined
76
- with the D3D11 backend: -ld3d11
77
78
On macOS and iOS, the implementation must be compiled as Objective-C.
79
80
On Emscripten:
81
- for WebGL2: add the linker option `-s USE_WEBGL2=1`
82
- for WebGPU: compile and link with `--use-port=emdawnwebgpu`
83
(for more exotic situations, read: https://dawn.googlesource.com/dawn/+/refs/heads/main/src/emdawnwebgpu/pkg/README.md)
84
85
sokol_gfx DOES NOT:
86
===================
87
- create a window, swapchain or the 3D-API context/device, you must do this
88
before sokol_gfx is initialized, and pass any required information
89
(like 3D device pointers) to the sokol_gfx initialization call
90
91
- present the rendered frame, how this is done exactly usually depends
92
on how the window and 3D-API context/device was created
93
94
- provide a unified shader language, instead 3D-API-specific shader
95
source-code or shader-bytecode must be provided (for the "official"
96
offline shader cross-compiler / code-generator, see here:
97
https://github.com/floooh/sokol-tools/blob/master/docs/sokol-shdc.md)
98
99
100
STEP BY STEP
101
============
102
--- to initialize sokol_gfx, after creating a window and a 3D-API
103
context/device, call:
104
105
sg_setup(const sg_desc*)
106
107
Depending on the selected 3D backend, sokol-gfx requires some
108
information about its runtime environment, like a GPU device pointer,
109
default swapchain pixel formats and so on. If you are using sokol_app.h
110
for the window system glue, you can use a helper function provided in
111
the sokol_glue.h header:
112
113
#include "sokol_gfx.h"
114
#include "sokol_app.h"
115
#include "sokol_glue.h"
116
//...
117
sg_setup(&(sg_desc){
118
.environment = sglue_environment(),
119
});
120
121
To get any logging output for errors and from the validation layer, you
122
need to provide a logging callback. Easiest way is through sokol_log.h:
123
124
#include "sokol_log.h"
125
//...
126
sg_setup(&(sg_desc){
127
//...
128
.logger.func = slog_func,
129
});
130
131
--- create resource objects (buffers, images, views, samplers, shaders
132
and pipeline objects)
133
134
sg_buffer sg_make_buffer(const sg_buffer_desc*)
135
sg_image sg_make_image(const sg_image_desc*)
136
sg_view sg_make_view(const sg_view_desc*)
137
sg_sampler sg_make_sampler(const sg_sampler_desc*)
138
sg_shader sg_make_shader(const sg_shader_desc*)
139
sg_pipeline sg_make_pipeline(const sg_pipeline_desc*)
140
141
--- start a render- or compute-pass:
142
143
sg_begin_pass(const sg_pass* pass);
144
145
Typically, render passes render into an externally provided swapchain which
146
presents the rendering result on the display. Such a 'swapchain pass'
147
is started like this:
148
149
sg_begin_pass(&(sg_pass){ .action = { ... }, .swapchain = sglue_swapchain() })
150
151
...where .action is an sg_pass_action struct containing actions to be performed
152
at the start and end of a render pass (such as clearing the render surfaces to
153
a specific color), and .swapchain is an sg_swapchain struct with all the required
154
information to render into the swapchain's surfaces.
155
156
To start an 'offscreen render pass' into sokol-gfx image objects, populate
157
the sg_pass.attachments nested struct with attachment view objects
158
(1..4 color-attachment-views for to render into, a depth-stencil-attachment-view
159
to provide the depth-stencil-buffer, and optionally 1..4 resolve-attachment-views
160
for an MSAA-resolve operation:
161
162
sg_begin_pass(&(sg_pass){
163
.action = { ... },
164
.attachments = {
165
.colors[0] = color_attachment_view,
166
.resolves[0] = optional_resolve_attachment_view,
167
.depth_stencil = depth_stencil_attachment_view,
168
},
169
});
170
171
To start a compute-pass, just set the .compute item to true:
172
173
sg_begin_pass(&(sg_pass){ .compute = true });
174
175
--- set the pipeline state for the next draw call with:
176
177
sg_apply_pipeline(sg_pipeline pip)
178
179
--- fill an sg_bindings struct with the resource bindings for the next
180
draw- or dispatch-call (0..N vertex buffers, 0 or 1 index buffer, 0..N views,
181
0..N samplers), and call
182
183
sg_apply_bindings(const sg_bindings* bindings)
184
185
...to update the resource bindings. Note that in a compute pass, no vertex-
186
or index-buffer bindings can be used, and in render passes, no storage-image bindings
187
are allowed. Those restrictions will be checked by the sokol-gfx validation layer.
188
189
--- optionally update shader uniform data with:
190
191
sg_apply_uniforms(int ub_slot, const sg_range* data)
192
193
Read the section 'UNIFORM DATA LAYOUT' to learn about the expected memory layout
194
of the uniform data passed into sg_apply_uniforms().
195
196
--- kick off a draw call with:
197
198
sg_draw(int base_element, int num_elements, int num_instances)
199
200
The sg_draw() function unifies all the different ways to render primitives
201
in a single call (indexed vs non-indexed rendering, and instanced vs non-instanced
202
rendering). In case of indexed rendering, base_element and num_element specify
203
indices in the currently bound index buffer. In case of non-indexed rendering
204
base_element and num_elements specify vertices in the currently bound
205
vertex-buffer(s). To perform instanced rendering, the rendering pipeline
206
must be setup for instancing (see sg_pipeline_desc below), a separate vertex buffer
207
containing per-instance data must be bound, and the num_instances parameter
208
must be > 1.
209
210
Alternatively, call:
211
212
sg_draw_ex(...)
213
214
to provide a base-vertex and/or base-instance which allows to render
215
from different sections of a vertex buffer without rebinding the
216
vertex buffer with a different offset. Note that the `sg_draw_ex()`
217
only has limited portability on OpenGL, check the sg_limits struct
218
members .draw_base_vertex and .draw_base_instance for runtime support,
219
those are generally true on non-GL-backends, and on GL the feature
220
flags are set according to the GL version:
221
222
- on GL base_instance != 0 is only supported since GL 4.2
223
- on GLES3.x, base_instance != 0 is not supported
224
- on GLES3.x, base_vertex is only supported since GLES3.2
225
(e.g. not supported on WebGL2)
226
227
--- ...or kick of a dispatch call to invoke a compute shader workload:
228
229
sg_dispatch(int num_groups_x, int num_groups_y, int num_groups_z)
230
231
The dispatch args define the number of 'compute workgroups' processed
232
by the currently applied compute shader.
233
234
--- finish the current pass with:
235
236
sg_end_pass()
237
238
--- when done with the current frame, call
239
240
sg_commit()
241
242
--- at the end of your program, shutdown sokol_gfx with:
243
244
sg_shutdown()
245
246
--- if you need to destroy resources before sg_shutdown(), call:
247
248
sg_destroy_buffer(sg_buffer buf)
249
sg_destroy_image(sg_image img)
250
sg_destroy_sampler(sg_sampler smp)
251
sg_destroy_shader(sg_shader shd)
252
sg_destroy_pipeline(sg_pipeline pip)
253
sg_destroy_view(sg_view view)
254
255
--- to set a new viewport rectangle, call:
256
257
sg_apply_viewport(int x, int y, int width, int height, bool origin_top_left)
258
259
...or if you want to specify the viewport rectangle with float values:
260
261
sg_apply_viewportf(float x, float y, float width, float height, bool origin_top_left)
262
263
--- to set a new scissor rect, call:
264
265
sg_apply_scissor_rect(int x, int y, int width, int height, bool origin_top_left)
266
267
...or with float values:
268
269
sg_apply_scissor_rectf(float x, float y, float width, float height, bool origin_top_left)
270
271
Both sg_apply_viewport() and sg_apply_scissor_rect() must be called
272
inside a rendering pass (e.g. not in a compute pass, or outside a pass)
273
274
Note that sg_begin_pass() will reset both the viewport and scissor
275
rectangles to cover the entire framebuffer.
276
277
--- to update (overwrite) the content of buffer and image resources, call:
278
279
sg_update_buffer(sg_buffer buf, const sg_range* data)
280
sg_update_image(sg_image img, const sg_image_data* data)
281
282
Buffers and images to be updated must have been created with
283
sg_buffer_desc.usage.dynamic_update or .stream_update.
284
285
Only one update per frame is allowed for buffer and image resources when
286
using the sg_update_*() functions. The rationale is to have a simple
287
protection from the CPU scribbling over data the GPU is currently
288
using, or the CPU having to wait for the GPU
289
290
Buffer and image updates can be partial, as long as a rendering
291
operation only references the valid (updated) data in the
292
buffer or image.
293
294
--- to append a chunk of data to a buffer resource, call:
295
296
int sg_append_buffer(sg_buffer buf, const sg_range* data)
297
298
The difference to sg_update_buffer() is that sg_append_buffer()
299
can be called multiple times per frame to append new data to the
300
buffer piece by piece, optionally interleaved with draw calls referencing
301
the previously written data.
302
303
sg_append_buffer() returns a byte offset to the start of the
304
written data, this offset can be assigned to
305
sg_bindings.vertex_buffer_offsets[n] or
306
sg_bindings.index_buffer_offset
307
308
Code example:
309
310
for (...) {
311
const void* data = ...;
312
const int num_bytes = ...;
313
int offset = sg_append_buffer(buf, &(sg_range) { .ptr=data, .size=num_bytes });
314
bindings.vertex_buffer_offsets[0] = offset;
315
sg_apply_pipeline(pip);
316
sg_apply_bindings(&bindings);
317
sg_apply_uniforms(...);
318
sg_draw(...);
319
}
320
321
A buffer to be used with sg_append_buffer() must have been created
322
with sg_buffer_desc.usage.dynamic_update or .stream_update.
323
324
If the application appends more data to the buffer then fits into
325
the buffer, the buffer will go into the "overflow" state for the
326
rest of the frame.
327
328
Any draw calls attempting to render an overflown buffer will be
329
silently dropped (in debug mode this will also result in a
330
validation error).
331
332
You can also check manually if a buffer is in overflow-state by calling
333
334
bool sg_query_buffer_overflow(sg_buffer buf)
335
336
You can manually check to see if an overflow would occur before adding
337
any data to a buffer by calling
338
339
bool sg_query_buffer_will_overflow(sg_buffer buf, size_t size)
340
341
NOTE: Due to restrictions in underlying 3D-APIs, appended chunks of
342
data will be 4-byte aligned in the destination buffer. This means
343
that there will be gaps in index buffers containing 16-bit indices
344
when the number of indices in a call to sg_append_buffer() is
345
odd. This isn't a problem when each call to sg_append_buffer()
346
is associated with one draw call, but will be problematic when
347
a single indexed draw call spans several appended chunks of indices.
348
349
--- to check at runtime for optional features, limits and pixelformat support,
350
call:
351
352
sg_features sg_query_features()
353
sg_limits sg_query_limits()
354
sg_pixelformat_info sg_query_pixelformat(sg_pixel_format fmt)
355
356
--- if you need to call into the underlying 3D-API directly, you must call:
357
358
sg_reset_state_cache()
359
360
...before calling sokol_gfx functions again
361
362
--- you can inspect the original sg_desc structure handed to sg_setup()
363
by calling sg_query_desc(). This will return an sg_desc struct with
364
the default values patched in instead of any zero-initialized values
365
366
--- you can get a desc struct matching the creation attributes of a
367
specific resource object via:
368
369
sg_buffer_desc sg_query_buffer_desc(sg_buffer buf)
370
sg_image_desc sg_query_image_desc(sg_image img)
371
sg_sampler_desc sg_query_sampler_desc(sg_sampler smp)
372
sg_shader_desc sq_query_shader_desc(sg_shader shd)
373
sg_pipeline_desc sg_query_pipeline_desc(sg_pipeline pip)
374
sg_view_desc sg_query_view_desc(sg_view view)
375
376
...but NOTE that the returned desc structs may be incomplete, only
377
creation attributes that are kept around internally after resource
378
creation will be filled in, and in some cases (like shaders) that's
379
very little. Any missing attributes will be set to zero. The returned
380
desc structs might still be useful as partial blueprint for creating
381
similar resources if filled up with the missing attributes.
382
383
Calling the query-desc functions on an invalid resource will return
384
completely zeroed structs (it makes sense to check the resource state
385
with sg_query_*_state() first)
386
387
--- you can query the default resource creation parameters through the functions
388
389
sg_buffer_desc sg_query_buffer_defaults(const sg_buffer_desc* desc)
390
sg_image_desc sg_query_image_defaults(const sg_image_desc* desc)
391
sg_sampler_desc sg_query_sampler_defaults(const sg_sampler_desc* desc)
392
sg_shader_desc sg_query_shader_defaults(const sg_shader_desc* desc)
393
sg_pipeline_desc sg_query_pipeline_defaults(const sg_pipeline_desc* desc)
394
sg_view_desc sg_query_view_defaults(const sg_view_desc* desc)
395
396
These functions take a pointer to a desc structure which may contain
397
zero-initialized items for default values. These zero-init values
398
will be replaced with their concrete values in the returned desc
399
struct.
400
401
--- you can inspect various internal resource runtime values via:
402
403
sg_buffer_info sg_query_buffer_info(sg_buffer buf)
404
sg_image_info sg_query_image_info(sg_image img)
405
sg_sampler_info sg_query_sampler_info(sg_sampler smp)
406
sg_shader_info sg_query_shader_info(sg_shader shd)
407
sg_pipeline_info sg_query_pipeline_info(sg_pipeline pip)
408
sg_view_info sg_query_view_info(sg_view view)
409
410
...please note that the returned info-structs are tied quite closely
411
to sokol_gfx.h internals, and may change more often than other
412
public API functions and structs.
413
414
-- you can query the type/flavour and parent resource of a view:
415
416
sg_view_type sg_query_view_type(sg_view view)
417
sg_image sg_query_view_image(sg_view view)
418
sg_buffer sg_query_view_buffer(sg_view view)
419
420
--- you can query stats and control stats collection via:
421
422
sg_query_stats()
423
sg_enable_stats()
424
sg_disable_stats()
425
sg_stats_enabled()
426
427
--- you can ask at runtime what backend sokol_gfx.h has been compiled for:
428
429
sg_backend sg_query_backend(void)
430
431
--- call the following helper functions to compute the number of
432
bytes in a texture row or surface for a specific pixel format.
433
These functions might be helpful when preparing image data for consumption
434
by sg_make_image() or sg_update_image():
435
436
int sg_query_row_pitch(sg_pixel_format fmt, int width, int int row_align_bytes);
437
int sg_query_surface_pitch(sg_pixel_format fmt, int width, int height, int row_align_bytes);
438
439
Width and height are generally in number pixels, but note that 'row' has different meaning
440
for uncompressed vs compressed pixel formats: for uncompressed formats, a row is identical
441
with a single line if pixels, while in compressed formats, one row is a line of *compression blocks*.
442
443
This is why calling sg_query_surface_pitch() for a compressed pixel format and height
444
N, N+1, N+2, ... may return the same result.
445
446
The row_align_bytes parameter is for added flexibility. For image data that goes into
447
the sg_make_image() or sg_update_image() this should generally be 1, because these
448
functions take tightly packed image data as input no matter what alignment restrictions
449
exist in the backend 3D APIs.
450
451
ON INITIALIZATION:
452
==================
453
When calling sg_setup(), a pointer to an sg_desc struct must be provided
454
which contains initialization options. These options provide two types
455
of information to sokol-gfx:
456
457
(1) upper bounds and limits needed to allocate various internal
458
data structures:
459
- the max number of resources of each type that can
460
be alive at the same time, this is used for allocating
461
internal pools
462
- the max overall size of uniform data that can be
463
updated per frame, including a worst-case alignment
464
per uniform update (this worst-case alignment is 256 bytes)
465
- the max size of all dynamic resource updates (sg_update_buffer,
466
sg_append_buffer and sg_update_image) per frame
467
- the max number of compute-dispatch calls in a compute pass
468
Not all of those limit values are used by all backends, but it is
469
good practice to provide them none-the-less.
470
471
(2) 3D backend "environment information" in a nested sg_environment struct:
472
- pointers to backend-specific context- or device-objects (for instance
473
the D3D11, WebGPU or Metal device objects)
474
- defaults for external swapchain pixel formats and sample counts,
475
these will be used as default values in image and pipeline objects,
476
and the sg_swapchain struct passed into sg_begin_pass()
477
Usually you provide a complete sg_environment struct through
478
a helper function, as an example look at the sglue_environment()
479
function in the sokol_glue.h header.
480
481
See the documentation block of the sg_desc struct below for more information.
482
483
484
ON RENDER PASSES
485
================
486
Relevant samples:
487
- https://floooh.github.io/sokol-html5/offscreen-sapp.html
488
- https://floooh.github.io/sokol-html5/offscreen-msaa-sapp.html
489
- https://floooh.github.io/sokol-html5/mrt-sapp.html
490
- https://floooh.github.io/sokol-html5/mrt-pixelformats-sapp.html
491
492
A render pass groups rendering commands into a set of render target images
493
(called 'render pass attachments'). Render target images can be used in subsequent
494
passes as textures (it is invalid to use the same image both as render target
495
and as texture in the same pass).
496
497
The following sokol-gfx functions must only be called inside a render-pass:
498
499
sg_apply_viewport[f]

Showing the first 500 of 26613 diff lines for this file. This diff is INCOMPLETE; read the file or clone the repository for the rest.

vendor/sokol/sokol_glue.hdeleted
@@ -1,206 +0,0 @@
1
#if defined(SOKOL_IMPL) && !defined(SOKOL_GLUE_IMPL)
2
#define SOKOL_GLUE_IMPL
3
#endif
4
#ifndef SOKOL_GLUE_INCLUDED
5
/*
6
sokol_glue.h -- glue helper functions for sokol headers
7
8
Project URL: https://github.com/floooh/sokol
9
10
Do this:
11
#define SOKOL_IMPL or
12
#define SOKOL_GLUE_IMPL
13
before you include this file in *one* C or C++ file to create the
14
implementation.
15
16
...optionally provide the following macros to override defaults:
17
18
SOKOL_ASSERT(c) - your own assert macro (default: assert(c))
19
SOKOL_GLUE_API_DECL - public function declaration prefix (default: extern)
20
SOKOL_API_DECL - same as SOKOL_GLUE_API_DECL
21
SOKOL_API_IMPL - public function implementation prefix (default: -)
22
23
If sokol_glue.h is compiled as a DLL, define the following before
24
including the declaration or implementation:
25
26
SOKOL_DLL
27
28
On Windows, SOKOL_DLL will define SOKOL_GLUE_API_DECL as __declspec(dllexport)
29
or __declspec(dllimport) as needed.
30
31
OVERVIEW
32
========
33
sokol_glue.h provides glue helper functions between sokol_gfx.h and sokol_app.h,
34
so that sokol_gfx.h doesn't need to depend on sokol_app.h but can be
35
used with different window system glue libraries.
36
37
PROVIDED FUNCTIONS
38
==================
39
40
sg_environment sglue_environment(void)
41
42
Returns an sg_environment struct initialized by calling sokol_app.h
43
functions. Use this in the sg_setup() call like this:
44
45
sg_setup(&(sg_desc){
46
.environment = sglue_environment(),
47
...
48
});
49
50
sg_swapchain sglue_swapchain(void)
51
52
Returns an sg_swapchain struct initialized by calling sokol_app.h
53
functions. Use this in sg_begin_pass() for a 'swapchain pass' like
54
this:
55
56
sg_begin_pass(&(sg_pass){ .swapchain = sglue_swapchain(), ... });
57
58
LICENSE
59
=======
60
zlib/libpng license
61
62
Copyright (c) 2018 Andre Weissflog
63
64
This software is provided 'as-is', without any express or implied warranty.
65
In no event will the authors be held liable for any damages arising from the
66
use of this software.
67
68
Permission is granted to anyone to use this software for any purpose,
69
including commercial applications, and to alter it and redistribute it
70
freely, subject to the following restrictions:
71
72
1. The origin of this software must not be misrepresented; you must not
73
claim that you wrote the original software. If you use this software in a
74
product, an acknowledgment in the product documentation would be
75
appreciated but is not required.
76
77
2. Altered source versions must be plainly marked as such, and must not
78
be misrepresented as being the original software.
79
80
3. This notice may not be removed or altered from any source
81
distribution.
82
*/
83
#define SOKOL_GLUE_INCLUDED
84
85
#if defined(SOKOL_API_DECL) && !defined(SOKOL_GLUE_API_DECL)
86
#define SOKOL_GLUE_API_DECL SOKOL_API_DECL
87
#endif
88
#ifndef SOKOL_GLUE_API_DECL
89
#if defined(_WIN32) && defined(SOKOL_DLL) && defined(SOKOL_GLUE_IMPL)
90
#define SOKOL_GLUE_API_DECL __declspec(dllexport)
91
#elif defined(_WIN32) && defined(SOKOL_DLL)
92
#define SOKOL_GLUE_API_DECL __declspec(dllimport)
93
#else
94
#define SOKOL_GLUE_API_DECL extern
95
#endif
96
#endif
97
98
#ifndef SOKOL_GFX_INCLUDED
99
#error "Please include sokol_gfx.h before sokol_glue.h"
100
#endif
101
102
#ifdef __cplusplus
103
extern "C" {
104
#endif
105
106
SOKOL_GLUE_API_DECL sg_environment sglue_environment(void);
107
SOKOL_GLUE_API_DECL sg_swapchain sglue_swapchain(void);
108
109
#ifdef __cplusplus
110
} /* extern "C" */
111
#endif
112
#endif /* SOKOL_GLUE_INCLUDED */
113
114
/*-- IMPLEMENTATION ----------------------------------------------------------*/
115
#ifdef SOKOL_GLUE_IMPL
116
#define SOKOL_GLUE_IMPL_INCLUDED (1)
117
#include <string.h> /* memset */
118
119
#ifndef SOKOL_APP_INCLUDED
120
#error "Please include sokol_app.h before the sokol_glue.h implementation"
121
#endif
122
123
#ifndef SOKOL_API_IMPL
124
#define SOKOL_API_IMPL
125
#endif
126
127
#ifndef _SOKOL_PRIVATE
128
#if defined(__GNUC__) || defined(__clang__)
129
#define _SOKOL_PRIVATE __attribute__((unused)) static
130
#else
131
#define _SOKOL_PRIVATE static
132
#endif
133
#endif
134
135
#ifndef SOKOL_ASSERT
136
#include <assert.h>
137
#define SOKOL_ASSERT(c) assert(c)
138
#endif
139
#ifndef SOKOL_UNREACHABLE
140
#define SOKOL_UNREACHABLE SOKOL_ASSERT(false)
141
#endif
142
143
_SOKOL_PRIVATE sg_pixel_format _sglue_to_sgpixelformat(sapp_pixel_format fmt) {
144
switch (fmt) {
145
case SAPP_PIXELFORMAT_NONE: return SG_PIXELFORMAT_NONE;
146
case SAPP_PIXELFORMAT_RGBA8: return SG_PIXELFORMAT_RGBA8;
147
case SAPP_PIXELFORMAT_SRGB8A8: return SG_PIXELFORMAT_SRGB8A8;
148
case SAPP_PIXELFORMAT_BGRA8: return SG_PIXELFORMAT_BGRA8;
149
case SAPP_PIXELFORMAT_DEPTH_STENCIL: return SG_PIXELFORMAT_DEPTH_STENCIL;
150
case SAPP_PIXELFORMAT_DEPTH: return SG_PIXELFORMAT_DEPTH;
151
case SAPP_PIXELFORMAT_SBGRA8: // FIXME!
152
default:
153
SOKOL_UNREACHABLE;
154
return SG_PIXELFORMAT_NONE;
155
}
156
}
157
158
SOKOL_API_IMPL sg_environment sglue_environment(void) {
159
sg_environment res;
160
memset(&res, 0, sizeof(res));
161
const sapp_environment env = sapp_get_environment();
162
res.defaults.color_format = _sglue_to_sgpixelformat(env.defaults.color_format);
163
res.defaults.depth_format = _sglue_to_sgpixelformat(env.defaults.depth_format);
164
res.defaults.sample_count = env.defaults.sample_count;
165
res.metal.device = env.metal.device;
166
res.d3d11.device = env.d3d11.device;
167
res.d3d11.device_context = env.d3d11.device_context;
168
res.wgpu.device = env.wgpu.device;
169
res.vulkan.physical_device = env.vulkan.physical_device;
170
res.vulkan.device = env.vulkan.device;
171
res.vulkan.queue = env.vulkan.queue;
172
res.vulkan.queue_family_index = env.vulkan.queue_family_index;
173
return res;
174
}
175
176
SOKOL_API_IMPL sg_swapchain sglue_swapchain(void) {
177
sg_swapchain res;
178
memset(&res, 0, sizeof(res));
179
const sapp_swapchain sc = sapp_get_swapchain();
180
res.width = sc.width;
181
res.height = sc.height;
182
res.sample_count = sc.sample_count;
183
res.color_format = _sglue_to_sgpixelformat(sc.color_format);
184
res.depth_format = _sglue_to_sgpixelformat(sc.depth_format);
185
res.metal.current_drawable = sc.metal.current_drawable;
186
res.metal.depth_stencil_texture = sc.metal.depth_stencil_texture;
187
res.metal.msaa_color_texture = sc.metal.msaa_color_texture;
188
res.d3d11.render_view = sc.d3d11.render_view;
189
res.d3d11.resolve_view = sc.d3d11.resolve_view;
190
res.d3d11.depth_stencil_view = sc.d3d11.depth_stencil_view;
191
res.wgpu.render_view = sc.wgpu.render_view;
192
res.wgpu.resolve_view = sc.wgpu.resolve_view;
193
res.wgpu.depth_stencil_view = sc.wgpu.depth_stencil_view;
194
res.vulkan.render_image = sc.vulkan.render_image;
195
res.vulkan.render_view = sc.vulkan.render_view;
196
res.vulkan.resolve_image = sc.vulkan.resolve_image;
197
res.vulkan.resolve_view = sc.vulkan.resolve_view;
198
res.vulkan.depth_stencil_image = sc.vulkan.depth_stencil_image;
199
res.vulkan.depth_stencil_view = sc.vulkan.depth_stencil_view;
200
res.vulkan.render_finished_semaphore = sc.vulkan.render_finished_semaphore;
201
res.vulkan.present_complete_semaphore = sc.vulkan.present_complete_semaphore;
202
res.gl.framebuffer = sc.gl.framebuffer;
203
return res;
204
}
205
206
#endif /* SOKOL_GLUE_IMPL */
vendor/sokol/sokol_gp.hdeleted
@@ -1,3112 +0,0 @@
1
/*
2
Minimal efficient cross platform 2D graphics painter for Sokol GFX.
3
sokol_gp - v0.7.0 - 06/Dec/2024
4
Eduardo Bart - [email protected]
5
https://github.com/edubart/sokol_gp
6
7
# Sokol GP
8
9
Minimal efficient cross platform 2D graphics painter in pure C
10
using modern graphics API through the excellent [Sokol GFX](https://github.com/floooh/sokol) library.
11
12
Sokol GP, or in short SGP, stands for Sokol Graphics Painter.
13
14
![sample-primitives](https://raw.githubusercontent.com/edubart/sokol_gp/master/screenshots/sample-primitives.png)
15
16
## Features
17
18
* Made and optimized only for **2D rendering only**, no 3D support.
19
* Minimal, in a pure single C header.
20
* Use modern unfixed pipeline graphics APIs for more efficiency.
21
* Cross platform (backed by Sokol GFX).
22
* D3D11/OpenGL 3.3/Metal/WebGPU graphics backends (through Sokol GFX).
23
* **Automatic batching** (merge recent draw calls into batches automatically).
24
* **Batch optimizer** (rearranges the ordering of draw calls to batch more).
25
* Uses preallocated memory (no allocations at runtime).
26
* Supports drawing basic 2D primitives (rectangles, triangles, lines and points).
27
* Supports the classic 2D color blending modes (color blend, add, modulate, multiply).
28
* Supports 2D space transformations and changing 2D space coordinate systems.
29
* Supports drawing the basic primitives (rectangles, triangles, lines and points).
30
* Supports multiple texture bindings.
31
* Supports custom fragment shaders with 2D primitives.
32
* Can be mixed with projects that are already using Sokol GFX.
33
34
## Why?
35
36
Sokol GFX is an excellent library for rendering using unfixed pipelines
37
of modern graphics cards, but it is too complex to use for simple 2D drawing,
38
and it's API is too generic and specialized for 3D rendering. To draw 2D stuff, the programmer
39
usually needs to setup custom shaders when using Sokol GFX, or use its Sokol GL
40
extra library, but Sokol GL also has an API with 3D design in mind, which
41
incurs some costs and limitations.
42
43
This library was created to draw 2D primitives through Sokol GFX with ease,
44
and by not considering 3D usage it is optimized for 2D rendering only,
45
furthermore it features an **automatic batch optimizer**, more details of it will be described below.
46
47
## Automatic batch optimizer
48
49
When drawing the library creates a draw command queue of all primitives yet to be drawn,
50
every time a new draw command is added the batch optimizer looks back up to the last
51
8 recent draw commands (this is adjustable), and try to rearrange and merge drawing commands
52
if it finds a previous draw command that meets the following criteria:
53
54
* The new draw command and previous command uses the *same primitive pipeline*
55
* The new draw command and previous command uses the *same shader uniforms*
56
* The new draw command and previous command uses the *same texture bindings*
57
* The new draw command and previous command does not have another intermediary
58
draw command *that overlaps* in-between them.
59
60
By doing this the batch optimizer is able for example to merge textured draw calls,
61
even if they were drawn with other intermediary different textures draws between them.
62
The effect is more efficiency when drawing, because less draw calls will be dispatched
63
to the GPU,
64
65
This library can avoid a lot of work of making an efficient 2D drawing batching system,
66
by automatically merging draw calls behind the scenes at runtime,
67
thus the programmer does not need to manage batched draw calls manually,
68
nor he needs to sort batched texture draw calls,
69
the library will do this seamlessly behind the scenes.
70
71
The batching algorithm is fast, but it has `O(n)` CPU complexity for every new draw command added,
72
where `n` is the `SGP_BATCH_OPTIMIZER_DEPTH` configuration.
73
In experiments using `8` as the default is a good default,
74
but you may want to try out different values depending on your case.
75
Using values that are too high is not recommended, because the algorithm may take too long
76
scanning previous draw commands, and that may consume more CPU resources.
77
78
The batch optimizer can be disabled by setting `SGP_BATCH_OPTIMIZER_DEPTH` to 0,
79
you can use that to measure its impact.
80
81
In the samples directory of this repository there is a
82
benchmark example that tests drawing with the bath optimizer enabled/disabled.
83
On my machine that benchmark was able to increase performance in a 2.2x factor when it is enabled.
84
In some private game projects the gains of the batch optimizer proved to increase FPS performance
85
above 1.5x by just replacing the graphics backend with this library, with no internal
86
changes to the game itself.
87
88
## Design choices
89
90
The library has some design choices with performance in mind that will be discussed briefly here.
91
92
Like Sokol GFX, Sokol GP will never do any allocation in the draw loop,
93
so when initializing you must configure beforehand the maximum size of the
94
draw command queue buffer and the vertices buffer.
95
96
All the 2D space transformation (functions like `sgp_rotate`) are done by the CPU and not by the GPU,
97
this is intentionally to avoid adding extra overhead in the GPU, because typically the number
98
of vertices of 2D applications are not that large, and it is more efficient to perform
99
all the transformation with the CPU right away rather than pushing extra buffers to the GPU
100
that ends up using more bandwidth of the CPU<->GPU bus.
101
In contrast 3D applications usually dispatches vertex transformations to the GPU using a vertex shader,
102
they do this because the amount of vertices of 3D objects can be very large
103
and it is usually the best choice, but this is not true for 2D rendering.
104
105
Many APIs to transform the 2D space before drawing a primitive are available, such as
106
translate, rotate and scale. They can be used as similarly as the ones available in 3D graphics APIs,
107
but they are crafted for 2D only, for example when using 2D we don't need to use a 4x4 or 3x3 matrix
108
to perform vertex transformation, instead the code is specialized for 2D and can use a 2x3 matrix,
109
saving extra CPU float computations.
110
111
All pipelines always use a texture associated with it, even when drawing non textured primitives,
112
because this minimizes graphics pipeline changes when mixing textured calls and non textured calls,
113
improving efficiency.
114
115
The library is coded in the style of Sokol GFX headers, reusing many macros from there,
116
you can change some of its semantics such as custom allocator, custom log function, and some
117
other details, read `sokol_gfx.h` documentation for more on that.
118
119
## Usage
120
121
Copy `sokol_gp.h` along with other Sokol headers to the same folder. Setup Sokol GFX
122
as you usually would, then add call to `sgp_setup(desc)` just after `sg_setup(desc)`, and
123
call to `sgp_shutdown()` just before `sg_shutdown()`. Note that you should usually check if
124
SGP is valid after its creation with `sgp_is_valid()` and exit gracefully with an error if not.
125
126
In your frame draw function add `sgp_begin(width, height)` before calling any SGP
127
draw function, then draw your primitives. At the end of the frame (or framebuffer) you
128
should **ALWAYS call** `sgp_flush()` between a Sokol GFX begin/end render pass,
129
the `sgp_flush()` will dispatch all draw commands to Sokol GFX. Then call `sgp_end()` immediately
130
to discard the draw command queue.
131
132
An actual example of this setup will be shown below.
133
134
## Quick usage example
135
136
The following is a quick example on how to this library with Sokol GFX and Sokol APP:
137
138
```c
139
// This is an example on how to set up and use Sokol GP to draw a filled rectangle.
140
141
// Includes Sokol GFX, Sokol GP and Sokol APP, doing all implementations.
142
#define SOKOL_IMPL
143
#include "sokol_gfx.h"
144
#include "sokol_gp.h"
145
#include "sokol_app.h"
146
#include "sokol_glue.h"
147
#include "sokol_log.h"
148
149
#include <stdio.h> // for fprintf()
150
#include <stdlib.h> // for exit()
151
#include <math.h> // for sinf() and cosf()
152
153
// Called on every frame of the application.
154
static void frame(void) {
155
// Get current window size.
156
int width = sapp_width(), height = sapp_height();
157
float ratio = width/(float)height;
158
159
// Begin recording draw commands for a frame buffer of size (width, height).
160
sgp_begin(width, height);
161
// Set frame buffer drawing region to (0,0,width,height).
162
sgp_viewport(0, 0, width, height);
163
// Set drawing coordinate space to (left=-ratio, right=ratio, top=1, bottom=-1).
164
sgp_project(-ratio, ratio, 1.0f, -1.0f);
165
166
// Clear the frame buffer.
167
sgp_set_color(0.1f, 0.1f, 0.1f, 1.0f);
168
sgp_clear();
169
170
// Draw an animated rectangle that rotates and changes its colors.
171
float time = sapp_frame_count() * sapp_frame_duration();
172
float r = sinf(time)*0.5+0.5, g = cosf(time)*0.5+0.5;
173
sgp_set_color(r, g, 0.3f, 1.0f);
174
sgp_rotate_at(time, 0.0f, 0.0f);
175
sgp_draw_filled_rect(-0.5f, -0.5f, 1.0f, 1.0f);
176
177
// Begin a render pass.
178
sg_pass pass = {.swapchain = sglue_swapchain()};
179
sg_begin_pass(&pass);
180
// Dispatch all draw commands to Sokol GFX.
181
sgp_flush();
182
// Finish a draw command queue, clearing it.
183
sgp_end();
184
// End render pass.
185
sg_end_pass();
186
// Commit Sokol render.
187
sg_commit();
188
}
189
190
// Called when the application is initializing.
191
static void init(void) {
192
// Initialize Sokol GFX.
193
sg_desc sgdesc = {
194
.environment = sglue_environment(),
195
.logger.func = slog_func
196
};
197
sg_setup(&sgdesc);
198
if (!sg_isvalid()) {
199
fprintf(stderr, "Failed to create Sokol GFX context!\n");
200
exit(-1);
201
}
202
203
// Initialize Sokol GP, adjust the size of command buffers for your own use.
204
sgp_desc sgpdesc = {0};
205
sgp_setup(&sgpdesc);
206
if (!sgp_is_valid()) {
207
fprintf(stderr, "Failed to create Sokol GP context: %s\n", sgp_get_error_message(sgp_get_last_error()));
208
exit(-1);
209
}
210
}
211
212
// Called when the application is shutting down.
213
static void cleanup(void) {
214
// Cleanup Sokol GP and Sokol GFX resources.
215
sgp_shutdown();
216
sg_shutdown();
217
}
218
219
// Implement application main through Sokol APP.
220
sapp_desc sokol_main(int argc, char* argv[]) {
221
(void)argc;
222
(void)argv;
223
return (sapp_desc){
224
.init_cb = init,
225
.frame_cb = frame,
226
.cleanup_cb = cleanup,
227
.window_title = "Rectangle (Sokol GP)",
228
.logger.func = slog_func,
229
};
230
}
231
```
232
233
To run this example, first copy the `sokol_gp.h` header alongside with other Sokol headers
234
to the same folder, then compile with any C compiler using the proper linking flags (read `sokol_gfx.h`).
235
236
## Complete Examples
237
238
In folder `samples` you can find the following complete examples covering all APIs of the library:
239
240
* [sample-primitives.c](https://github.com/edubart/sokol_gp/blob/master/samples/sample-primitives.c): This is an example showing all drawing primitives and transformations APIs.
241
* [sample-blend.c](https://github.com/edubart/sokol_gp/blob/master/samples/sample-blend.c): This is an example showing all blend modes between 3 rectangles.
242
* [sample-framebuffer.c](https://github.com/edubart/sokol_gp/blob/master/samples/sample-framebuffer.c): This is an example showing how to use multiple `sgp_begin()` with frame buffers.
243
* [sample-sdf.c](https://github.com/edubart/sokol_gp/blob/master/samples/sample-sdf.c): This is an example on how to create custom shaders.
244
* [sample-effect.c](https://github.com/edubart/sokol_gp/blob/master/samples/sample-effect.c): This is an example on how to use custom shaders for 2D drawing.
245
* [sample-bench.c](https://github.com/edubart/sokol_gp/blob/master/samples/sample-bench.c): This is a heavy example used for benchmarking purposes.
246
247
These examples are used as the test suite for the library, you can build them by typing `make`.
248
249
## Error handling
250
251
It is possible that after many draw calls the command or vertex buffer may overflow,
252
in that case the library will set an error error state and will continue to operate normally,
253
but when flushing the drawing command queue with `sgp_flush()` no draw command will be dispatched.
254
This can happen because the library uses pre allocated buffers, in such
255
cases the issue can be fixed by increasing the prefixed command queue buffer and the vertices buffer
256
when calling `sgp_setup()`.
257
258
Making invalid number of push/pops of `sgp_push_transform()` and `sgp_pop_transform()`,
259
or nesting too many `sgp_begin()` and `sgp_end()` may also lead to errors, that
260
is a usage mistake.
261
262
You can enable the `SOKOL_DEBUG` macro in such cases to debug, or handle
263
the error programmatically by reading `sgp_get_last_error()` after calling `sgp_end()`.
264
It is also advised to leave `SOKOL_DEBUG` enabled when developing with Sokol, so you can
265
catch mistakes early.
266
267
## Blend modes
268
269
The library supports the most usual blend modes used in 2D, which are the following:
270
271
- `SGP_BLENDMODE_NONE` - No blending (`dstRGBA = srcRGBA`).
272
- `SGP_BLENDMODE_BLEND` - Alpha blending (`dstRGB = (srcRGB * srcA) + (dstRGB * (1-srcA))` and `dstA = srcA + (dstA * (1-srcA))`)
273
- `SGP_BLENDMODE_BLEND_PREMULTIPLIED` - Pre-multiplied alpha blending (`dstRGBA = srcRGBA + (dstRGBA * (1-srcA))`)
274
- `SGP_BLENDMODE_ADD` - Additive blending (`dstRGB = (srcRGB * srcA) + dstRGB` and `dstA = dstA`)
275
- `SGP_BLENDMODE_ADD_PREMULTIPLIED` - Pre-multiplied additive blending (`dstRGB = srcRGB + dstRGB` and `dstA = dstA`)
276
- `SGP_BLENDMODE_MOD` - Color modulate (`dstRGB = srcRGB * dstRGB` and `dstA = dstA`)
277
- `SGP_BLENDMODE_MUL` - Color multiply (`dstRGB = (srcRGB * dstRGB) + (dstRGB * (1-srcA))` and `dstA = (srcA * dstA) + (dstA * (1-srcA))`)
278
279
## Changing 2D coordinate system
280
281
You can change the screen area to draw by calling `sgp_viewport(x, y, width, height)`.
282
You can change the coordinate system of the 2D space by calling `sgp_project(left, right, top, bottom)`,
283
with it.
284
285
## Transforming 2D space
286
287
You can translate, rotate or scale the 2D space before a draw call, by using the transformation
288
functions the library provides, such as `sgp_translate(x, y)`, `sgp_rotate(theta)`, etc.
289
Check the cheat sheet or the header for more.
290
291
To save and restore the transformation state you should call `sgp_push_transform()` and
292
later `sgp_pop_transform()`.
293
294
## Drawing primitives
295
296
The library provides drawing functions for all the basic primitives, that is,
297
for points, lines, triangles and rectangles, such as `sgp_draw_line()` and `sgp_draw_filled_rect()`.
298
Check the cheat sheet or the header for more.
299
All of them have batched variations.
300
301
## Drawing textured primitives
302
303
To draw textured rectangles you can use `sgp_set_image(0, img)` and then sgp_draw_filled_rect()`,
304
this will draw an entire texture into a rectangle.
305
You should later reset the image with `sgp_reset_image(0)` to restore the bound image to default white image,
306
otherwise you will have glitches when drawing a solid color.
307
308
In case you want to draw a specific source from the texture,
309
you should use `sgp_draw_textured_rect()` instead.
310
311
By default textures are drawn using a simple nearest filter sampler,
312
you can change the sampler with `sgp_set_sampler(0, smp)` before drawing a texture,
313
it's recommended to restore the default sampler using `sgp_reset_sampler(0)`.
314
315
## Color modulation
316
317
All common pipelines have color modulation, and you can modulate
318
a color before a draw by setting the current state color with `sgp_set_color(r,g,b,a)`,
319
later you should reset the color to default (white) with `sgp_reset_color()`.
320
321
## Custom shaders
322
323
When using a custom shader, you must create a pipeline for it with `sgp_make_pipeline(desc)`,
324
using shader, blend mode and a draw primitive associated with it. Then you should
325
call `sgp_set_pipeline()` before the shader draw call. You are responsible for using
326
the same blend mode and drawing primitive as the created pipeline.
327
328
Custom uniforms can be passed to the shader with `sgp_set_uniform(vs_data, vs_size, fs_data, fs_size)`,
329
where you should always pass a pointer to a struct with exactly the same schema and size
330
as the one defined in the vertex and fragment shaders.
331
332
Although you can create custom shaders for each graphics backend manually,
333
it is advised should use the Sokol shader compiler [SHDC](https://github.com/floooh/sokol-tools/blob/master/docs/sokol-shdc.md),
334
because it can generate shaders for multiple backends from a single `.glsl` file,
335
and this usually works well.
336
337
By default the library uniform buffer per draw call has just 8 float uniforms
338
(`SGP_UNIFORM_CONTENT_SLOTS` configuration), and that may be too low to use with custom shaders.
339
This is the default because typically newcomers may not want to use custom 2D shaders,
340
and increasing a larger value means more overhead.
341
If you are using custom shaders please increase this value to be large enough to hold
342
the number of uniforms of your largest shader.
343
344
## Library configuration
345
346
The following macros can be defined before including to change the library behavior:
347
348
- `SGP_BATCH_OPTIMIZER_DEPTH` - Number of draw commands that the batch optimizer looks back at. Default is 8.
349
- `SGP_UNIFORM_CONTENT_SLOTS` - Maximum number of floats that can be stored in each draw call uniform buffer. Default is 8.
350
- `SGP_TEXTURE_SLOTS` - Maximum number of textures that can be bound per draw call. Default is 4.
351
352
## License
353
354
MIT, see LICENSE file or the end of `sokol_gp.h` file.
355
*/
356
357
#if defined(SOKOL_IMPL) && !defined(SOKOL_GP_IMPL)
358
#define SOKOL_GP_IMPL
359
#endif
360
361
#ifndef SOKOL_GP_INCLUDED
362
#define SOKOL_GP_INCLUDED 1
363
364
#ifndef SOKOL_GFX_INCLUDED
365
#error "Please include sokol_gfx.h before sokol_gp.h"
366
#endif
367
368
/* Number of draw commands that the batch optimizer looks back at.
369
8 is a fair default value, but could be tuned per application.
370
1 makes the batch optimizer try to merge only the very last draw call.
371
0 disables the batch optimizer
372
*/
373
#ifndef SGP_BATCH_OPTIMIZER_DEPTH
374
#define SGP_BATCH_OPTIMIZER_DEPTH 8
375
#endif
376
377
/* Number of uniform floats (4-bytes) slots that can be set in a shader.
378
Increase this value if you need to use shader with many uniforms.
379
*/
380
#ifndef SGP_UNIFORM_CONTENT_SLOTS
381
#define SGP_UNIFORM_CONTENT_SLOTS 8
382
#endif
383
384
/* Number of texture slots that can be bound in a pipeline. */
385
#ifndef SGP_TEXTURE_SLOTS
386
#define SGP_TEXTURE_SLOTS 4
387
#endif
388
389
#if defined(SOKOL_API_DECL) && !defined(SOKOL_GP_API_DECL)
390
#define SOKOL_GP_API_DECL SOKOL_API_DECL
391
#endif
392
#ifndef SOKOL_GP_API_DECL
393
#if defined(_WIN32) && defined(SOKOL_DLL) && defined(SOKOL_GP_IMPL)
394
#define SOKOL_GP_API_DECL __declspec(dllexport)
395
#elif defined(_WIN32) && defined(SOKOL_DLL)
396
#define SOKOL_GP_API_DECL __declspec(dllimport)
397
#else
398
#define SOKOL_GP_API_DECL extern
399
#endif
400
#endif
401
402
#ifndef SOKOL_LOG
403
#ifdef SOKOL_DEBUG
404
#include <stdio.h>
405
#define SOKOL_LOG(s) { SOKOL_ASSERT(s); puts(s); }
406
#else
407
#define SOKOL_LOG(s)
408
#endif
409
#endif
410
411
#include <stdbool.h>
412
#include <stdint.h>
413
414
#ifdef __cplusplus
415
extern "C" {
416
#endif
417
418
/* List of possible error codes. */
419
typedef enum sgp_error {
420
SGP_NO_ERROR = 0,
421
SGP_ERROR_SOKOL_INVALID,
422
SGP_ERROR_VERTICES_FULL,
423
SGP_ERROR_UNIFORMS_FULL,
424
SGP_ERROR_COMMANDS_FULL,
425
SGP_ERROR_VERTICES_OVERFLOW,
426
SGP_ERROR_TRANSFORM_STACK_OVERFLOW,
427
SGP_ERROR_TRANSFORM_STACK_UNDERFLOW,
428
SGP_ERROR_STATE_STACK_OVERFLOW,
429
SGP_ERROR_STATE_STACK_UNDERFLOW,
430
SGP_ERROR_ALLOC_FAILED,
431
SGP_ERROR_MAKE_VERTEX_BUFFER_FAILED,
432
SGP_ERROR_MAKE_WHITE_IMAGE_FAILED,
433
SGP_ERROR_MAKE_WHITE_VIEW_FAILED,
434
SGP_ERROR_MAKE_NEAREST_SAMPLER_FAILED,
435
SGP_ERROR_MAKE_COMMON_SHADER_FAILED,
436
SGP_ERROR_MAKE_COMMON_PIPELINE_FAILED,
437
} sgp_error;
438
439
/* Blend modes. */
440
typedef enum sgp_blend_mode {
441
SGP_BLENDMODE_NONE = 0, /* No blending
442
dstRGBA = srcRGBA */
443
SGP_BLENDMODE_BLEND, /* Alpha blending.
444
dstRGB = (srcRGB * srcA) + (dstRGB * (1-srcA))
445
dstA = srcA + (dstA * (1-srcA)) */
446
SGP_BLENDMODE_BLEND_PREMULTIPLIED, /* Pre-multiplied alpha blending.
447
dstRGBA = srcRGBA + (dstRGBA * (1-srcA)) */
448
SGP_BLENDMODE_ADD, /* Additive blending.
449
dstRGB = (srcRGB * srcA) + dstRGB
450
dstA = dstA */
451
SGP_BLENDMODE_ADD_PREMULTIPLIED, /* Pre-multiplied additive blending.
452
dstRGB = srcRGB + dstRGB
453
dstA = dstA */
454
SGP_BLENDMODE_MOD, /* Color modulate.
455
dstRGB = srcRGB * dstRGB
456
dstA = dstA */
457
SGP_BLENDMODE_MUL, /* Color multiply.
458
dstRGB = (srcRGB * dstRGB) + (dstRGB * (1-srcA))
459
dstA = (srcA * dstA) + (dstA * (1-srcA)) */
460
_SGP_BLENDMODE_NUM
461
} sgp_blend_mode;
462
463
typedef enum sgp_vs_attr_location {
464
SGP_VS_ATTR_COORD = 0,
465
SGP_VS_ATTR_COLOR = 1
466
} sgp_vs_attr_location;
467
468
typedef enum sgp_uniform_slot {
469
SGP_UNIFORM_SLOT_VERTEX = 0,
470
SGP_UNIFORM_SLOT_FRAGMENT = 1
471
} sgp_uniform_slot;
472
473
typedef struct sgp_isize {
474
int w, h;
475
} sgp_isize;
476
477
typedef struct sgp_irect {
478
int x, y, w, h;
479
} sgp_irect;
480
481
typedef struct sgp_rect {
482
float x, y, w, h;
483
} sgp_rect;
484
485
typedef struct sgp_textured_rect {
486
sgp_rect dst;
487
sgp_rect src;
488
} sgp_textured_rect;
489
490
typedef struct sgp_vec2 {
491
float x, y;
492
} sgp_vec2;
493
494
typedef sgp_vec2 sgp_point;
495
496
typedef struct sgp_line {
497
sgp_point a, b;
498
} sgp_line;
499

Showing the first 500 of 3114 diff lines for this file. This diff is INCOMPLETE; read the file or clone the repository for the rest.

vendor/sokol/sokol_log.hdeleted
@@ -1,334 +0,0 @@
1
#if defined(SOKOL_IMPL) && !defined(SOKOL_LOG_IMPL)
2
#define SOKOL_LOG_IMPL
3
#endif
4
#ifndef SOKOL_LOG_INCLUDED
5
/*
6
sokol_log.h -- common logging callback for sokol headers
7
8
Project URL: https://github.com/floooh/sokol
9
10
Example code: https://github.com/floooh/sokol-samples
11
12
Do this:
13
#define SOKOL_IMPL or
14
#define SOKOL_LOG_IMPL
15
before you include this file in *one* C or C++ file to create the
16
implementation.
17
18
Optionally provide the following defines when building the implementation:
19
20
SOKOL_ASSERT(c) - your own assert macro (default: assert(c))
21
SOKOL_UNREACHABLE() - a guard macro for unreachable code (default: assert(false))
22
SOKOL_LOG_API_DECL - public function declaration prefix (default: extern)
23
SOKOL_API_DECL - same as SOKOL_GFX_API_DECL
24
SOKOL_API_IMPL - public function implementation prefix (default: -)
25
26
Optionally define the following for verbose output:
27
28
SOKOL_DEBUG - by default this is defined if NDEBUG is not defined
29
30
31
OVERVIEW
32
========
33
sokol_log.h provides a default logging callback for other sokol headers.
34
35
To use the default log callback, just include sokol_log.h and provide
36
a function pointer to the 'slog_func' function when setting up the
37
sokol library:
38
39
For instance with sokol_audio.h:
40
41
#include "sokol_log.h"
42
...
43
saudio_setup(&(saudio_desc){ .logger.func = slog_func });
44
45
Logging output goes to stderr and/or a platform specific logging subsystem
46
(which means that in some scenarios you might see logging messages duplicated):
47
48
- Windows: stderr + OutputDebugStringA()
49
- macOS/iOS/Linux: stderr + syslog()
50
- Emscripten: console.info()/warn()/error()
51
- Android: __android_log_write()
52
53
On Windows with sokol_app.h also note the runtime config items to make
54
stdout/stderr output visible on the console for WinMain() applications
55
via sapp_desc.win32.console_attach or sapp_desc.win32.console_create,
56
however when running in a debugger on Windows, the logging output should
57
show up on the debug output UI panel.
58
59
In debug mode, a log message might look like this:
60
61
[sspine][error][id:12] /Users/floh/projects/sokol/util/sokol_spine.h:3472:0:
62
SKELETON_DESC_NO_ATLAS: no atlas object provided in sspine_skeleton_desc.atlas
63
64
The source path and line number is formatted like compiler errors, in some IDEs (like VSCode)
65
such error messages are clickable.
66
67
In release mode, logging is less verbose as to not bloat the executable with string data, but you still get
68
enough information to identify the type and location of an error:
69
70
[sspine][error][id:12][line:3472]
71
72
RULES FOR WRITING YOUR OWN LOGGING FUNCTION
73
===========================================
74
- must be re-entrant because it might be called from different threads
75
- must treat **all** provided string pointers as optional (can be null)
76
- don't store the string pointers, copy the string data instead
77
- must not return for log level panic
78
79
LICENSE
80
=======
81
zlib/libpng license
82
83
Copyright (c) 2023 Andre Weissflog
84
85
This software is provided 'as-is', without any express or implied warranty.
86
In no event will the authors be held liable for any damages arising from the
87
use of this software.
88
89
Permission is granted to anyone to use this software for any purpose,
90
including commercial applications, and to alter it and redistribute it
91
freely, subject to the following restrictions:
92
93
1. The origin of this software must not be misrepresented; you must not
94
claim that you wrote the original software. If you use this software in a
95
product, an acknowledgment in the product documentation would be
96
appreciated but is not required.
97
98
2. Altered source versions must be plainly marked as such, and must not
99
be misrepresented as being the original software.
100
101
3. This notice may not be removed or altered from any source
102
distribution.
103
*/
104
#define SOKOL_LOG_INCLUDED (1)
105
#include <stdint.h>
106
107
#if defined(SOKOL_API_DECL) && !defined(SOKOL_LOG_API_DECL)
108
#define SOKOL_LOG_API_DECL SOKOL_API_DECL
109
#endif
110
#ifndef SOKOL_LOG_API_DECL
111
#if defined(_WIN32) && defined(SOKOL_DLL) && defined(SOKOL_LOG_IMPL)
112
#define SOKOL_LOG_API_DECL __declspec(dllexport)
113
#elif defined(_WIN32) && defined(SOKOL_DLL)
114
#define SOKOL_LOG_API_DECL __declspec(dllimport)
115
#else
116
#define SOKOL_LOG_API_DECL extern
117
#endif
118
#endif
119
120
#ifdef __cplusplus
121
extern "C" {
122
#endif
123
124
/*
125
Plug this function into the 'logger.func' struct item when initializing any of the sokol
126
headers. For instance for sokol_audio.h it would look like this:
127
128
saudio_setup(&(saudio_desc){
129
.logger = {
130
.func = slog_func
131
}
132
});
133
*/
134
SOKOL_LOG_API_DECL void slog_func(const char* tag, uint32_t log_level, uint32_t log_item, const char* message, uint32_t line_nr, const char* filename, void* user_data);
135
136
#ifdef __cplusplus
137
} // extern "C"
138
#endif
139
#endif // SOKOL_LOG_INCLUDED
140
141
// ██ ███ ███ ██████ ██ ███████ ███ ███ ███████ ███ ██ ████████ █████ ████████ ██ ██████ ███ ██
142
// ██ ████ ████ ██ ██ ██ ██ ████ ████ ██ ████ ██ ██ ██ ██ ██ ██ ██ ██ ████ ██
143
// ██ ██ ████ ██ ██████ ██ █████ ██ ████ ██ █████ ██ ██ ██ ██ ███████ ██ ██ ██ ██ ██ ██ ██
144
// ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
145
// ██ ██ ██ ██ ███████ ███████ ██ ██ ███████ ██ ████ ██ ██ ██ ██ ██ ██████ ██ ████
146
//
147
// >>implementation
148
#ifdef SOKOL_LOG_IMPL
149
#define SOKOL_LOG_IMPL_INCLUDED (1)
150
151
#ifndef SOKOL_API_IMPL
152
#define SOKOL_API_IMPL
153
#endif
154
#ifndef SOKOL_DEBUG
155
#ifndef NDEBUG
156
#define SOKOL_DEBUG
157
#endif
158
#endif
159
#ifndef SOKOL_ASSERT
160
#include <assert.h>
161
#define SOKOL_ASSERT(c) assert(c)
162
#endif
163
164
#ifndef _SOKOL_PRIVATE
165
#if defined(__GNUC__) || defined(__clang__)
166
#define _SOKOL_PRIVATE __attribute__((unused)) static
167
#else
168
#define _SOKOL_PRIVATE static
169
#endif
170
#endif
171
172
#ifndef _SOKOL_UNUSED
173
#define _SOKOL_UNUSED(x) (void)(x)
174
#endif
175
176
// platform detection
177
#if defined(__APPLE__)
178
#define _SLOG_APPLE (1)
179
#elif defined(__EMSCRIPTEN__)
180
#define _SLOG_EMSCRIPTEN (1)
181
#elif defined(_WIN32)
182
#define _SLOG_WINDOWS (1)
183
#elif defined(__ANDROID__)
184
#define _SLOG_ANDROID (1)
185
#elif defined(__linux__) || defined(__unix__)
186
#define _SLOG_LINUX (1)
187
#else
188
#error "sokol_log.h: unknown platform"
189
#endif
190
191
#include <stdlib.h> // abort
192
#include <stdio.h> // fputs
193
#include <stddef.h> // size_t
194
195
#if defined(_SLOG_EMSCRIPTEN)
196
#include <emscripten/emscripten.h>
197
#elif defined(_SLOG_WINDOWS)
198
#ifndef WIN32_LEAN_AND_MEAN
199
#define WIN32_LEAN_AND_MEAN
200
#endif
201
#ifndef NOMINMAX
202
#define NOMINMAX
203
#endif
204
#include <windows.h>
205
#elif defined(_SLOG_ANDROID)
206
#include <android/log.h>
207
#elif defined(_SLOG_LINUX) || defined(_SLOG_APPLE)
208
#include <syslog.h>
209
#endif
210
211
// size of line buffer (on stack!) in bytes including terminating zero
212
#define _SLOG_LINE_LENGTH (512)
213
214
_SOKOL_PRIVATE char* _slog_append(const char* str, char* dst, char* end) {
215
if (str) {
216
char c;
217
while (((c = *str++) != 0) && (dst < (end - 1))) {
218
*dst++ = c;
219
}
220
}
221
*dst = 0;
222
return dst;
223
}
224
225
_SOKOL_PRIVATE char* _slog_itoa(uint32_t x, char* buf, size_t buf_size) {
226
const size_t max_digits_and_null = 11;
227
if (buf_size < max_digits_and_null) {
228
return 0;
229
}
230
char* p = buf + max_digits_and_null;
231
*--p = 0;
232
do {
233
*--p = '0' + (x % 10);
234
x /= 10;
235
} while (x != 0);
236
return p;
237
}
238
239
#if defined(_SLOG_EMSCRIPTEN)
240
EM_JS(void, slog_js_log, (uint32_t level, const char* c_str), {
241
const str = UTF8ToString(c_str);
242
switch (level) {
243
case 0: console.error(str); break;
244
case 1: console.error(str); break;
245
case 2: console.warn(str); break;
246
default: console.info(str); break;
247
}
248
})
249
#endif
250
251
SOKOL_API_IMPL void slog_func(const char* tag, uint32_t log_level, uint32_t log_item, const char* message, uint32_t line_nr, const char* filename, void* user_data) {
252
_SOKOL_UNUSED(user_data);
253
254
const char* log_level_str;
255
switch (log_level) {
256
case 0: log_level_str = "panic"; break;
257
case 1: log_level_str = "error"; break;
258
case 2: log_level_str = "warning"; break;
259
default: log_level_str = "info"; break;
260
}
261
262
// build log output line
263
char line_buf[_SLOG_LINE_LENGTH];
264
char* str = line_buf;
265
char* end = line_buf + sizeof(line_buf);
266
char num_buf[32];
267
if (tag) {
268
str = _slog_append("[", str, end);
269
str = _slog_append(tag, str, end);
270
str = _slog_append("]", str, end);
271
}
272
str = _slog_append("[", str, end);
273
str = _slog_append(log_level_str, str, end);
274
str = _slog_append("]", str, end);
275
str = _slog_append("[id:", str, end);
276
str = _slog_append(_slog_itoa(log_item, num_buf, sizeof(num_buf)), str, end);
277
str = _slog_append("]", str, end);
278
// if a filename is provided, build a clickable log message that's compatible with compiler error messages
279
if (filename) {
280
str = _slog_append(" ", str, end);
281
#if defined(_MSC_VER)
282
// MSVC compiler error format
283
str = _slog_append(filename, str, end);
284
str = _slog_append("(", str, end);
285
str = _slog_append(_slog_itoa(line_nr, num_buf, sizeof(num_buf)), str, end);
286
str = _slog_append("): ", str, end);
287
#else
288
// gcc/clang compiler error format
289
str = _slog_append(filename, str, end);
290
str = _slog_append(":", str, end);
291
str = _slog_append(_slog_itoa(line_nr, num_buf, sizeof(num_buf)), str, end);
292
str = _slog_append(":0: ", str, end);
293
#endif
294
}
295
else {
296
str = _slog_append("[line:", str, end);
297
str = _slog_append(_slog_itoa(line_nr, num_buf, sizeof(num_buf)), str, end);
298
str = _slog_append("] ", str, end);
299
}
300
if (message) {
301
str = _slog_append("\n\t", str, end);
302
str = _slog_append(message, str, end);
303
}
304
str = _slog_append("\n\n", str, end);
305
if (0 == log_level) {
306
str = _slog_append("ABORTING because of [panic]\n", str, end);
307
(void)str;
308
}
309
310
// print to stderr?
311
#if defined(_SLOG_LINUX) || defined(_SLOG_WINDOWS) || defined(_SLOG_APPLE)
312
fputs(line_buf, stderr);
313
#endif
314
315
// platform specific logging calls
316
#if defined(_SLOG_WINDOWS)
317
OutputDebugStringA(line_buf);
318
#elif defined(_SLOG_ANDROID)
319
int prio;
320
switch (log_level) {
321
case 0: prio = ANDROID_LOG_FATAL; break;
322
case 1: prio = ANDROID_LOG_ERROR; break;
323
case 2: prio = ANDROID_LOG_WARN; break;
324
default: prio = ANDROID_LOG_INFO; break;
325
}
326
__android_log_write(prio, "SOKOL", line_buf);
327
#elif defined(_SLOG_EMSCRIPTEN)
328
slog_js_log(log_level, line_buf);
329
#endif
330
if (0 == log_level) {
331
abort();
332
}
333
}
334
#endif // SOKOL_LOG_IMPL
vendor/sokol/sokol_time.hdeleted
@@ -1,319 +0,0 @@
1
#if defined(SOKOL_IMPL) && !defined(SOKOL_TIME_IMPL)
2
#define SOKOL_TIME_IMPL
3
#endif
4
#ifndef SOKOL_TIME_INCLUDED
5
/*
6
sokol_time.h -- simple cross-platform time measurement
7
8
Project URL: https://github.com/floooh/sokol
9
10
Do this:
11
#define SOKOL_IMPL or
12
#define SOKOL_TIME_IMPL
13
before you include this file in *one* C or C++ file to create the
14
implementation.
15
16
Optionally provide the following defines with your own implementations:
17
SOKOL_ASSERT(c) - your own assert macro (default: assert(c))
18
SOKOL_TIME_API_DECL - public function declaration prefix (default: extern)
19
SOKOL_API_DECL - same as SOKOL_TIME_API_DECL
20
SOKOL_API_IMPL - public function implementation prefix (default: -)
21
22
If sokol_time.h is compiled as a DLL, define the following before
23
including the declaration or implementation:
24
25
SOKOL_DLL
26
27
On Windows, SOKOL_DLL will define SOKOL_TIME_API_DECL as __declspec(dllexport)
28
or __declspec(dllimport) as needed.
29
30
void stm_setup();
31
Call once before any other functions to initialize sokol_time
32
(this calls for instance QueryPerformanceFrequency on Windows)
33
34
uint64_t stm_now();
35
Get current point in time in unspecified 'ticks'. The value that
36
is returned has no relation to the 'wall-clock' time and is
37
not in a specific time unit, it is only useful to compute
38
time differences.
39
40
uint64_t stm_diff(uint64_t new, uint64_t old);
41
Computes the time difference between new and old. This will always
42
return a positive, non-zero value.
43
44
uint64_t stm_since(uint64_t start);
45
Takes the current time, and returns the elapsed time since start
46
(this is a shortcut for "stm_diff(stm_now(), start)")
47
48
uint64_t stm_laptime(uint64_t* last_time);
49
This is useful for measuring frame time and other recurring
50
events. It takes the current time, returns the time difference
51
to the value in last_time, and stores the current time in
52
last_time for the next call. If the value in last_time is 0,
53
the return value will be zero (this usually happens on the
54
very first call).
55
56
uint64_t stm_round_to_common_refresh_rate(uint64_t duration)
57
This oddly named function takes a measured frame time and
58
returns the closest "nearby" common display refresh rate frame duration
59
in ticks. If the input duration isn't close to any common display
60
refresh rate, the input duration will be returned unchanged as a fallback.
61
The main purpose of this function is to remove jitter/inaccuracies from
62
measured frame times, and instead use the display refresh rate as
63
frame duration.
64
NOTE: for more robust frame timing, consider using the
65
sokol_app.h function sapp_frame_duration()
66
67
Use the following functions to convert a duration in ticks into
68
useful time units:
69
70
double stm_sec(uint64_t ticks);
71
double stm_ms(uint64_t ticks);
72
double stm_us(uint64_t ticks);
73
double stm_ns(uint64_t ticks);
74
Converts a tick value into seconds, milliseconds, microseconds
75
or nanoseconds. Note that not all platforms will have nanosecond
76
or even microsecond precision.
77
78
Uses the following time measurement functions under the hood:
79
80
Windows: QueryPerformanceFrequency() / QueryPerformanceCounter()
81
MacOS/iOS: mach_absolute_time()
82
emscripten: emscripten_get_now()
83
Linux+others: clock_gettime(CLOCK_MONOTONIC)
84
85
zlib/libpng license
86
87
Copyright (c) 2018 Andre Weissflog
88
89
This software is provided 'as-is', without any express or implied warranty.
90
In no event will the authors be held liable for any damages arising from the
91
use of this software.
92
93
Permission is granted to anyone to use this software for any purpose,
94
including commercial applications, and to alter it and redistribute it
95
freely, subject to the following restrictions:
96
97
1. The origin of this software must not be misrepresented; you must not
98
claim that you wrote the original software. If you use this software in a
99
product, an acknowledgment in the product documentation would be
100
appreciated but is not required.
101
102
2. Altered source versions must be plainly marked as such, and must not
103
be misrepresented as being the original software.
104
105
3. This notice may not be removed or altered from any source
106
distribution.
107
*/
108
#define SOKOL_TIME_INCLUDED (1)
109
#include <stdint.h>
110
111
#if defined(SOKOL_API_DECL) && !defined(SOKOL_TIME_API_DECL)
112
#define SOKOL_TIME_API_DECL SOKOL_API_DECL
113
#endif
114
#ifndef SOKOL_TIME_API_DECL
115
#if defined(_WIN32) && defined(SOKOL_DLL) && defined(SOKOL_TIME_IMPL)
116
#define SOKOL_TIME_API_DECL __declspec(dllexport)
117
#elif defined(_WIN32) && defined(SOKOL_DLL)
118
#define SOKOL_TIME_API_DECL __declspec(dllimport)
119
#else
120
#define SOKOL_TIME_API_DECL extern
121
#endif
122
#endif
123
124
#ifdef __cplusplus
125
extern "C" {
126
#endif
127
128
SOKOL_TIME_API_DECL void stm_setup(void);
129
SOKOL_TIME_API_DECL uint64_t stm_now(void);
130
SOKOL_TIME_API_DECL uint64_t stm_diff(uint64_t new_ticks, uint64_t old_ticks);
131
SOKOL_TIME_API_DECL uint64_t stm_since(uint64_t start_ticks);
132
SOKOL_TIME_API_DECL uint64_t stm_laptime(uint64_t* last_time);
133
SOKOL_TIME_API_DECL uint64_t stm_round_to_common_refresh_rate(uint64_t frame_ticks);
134
SOKOL_TIME_API_DECL double stm_sec(uint64_t ticks);
135
SOKOL_TIME_API_DECL double stm_ms(uint64_t ticks);
136
SOKOL_TIME_API_DECL double stm_us(uint64_t ticks);
137
SOKOL_TIME_API_DECL double stm_ns(uint64_t ticks);
138
139
#ifdef __cplusplus
140
} /* extern "C" */
141
#endif
142
#endif // SOKOL_TIME_INCLUDED
143
144
/*-- IMPLEMENTATION ----------------------------------------------------------*/
145
#ifdef SOKOL_TIME_IMPL
146
#define SOKOL_TIME_IMPL_INCLUDED (1)
147
#include <string.h> /* memset */
148
149
#ifndef SOKOL_API_IMPL
150
#define SOKOL_API_IMPL
151
#endif
152
#ifndef SOKOL_ASSERT
153
#include <assert.h>
154
#define SOKOL_ASSERT(c) assert(c)
155
#endif
156
#ifndef _SOKOL_PRIVATE
157
#if defined(__GNUC__) || defined(__clang__)
158
#define _SOKOL_PRIVATE __attribute__((unused)) static
159
#else
160
#define _SOKOL_PRIVATE static
161
#endif
162
#endif
163
164
#if defined(_WIN32)
165
#ifndef WIN32_LEAN_AND_MEAN
166
#define WIN32_LEAN_AND_MEAN
167
#endif
168
#include <windows.h>
169
typedef struct {
170
uint32_t initialized;
171
LARGE_INTEGER freq;
172
LARGE_INTEGER start;
173
} _stm_state_t;
174
#elif defined(__APPLE__) && defined(__MACH__)
175
#include <mach/mach_time.h>
176
typedef struct {
177
uint32_t initialized;
178
mach_timebase_info_data_t timebase;
179
uint64_t start;
180
} _stm_state_t;
181
#elif defined(__EMSCRIPTEN__)
182
#include <emscripten/emscripten.h>
183
typedef struct {
184
uint32_t initialized;
185
double start;
186
} _stm_state_t;
187
#else /* anything else, this will need more care for non-Linux platforms */
188
#ifdef ESP8266
189
// On the ESP8266, clock_gettime ignores the first argument and CLOCK_MONOTONIC isn't defined
190
#define CLOCK_MONOTONIC 0
191
#endif
192
#include <time.h>
193
typedef struct {
194
uint32_t initialized;
195
uint64_t start;
196
} _stm_state_t;
197
#endif
198
static _stm_state_t _stm;
199
200
/* prevent 64-bit overflow when computing relative timestamp
201
see https://gist.github.com/jspohr/3dc4f00033d79ec5bdaf67bc46c813e3
202
*/
203
#if defined(_WIN32) || (defined(__APPLE__) && defined(__MACH__))
204
_SOKOL_PRIVATE int64_t _stm_int64_muldiv(int64_t value, int64_t numer, int64_t denom) {
205
int64_t q = value / denom;
206
int64_t r = value % denom;
207
return q * numer + r * numer / denom;
208
}
209
#endif
210
211
SOKOL_API_IMPL void stm_setup(void) {
212
memset(&_stm, 0, sizeof(_stm));
213
_stm.initialized = 0xABCDABCD;
214
#if defined(_WIN32)
215
QueryPerformanceFrequency(&_stm.freq);
216
QueryPerformanceCounter(&_stm.start);
217
#elif defined(__APPLE__) && defined(__MACH__)
218
mach_timebase_info(&_stm.timebase);
219
_stm.start = mach_absolute_time();
220
#elif defined(__EMSCRIPTEN__)
221
_stm.start = emscripten_get_now();
222
#else
223
struct timespec ts;
224
clock_gettime(CLOCK_MONOTONIC, &ts);
225
_stm.start = (uint64_t)ts.tv_sec*1000000000 + (uint64_t)ts.tv_nsec;
226
#endif
227
}
228
229
SOKOL_API_IMPL uint64_t stm_now(void) {
230
SOKOL_ASSERT(_stm.initialized == 0xABCDABCD);
231
uint64_t now;
232
#if defined(_WIN32)
233
LARGE_INTEGER qpc_t;
234
QueryPerformanceCounter(&qpc_t);
235
now = (uint64_t) _stm_int64_muldiv(qpc_t.QuadPart - _stm.start.QuadPart, 1000000000, _stm.freq.QuadPart);
236
#elif defined(__APPLE__) && defined(__MACH__)
237
const uint64_t mach_now = mach_absolute_time() - _stm.start;
238
now = (uint64_t) _stm_int64_muldiv((int64_t)mach_now, (int64_t)_stm.timebase.numer, (int64_t)_stm.timebase.denom);
239
#elif defined(__EMSCRIPTEN__)
240
double js_now = emscripten_get_now() - _stm.start;
241
now = (uint64_t) (js_now * 1000000.0);
242
#else
243
struct timespec ts;
244
clock_gettime(CLOCK_MONOTONIC, &ts);
245
now = ((uint64_t)ts.tv_sec*1000000000 + (uint64_t)ts.tv_nsec) - _stm.start;
246
#endif
247
return now;
248
}
249
250
SOKOL_API_IMPL uint64_t stm_diff(uint64_t new_ticks, uint64_t old_ticks) {
251
if (new_ticks > old_ticks) {
252
return new_ticks - old_ticks;
253
}
254
else {
255
return 1;
256
}
257
}
258
259
SOKOL_API_IMPL uint64_t stm_since(uint64_t start_ticks) {
260
return stm_diff(stm_now(), start_ticks);
261
}
262
263
SOKOL_API_IMPL uint64_t stm_laptime(uint64_t* last_time) {
264
SOKOL_ASSERT(last_time);
265
uint64_t dt = 0;
266
uint64_t now = stm_now();
267
if (0 != *last_time) {
268
dt = stm_diff(now, *last_time);
269
}
270
*last_time = now;
271
return dt;
272
}
273
274
// first number is frame duration in ns, second number is tolerance in ns,
275
// the resulting min/max values must not overlap!
276
static const uint64_t _stm_refresh_rates[][2] = {
277
{ 16666667, 1000000 }, // 60 Hz: 16.6667 +- 1ms
278
{ 13888889, 250000 }, // 72 Hz: 13.8889 +- 0.25ms
279
{ 13333333, 250000 }, // 75 Hz: 13.3333 +- 0.25ms
280
{ 11764706, 250000 }, // 85 Hz: 11.7647 +- 0.25
281
{ 11111111, 250000 }, // 90 Hz: 11.1111 +- 0.25ms
282
{ 10000000, 500000 }, // 100 Hz: 10.0000 +- 0.5ms
283
{ 8333333, 500000 }, // 120 Hz: 8.3333 +- 0.5ms
284
{ 6944445, 500000 }, // 144 Hz: 6.9445 +- 0.5ms
285
{ 4166667, 1000000 }, // 240 Hz: 4.1666 +- 1ms
286
{ 0, 0 }, // keep the last element always at zero
287
};
288
289
SOKOL_API_IMPL uint64_t stm_round_to_common_refresh_rate(uint64_t ticks) {
290
uint64_t ns;
291
int i = 0;
292
while (0 != (ns = _stm_refresh_rates[i][0])) {
293
uint64_t tol = _stm_refresh_rates[i][1];
294
if ((ticks > (ns - tol)) && (ticks < (ns + tol))) {
295
return ns;
296
}
297
i++;
298
}
299
// fallthrough: didn't fit into any buckets
300
return ticks;
301
}
302
303
SOKOL_API_IMPL double stm_sec(uint64_t ticks) {
304
return (double)ticks / 1000000000.0;
305
}
306
307
SOKOL_API_IMPL double stm_ms(uint64_t ticks) {
308
return (double)ticks / 1000000.0;
309
}
310
311
SOKOL_API_IMPL double stm_us(uint64_t ticks) {
312
return (double)ticks / 1000.0;
313
}
314
315
SOKOL_API_IMPL double stm_ns(uint64_t ticks) {
316
return (double)ticks;
317
}
318
#endif /* SOKOL_TIME_IMPL */
319
vendor/stb/stb_image.hdeleted
@@ -1,7988 +0,0 @@
1
/* stb_image - v2.30 - public domain image loader - http://nothings.org/stb
2
no warranty implied; use at your own risk
3
4
Do this:
5
#define STB_IMAGE_IMPLEMENTATION
6
before you include this file in *one* C or C++ file to create the implementation.
7
8
// i.e. it should look like this:
9
#include ...
10
#include ...
11
#include ...
12
#define STB_IMAGE_IMPLEMENTATION
13
#include "stb_image.h"
14
15
You can #define STBI_ASSERT(x) before the #include to avoid using assert.h.
16
And #define STBI_MALLOC, STBI_REALLOC, and STBI_FREE to avoid using malloc,realloc,free
17
18
19
QUICK NOTES:
20
Primarily of interest to game developers and other people who can
21
avoid problematic images and only need the trivial interface
22
23
JPEG baseline & progressive (12 bpc/arithmetic not supported, same as stock IJG lib)
24
PNG 1/2/4/8/16-bit-per-channel
25
26
TGA (not sure what subset, if a subset)
27
BMP non-1bpp, non-RLE
28
PSD (composited view only, no extra channels, 8/16 bit-per-channel)
29
30
GIF (*comp always reports as 4-channel)
31
HDR (radiance rgbE format)
32
PIC (Softimage PIC)
33
PNM (PPM and PGM binary only)
34
35
Animated GIF still needs a proper API, but here's one way to do it:
36
http://gist.github.com/urraka/685d9a6340b26b830d49
37
38
- decode from memory or through FILE (define STBI_NO_STDIO to remove code)
39
- decode from arbitrary I/O callbacks
40
- SIMD acceleration on x86/x64 (SSE2) and ARM (NEON)
41
42
Full documentation under "DOCUMENTATION" below.
43
44
45
LICENSE
46
47
See end of file for license information.
48
49
RECENT REVISION HISTORY:
50
51
2.30 (2024-05-31) avoid erroneous gcc warning
52
2.29 (2023-05-xx) optimizations
53
2.28 (2023-01-29) many error fixes, security errors, just tons of stuff
54
2.27 (2021-07-11) document stbi_info better, 16-bit PNM support, bug fixes
55
2.26 (2020-07-13) many minor fixes
56
2.25 (2020-02-02) fix warnings
57
2.24 (2020-02-02) fix warnings; thread-local failure_reason and flip_vertically
58
2.23 (2019-08-11) fix clang static analysis warning
59
2.22 (2019-03-04) gif fixes, fix warnings
60
2.21 (2019-02-25) fix typo in comment
61
2.20 (2019-02-07) support utf8 filenames in Windows; fix warnings and platform ifdefs
62
2.19 (2018-02-11) fix warning
63
2.18 (2018-01-30) fix warnings
64
2.17 (2018-01-29) bugfix, 1-bit BMP, 16-bitness query, fix warnings
65
2.16 (2017-07-23) all functions have 16-bit variants; optimizations; bugfixes
66
2.15 (2017-03-18) fix png-1,2,4; all Imagenet JPGs; no runtime SSE detection on GCC
67
2.14 (2017-03-03) remove deprecated STBI_JPEG_OLD; fixes for Imagenet JPGs
68
2.13 (2016-12-04) experimental 16-bit API, only for PNG so far; fixes
69
2.12 (2016-04-02) fix typo in 2.11 PSD fix that caused crashes
70
2.11 (2016-04-02) 16-bit PNGS; enable SSE2 in non-gcc x64
71
RGB-format JPEG; remove white matting in PSD;
72
allocate large structures on the stack;
73
correct channel count for PNG & BMP
74
2.10 (2016-01-22) avoid warning introduced in 2.09
75
2.09 (2016-01-16) 16-bit TGA; comments in PNM files; STBI_REALLOC_SIZED
76
77
See end of file for full revision history.
78
79
80
============================ Contributors =========================
81
82
Image formats Extensions, features
83
Sean Barrett (jpeg, png, bmp) Jetro Lauha (stbi_info)
84
Nicolas Schulz (hdr, psd) Martin "SpartanJ" Golini (stbi_info)
85
Jonathan Dummer (tga) James "moose2000" Brown (iPhone PNG)
86
Jean-Marc Lienher (gif) Ben "Disch" Wenger (io callbacks)
87
Tom Seddon (pic) Omar Cornut (1/2/4-bit PNG)
88
Thatcher Ulrich (psd) Nicolas Guillemot (vertical flip)
89
Ken Miller (pgm, ppm) Richard Mitton (16-bit PSD)
90
github:urraka (animated gif) Junggon Kim (PNM comments)
91
Christopher Forseth (animated gif) Daniel Gibson (16-bit TGA)
92
socks-the-fox (16-bit PNG)
93
Jeremy Sawicki (handle all ImageNet JPGs)
94
Optimizations & bugfixes Mikhail Morozov (1-bit BMP)
95
Fabian "ryg" Giesen Anael Seghezzi (is-16-bit query)
96
Arseny Kapoulkine Simon Breuss (16-bit PNM)
97
John-Mark Allen
98
Carmelo J Fdez-Aguera
99
100
Bug & warning fixes
101
Marc LeBlanc David Woo Guillaume George Martins Mozeiko
102
Christpher Lloyd Jerry Jansson Joseph Thomson Blazej Dariusz Roszkowski
103
Phil Jordan Dave Moore Roy Eltham
104
Hayaki Saito Nathan Reed Won Chun
105
Luke Graham Johan Duparc Nick Verigakis the Horde3D community
106
Thomas Ruf Ronny Chevalier github:rlyeh
107
Janez Zemva John Bartholomew Michal Cichon github:romigrou
108
Jonathan Blow Ken Hamada Tero Hanninen github:svdijk
109
Eugene Golushkov Laurent Gomila Cort Stratton github:snagar
110
Aruelien Pocheville Sergio Gonzalez Thibault Reuille github:Zelex
111
Cass Everitt Ryamond Barbiero github:grim210
112
Paul Du Bois Engin Manap Aldo Culquicondor github:sammyhw
113
Philipp Wiesemann Dale Weiler Oriol Ferrer Mesia github:phprus
114
Josh Tobin Neil Bickford Matthew Gregan github:poppolopoppo
115
Julian Raschke Gregory Mullen Christian Floisand github:darealshinji
116
Baldur Karlsson Kevin Schmidt JR Smith github:Michaelangel007
117
Brad Weinberger Matvey Cherevko github:mosra
118
Luca Sas Alexander Veselov Zack Middleton [reserved]
119
Ryan C. Gordon [reserved] [reserved]
120
DO NOT ADD YOUR NAME HERE
121
122
Jacko Dirks
123
124
To add your name to the credits, pick a random blank space in the middle and fill it.
125
80% of merge conflicts on stb PRs are due to people adding their name at the end
126
of the credits.
127
*/
128
129
#ifndef STBI_INCLUDE_STB_IMAGE_H
130
#define STBI_INCLUDE_STB_IMAGE_H
131
132
// DOCUMENTATION
133
//
134
// Limitations:
135
// - no 12-bit-per-channel JPEG
136
// - no JPEGs with arithmetic coding
137
// - GIF always returns *comp=4
138
//
139
// Basic usage (see HDR discussion below for HDR usage):
140
// int x,y,n;
141
// unsigned char *data = stbi_load(filename, &x, &y, &n, 0);
142
// // ... process data if not NULL ...
143
// // ... x = width, y = height, n = # 8-bit components per pixel ...
144
// // ... replace '0' with '1'..'4' to force that many components per pixel
145
// // ... but 'n' will always be the number that it would have been if you said 0
146
// stbi_image_free(data);
147
//
148
// Standard parameters:
149
// int *x -- outputs image width in pixels
150
// int *y -- outputs image height in pixels
151
// int *channels_in_file -- outputs # of image components in image file
152
// int desired_channels -- if non-zero, # of image components requested in result
153
//
154
// The return value from an image loader is an 'unsigned char *' which points
155
// to the pixel data, or NULL on an allocation failure or if the image is
156
// corrupt or invalid. The pixel data consists of *y scanlines of *x pixels,
157
// with each pixel consisting of N interleaved 8-bit components; the first
158
// pixel pointed to is top-left-most in the image. There is no padding between
159
// image scanlines or between pixels, regardless of format. The number of
160
// components N is 'desired_channels' if desired_channels is non-zero, or
161
// *channels_in_file otherwise. If desired_channels is non-zero,
162
// *channels_in_file has the number of components that _would_ have been
163
// output otherwise. E.g. if you set desired_channels to 4, you will always
164
// get RGBA output, but you can check *channels_in_file to see if it's trivially
165
// opaque because e.g. there were only 3 channels in the source image.
166
//
167
// An output image with N components has the following components interleaved
168
// in this order in each pixel:
169
//
170
// N=#comp components
171
// 1 grey
172
// 2 grey, alpha
173
// 3 red, green, blue
174
// 4 red, green, blue, alpha
175
//
176
// If image loading fails for any reason, the return value will be NULL,
177
// and *x, *y, *channels_in_file will be unchanged. The function
178
// stbi_failure_reason() can be queried for an extremely brief, end-user
179
// unfriendly explanation of why the load failed. Define STBI_NO_FAILURE_STRINGS
180
// to avoid compiling these strings at all, and STBI_FAILURE_USERMSG to get slightly
181
// more user-friendly ones.
182
//
183
// Paletted PNG, BMP, GIF, and PIC images are automatically depalettized.
184
//
185
// To query the width, height and component count of an image without having to
186
// decode the full file, you can use the stbi_info family of functions:
187
//
188
// int x,y,n,ok;
189
// ok = stbi_info(filename, &x, &y, &n);
190
// // returns ok=1 and sets x, y, n if image is a supported format,
191
// // 0 otherwise.
192
//
193
// Note that stb_image pervasively uses ints in its public API for sizes,
194
// including sizes of memory buffers. This is now part of the API and thus
195
// hard to change without causing breakage. As a result, the various image
196
// loaders all have certain limits on image size; these differ somewhat
197
// by format but generally boil down to either just under 2GB or just under
198
// 1GB. When the decoded image would be larger than this, stb_image decoding
199
// will fail.
200
//
201
// Additionally, stb_image will reject image files that have any of their
202
// dimensions set to a larger value than the configurable STBI_MAX_DIMENSIONS,
203
// which defaults to 2**24 = 16777216 pixels. Due to the above memory limit,
204
// the only way to have an image with such dimensions load correctly
205
// is for it to have a rather extreme aspect ratio. Either way, the
206
// assumption here is that such larger images are likely to be malformed
207
// or malicious. If you do need to load an image with individual dimensions
208
// larger than that, and it still fits in the overall size limit, you can
209
// #define STBI_MAX_DIMENSIONS on your own to be something larger.
210
//
211
// ===========================================================================
212
//
213
// UNICODE:
214
//
215
// If compiling for Windows and you wish to use Unicode filenames, compile
216
// with
217
// #define STBI_WINDOWS_UTF8
218
// and pass utf8-encoded filenames. Call stbi_convert_wchar_to_utf8 to convert
219
// Windows wchar_t filenames to utf8.
220
//
221
// ===========================================================================
222
//
223
// Philosophy
224
//
225
// stb libraries are designed with the following priorities:
226
//
227
// 1. easy to use
228
// 2. easy to maintain
229
// 3. good performance
230
//
231
// Sometimes I let "good performance" creep up in priority over "easy to maintain",
232
// and for best performance I may provide less-easy-to-use APIs that give higher
233
// performance, in addition to the easy-to-use ones. Nevertheless, it's important
234
// to keep in mind that from the standpoint of you, a client of this library,
235
// all you care about is #1 and #3, and stb libraries DO NOT emphasize #3 above all.
236
//
237
// Some secondary priorities arise directly from the first two, some of which
238
// provide more explicit reasons why performance can't be emphasized.
239
//
240
// - Portable ("ease of use")
241
// - Small source code footprint ("easy to maintain")
242
// - No dependencies ("ease of use")
243
//
244
// ===========================================================================
245
//
246
// I/O callbacks
247
//
248
// I/O callbacks allow you to read from arbitrary sources, like packaged
249
// files or some other source. Data read from callbacks are processed
250
// through a small internal buffer (currently 128 bytes) to try to reduce
251
// overhead.
252
//
253
// The three functions you must define are "read" (reads some bytes of data),
254
// "skip" (skips some bytes of data), "eof" (reports if the stream is at the end).
255
//
256
// ===========================================================================
257
//
258
// SIMD support
259
//
260
// The JPEG decoder will try to automatically use SIMD kernels on x86 when
261
// supported by the compiler. For ARM Neon support, you must explicitly
262
// request it.
263
//
264
// (The old do-it-yourself SIMD API is no longer supported in the current
265
// code.)
266
//
267
// On x86, SSE2 will automatically be used when available based on a run-time
268
// test; if not, the generic C versions are used as a fall-back. On ARM targets,
269
// the typical path is to have separate builds for NEON and non-NEON devices
270
// (at least this is true for iOS and Android). Therefore, the NEON support is
271
// toggled by a build flag: define STBI_NEON to get NEON loops.
272
//
273
// If for some reason you do not want to use any of SIMD code, or if
274
// you have issues compiling it, you can disable it entirely by
275
// defining STBI_NO_SIMD.
276
//
277
// ===========================================================================
278
//
279
// HDR image support (disable by defining STBI_NO_HDR)
280
//
281
// stb_image supports loading HDR images in general, and currently the Radiance
282
// .HDR file format specifically. You can still load any file through the existing
283
// interface; if you attempt to load an HDR file, it will be automatically remapped
284
// to LDR, assuming gamma 2.2 and an arbitrary scale factor defaulting to 1;
285
// both of these constants can be reconfigured through this interface:
286
//
287
// stbi_hdr_to_ldr_gamma(2.2f);
288
// stbi_hdr_to_ldr_scale(1.0f);
289
//
290
// (note, do not use _inverse_ constants; stbi_image will invert them
291
// appropriately).
292
//
293
// Additionally, there is a new, parallel interface for loading files as
294
// (linear) floats to preserve the full dynamic range:
295
//
296
// float *data = stbi_loadf(filename, &x, &y, &n, 0);
297
//
298
// If you load LDR images through this interface, those images will
299
// be promoted to floating point values, run through the inverse of
300
// constants corresponding to the above:
301
//
302
// stbi_ldr_to_hdr_scale(1.0f);
303
// stbi_ldr_to_hdr_gamma(2.2f);
304
//
305
// Finally, given a filename (or an open file or memory block--see header
306
// file for details) containing image data, you can query for the "most
307
// appropriate" interface to use (that is, whether the image is HDR or
308
// not), using:
309
//
310
// stbi_is_hdr(char *filename);
311
//
312
// ===========================================================================
313
//
314
// iPhone PNG support:
315
//
316
// We optionally support converting iPhone-formatted PNGs (which store
317
// premultiplied BGRA) back to RGB, even though they're internally encoded
318
// differently. To enable this conversion, call
319
// stbi_convert_iphone_png_to_rgb(1).
320
//
321
// Call stbi_set_unpremultiply_on_load(1) as well to force a divide per
322
// pixel to remove any premultiplied alpha *only* if the image file explicitly
323
// says there's premultiplied data (currently only happens in iPhone images,
324
// and only if iPhone convert-to-rgb processing is on).
325
//
326
// ===========================================================================
327
//
328
// ADDITIONAL CONFIGURATION
329
//
330
// - You can suppress implementation of any of the decoders to reduce
331
// your code footprint by #defining one or more of the following
332
// symbols before creating the implementation.
333
//
334
// STBI_NO_JPEG
335
// STBI_NO_PNG
336
// STBI_NO_BMP
337
// STBI_NO_PSD
338
// STBI_NO_TGA
339
// STBI_NO_GIF
340
// STBI_NO_HDR
341
// STBI_NO_PIC
342
// STBI_NO_PNM (.ppm and .pgm)
343
//
344
// - You can request *only* certain decoders and suppress all other ones
345
// (this will be more forward-compatible, as addition of new decoders
346
// doesn't require you to disable them explicitly):
347
//
348
// STBI_ONLY_JPEG
349
// STBI_ONLY_PNG
350
// STBI_ONLY_BMP
351
// STBI_ONLY_PSD
352
// STBI_ONLY_TGA
353
// STBI_ONLY_GIF
354
// STBI_ONLY_HDR
355
// STBI_ONLY_PIC
356
// STBI_ONLY_PNM (.ppm and .pgm)
357
//
358
// - If you use STBI_NO_PNG (or _ONLY_ without PNG), and you still
359
// want the zlib decoder to be available, #define STBI_SUPPORT_ZLIB
360
//
361
// - If you define STBI_MAX_DIMENSIONS, stb_image will reject images greater
362
// than that size (in either width or height) without further processing.
363
// This is to let programs in the wild set an upper bound to prevent
364
// denial-of-service attacks on untrusted data, as one could generate a
365
// valid image of gigantic dimensions and force stb_image to allocate a
366
// huge block of memory and spend disproportionate time decoding it. By
367
// default this is set to (1 << 24), which is 16777216, but that's still
368
// very big.
369
370
#ifndef STBI_NO_STDIO
371
#include <stdio.h>
372
#endif // STBI_NO_STDIO
373
374
#define STBI_VERSION 1
375
376
enum
377
{
378
STBI_default = 0, // only used for desired_channels
379
380
STBI_grey = 1,
381
STBI_grey_alpha = 2,
382
STBI_rgb = 3,
383
STBI_rgb_alpha = 4
384
};
385
386
#include <stdlib.h>
387
typedef unsigned char stbi_uc;
388
typedef unsigned short stbi_us;
389
390
#ifdef __cplusplus
391
extern "C" {
392
#endif
393
394
#ifndef STBIDEF
395
#ifdef STB_IMAGE_STATIC
396
#define STBIDEF static
397
#else
398
#define STBIDEF extern
399
#endif
400
#endif
401
402
//////////////////////////////////////////////////////////////////////////////
403
//
404
// PRIMARY API - works on images of any type
405
//
406
407
//
408
// load image by filename, open file, or memory buffer
409
//
410
411
typedef struct
412
{
413
int (*read) (void *user,char *data,int size); // fill 'data' with 'size' bytes. return number of bytes actually read
414
void (*skip) (void *user,int n); // skip the next 'n' bytes, or 'unget' the last -n bytes if negative
415
int (*eof) (void *user); // returns nonzero if we are at end of file/data
416
} stbi_io_callbacks;
417
418
////////////////////////////////////
419
//
420
// 8-bits-per-channel interface
421
//
422
423
STBIDEF stbi_uc *stbi_load_from_memory (stbi_uc const *buffer, int len , int *x, int *y, int *channels_in_file, int desired_channels);
424
STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk , void *user, int *x, int *y, int *channels_in_file, int desired_channels);
425
426
#ifndef STBI_NO_STDIO
427
STBIDEF stbi_uc *stbi_load (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels);
428
STBIDEF stbi_uc *stbi_load_from_file (FILE *f, int *x, int *y, int *channels_in_file, int desired_channels);
429
// for stbi_load_from_file, file pointer is left pointing immediately after image
430
#endif
431
432
#ifndef STBI_NO_GIF
433
STBIDEF stbi_uc *stbi_load_gif_from_memory(stbi_uc const *buffer, int len, int **delays, int *x, int *y, int *z, int *comp, int req_comp);
434
#endif
435
436
#ifdef STBI_WINDOWS_UTF8
437
STBIDEF int stbi_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input);
438
#endif
439
440
////////////////////////////////////
441
//
442
// 16-bits-per-channel interface
443
//
444
445
STBIDEF stbi_us *stbi_load_16_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels);
446
STBIDEF stbi_us *stbi_load_16_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels);
447
448
#ifndef STBI_NO_STDIO
449
STBIDEF stbi_us *stbi_load_16 (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels);
450
STBIDEF stbi_us *stbi_load_from_file_16(FILE *f, int *x, int *y, int *channels_in_file, int desired_channels);
451
#endif
452
453
////////////////////////////////////
454
//
455
// float-per-channel interface
456
//
457
#ifndef STBI_NO_LINEAR
458
STBIDEF float *stbi_loadf_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels);
459
STBIDEF float *stbi_loadf_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels);
460
461
#ifndef STBI_NO_STDIO
462
STBIDEF float *stbi_loadf (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels);
463
STBIDEF float *stbi_loadf_from_file (FILE *f, int *x, int *y, int *channels_in_file, int desired_channels);
464
#endif
465
#endif
466
467
#ifndef STBI_NO_HDR
468
STBIDEF void stbi_hdr_to_ldr_gamma(float gamma);
469
STBIDEF void stbi_hdr_to_ldr_scale(float scale);
470
#endif // STBI_NO_HDR
471
472
#ifndef STBI_NO_LINEAR
473
STBIDEF void stbi_ldr_to_hdr_gamma(float gamma);
474
STBIDEF void stbi_ldr_to_hdr_scale(float scale);
475
#endif // STBI_NO_LINEAR
476
477
// stbi_is_hdr is always defined, but always returns false if STBI_NO_HDR
478
STBIDEF int stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user);
479
STBIDEF int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len);
480
#ifndef STBI_NO_STDIO
481
STBIDEF int stbi_is_hdr (char const *filename);
482
STBIDEF int stbi_is_hdr_from_file(FILE *f);
483
#endif // STBI_NO_STDIO
484
485
486
// get a VERY brief reason for failure
487
// on most compilers (and ALL modern mainstream compilers) this is threadsafe
488
STBIDEF const char *stbi_failure_reason (void);
489
490
// free the loaded image -- this is just free()
491
STBIDEF void stbi_image_free (void *retval_from_stbi_load);
492
493
// get image dimensions & components without fully decoding
494
STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp);
495
STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp);
496
STBIDEF int stbi_is_16_bit_from_memory(stbi_uc const *buffer, int len);
497
STBIDEF int stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *clbk, void *user);
498
499
#ifndef STBI_NO_STDIO

Showing the first 500 of 7989 diff lines for this file. This diff is INCOMPLETE; read the file or clone the repository for the rest.

vendor/stb/stb_truetype.hdeleted
@@ -1,5079 +0,0 @@
1
// stb_truetype.h - v1.26 - public domain
2
// authored from 2009-2021 by Sean Barrett / RAD Game Tools
3
//
4
// =======================================================================
5
//
6
// NO SECURITY GUARANTEE -- DO NOT USE THIS ON UNTRUSTED FONT FILES
7
//
8
// This library does no range checking of the offsets found in the file,
9
// meaning an attacker can use it to read arbitrary memory.
10
//
11
// =======================================================================
12
//
13
// This library processes TrueType files:
14
// parse files
15
// extract glyph metrics
16
// extract glyph shapes
17
// render glyphs to one-channel bitmaps with antialiasing (box filter)
18
// render glyphs to one-channel SDF bitmaps (signed-distance field/function)
19
//
20
// Todo:
21
// non-MS cmaps
22
// crashproof on bad data
23
// hinting? (no longer patented)
24
// cleartype-style AA?
25
// optimize: use simple memory allocator for intermediates
26
// optimize: build edge-list directly from curves
27
// optimize: rasterize directly from curves?
28
//
29
// ADDITIONAL CONTRIBUTORS
30
//
31
// Mikko Mononen: compound shape support, more cmap formats
32
// Tor Andersson: kerning, subpixel rendering
33
// Dougall Johnson: OpenType / Type 2 font handling
34
// Daniel Ribeiro Maciel: basic GPOS-based kerning
35
//
36
// Misc other:
37
// Ryan Gordon
38
// Simon Glass
39
// github:IntellectualKitty
40
// Imanol Celaya
41
// Daniel Ribeiro Maciel
42
//
43
// Bug/warning reports/fixes:
44
// "Zer" on mollyrocket Fabian "ryg" Giesen github:NiLuJe
45
// Cass Everitt Martins Mozeiko github:aloucks
46
// stoiko (Haemimont Games) Cap Petschulat github:oyvindjam
47
// Brian Hook Omar Cornut github:vassvik
48
// Walter van Niftrik Ryan Griege
49
// David Gow Peter LaValle
50
// David Given Sergey Popov
51
// Ivan-Assen Ivanov Giumo X. Clanjor
52
// Anthony Pesch Higor Euripedes
53
// Johan Duparc Thomas Fields
54
// Hou Qiming Derek Vinyard
55
// Rob Loach Cort Stratton
56
// Kenney Phillis Jr. Brian Costabile
57
// Ken Voskuil (kaesve) Yakov Galka
58
//
59
// VERSION HISTORY
60
//
61
// 1.26 (2021-08-28) fix broken rasterizer
62
// 1.25 (2021-07-11) many fixes
63
// 1.24 (2020-02-05) fix warning
64
// 1.23 (2020-02-02) query SVG data for glyphs; query whole kerning table (but only kern not GPOS)
65
// 1.22 (2019-08-11) minimize missing-glyph duplication; fix kerning if both 'GPOS' and 'kern' are defined
66
// 1.21 (2019-02-25) fix warning
67
// 1.20 (2019-02-07) PackFontRange skips missing codepoints; GetScaleFontVMetrics()
68
// 1.19 (2018-02-11) GPOS kerning, STBTT_fmod
69
// 1.18 (2018-01-29) add missing function
70
// 1.17 (2017-07-23) make more arguments const; doc fix
71
// 1.16 (2017-07-12) SDF support
72
// 1.15 (2017-03-03) make more arguments const
73
// 1.14 (2017-01-16) num-fonts-in-TTC function
74
// 1.13 (2017-01-02) support OpenType fonts, certain Apple fonts
75
// 1.12 (2016-10-25) suppress warnings about casting away const with -Wcast-qual
76
// 1.11 (2016-04-02) fix unused-variable warning
77
// 1.10 (2016-04-02) user-defined fabs(); rare memory leak; remove duplicate typedef
78
// 1.09 (2016-01-16) warning fix; avoid crash on outofmem; use allocation userdata properly
79
// 1.08 (2015-09-13) document stbtt_Rasterize(); fixes for vertical & horizontal edges
80
// 1.07 (2015-08-01) allow PackFontRanges to accept arrays of sparse codepoints;
81
// variant PackFontRanges to pack and render in separate phases;
82
// fix stbtt_GetFontOFfsetForIndex (never worked for non-0 input?);
83
// fixed an assert() bug in the new rasterizer
84
// replace assert() with STBTT_assert() in new rasterizer
85
//
86
// Full history can be found at the end of this file.
87
//
88
// LICENSE
89
//
90
// See end of file for license information.
91
//
92
// USAGE
93
//
94
// Include this file in whatever places need to refer to it. In ONE C/C++
95
// file, write:
96
// #define STB_TRUETYPE_IMPLEMENTATION
97
// before the #include of this file. This expands out the actual
98
// implementation into that C/C++ file.
99
//
100
// To make the implementation private to the file that generates the implementation,
101
// #define STBTT_STATIC
102
//
103
// Simple 3D API (don't ship this, but it's fine for tools and quick start)
104
// stbtt_BakeFontBitmap() -- bake a font to a bitmap for use as texture
105
// stbtt_GetBakedQuad() -- compute quad to draw for a given char
106
//
107
// Improved 3D API (more shippable):
108
// #include "stb_rect_pack.h" -- optional, but you really want it
109
// stbtt_PackBegin()
110
// stbtt_PackSetOversampling() -- for improved quality on small fonts
111
// stbtt_PackFontRanges() -- pack and renders
112
// stbtt_PackEnd()
113
// stbtt_GetPackedQuad()
114
//
115
// "Load" a font file from a memory buffer (you have to keep the buffer loaded)
116
// stbtt_InitFont()
117
// stbtt_GetFontOffsetForIndex() -- indexing for TTC font collections
118
// stbtt_GetNumberOfFonts() -- number of fonts for TTC font collections
119
//
120
// Render a unicode codepoint to a bitmap
121
// stbtt_GetCodepointBitmap() -- allocates and returns a bitmap
122
// stbtt_MakeCodepointBitmap() -- renders into bitmap you provide
123
// stbtt_GetCodepointBitmapBox() -- how big the bitmap must be
124
//
125
// Character advance/positioning
126
// stbtt_GetCodepointHMetrics()
127
// stbtt_GetFontVMetrics()
128
// stbtt_GetFontVMetricsOS2()
129
// stbtt_GetCodepointKernAdvance()
130
//
131
// Starting with version 1.06, the rasterizer was replaced with a new,
132
// faster and generally-more-precise rasterizer. The new rasterizer more
133
// accurately measures pixel coverage for anti-aliasing, except in the case
134
// where multiple shapes overlap, in which case it overestimates the AA pixel
135
// coverage. Thus, anti-aliasing of intersecting shapes may look wrong. If
136
// this turns out to be a problem, you can re-enable the old rasterizer with
137
// #define STBTT_RASTERIZER_VERSION 1
138
// which will incur about a 15% speed hit.
139
//
140
// ADDITIONAL DOCUMENTATION
141
//
142
// Immediately after this block comment are a series of sample programs.
143
//
144
// After the sample programs is the "header file" section. This section
145
// includes documentation for each API function.
146
//
147
// Some important concepts to understand to use this library:
148
//
149
// Codepoint
150
// Characters are defined by unicode codepoints, e.g. 65 is
151
// uppercase A, 231 is lowercase c with a cedilla, 0x7e30 is
152
// the hiragana for "ma".
153
//
154
// Glyph
155
// A visual character shape (every codepoint is rendered as
156
// some glyph)
157
//
158
// Glyph index
159
// A font-specific integer ID representing a glyph
160
//
161
// Baseline
162
// Glyph shapes are defined relative to a baseline, which is the
163
// bottom of uppercase characters. Characters extend both above
164
// and below the baseline.
165
//
166
// Current Point
167
// As you draw text to the screen, you keep track of a "current point"
168
// which is the origin of each character. The current point's vertical
169
// position is the baseline. Even "baked fonts" use this model.
170
//
171
// Vertical Font Metrics
172
// The vertical qualities of the font, used to vertically position
173
// and space the characters. See docs for stbtt_GetFontVMetrics.
174
//
175
// Font Size in Pixels or Points
176
// The preferred interface for specifying font sizes in stb_truetype
177
// is to specify how tall the font's vertical extent should be in pixels.
178
// If that sounds good enough, skip the next paragraph.
179
//
180
// Most font APIs instead use "points", which are a common typographic
181
// measurement for describing font size, defined as 72 points per inch.
182
// stb_truetype provides a point API for compatibility. However, true
183
// "per inch" conventions don't make much sense on computer displays
184
// since different monitors have different number of pixels per
185
// inch. For example, Windows traditionally uses a convention that
186
// there are 96 pixels per inch, thus making 'inch' measurements have
187
// nothing to do with inches, and thus effectively defining a point to
188
// be 1.333 pixels. Additionally, the TrueType font data provides
189
// an explicit scale factor to scale a given font's glyphs to points,
190
// but the author has observed that this scale factor is often wrong
191
// for non-commercial fonts, thus making fonts scaled in points
192
// according to the TrueType spec incoherently sized in practice.
193
//
194
// DETAILED USAGE:
195
//
196
// Scale:
197
// Select how high you want the font to be, in points or pixels.
198
// Call ScaleForPixelHeight or ScaleForMappingEmToPixels to compute
199
// a scale factor SF that will be used by all other functions.
200
//
201
// Baseline:
202
// You need to select a y-coordinate that is the baseline of where
203
// your text will appear. Call GetFontBoundingBox to get the baseline-relative
204
// bounding box for all characters. SF*-y0 will be the distance in pixels
205
// that the worst-case character could extend above the baseline, so if
206
// you want the top edge of characters to appear at the top of the
207
// screen where y=0, then you would set the baseline to SF*-y0.
208
//
209
// Current point:
210
// Set the current point where the first character will appear. The
211
// first character could extend left of the current point; this is font
212
// dependent. You can either choose a current point that is the leftmost
213
// point and hope, or add some padding, or check the bounding box or
214
// left-side-bearing of the first character to be displayed and set
215
// the current point based on that.
216
//
217
// Displaying a character:
218
// Compute the bounding box of the character. It will contain signed values
219
// relative to <current_point, baseline>. I.e. if it returns x0,y0,x1,y1,
220
// then the character should be displayed in the rectangle from
221
// <current_point+SF*x0, baseline+SF*y0> to <current_point+SF*x1,baseline+SF*y1).
222
//
223
// Advancing for the next character:
224
// Call GlyphHMetrics, and compute 'current_point += SF * advance'.
225
//
226
//
227
// ADVANCED USAGE
228
//
229
// Quality:
230
//
231
// - Use the functions with Subpixel at the end to allow your characters
232
// to have subpixel positioning. Since the font is anti-aliased, not
233
// hinted, this is very import for quality. (This is not possible with
234
// baked fonts.)
235
//
236
// - Kerning is now supported, and if you're supporting subpixel rendering
237
// then kerning is worth using to give your text a polished look.
238
//
239
// Performance:
240
//
241
// - Convert Unicode codepoints to glyph indexes and operate on the glyphs;
242
// if you don't do this, stb_truetype is forced to do the conversion on
243
// every call.
244
//
245
// - There are a lot of memory allocations. We should modify it to take
246
// a temp buffer and allocate from the temp buffer (without freeing),
247
// should help performance a lot.
248
//
249
// NOTES
250
//
251
// The system uses the raw data found in the .ttf file without changing it
252
// and without building auxiliary data structures. This is a bit inefficient
253
// on little-endian systems (the data is big-endian), but assuming you're
254
// caching the bitmaps or glyph shapes this shouldn't be a big deal.
255
//
256
// It appears to be very hard to programmatically determine what font a
257
// given file is in a general way. I provide an API for this, but I don't
258
// recommend it.
259
//
260
//
261
// PERFORMANCE MEASUREMENTS FOR 1.06:
262
//
263
// 32-bit 64-bit
264
// Previous release: 8.83 s 7.68 s
265
// Pool allocations: 7.72 s 6.34 s
266
// Inline sort : 6.54 s 5.65 s
267
// New rasterizer : 5.63 s 5.00 s
268
269
//////////////////////////////////////////////////////////////////////////////
270
//////////////////////////////////////////////////////////////////////////////
271
////
272
//// SAMPLE PROGRAMS
273
////
274
//
275
// Incomplete text-in-3d-api example, which draws quads properly aligned to be lossless.
276
// See "tests/truetype_demo_win32.c" for a complete version.
277
#if 0
278
#define STB_TRUETYPE_IMPLEMENTATION // force following include to generate implementation
279
#include "stb_truetype.h"
280
281
unsigned char ttf_buffer[1<<20];
282
unsigned char temp_bitmap[512*512];
283
284
stbtt_bakedchar cdata[96]; // ASCII 32..126 is 95 glyphs
285
GLuint ftex;
286
287
void my_stbtt_initfont(void)
288
{
289
fread(ttf_buffer, 1, 1<<20, fopen("c:/windows/fonts/times.ttf", "rb"));
290
stbtt_BakeFontBitmap(ttf_buffer,0, 32.0, temp_bitmap,512,512, 32,96, cdata); // no guarantee this fits!
291
// can free ttf_buffer at this point
292
glGenTextures(1, &ftex);
293
glBindTexture(GL_TEXTURE_2D, ftex);
294
glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, 512,512, 0, GL_ALPHA, GL_UNSIGNED_BYTE, temp_bitmap);
295
// can free temp_bitmap at this point
296
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
297
}
298
299
void my_stbtt_print(float x, float y, char *text)
300
{
301
// assume orthographic projection with units = screen pixels, origin at top left
302
glEnable(GL_BLEND);
303
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
304
glEnable(GL_TEXTURE_2D);
305
glBindTexture(GL_TEXTURE_2D, ftex);
306
glBegin(GL_QUADS);
307
while (*text) {
308
if (*text >= 32 && *text < 128) {
309
stbtt_aligned_quad q;
310
stbtt_GetBakedQuad(cdata, 512,512, *text-32, &x,&y,&q,1);//1=opengl & d3d10+,0=d3d9
311
glTexCoord2f(q.s0,q.t0); glVertex2f(q.x0,q.y0);
312
glTexCoord2f(q.s1,q.t0); glVertex2f(q.x1,q.y0);
313
glTexCoord2f(q.s1,q.t1); glVertex2f(q.x1,q.y1);
314
glTexCoord2f(q.s0,q.t1); glVertex2f(q.x0,q.y1);
315
}
316
++text;
317
}
318
glEnd();
319
}
320
#endif
321
//
322
//
323
//////////////////////////////////////////////////////////////////////////////
324
//
325
// Complete program (this compiles): get a single bitmap, print as ASCII art
326
//
327
#if 0
328
#include <stdio.h>
329
#define STB_TRUETYPE_IMPLEMENTATION // force following include to generate implementation
330
#include "stb_truetype.h"
331
332
char ttf_buffer[1<<25];
333
334
int main(int argc, char **argv)
335
{
336
stbtt_fontinfo font;
337
unsigned char *bitmap;
338
int w,h,i,j,c = (argc > 1 ? atoi(argv[1]) : 'a'), s = (argc > 2 ? atoi(argv[2]) : 20);
339
340
fread(ttf_buffer, 1, 1<<25, fopen(argc > 3 ? argv[3] : "c:/windows/fonts/arialbd.ttf", "rb"));
341
342
stbtt_InitFont(&font, ttf_buffer, stbtt_GetFontOffsetForIndex(ttf_buffer,0));
343
bitmap = stbtt_GetCodepointBitmap(&font, 0,stbtt_ScaleForPixelHeight(&font, s), c, &w, &h, 0,0);
344
345
for (j=0; j < h; ++j) {
346
for (i=0; i < w; ++i)
347
putchar(" .:ioVM@"[bitmap[j*w+i]>>5]);
348
putchar('\n');
349
}
350
return 0;
351
}
352
#endif
353
//
354
// Output:
355
//
356
// .ii.
357
// @@@@@@.
358
// V@Mio@@o
359
// :i. V@V
360
// :oM@@M
361
// :@@@MM@M
362
// @@o o@M
363
// :@@. M@M
364
// @@@o@@@@
365
// :M@@V:@@.
366
//
367
//////////////////////////////////////////////////////////////////////////////
368
//
369
// Complete program: print "Hello World!" banner, with bugs
370
//
371
#if 0
372
char buffer[24<<20];
373
unsigned char screen[20][79];
374
375
int main(int arg, char **argv)
376
{
377
stbtt_fontinfo font;
378
int i,j,ascent,baseline,ch=0;
379
float scale, xpos=2; // leave a little padding in case the character extends left
380
char *text = "Heljo World!"; // intentionally misspelled to show 'lj' brokenness
381
382
fread(buffer, 1, 1000000, fopen("c:/windows/fonts/arialbd.ttf", "rb"));
383
stbtt_InitFont(&font, buffer, 0);
384
385
scale = stbtt_ScaleForPixelHeight(&font, 15);
386
stbtt_GetFontVMetrics(&font, &ascent,0,0);
387
baseline = (int) (ascent*scale);
388
389
while (text[ch]) {
390
int advance,lsb,x0,y0,x1,y1;
391
float x_shift = xpos - (float) floor(xpos);
392
stbtt_GetCodepointHMetrics(&font, text[ch], &advance, &lsb);
393
stbtt_GetCodepointBitmapBoxSubpixel(&font, text[ch], scale,scale,x_shift,0, &x0,&y0,&x1,&y1);
394
stbtt_MakeCodepointBitmapSubpixel(&font, &screen[baseline + y0][(int) xpos + x0], x1-x0,y1-y0, 79, scale,scale,x_shift,0, text[ch]);
395
// note that this stomps the old data, so where character boxes overlap (e.g. 'lj') it's wrong
396
// because this API is really for baking character bitmaps into textures. if you want to render
397
// a sequence of characters, you really need to render each bitmap to a temp buffer, then
398
// "alpha blend" that into the working buffer
399
xpos += (advance * scale);
400
if (text[ch+1])
401
xpos += scale*stbtt_GetCodepointKernAdvance(&font, text[ch],text[ch+1]);
402
++ch;
403
}
404
405
for (j=0; j < 20; ++j) {
406
for (i=0; i < 78; ++i)
407
putchar(" .:ioVM@"[screen[j][i]>>5]);
408
putchar('\n');
409
}
410
411
return 0;
412
}
413
#endif
414
415
416
//////////////////////////////////////////////////////////////////////////////
417
//////////////////////////////////////////////////////////////////////////////
418
////
419
//// INTEGRATION WITH YOUR CODEBASE
420
////
421
//// The following sections allow you to supply alternate definitions
422
//// of C library functions used by stb_truetype, e.g. if you don't
423
//// link with the C runtime library.
424
425
#ifdef STB_TRUETYPE_IMPLEMENTATION
426
// #define your own (u)stbtt_int8/16/32 before including to override this
427
#ifndef stbtt_uint8
428
typedef unsigned char stbtt_uint8;
429
typedef signed char stbtt_int8;
430
typedef unsigned short stbtt_uint16;
431
typedef signed short stbtt_int16;
432
typedef unsigned int stbtt_uint32;
433
typedef signed int stbtt_int32;
434
#endif
435
436
typedef char stbtt__check_size32[sizeof(stbtt_int32)==4 ? 1 : -1];
437
typedef char stbtt__check_size16[sizeof(stbtt_int16)==2 ? 1 : -1];
438
439
// e.g. #define your own STBTT_ifloor/STBTT_iceil() to avoid math.h
440
#ifndef STBTT_ifloor
441
#include <math.h>
442
#define STBTT_ifloor(x) ((int) floor(x))
443
#define STBTT_iceil(x) ((int) ceil(x))
444
#endif
445
446
#ifndef STBTT_sqrt
447
#include <math.h>
448
#define STBTT_sqrt(x) sqrt(x)
449
#define STBTT_pow(x,y) pow(x,y)
450
#endif
451
452
#ifndef STBTT_fmod
453
#include <math.h>
454
#define STBTT_fmod(x,y) fmod(x,y)
455
#endif
456
457
#ifndef STBTT_cos
458
#include <math.h>
459
#define STBTT_cos(x) cos(x)
460
#define STBTT_acos(x) acos(x)
461
#endif
462
463
#ifndef STBTT_fabs
464
#include <math.h>
465
#define STBTT_fabs(x) fabs(x)
466
#endif
467
468
// #define your own functions "STBTT_malloc" / "STBTT_free" to avoid malloc.h
469
#ifndef STBTT_malloc
470
#include <stdlib.h>
471
#define STBTT_malloc(x,u) ((void)(u),malloc(x))
472
#define STBTT_free(x,u) ((void)(u),free(x))
473
#endif
474
475
#ifndef STBTT_assert
476
#include <assert.h>
477
#define STBTT_assert(x) assert(x)
478
#endif
479
480
#ifndef STBTT_strlen
481
#include <string.h>
482
#define STBTT_strlen(x) strlen(x)
483
#endif
484
485
#ifndef STBTT_memcpy
486
#include <string.h>
487
#define STBTT_memcpy memcpy
488
#define STBTT_memset memset
489
#endif
490
#endif
491
492
///////////////////////////////////////////////////////////////////////////////
493
///////////////////////////////////////////////////////////////////////////////
494
////
495
//// INTERFACE
496
////
497
////
498
499
#ifndef __STB_INCLUDE_STB_TRUETYPE_H__

Showing the first 500 of 5080 diff lines for this file. This diff is INCOMPLETE; read the file or clone the repository for the rest.

vendor/stb/stb_vorbis.cdeleted
@@ -1,5584 +0,0 @@
1
// Ogg Vorbis audio decoder - v1.22 - public domain
2
// http://nothings.org/stb_vorbis/
3
//
4
// Original version written by Sean Barrett in 2007.
5
//
6
// Originally sponsored by RAD Game Tools. Seeking implementation
7
// sponsored by Phillip Bennefall, Marc Andersen, Aaron Baker,
8
// Elias Software, Aras Pranckevicius, and Sean Barrett.
9
//
10
// LICENSE
11
//
12
// See end of file for license information.
13
//
14
// Limitations:
15
//
16
// - floor 0 not supported (used in old ogg vorbis files pre-2004)
17
// - lossless sample-truncation at beginning ignored
18
// - cannot concatenate multiple vorbis streams
19
// - sample positions are 32-bit, limiting seekable 192Khz
20
// files to around 6 hours (Ogg supports 64-bit)
21
//
22
// Feature contributors:
23
// Dougall Johnson (sample-exact seeking)
24
//
25
// Bugfix/warning contributors:
26
// Terje Mathisen Niklas Frykholm Andy Hill
27
// Casey Muratori John Bolton Gargaj
28
// Laurent Gomila Marc LeBlanc Ronny Chevalier
29
// Bernhard Wodo Evan Balster github:alxprd
30
// Tom Beaumont Ingo Leitgeb Nicolas Guillemot
31
// Phillip Bennefall Rohit Thiago Goulart
32
// github:manxorist Saga Musix github:infatum
33
// Timur Gagiev Maxwell Koo Peter Waller
34
// github:audinowho Dougall Johnson David Reid
35
// github:Clownacy Pedro J. Estebanez Remi Verschelde
36
// AnthoFoxo github:morlat Gabriel Ravier
37
//
38
// Partial history:
39
// 1.22 - 2021-07-11 - various small fixes
40
// 1.21 - 2021-07-02 - fix bug for files with no comments
41
// 1.20 - 2020-07-11 - several small fixes
42
// 1.19 - 2020-02-05 - warnings
43
// 1.18 - 2020-02-02 - fix seek bugs; parse header comments; misc warnings etc.
44
// 1.17 - 2019-07-08 - fix CVE-2019-13217..CVE-2019-13223 (by ForAllSecure)
45
// 1.16 - 2019-03-04 - fix warnings
46
// 1.15 - 2019-02-07 - explicit failure if Ogg Skeleton data is found
47
// 1.14 - 2018-02-11 - delete bogus dealloca usage
48
// 1.13 - 2018-01-29 - fix truncation of last frame (hopefully)
49
// 1.12 - 2017-11-21 - limit residue begin/end to blocksize/2 to avoid large temp allocs in bad/corrupt files
50
// 1.11 - 2017-07-23 - fix MinGW compilation
51
// 1.10 - 2017-03-03 - more robust seeking; fix negative ilog(); clear error in open_memory
52
// 1.09 - 2016-04-04 - back out 'truncation of last frame' fix from previous version
53
// 1.08 - 2016-04-02 - warnings; setup memory leaks; truncation of last frame
54
// 1.07 - 2015-01-16 - fixes for crashes on invalid files; warning fixes; const
55
// 1.06 - 2015-08-31 - full, correct support for seeking API (Dougall Johnson)
56
// some crash fixes when out of memory or with corrupt files
57
// fix some inappropriately signed shifts
58
// 1.05 - 2015-04-19 - don't define __forceinline if it's redundant
59
// 1.04 - 2014-08-27 - fix missing const-correct case in API
60
// 1.03 - 2014-08-07 - warning fixes
61
// 1.02 - 2014-07-09 - declare qsort comparison as explicitly _cdecl in Windows
62
// 1.01 - 2014-06-18 - fix stb_vorbis_get_samples_float (interleaved was correct)
63
// 1.0 - 2014-05-26 - fix memory leaks; fix warnings; fix bugs in >2-channel;
64
// (API change) report sample rate for decode-full-file funcs
65
//
66
// See end of file for full version history.
67
68
69
//////////////////////////////////////////////////////////////////////////////
70
//
71
// HEADER BEGINS HERE
72
//
73
74
#ifndef STB_VORBIS_INCLUDE_STB_VORBIS_H
75
#define STB_VORBIS_INCLUDE_STB_VORBIS_H
76
77
#if defined(STB_VORBIS_NO_CRT) && !defined(STB_VORBIS_NO_STDIO)
78
#define STB_VORBIS_NO_STDIO 1
79
#endif
80
81
#ifndef STB_VORBIS_NO_STDIO
82
#include <stdio.h>
83
#endif
84
85
#ifdef __cplusplus
86
extern "C" {
87
#endif
88
89
/////////// THREAD SAFETY
90
91
// Individual stb_vorbis* handles are not thread-safe; you cannot decode from
92
// them from multiple threads at the same time. However, you can have multiple
93
// stb_vorbis* handles and decode from them independently in multiple thrads.
94
95
96
/////////// MEMORY ALLOCATION
97
98
// normally stb_vorbis uses malloc() to allocate memory at startup,
99
// and alloca() to allocate temporary memory during a frame on the
100
// stack. (Memory consumption will depend on the amount of setup
101
// data in the file and how you set the compile flags for speed
102
// vs. size. In my test files the maximal-size usage is ~150KB.)
103
//
104
// You can modify the wrapper functions in the source (setup_malloc,
105
// setup_temp_malloc, temp_malloc) to change this behavior, or you
106
// can use a simpler allocation model: you pass in a buffer from
107
// which stb_vorbis will allocate _all_ its memory (including the
108
// temp memory). "open" may fail with a VORBIS_outofmem if you
109
// do not pass in enough data; there is no way to determine how
110
// much you do need except to succeed (at which point you can
111
// query get_info to find the exact amount required. yes I know
112
// this is lame).
113
//
114
// If you pass in a non-NULL buffer of the type below, allocation
115
// will occur from it as described above. Otherwise just pass NULL
116
// to use malloc()/alloca()
117
118
typedef struct
119
{
120
char *alloc_buffer;
121
int alloc_buffer_length_in_bytes;
122
} stb_vorbis_alloc;
123
124
125
/////////// FUNCTIONS USEABLE WITH ALL INPUT MODES
126
127
typedef struct stb_vorbis stb_vorbis;
128
129
typedef struct
130
{
131
unsigned int sample_rate;
132
int channels;
133
134
unsigned int setup_memory_required;
135
unsigned int setup_temp_memory_required;
136
unsigned int temp_memory_required;
137
138
int max_frame_size;
139
} stb_vorbis_info;
140
141
typedef struct
142
{
143
char *vendor;
144
145
int comment_list_length;
146
char **comment_list;
147
} stb_vorbis_comment;
148
149
// get general information about the file
150
extern stb_vorbis_info stb_vorbis_get_info(stb_vorbis *f);
151
152
// get ogg comments
153
extern stb_vorbis_comment stb_vorbis_get_comment(stb_vorbis *f);
154
155
// get the last error detected (clears it, too)
156
extern int stb_vorbis_get_error(stb_vorbis *f);
157
158
// close an ogg vorbis file and free all memory in use
159
extern void stb_vorbis_close(stb_vorbis *f);
160
161
// this function returns the offset (in samples) from the beginning of the
162
// file that will be returned by the next decode, if it is known, or -1
163
// otherwise. after a flush_pushdata() call, this may take a while before
164
// it becomes valid again.
165
// NOT WORKING YET after a seek with PULLDATA API
166
extern int stb_vorbis_get_sample_offset(stb_vorbis *f);
167
168
// returns the current seek point within the file, or offset from the beginning
169
// of the memory buffer. In pushdata mode it returns 0.
170
extern unsigned int stb_vorbis_get_file_offset(stb_vorbis *f);
171
172
/////////// PUSHDATA API
173
174
#ifndef STB_VORBIS_NO_PUSHDATA_API
175
176
// this API allows you to get blocks of data from any source and hand
177
// them to stb_vorbis. you have to buffer them; stb_vorbis will tell
178
// you how much it used, and you have to give it the rest next time;
179
// and stb_vorbis may not have enough data to work with and you will
180
// need to give it the same data again PLUS more. Note that the Vorbis
181
// specification does not bound the size of an individual frame.
182
183
extern stb_vorbis *stb_vorbis_open_pushdata(
184
const unsigned char * datablock, int datablock_length_in_bytes,
185
int *datablock_memory_consumed_in_bytes,
186
int *error,
187
const stb_vorbis_alloc *alloc_buffer);
188
// create a vorbis decoder by passing in the initial data block containing
189
// the ogg&vorbis headers (you don't need to do parse them, just provide
190
// the first N bytes of the file--you're told if it's not enough, see below)
191
// on success, returns an stb_vorbis *, does not set error, returns the amount of
192
// data parsed/consumed on this call in *datablock_memory_consumed_in_bytes;
193
// on failure, returns NULL on error and sets *error, does not change *datablock_memory_consumed
194
// if returns NULL and *error is VORBIS_need_more_data, then the input block was
195
// incomplete and you need to pass in a larger block from the start of the file
196
197
extern int stb_vorbis_decode_frame_pushdata(
198
stb_vorbis *f,
199
const unsigned char *datablock, int datablock_length_in_bytes,
200
int *channels, // place to write number of float * buffers
201
float ***output, // place to write float ** array of float * buffers
202
int *samples // place to write number of output samples
203
);
204
// decode a frame of audio sample data if possible from the passed-in data block
205
//
206
// return value: number of bytes we used from datablock
207
//
208
// possible cases:
209
// 0 bytes used, 0 samples output (need more data)
210
// N bytes used, 0 samples output (resynching the stream, keep going)
211
// N bytes used, M samples output (one frame of data)
212
// note that after opening a file, you will ALWAYS get one N-bytes,0-sample
213
// frame, because Vorbis always "discards" the first frame.
214
//
215
// Note that on resynch, stb_vorbis will rarely consume all of the buffer,
216
// instead only datablock_length_in_bytes-3 or less. This is because it wants
217
// to avoid missing parts of a page header if they cross a datablock boundary,
218
// without writing state-machiney code to record a partial detection.
219
//
220
// The number of channels returned are stored in *channels (which can be
221
// NULL--it is always the same as the number of channels reported by
222
// get_info). *output will contain an array of float* buffers, one per
223
// channel. In other words, (*output)[0][0] contains the first sample from
224
// the first channel, and (*output)[1][0] contains the first sample from
225
// the second channel.
226
//
227
// *output points into stb_vorbis's internal output buffer storage; these
228
// buffers are owned by stb_vorbis and application code should not free
229
// them or modify their contents. They are transient and will be overwritten
230
// once you ask for more data to get decoded, so be sure to grab any data
231
// you need before then.
232
233
extern void stb_vorbis_flush_pushdata(stb_vorbis *f);
234
// inform stb_vorbis that your next datablock will not be contiguous with
235
// previous ones (e.g. you've seeked in the data); future attempts to decode
236
// frames will cause stb_vorbis to resynchronize (as noted above), and
237
// once it sees a valid Ogg page (typically 4-8KB, as large as 64KB), it
238
// will begin decoding the _next_ frame.
239
//
240
// if you want to seek using pushdata, you need to seek in your file, then
241
// call stb_vorbis_flush_pushdata(), then start calling decoding, then once
242
// decoding is returning you data, call stb_vorbis_get_sample_offset, and
243
// if you don't like the result, seek your file again and repeat.
244
#endif
245
246
247
////////// PULLING INPUT API
248
249
#ifndef STB_VORBIS_NO_PULLDATA_API
250
// This API assumes stb_vorbis is allowed to pull data from a source--
251
// either a block of memory containing the _entire_ vorbis stream, or a
252
// FILE * that you or it create, or possibly some other reading mechanism
253
// if you go modify the source to replace the FILE * case with some kind
254
// of callback to your code. (But if you don't support seeking, you may
255
// just want to go ahead and use pushdata.)
256
257
#if !defined(STB_VORBIS_NO_STDIO) && !defined(STB_VORBIS_NO_INTEGER_CONVERSION)
258
extern int stb_vorbis_decode_filename(const char *filename, int *channels, int *sample_rate, short **output);
259
#endif
260
#if !defined(STB_VORBIS_NO_INTEGER_CONVERSION)
261
extern int stb_vorbis_decode_memory(const unsigned char *mem, int len, int *channels, int *sample_rate, short **output);
262
#endif
263
// decode an entire file and output the data interleaved into a malloc()ed
264
// buffer stored in *output. The return value is the number of samples
265
// decoded, or -1 if the file could not be opened or was not an ogg vorbis file.
266
// When you're done with it, just free() the pointer returned in *output.
267
268
extern stb_vorbis * stb_vorbis_open_memory(const unsigned char *data, int len,
269
int *error, const stb_vorbis_alloc *alloc_buffer);
270
// create an ogg vorbis decoder from an ogg vorbis stream in memory (note
271
// this must be the entire stream!). on failure, returns NULL and sets *error
272
273
#ifndef STB_VORBIS_NO_STDIO
274
extern stb_vorbis * stb_vorbis_open_filename(const char *filename,
275
int *error, const stb_vorbis_alloc *alloc_buffer);
276
// create an ogg vorbis decoder from a filename via fopen(). on failure,
277
// returns NULL and sets *error (possibly to VORBIS_file_open_failure).
278
279
extern stb_vorbis * stb_vorbis_open_file(FILE *f, int close_handle_on_close,
280
int *error, const stb_vorbis_alloc *alloc_buffer);
281
// create an ogg vorbis decoder from an open FILE *, looking for a stream at
282
// the _current_ seek point (ftell). on failure, returns NULL and sets *error.
283
// note that stb_vorbis must "own" this stream; if you seek it in between
284
// calls to stb_vorbis, it will become confused. Moreover, if you attempt to
285
// perform stb_vorbis_seek_*() operations on this file, it will assume it
286
// owns the _entire_ rest of the file after the start point. Use the next
287
// function, stb_vorbis_open_file_section(), to limit it.
288
289
extern stb_vorbis * stb_vorbis_open_file_section(FILE *f, int close_handle_on_close,
290
int *error, const stb_vorbis_alloc *alloc_buffer, unsigned int len);
291
// create an ogg vorbis decoder from an open FILE *, looking for a stream at
292
// the _current_ seek point (ftell); the stream will be of length 'len' bytes.
293
// on failure, returns NULL and sets *error. note that stb_vorbis must "own"
294
// this stream; if you seek it in between calls to stb_vorbis, it will become
295
// confused.
296
#endif
297
298
extern int stb_vorbis_seek_frame(stb_vorbis *f, unsigned int sample_number);
299
extern int stb_vorbis_seek(stb_vorbis *f, unsigned int sample_number);
300
// these functions seek in the Vorbis file to (approximately) 'sample_number'.
301
// after calling seek_frame(), the next call to get_frame_*() will include
302
// the specified sample. after calling stb_vorbis_seek(), the next call to
303
// stb_vorbis_get_samples_* will start with the specified sample. If you
304
// do not need to seek to EXACTLY the target sample when using get_samples_*,
305
// you can also use seek_frame().
306
307
extern int stb_vorbis_seek_start(stb_vorbis *f);
308
// this function is equivalent to stb_vorbis_seek(f,0)
309
310
extern unsigned int stb_vorbis_stream_length_in_samples(stb_vorbis *f);
311
extern float stb_vorbis_stream_length_in_seconds(stb_vorbis *f);
312
// these functions return the total length of the vorbis stream
313
314
extern int stb_vorbis_get_frame_float(stb_vorbis *f, int *channels, float ***output);
315
// decode the next frame and return the number of samples. the number of
316
// channels returned are stored in *channels (which can be NULL--it is always
317
// the same as the number of channels reported by get_info). *output will
318
// contain an array of float* buffers, one per channel. These outputs will
319
// be overwritten on the next call to stb_vorbis_get_frame_*.
320
//
321
// You generally should not intermix calls to stb_vorbis_get_frame_*()
322
// and stb_vorbis_get_samples_*(), since the latter calls the former.
323
324
#ifndef STB_VORBIS_NO_INTEGER_CONVERSION
325
extern int stb_vorbis_get_frame_short_interleaved(stb_vorbis *f, int num_c, short *buffer, int num_shorts);
326
extern int stb_vorbis_get_frame_short (stb_vorbis *f, int num_c, short **buffer, int num_samples);
327
#endif
328
// decode the next frame and return the number of *samples* per channel.
329
// Note that for interleaved data, you pass in the number of shorts (the
330
// size of your array), but the return value is the number of samples per
331
// channel, not the total number of samples.
332
//
333
// The data is coerced to the number of channels you request according to the
334
// channel coercion rules (see below). You must pass in the size of your
335
// buffer(s) so that stb_vorbis will not overwrite the end of the buffer.
336
// The maximum buffer size needed can be gotten from get_info(); however,
337
// the Vorbis I specification implies an absolute maximum of 4096 samples
338
// per channel.
339
340
// Channel coercion rules:
341
// Let M be the number of channels requested, and N the number of channels present,
342
// and Cn be the nth channel; let stereo L be the sum of all L and center channels,
343
// and stereo R be the sum of all R and center channels (channel assignment from the
344
// vorbis spec).
345
// M N output
346
// 1 k sum(Ck) for all k
347
// 2 * stereo L, stereo R
348
// k l k > l, the first l channels, then 0s
349
// k l k <= l, the first k channels
350
// Note that this is not _good_ surround etc. mixing at all! It's just so
351
// you get something useful.
352
353
extern int stb_vorbis_get_samples_float_interleaved(stb_vorbis *f, int channels, float *buffer, int num_floats);
354
extern int stb_vorbis_get_samples_float(stb_vorbis *f, int channels, float **buffer, int num_samples);
355
// gets num_samples samples, not necessarily on a frame boundary--this requires
356
// buffering so you have to supply the buffers. DOES NOT APPLY THE COERCION RULES.
357
// Returns the number of samples stored per channel; it may be less than requested
358
// at the end of the file. If there are no more samples in the file, returns 0.
359
360
#ifndef STB_VORBIS_NO_INTEGER_CONVERSION
361
extern int stb_vorbis_get_samples_short_interleaved(stb_vorbis *f, int channels, short *buffer, int num_shorts);
362
extern int stb_vorbis_get_samples_short(stb_vorbis *f, int channels, short **buffer, int num_samples);
363
#endif
364
// gets num_samples samples, not necessarily on a frame boundary--this requires
365
// buffering so you have to supply the buffers. Applies the coercion rules above
366
// to produce 'channels' channels. Returns the number of samples stored per channel;
367
// it may be less than requested at the end of the file. If there are no more
368
// samples in the file, returns 0.
369
370
#endif
371
372
//////// ERROR CODES
373
374
enum STBVorbisError
375
{
376
VORBIS__no_error,
377
378
VORBIS_need_more_data=1, // not a real error
379
380
VORBIS_invalid_api_mixing, // can't mix API modes
381
VORBIS_outofmem, // not enough memory
382
VORBIS_feature_not_supported, // uses floor 0
383
VORBIS_too_many_channels, // STB_VORBIS_MAX_CHANNELS is too small
384
VORBIS_file_open_failure, // fopen() failed
385
VORBIS_seek_without_length, // can't seek in unknown-length file
386
387
VORBIS_unexpected_eof=10, // file is truncated?
388
VORBIS_seek_invalid, // seek past EOF
389
390
// decoding errors (corrupt/invalid stream) -- you probably
391
// don't care about the exact details of these
392
393
// vorbis errors:
394
VORBIS_invalid_setup=20,
395
VORBIS_invalid_stream,
396
397
// ogg errors:
398
VORBIS_missing_capture_pattern=30,
399
VORBIS_invalid_stream_structure_version,
400
VORBIS_continued_packet_flag_invalid,
401
VORBIS_incorrect_stream_serial_number,
402
VORBIS_invalid_first_page,
403
VORBIS_bad_packet_type,
404
VORBIS_cant_find_last_page,
405
VORBIS_seek_failed,
406
VORBIS_ogg_skeleton_not_supported
407
};
408
409
410
#ifdef __cplusplus
411
}
412
#endif
413
414
#endif // STB_VORBIS_INCLUDE_STB_VORBIS_H
415
//
416
// HEADER ENDS HERE
417
//
418
//////////////////////////////////////////////////////////////////////////////
419
420
#ifndef STB_VORBIS_HEADER_ONLY
421
422
// global configuration settings (e.g. set these in the project/makefile),
423
// or just set them in this file at the top (although ideally the first few
424
// should be visible when the header file is compiled too, although it's not
425
// crucial)
426
427
// STB_VORBIS_NO_PUSHDATA_API
428
// does not compile the code for the various stb_vorbis_*_pushdata()
429
// functions
430
// #define STB_VORBIS_NO_PUSHDATA_API
431
432
// STB_VORBIS_NO_PULLDATA_API
433
// does not compile the code for the non-pushdata APIs
434
// #define STB_VORBIS_NO_PULLDATA_API
435
436
// STB_VORBIS_NO_STDIO
437
// does not compile the code for the APIs that use FILE *s internally
438
// or externally (implied by STB_VORBIS_NO_PULLDATA_API)
439
// #define STB_VORBIS_NO_STDIO
440
441
// STB_VORBIS_NO_INTEGER_CONVERSION
442
// does not compile the code for converting audio sample data from
443
// float to integer (implied by STB_VORBIS_NO_PULLDATA_API)
444
// #define STB_VORBIS_NO_INTEGER_CONVERSION
445
446
// STB_VORBIS_NO_FAST_SCALED_FLOAT
447
// does not use a fast float-to-int trick to accelerate float-to-int on
448
// most platforms which requires endianness be defined correctly.
449
//#define STB_VORBIS_NO_FAST_SCALED_FLOAT
450
451
452
// STB_VORBIS_MAX_CHANNELS [number]
453
// globally define this to the maximum number of channels you need.
454
// The spec does not put a restriction on channels except that
455
// the count is stored in a byte, so 255 is the hard limit.
456
// Reducing this saves about 16 bytes per value, so using 16 saves
457
// (255-16)*16 or around 4KB. Plus anything other memory usage
458
// I forgot to account for. Can probably go as low as 8 (7.1 audio),
459
// 6 (5.1 audio), or 2 (stereo only).
460
#ifndef STB_VORBIS_MAX_CHANNELS
461
#define STB_VORBIS_MAX_CHANNELS 16 // enough for anyone?
462
#endif
463
464
// STB_VORBIS_PUSHDATA_CRC_COUNT [number]
465
// after a flush_pushdata(), stb_vorbis begins scanning for the
466
// next valid page, without backtracking. when it finds something
467
// that looks like a page, it streams through it and verifies its
468
// CRC32. Should that validation fail, it keeps scanning. But it's
469
// possible that _while_ streaming through to check the CRC32 of
470
// one candidate page, it sees another candidate page. This #define
471
// determines how many "overlapping" candidate pages it can search
472
// at once. Note that "real" pages are typically ~4KB to ~8KB, whereas
473
// garbage pages could be as big as 64KB, but probably average ~16KB.
474
// So don't hose ourselves by scanning an apparent 64KB page and
475
// missing a ton of real ones in the interim; so minimum of 2
476
#ifndef STB_VORBIS_PUSHDATA_CRC_COUNT
477
#define STB_VORBIS_PUSHDATA_CRC_COUNT 4
478
#endif
479
480
// STB_VORBIS_FAST_HUFFMAN_LENGTH [number]
481
// sets the log size of the huffman-acceleration table. Maximum
482
// supported value is 24. with larger numbers, more decodings are O(1),
483
// but the table size is larger so worse cache missing, so you'll have
484
// to probe (and try multiple ogg vorbis files) to find the sweet spot.
485
#ifndef STB_VORBIS_FAST_HUFFMAN_LENGTH
486
#define STB_VORBIS_FAST_HUFFMAN_LENGTH 10
487
#endif
488
489
// STB_VORBIS_FAST_BINARY_LENGTH [number]
490
// sets the log size of the binary-search acceleration table. this
491
// is used in similar fashion to the fast-huffman size to set initial
492
// parameters for the binary search
493
494
// STB_VORBIS_FAST_HUFFMAN_INT
495
// The fast huffman tables are much more efficient if they can be
496
// stored as 16-bit results instead of 32-bit results. This restricts
497
// the codebooks to having only 65535 possible outcomes, though.
498
// (At least, accelerated by the huffman table.)
499
#ifndef STB_VORBIS_FAST_HUFFMAN_INT

Showing the first 500 of 5585 diff lines for this file. This diff is INCOMPLETE; read the file or clone the repository for the rest.