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 (sokol_app, sokol_time, sokol_log)
  • sigil-graphics: 2D rendering, images, fonts (sokol_gfx, sokol_gp, sokol_glue, stb_image, stb_truetype)
  • sigil-audio: Audio playback and streaming (sokol_audio, stb_vorbis)

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 <david@daviwil.com>")
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 - edub4rt@gmail.com
−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.