diff options
| author | Andre Weissflog <floooh@gmail.com> | 2025-11-19 13:29:12 +0100 |
|---|---|---|
| committer | Andre Weissflog <floooh@gmail.com> | 2025-11-19 13:29:12 +0100 |
| commit | bf8ebc538e6b6edf2d30892f657c4d3a34c040c6 (patch) | |
| tree | 73fbe160da6fe6a48c1474ef244f1dee5f92c0cb | |
| parent | 09a31200a381974c0ecd2b1e94be9f66f62a35a5 (diff) | |
| parent | b517f27e7d6bdefc7883110e42dab27cba800b50 (diff) | |
Merge branch 'master' into experimental-vulkan
| -rw-r--r-- | .github/workflows/gen_bindings.yml | 10 | ||||
| -rw-r--r-- | .gitignore | 1 | ||||
| -rw-r--r-- | CHANGELOG.md | 73 | ||||
| -rw-r--r-- | README.md | 12 | ||||
| -rw-r--r-- | bindgen/README.md | 2 | ||||
| -rw-r--r-- | bindgen/gen_c3.py | 2 | ||||
| -rw-r--r-- | sokol_app.h | 59 | ||||
| -rw-r--r-- | sokol_args.h | 2 | ||||
| -rw-r--r-- | sokol_audio.h | 346 | ||||
| -rw-r--r-- | sokol_gfx.h | 78 | ||||
| -rw-r--r-- | tests/functional/sokol_args_test.c | 12 | ||||
| -rw-r--r-- | util/sokol_gfx_imgui.h | 4 | ||||
| -rw-r--r-- | util/sokol_imgui.h | 3 | ||||
| -rw-r--r-- | util/sokol_spine.h | 10 |
14 files changed, 562 insertions, 52 deletions
diff --git a/.github/workflows/gen_bindings.yml b/.github/workflows/gen_bindings.yml index b7f6b4c4..713a7367 100644 --- a/.github/workflows/gen_bindings.yml +++ b/.github/workflows/gen_bindings.yml @@ -60,7 +60,7 @@ jobs: path: bindgen/sokol-rust - uses: actions/checkout@main with: - repository: kassane/sokol-d + repository: floooh/sokol-d path: bindgen/sokol-d - uses: actions/checkout@main with: @@ -131,7 +131,7 @@ jobs: repository: floooh/sokol-zig - uses: mlugg/setup-zig@v2 with: - version: master + version: 0.15.2 - uses: actions/download-artifact@main with: name: ignore-me-zig @@ -293,7 +293,7 @@ jobs: steps: - uses: actions/checkout@main with: - repository: kassane/sokol-d + repository: floooh/sokol-d - uses: egor-tensin/vs-shell@v2 # get cl.exe (default for Windows) - uses: dlang-community/setup-dlang@v2 with: @@ -374,7 +374,7 @@ jobs: repository: floooh/sokol-c3 - uses: radekm/setup-c3@v2 with: - version: v0.7.5 + version: v0.7.7 - uses: actions/download-artifact@main with: name: ignore-me-c3 @@ -488,7 +488,7 @@ jobs: steps: - uses: actions/checkout@v4 with: - repository: kassane/sokol-d + repository: floooh/sokol-d ssh-key: ${{ secrets.GHACTIONS_D_PUSH }} - uses: actions/download-artifact@v4 with: @@ -5,3 +5,4 @@ build/ .fips-* *.pyc #<fips +**/.DS_Store diff --git a/CHANGELOG.md b/CHANGELOG.md index e7968fa5..e87785cf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,78 @@ ## Updates +### 13-Nov-2025 + +- sokol_audio.h gained a new backend for the Nintendo 3DS. + See PR https://github.com/floooh/sokol/pull/1372 for details. + Many thanks again to @CrackedPixel! + +### 27-Oct-2025 + +- The repository for the D bindings has moved from https://github.com/kassane/sokol-d + to https://github.com/floooh/sokol-d, see https://github.com/floooh/sokol-d/discussions/36#discussioncomment-14790873 + for details, this also means that the level of support for the D bindings + will need to be reduced unfortunately (especially when it comes to Dub packaging), + the automatic bindings generation will continue to work though. + +### 24-Oct-2025 + +- sokol_gfx.h: add a missing validation layer check in sg_begin_pass(): + when providing a resolve attachment, the associated color attachment must + have a sample_count > 1. + + PR: https://github.com/floooh/sokol/pull/1366 + +- sokol_app.h ios: the iOS backend now suports some tvOS features + via PR https://github.com/floooh/sokol/pull/1346, many thanks + to @tomasandrle! + +### 23-Oct-2025 + +- sokol_gfx.h webgpu: the viewport rectangle is no longer clipped against + the visible area. This was a design wart in an older version of the + WebGPU spec which has been relaxed by now. + + PR: https://github.com/floooh/sokol/pull/1362 + +- sokol_gfx.h gl: fix a somewhat esoteric regression in the GL backend + feature detection code when an external GL loader is used which provides + a GL version older than 4.6. This regression was introduced in PR + https://github.com/floooh/sokol/pull/1347. + + Fix PR: https://github.com/floooh/sokol/pull/1363 + +### 21-Oct-2025 + +- sokol_spine.h: merged PR https://github.com/floooh/sokol/pull/1361 which + fixes multiply-blend-mode and a validation layer issue when switching + between blend modes. Many thanks to @bryanjeal! + +### 20-Oct-2025 + +- sokol_args.h: key-args-strings are no longer escaped (the documentation actually + stated this, but the implementation behaved differently) + + PR: https://github.com/floooh/sokol/pull/1355 + Ticket: https://github.com/floooh/sokol/issues/1353 + + Many thanks to @cloudwu for identifying and fixing the issue! + +- sokol_audio.h: added a new backend for the PS Vita via PR https://github.com/floooh/sokol/pull/1358 + Please note that I cannot maintain the backend or help with any issues, and + normally I wouldn't merge a PR under such circumstances, but since it is very + little and straightforward code an exception is justified I guess :) + + Many thanks to @CrackedPixel for the PR! + +### 10-Oct-2025 + +sokol_gfx.h gl: fix breakage in the GL backend when `SOKOL_EXTERNAL_GL_LOADER` +is defined. + +Issue: https://github.com/floooh/sokol/issues/1345 + +PR: https://github.com/floooh/sokol/pull/1347 + ### 06-Oct-2025 sokol_app.h macos: minor code cleanup to unify the per-frame @@ -8,7 +8,7 @@ [**See what's new**](https://github.com/floooh/sokol/blob/master/CHANGELOG.md) (**04-Oct-2025**: new sokol_gfx.h function sg_draw_ex() added) -[](/../../actions/workflows/main.yml) [](/../../actions/workflows/gen_bindings.yml) [](https://github.com/floooh/sokol-zig/actions/workflows/main.yml) [](https://github.com/floooh/sokol-nim/actions/workflows/main.yml) [](https://github.com/floooh/sokol-odin/actions/workflows/main.yml)[](https://github.com/floooh/sokol-rust/actions/workflows/main.yml)[](https://github.com/kassane/sokol-d/actions/workflows/build.yml)[](https://github.com/floooh/sokol-c3/actions/workflows/build.yml) +[](/../../actions/workflows/main.yml) [](/../../actions/workflows/gen_bindings.yml) [](https://github.com/floooh/sokol-zig/actions/workflows/main.yml) [](https://github.com/floooh/sokol-nim/actions/workflows/main.yml) [](https://github.com/floooh/sokol-odin/actions/workflows/main.yml)[](https://github.com/floooh/sokol-rust/actions/workflows/main.yml)[](https://github.com/floooh/sokol-d/actions/workflows/build.yml)[](https://github.com/floooh/sokol-c3/actions/workflows/build.yml) ## Examples and Related Projects @@ -21,8 +21,6 @@ Aras Pranckevičius, PC/web port via sokol ([source](https://github.com/aras-p/d - [sokol_gp.h](https://github.com/edubart/sokol_gp) a 2D shape drawing library on top of sokol_gfx.h -- [LearnOpenGL examples ported to sokol-gfx](https://zeromake.github.io/learnopengl-examples/) ([git repo](https://github.com/zeromake/learnopengl-examples)) - - [Dear ImGui starterkit](https://github.com/floooh/cimgui-sokol-starterkit) a self-contained starterkit for writing Dear ImGui apps in C. - [qoiview](https://github.com/floooh/qoiview) a basic viewer for the new QOI image file format @@ -31,6 +29,10 @@ Aras Pranckevičius, PC/web port via sokol ([source](https://github.com/aras-p/d - A 'single-file' [Pacman clone in C99](https://github.com/floooh/pacman.c/), also available in [Zig](https://github.com/floooh/pacman.zig/) +- [Soluna](https://github.com/cloudwu/soluna), a framework to make 2D games in Lua by @cloudwu + +- [Deep Future](https://github.com/cloudwu/deepfuture): ...and a game implemented with Soluna + - [Solar Storm](https://store.steampowered.com/app/2754920/Solar_Storm/), a turn-based scifi artillery game built with Odin and Sokol, released on Steam. - [Spanking Runners (Samogonki)](https://store.steampowered.com/app/2599800/Spanking_Runners/), arcade racing in a bright and unusual world, released on Steam. @@ -46,6 +48,8 @@ Aras Pranckevičius, PC/web port via sokol ([source](https://github.com/aras-p/d - ['Dealer's Dungeon'](https://dealers-dungeon.com/demo/) ([lower graphics quality](https://dealers-dungeon.com/demo/?q=3), [source](https://github.com/bqqbarbhg/spear)) +- [LearnOpenGL examples ported to sokol-gfx (may be outdated)](https://zeromake.github.io/learnopengl-examples/) ([git repo](https://github.com/zeromake/learnopengl-examples)) + - [Command line tools](https://github.com/floooh/sokol-tools) (shader compiler) - [How to build without a build system](https://github.com/floooh/sokol-samples#how-to-build-without-a-build-system): @@ -82,7 +86,7 @@ These are automatically updated on changes to the C headers: - [sokol-odin](https://github.com/floooh/sokol-odin) - [sokol-nim](https://github.com/floooh/sokol-nim) - [sokol-rust](https://github.com/floooh/sokol-rust) -- [sokol-d](https://github.com/kassane/sokol-d) +- [sokol-d](https://github.com/floooh/sokol-d) - [sokol-jai](https://github.com/colinbellino/sokol-jai) - [sokol-c3](https://github.com/floooh/sokol-c3) diff --git a/bindgen/README.md b/bindgen/README.md index 8d4805e9..95c12fe1 100644 --- a/bindgen/README.md +++ b/bindgen/README.md @@ -24,7 +24,7 @@ To update the Zig bindings: > git clone https://github.com/floooh/sokol-nim > git clone https://github.com/floooh/sokol-odin > git clone https://github.com/floooh/sokol-rust -> git clone https://github.com/kassane/sokol-d +> git clone https://github.com/floooh/sokol-d > git clone https://github.com/colinbellino/sokol-jai > git clone https://github.com/floooh/sokol-c3 > python3 gen_all.py diff --git a/bindgen/gen_c3.py b/bindgen/gen_c3.py index 1259e6d9..b2e5f437 100644 --- a/bindgen/gen_c3.py +++ b/bindgen/gen_c3.py @@ -327,7 +327,7 @@ def gen_c_imports(inp, c_prefix, prefix): args = funcdecl_args_c(decl, prefix) res_type = funcdecl_result_c(decl, prefix) res_str = 'void' if res_type == '' else res_type - l(f'extern fn {res_str} {check_override(as_snake_case(decl["name"], c_prefix))}({args}) @extern("{decl["name"]}");') + l(f'extern fn {res_str} {check_override(as_snake_case(decl["name"], c_prefix))}({args}) @cname("{decl["name"]}");') l('') def gen_consts(decl, prefix): diff --git a/sokol_app.h b/sokol_app.h index 2edc2891..b6638088 100644 --- a/sokol_app.h +++ b/sokol_app.h @@ -1206,6 +1206,11 @@ doesn't matter if the application is started from the command line or via double-click. + NOTE: setting both win32_console_attach and win32_console_create + to true also makes sense and has the effect that output + will appear in the existing terminal when started from the cmdline, and + otherwise (when started via double-click) will open a console window. + MEMORY ALLOCATION OVERRIDE ========================== You can override the memory allocation functions at initialization time @@ -2278,6 +2283,9 @@ inline void sapp_run(const sapp_desc& desc) { return sapp_run(&desc); } #if !defined(SOKOL_METAL) && !defined(SOKOL_GLES3) #error("sokol_app.h: unknown 3D API selected for iOS, must be SOKOL_METAL or SOKOL_GLES3") #endif + #if TARGET_OS_TV + #define _SAPP_TVOS (1) + #endif #endif #elif defined(__EMSCRIPTEN__) // Emscripten @@ -6098,7 +6106,9 @@ _SOKOL_PRIVATE void _sapp_ios_mtl_init(void) { */ _sapp.ios.view.autoResizeDrawable = false; _sapp.ios.view.userInteractionEnabled = YES; +#if !defined(_SAPP_TVOS) _sapp.ios.view.multipleTouchEnabled = YES; +#endif _sapp.ios.view_ctrl = [[UIViewController alloc] init]; _sapp.ios.view_ctrl.modalPresentationStyle = UIModalPresentationFullScreen; _sapp.ios.view_ctrl.view = _sapp.ios.view; @@ -6201,6 +6211,31 @@ _SOKOL_PRIVATE void _sapp_ios_app_event(sapp_event_type type) { } } +_SOKOL_PRIVATE void _sapp_tvos_press_event(sapp_event_type type, NSSet<UIPress *>* presses) { + if (_sapp_events_enabled()) { + for (UIPress *press in presses) { + sapp_keycode key = SAPP_KEYCODE_INVALID; + switch (press.type) { + case UIPressTypeUpArrow: key = SAPP_KEYCODE_UP; break; + case UIPressTypeDownArrow: key = SAPP_KEYCODE_DOWN; break; + case UIPressTypeLeftArrow: key = SAPP_KEYCODE_LEFT; break; + case UIPressTypeRightArrow: key = SAPP_KEYCODE_RIGHT; break; + case UIPressTypeSelect: key = SAPP_KEYCODE_ENTER; break; + case UIPressTypeMenu: key = SAPP_KEYCODE_MENU; break; + case UIPressTypePlayPause: key = SAPP_KEYCODE_PAUSE; break; + default: break; + } + if (key != SAPP_KEYCODE_INVALID) { + _sapp_init_event(type); + _sapp.event.key_code = key; + _sapp.event.key_repeat = false; + _sapp.event.modifiers = 0; + _sapp_call_event(&_sapp.event); + } + } + } +} + _SOKOL_PRIVATE void _sapp_ios_touch_event(sapp_event_type type, NSSet<UITouch *>* touches, UIEvent* event) { if (_sapp_events_enabled()) { _sapp_init_event(type); @@ -6256,6 +6291,7 @@ _SOKOL_PRIVATE void _sapp_ios_show_keyboard(bool shown) { _sapp.ios.textfield.delegate = _sapp.ios.textfield_dlg; [_sapp.ios.view_ctrl.view addSubview:_sapp.ios.textfield]; +#if !defined(_SAPP_TVOS) [[NSNotificationCenter defaultCenter] addObserver:_sapp.ios.textfield_dlg selector:@selector(keyboardWasShown:) name:UIKeyboardDidShowNotification object:nil]; @@ -6265,6 +6301,7 @@ _SOKOL_PRIVATE void _sapp_ios_show_keyboard(bool shown) { [[NSNotificationCenter defaultCenter] addObserver:_sapp.ios.textfield_dlg selector:@selector(keyboardDidChangeFrame:) name:UIKeyboardDidChangeFrameNotification object:nil]; +#endif } if (shown) { // setting the text field as first responder brings up the onscreen keyboard @@ -6327,6 +6364,7 @@ _SOKOL_PRIVATE void _sapp_ios_show_keyboard(bool shown) { - (void)keyboardWasShown:(NSNotification*)notif { _sapp.onscreen_keyboard_shown = true; /* query the keyboard's size, and modify the content view's size */ +#if !defined(_SAPP_TVOS) if (_sapp.desc.ios.keyboard_resizes_canvas) { NSDictionary* info = notif.userInfo; CGFloat kbd_h = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size.height; @@ -6334,6 +6372,7 @@ _SOKOL_PRIVATE void _sapp_ios_show_keyboard(bool shown) { view_frame.size.height -= kbd_h; _sapp.ios.view.frame = view_frame; } +#endif } - (void)keyboardWillBeHidden:(NSNotification*)notif { _sapp.onscreen_keyboard_shown = false; @@ -6343,6 +6382,7 @@ _SOKOL_PRIVATE void _sapp_ios_show_keyboard(bool shown) { } - (void)keyboardDidChangeFrame:(NSNotification*)notif { /* this is for the case when the screen rotation changes while the keyboard is open */ +#if !defined(_SAPP_TVOS) if (_sapp.onscreen_keyboard_shown && _sapp.desc.ios.keyboard_resizes_canvas) { NSDictionary* info = notif.userInfo; CGFloat kbd_h = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size.height; @@ -6350,6 +6390,7 @@ _SOKOL_PRIVATE void _sapp_ios_show_keyboard(bool shown) { view_frame.size.height -= kbd_h; _sapp.ios.view.frame = view_frame; } +#endif } - (BOOL)textField:(UITextField*)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString*)string { if (_sapp_events_enabled()) { @@ -6410,6 +6451,17 @@ _SOKOL_PRIVATE void _sapp_ios_show_keyboard(bool shown) { - (BOOL)isOpaque { return YES; } +- (void)pressesBegan:(NSSet<UIPress *> *)presses withEvent:(UIPressesEvent *)event { + _sapp_tvos_press_event(SAPP_EVENTTYPE_KEY_DOWN, presses); +} +- (void)pressesChanged:(NSSet<UIPress *> *)presses withEvent:(UIPressesEvent *)event { +} +- (void)pressesEnded:(NSSet<UIPress *> *)presses withEvent:(UIPressesEvent *)event { + _sapp_tvos_press_event(SAPP_EVENTTYPE_KEY_UP, presses); +} +- (void)pressesCancelled:(NSSet<UIPress *> *)presses withEvent:(UIPressesEvent *)event { + _sapp_tvos_press_event(SAPP_EVENTTYPE_KEY_UP, presses); +} - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent*)event { _sapp_ios_touch_event(SAPP_EVENTTYPE_TOUCHES_BEGAN, touches, event); } @@ -9372,11 +9424,12 @@ _SOKOL_PRIVATE void _sapp_win32_destroy_icons(void) { _SOKOL_PRIVATE void _sapp_win32_init_console(void) { if (_sapp.desc.win32.console_create || _sapp.desc.win32.console_attach) { BOOL con_valid = FALSE; - if (_sapp.desc.win32.console_create) { - con_valid = AllocConsole(); - } else if (_sapp.desc.win32.console_attach) { + if (_sapp.desc.win32.console_attach) { con_valid = AttachConsole(ATTACH_PARENT_PROCESS); } + if (!con_valid && _sapp.desc.win32.console_create) { + con_valid = AllocConsole(); + } if (con_valid) { FILE* res_fp = 0; errno_t err; diff --git a/sokol_args.h b/sokol_args.h index e39b6f29..b532c90e 100644 --- a/sokol_args.h +++ b/sokol_args.h @@ -600,7 +600,7 @@ _SOKOL_PRIVATE bool _sargs_parse_carg(const char* src) { if (_sargs_in_escape()) { c = _sargs_escape(c); _sargs_end_escape(); - } else if (_sargs_is_escape(c)) { + } else if (_sargs_is_escape(c) && _sargs_parsing_val()) { _sargs_start_escape(); continue; } diff --git a/sokol_audio.h b/sokol_audio.h index a64eabc9..bce5631a 100644 --- a/sokol_audio.h +++ b/sokol_audio.h @@ -42,6 +42,8 @@ - on Android: aaudio - on Windows with MSVC or Clang toolchain: no action needed, libs are defined in-source via pragma-comment-lib - on Windows with MINGW/MSYS2 gcc: compile with '-mwin32' and link with -lole32 + - on Vita: SceAudio + - on 3DS: NDSP (libctru) FEATURE OVERVIEW ================ @@ -55,6 +57,8 @@ - iOS: CoreAudio+AVAudioSession - emscripten: WebAudio with ScriptProcessorNode - Android: AAudio + - Vita: SceAudio + - 3DS: NDSP (libctru) Sokol Audio will not do any buffer mixing or volume control, if you have multiple independent input streams of sample data you need to perform the @@ -379,6 +383,52 @@ header must be present (usually both are installed with some sort of ALSA development package). + THE VITA BACKEND + ================ + The VITA backend is automatically selected when compiling with vitasdk + ('PSP2_SDK_VERSION' is defined). + + For thread synchronisation, the pthread_mutex_* functions are used. + + Samples are converted from float to short (uint16_t) to maintain + all the same interface/api as other platforms. + + You may use any supported sample rate you wish, but all audio MUST + match the same sample rate you choose. + + This uses the "BGM" port to allow selecting the sample rate ("Main" + port is restricted to 48000 only). + + You need to link with the 'SceAudio' library, and the <psp2/audioout.h> + header must be present (usually both are installed with the vitasdk). + + THE 3DS BACKEND + ================ + The 3DS backend is automatically selected when compiling with libctru + ('__3DS__' is defined). + + Running a separate thread on the older 3ds is not a good idea and I + was not able to get it working without slowing down the main thread + too much (it has a single core available with cooperative threads). + + The NDSP seems to work better by using its ndspSetCallback method. + + You may use any supported sample rate you wish, but all audio MUST + match the same sample rate you choose or it will sound slowed down + or sped up. + + The queue size and other NDSP specific parameters can be chosen by + the provided 'saudio_n3ds_desc' type. Defaults will be used if + nothing is provided. + + There is a known issue of a noticeable delay when starting a new + sound on emulators. I was not able to improve this to my liking + and ~300ms can be expected. This can be improved by using a lower + buffer size than the 2048 default but I would not suggest under + 1536. It may crash under 1408, and they must be in multiples of 128. + Note: I was NOT able to reproduce this issue on a real device and + the audio worked perfectly. + MEMORY ALLOCATION OVERRIDE ========================== @@ -537,6 +587,9 @@ extern "C" { _SAUDIO_LOGITEM_XMACRO(COREAUDIO_ALLOCATE_BUFFER_FAILED, "AudioQueueAllocateBuffer() failed") \ _SAUDIO_LOGITEM_XMACRO(COREAUDIO_START_FAILED, "AudioQueueStart() failed") \ _SAUDIO_LOGITEM_XMACRO(BACKEND_BUFFER_SIZE_ISNT_MULTIPLE_OF_PACKET_SIZE, "backend buffer size isn't multiple of packet size") \ + _SAUDIO_LOGITEM_XMACRO(VITA_SCEAUDIO_OPEN_FAILED, "sceAudioOutOpenPort() failed") \ + _SAUDIO_LOGITEM_XMACRO(VITA_PTHREAD_CREATE_FAILED, "pthread_create() failed") \ + _SAUDIO_LOGITEM_XMACRO(N3DS_NDSP_OPEN_FAILED, "ndspInit() failed") \ #define _SAUDIO_LOGITEM_XMACRO(item,msg) SAUDIO_LOGITEM_##item, typedef enum saudio_log_item { @@ -576,6 +629,31 @@ typedef struct saudio_allocator { void* user_data; } saudio_allocator; +typedef enum saudio_n3ds_ndspinterptype { + SAUDIO_N3DS_DSP_INTERP_POLYPHASE = 0, + SAUDIO_N3DS_DSP_INTERP_LINEAR = 1, + SAUDIO_N3DS_DSP_INTERP_NONE = 2, +} saudio_n3ds_ndspinterptype; + +typedef struct saudio_n3ds_desc { + /* the 3DS requires multiple queues that it alternates between. */ + /* a single buffer will "work" but is choppy due to a slight */ + /* delay when it changes queues. */ + int queue_count; /* default value = 2 */ + + /* NDSP_INTERP_POLYPHASE = 0 (high quality, slower) */ + /* NDSP_INTERP_LINEAR = 1 (med quality, medium) */ + /* NDSP_INTERP_NONE = 2 (low quality, fast) */ + saudio_n3ds_ndspinterptype interpolation_type; /* default value = 0 */ + + /* 3DS supports different audio channels. they can be used */ + /* in a variety of ways as independent streams etc. */ + /* this implementation in sokol does NOT allow multiple */ + /* due to calling the global ndspInit/ndspExit functions. */ + /* valid range 0-23 */ + int channel_id; /* default value = 0 */ +} saudio_n3ds_desc; + typedef struct saudio_desc { int sample_rate; // requested sample rate int num_channels; // number of channels, default: 1 (mono) @@ -585,6 +663,7 @@ typedef struct saudio_desc { void (*stream_cb)(float* buffer, int num_frames, int num_channels); // optional streaming callback (no user data) void (*stream_userdata_cb)(float* buffer, int num_frames, int num_channels, void* user_data); //... and with user data void* user_data; // optional user data argument for stream_userdata_cb + saudio_n3ds_desc n3ds; // optional data for use on n3ds saudio_allocator allocator; // optional allocation override functions saudio_logger logger; // optional logging function (default: NO LOGGING!) } saudio_desc; @@ -687,6 +766,12 @@ inline void saudio_setup(const saudio_desc& desc) { return saudio_setup(&desc); #define _SAUDIO_ANDROID (1) #elif defined(__linux__) || defined(__unix__) #define _SAUDIO_LINUX (1) +#elif defined(PSP2_SDK_VERSION) + #define _SAUDIO_VITA (1) + #include <psp2/audioout.h> +#elif defined(__3DS__) + #define _SAUDIO_N3DS (1) + #include <3ds.h> #else #error "sokol_audio.h: Unknown platform" #endif @@ -782,6 +867,11 @@ inline void saudio_setup(const saudio_desc& desc) { return saudio_setup(&desc); #elif defined(__EMSCRIPTEN__) #define _SAUDIO_NOTHREADS (1) #include <emscripten/emscripten.h> +#elif defined(_SAUDIO_VITA) + #define _SAUDIO_PTHREADS (1) + #include <pthread.h> +#elif defined(_SAUDIO_N3DS) + #define _SAUDIO_NOTHREADS (1) #endif #define _saudio_def(val, def) (((val) == 0) ? (def) : (val)) @@ -982,6 +1072,30 @@ typedef struct { uint8_t* buffer; } _saudio_web_backend_t; +#elif defined(_SAUDIO_VITA) + +typedef struct { + int device; + float* buffer; + int16_t* buffer_vita; + int buffer_byte_size; + int buffer_frames; + pthread_t thread; + bool thread_stop; +} _saudio_vita_backend_t; + +#elif defined(_SAUDIO_N3DS) + +typedef struct { + saudio_n3ds_desc n3ds_desc; /* n3ds specific data */ + float* buffer; /* used by sokol as floats */ + int16_t* buffer_n3ds; /* sokol buffer converted to int16 */ + ndspWaveBuf* queue_n3ds; /* device queues on 3DS */ + int samples_per_buffer; /* frames * channel count */ + int buffer_byte_size; + bool thread_stop; +} _saudio_n3ds_backend_t; + #else #error "unknown platform" #endif @@ -998,6 +1112,10 @@ typedef _saudio_wasapi_backend_t _saudio_backend_t; typedef _saudio_aaudio_backend_t _saudio_backend_t; #elif defined(_SAUDIO_LINUX) typedef _saudio_alsa_backend_t _saudio_backend_t; +#elif defined(_SAUDIO_VITA) +typedef _saudio_vita_backend_t _saudio_backend_t; +#elif defined(_SAUDIO_N3DS) +typedef _saudio_n3ds_backend_t _saudio_backend_t; #endif /* a ringbuffer structure */ @@ -1184,6 +1302,26 @@ _SOKOL_PRIVATE void _saudio_mutex_lock(_saudio_mutex_t* m) { _SOKOL_PRIVATE void _saudio_mutex_unlock(_saudio_mutex_t* m) { LeaveCriticalSection(&m->critsec); } +#elif defined(_SAUDIO_VITA) + +_SOKOL_PRIVATE void _saudio_mutex_init(_saudio_mutex_t* m) { + pthread_mutexattr_t attr; + pthread_mutexattr_init(&attr); + pthread_mutex_init(&m->mutex, &attr); +} + +_SOKOL_PRIVATE void _saudio_mutex_destroy(_saudio_mutex_t* m) { + pthread_mutex_destroy(&m->mutex); +} + +_SOKOL_PRIVATE void _saudio_mutex_lock(_saudio_mutex_t* m) { + pthread_mutex_lock(&m->mutex); +} + +_SOKOL_PRIVATE void _saudio_mutex_unlock(_saudio_mutex_t* m) { + pthread_mutex_unlock(&m->mutex); +} + #else #error "sokol_audio.h: unknown platform!" #endif @@ -2144,6 +2282,206 @@ _SOKOL_PRIVATE bool _saudio_coreaudio_backend_init(void) { return true; } +// ██ ██ ██ ████████ █████ +// ██ ██ ██ ██ ██ ██ +// ██ ██ ██ ██ ███████ +// ██ ██ ██ ██ ██ ██ +// █████ ██ ██ ██ ██ +// +// >>vita +#elif defined(_SAUDIO_VITA) + +/* the streaming callback runs in a separate thread */ +_SOKOL_PRIVATE void* _saudio_vita_cb(void* param) { + _SOKOL_UNUSED(param); + while (!_saudio.backend.thread_stop) { + for (int i = 0; i < (_saudio.buffer_frames * _saudio.num_channels); i++) { + _saudio.backend.buffer_vita[i] = (int16_t)(_saudio.backend.buffer[i] * 32767.0f); + } + int write_res = sceAudioOutOutput(_saudio.backend.device, _saudio.backend.buffer_vita); + if (write_res < 0) { + /* underrun occurred */ + } + else { + /* fill the streaming buffer with new data */ + if (_saudio_has_callback()) { + _saudio_stream_callback(_saudio.backend.buffer, _saudio.backend.buffer_frames, _saudio.num_channels); + } + else { + if (0 == _saudio_fifo_read(&_saudio.fifo, (uint8_t*)_saudio.backend.buffer, _saudio.backend.buffer_byte_size)) { + /* not enough read data available, fill the entire buffer with silence */ + _saudio_clear(_saudio.backend.buffer, (size_t)_saudio.backend.buffer_byte_size); + } + } + } + } + return 0; +} + +_SOKOL_PRIVATE bool _saudio_vita_backend_init(void) { + SceAudioOutMode sceAudioOutMode = _saudio.num_channels == 1 ? SCE_AUDIO_OUT_MODE_MONO : SCE_AUDIO_OUT_MODE_STEREO; + int rc = sceAudioOutOpenPort(SCE_AUDIO_OUT_PORT_TYPE_BGM, _saudio.buffer_frames, _saudio.sample_rate, sceAudioOutMode); + if (rc < 0) { + _SAUDIO_ERROR(VITA_SCEAUDIO_OPEN_FAILED); + return false; + } + _saudio.backend.device = rc; + + /* read back actual sample rate and channels */ + _saudio.sample_rate = (int)_saudio.sample_rate; + _saudio.bytes_per_frame = _saudio.num_channels * (int)sizeof(float); + + /* allocate the streaming buffer */ + _saudio.backend.buffer_byte_size = _saudio.buffer_frames * _saudio.bytes_per_frame; + _saudio.backend.buffer_frames = _saudio.buffer_frames; + _saudio.backend.buffer = (float*) _saudio_malloc_clear((size_t)_saudio.backend.buffer_byte_size); + _saudio.backend.buffer_vita = (int16_t*) _saudio_malloc_clear((size_t)(_saudio.buffer_frames * _saudio.num_channels * (int)sizeof(int16_t))); + + /* create the buffer-streaming start thread */ + if (0 != pthread_create(&_saudio.backend.thread, 0, _saudio_vita_cb, 0)) { + _SAUDIO_ERROR(VITA_PTHREAD_CREATE_FAILED); + if (_saudio.backend.device >= 0) { + sceAudioOutReleasePort(_saudio.backend.device); + _saudio.backend.device = -1; + } + return false; + } + + return true; +} + +_SOKOL_PRIVATE void _saudio_vita_backend_shutdown(void) { + _saudio.backend.thread_stop = true; + pthread_join(_saudio.backend.thread, 0); + sceAudioOutReleasePort(_saudio.backend.device); + _saudio_free(_saudio.backend.buffer_vita); + _saudio_free(_saudio.backend.buffer); +} + +// ███████ ██████ ███████ +// ██ ██ ██ ██ +// ██████ ██ ██ ███████ +// ██ ██ ██ ██ +// ███████ ██████ ███████ +// +// >>3ds +#elif defined(_SAUDIO_N3DS) + +/* NDSP triggers a callback for _saudio_n3ds_cb on the main thread */ +_SOKOL_PRIVATE void _saudio_n3ds_cb(void*) { + if(_saudio.backend.thread_stop) { + return; + } + + const float scale = 32767.0f; + + ndspWaveBuf* bufferPtr = 0; + bufferPtr = 0; + int i = 0; + + /* pick an available queue */ + for (i = 0; i < _saudio.backend.n3ds_desc.queue_count; ++i) { + if (_saudio.backend.queue_n3ds[i].status == NDSP_WBUF_DONE) { + bufferPtr = &_saudio.backend.queue_n3ds[i]; + break; + } + } + + if (!bufferPtr) { + /* no buffers are available. we don't want to play */ + /* anything, but we also don't want to drain the queue */ + return; + } + + int16_t* target_buffer = bufferPtr->data_pcm16; + const float* source_buffer = _saudio.backend.buffer; + for (i = 0; i < _saudio.backend.samples_per_buffer; i++) { + /* data_pcm16 points to a region in the linear alloc _saudio.backend.buffer_n3ds */ + target_buffer[i] = (int16_t)(source_buffer[i] * scale); + } + + bufferPtr->nsamples = _saudio.buffer_frames; /* nsamples is actually frames */ + ndspChnWaveBufAdd(_saudio.backend.n3ds_desc.channel_id, bufferPtr); + DSP_FlushDataCache(target_buffer, bufferPtr->nsamples * sizeof(int16_t)); + + /* fill the streaming buffer with new data */ + if (_saudio_has_callback()) { + _saudio_stream_callback(_saudio.backend.buffer, _saudio.buffer_frames, _saudio.num_channels); + } + else { + if (0 == _saudio_fifo_read(&_saudio.fifo, (uint8_t*)_saudio.backend.buffer, _saudio.backend.buffer_byte_size)) { + /* not enough read data available, fill the entire buffer with silence */ + _saudio_clear(_saudio.backend.buffer, (size_t)_saudio.backend.buffer_byte_size); + } + } +} + +_SOKOL_PRIVATE bool _saudio_n3ds_backend_init(void) { + int rc = ndspInit(); + if (rc != 0) { + _SAUDIO_ERROR(N3DS_NDSP_OPEN_FAILED); + return false; + } + + /* set defaults if not provided */ + _saudio.backend.n3ds_desc.queue_count = _saudio_def(_saudio.desc.n3ds.queue_count, 2); + _saudio.backend.n3ds_desc.interpolation_type = _saudio_def(_saudio.desc.n3ds.interpolation_type, SAUDIO_N3DS_DSP_INTERP_POLYPHASE); + _saudio.backend.n3ds_desc.channel_id = _saudio_def(_saudio.desc.n3ds.channel_id, 0); + + /* clamp to 2 channels max */ + if (_saudio.num_channels > 2) { + _saudio.num_channels = 2; + } + + ndspChnReset(_saudio.backend.n3ds_desc.channel_id); + ndspChnWaveBufClear(_saudio.backend.n3ds_desc.channel_id); + ndspChnSetInterp(_saudio.backend.n3ds_desc.channel_id, (ndspInterpType)_saudio.backend.n3ds_desc.interpolation_type); /* cast to n3ds enum */ + ndspChnSetRate(_saudio.backend.n3ds_desc.channel_id, _saudio.sample_rate); + ndspChnSetFormat(_saudio.backend.n3ds_desc.channel_id, _saudio.num_channels == 1 ? NDSP_FORMAT_MONO_PCM16 : NDSP_FORMAT_STEREO_PCM16); + ndspSetOutputMode(_saudio.num_channels == 1 ? NDSP_OUTPUT_MONO : NDSP_OUTPUT_STEREO); + + /* read back actual sample rate and channels */ + _saudio.sample_rate = (int)_saudio.sample_rate; + _saudio.bytes_per_frame = _saudio.num_channels * (int)sizeof(float); + + /* allocate the streaming buffer */ + _saudio.backend.samples_per_buffer = _saudio.buffer_frames * _saudio.num_channels; + _saudio.backend.buffer_byte_size = _saudio.buffer_frames * _saudio.bytes_per_frame; + _saudio.backend.buffer = (float*) _saudio_malloc_clear((size_t)_saudio.backend.buffer_byte_size); + _saudio.backend.buffer_n3ds = (int16_t*)linearAlloc(_saudio.backend.n3ds_desc.queue_count * _saudio.backend.samples_per_buffer * sizeof(int16_t)); + _saudio.backend.queue_n3ds = (ndspWaveBuf*)_saudio_malloc(_saudio.backend.n3ds_desc.queue_count * sizeof(ndspWaveBuf)); + + /* prepare the 3ds audio queues */ + int16_t* bufferPtrCopy = _saudio.backend.buffer_n3ds; + for (int i = 0; i < _saudio.backend.n3ds_desc.queue_count; ++i) { + _saudio.backend.queue_n3ds[i].data_vaddr = bufferPtrCopy; /* point the queue at the section of the linear buffer */ + _saudio.backend.queue_n3ds[i].looping = false; /* the user should handle looping on their end */ + _saudio.backend.queue_n3ds[i].status = NDSP_WBUF_DONE; /* default to done status for buffering logic */ + + bufferPtrCopy += _saudio.backend.samples_per_buffer; + } + + /* instead of a thread, ndsp will trigger a callback */ + /* when it needs more data. */ + ndspSetCallback(_saudio_n3ds_cb, 0); + + return true; +} + +_SOKOL_PRIVATE void _saudio_n3ds_backend_shutdown(void) { + _saudio.backend.thread_stop = true; + + if (_saudio.backend.n3ds_desc.channel_id >= 0) { + ndspChnWaveBufClear(_saudio.backend.n3ds_desc.channel_id); + _saudio.backend.n3ds_desc.channel_id = -1; + } + + ndspExit(); + + _saudio_free(_saudio.backend.queue_n3ds); + _saudio_free(_saudio.backend.buffer_n3ds); + _saudio_free(_saudio.backend.buffer); +} #else #error "unsupported platform" #endif @@ -2161,6 +2499,10 @@ bool _saudio_backend_init(void) { return _saudio_aaudio_backend_init(); #elif defined(_SAUDIO_APPLE) return _saudio_coreaudio_backend_init(); + #elif defined(_SAUDIO_VITA) + return _saudio_vita_backend_init(); + #elif defined(_SAUDIO_N3DS) + return _saudio_n3ds_backend_init(); #else #error "unknown platform" #endif @@ -2179,6 +2521,10 @@ void _saudio_backend_shutdown(void) { _saudio_aaudio_backend_shutdown(); #elif defined(_SAUDIO_APPLE) _saudio_coreaudio_backend_shutdown(); + #elif defined(_SAUDIO_VITA) + _saudio_vita_backend_shutdown(); + #elif defined(_SAUDIO_N3DS) + _saudio_n3ds_backend_shutdown(); #else #error "unknown platform" #endif diff --git a/sokol_gfx.h b/sokol_gfx.h index c0c45268..2ceb9f19 100644 --- a/sokol_gfx.h +++ b/sokol_gfx.h @@ -4657,7 +4657,8 @@ typedef struct sg_frame_stats { _SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_COLORATTACHMENTVIEW_IMAGE_ALIVE, "sg_begin_pass: color attachment view's image object is uninitialized or no longer alive") \ _SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_COLORATTACHMENTVIEW_IMAGE_VALID, "sg_begin_pass: color attachment view's image is not in valid state (SG_RESOURCESTATE_VALID)") \ _SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_COLORATTACHMENTVIEW_SIZES, "sg_begin_pass: all color attachments must have the same width and height") \ - _SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_COLORATTACHMENTVIEW_SAMPLECOUNTS, "sg_begin_pass: all color attachments must have the same sample count") \ + _SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_COLORATTACHMENTVIEW_SAMPLECOUNT, "sg_begin_pass: when resolve attachments are provided, the color attachment sample count must be 1") \ + _SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_COLORATTACHMENTVIEW_SAMPLECOUNTS_EQUAL, "sg_begin_pass: all color attachments must have the same sample count") \ _SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_RESOLVEATTACHMENTVIEW_NO_COLORATTACHMENTVIEW, "sg_begin_pass: a resolve attachment view must have an associated color attachment view at the same index") \ _SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_RESOLVEATTACHMENTVIEW_ALIVE, "sg_begin_pass: resolve attachment view no longer alive") \ _SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_RESOLVEATTACHMENTVIEW_VALID, "sg_begin_pass: resolve attachment view not in valid state (SG_RESOURCESTATE_VALID)") \ @@ -5491,11 +5492,6 @@ inline int sg_append_buffer(sg_buffer buf_id, const sg_range& data) { return sg_ #endif #include <windows.h> #pragma comment (lib, "kernel32") // GetProcAddress() - #define _SOKOL_GL_HAS_COMPUTE (1) - #define _SOKOL_GL_HAS_TEXSTORAGE (1) - #define _SOKOL_GL_HAS_TEXVIEWS (1) - #define _SOKOL_GL_HAS_BASEVERTEX (1) - #define _SOKOL_GL_HAS_BASEINSTANCE (1) #endif #elif defined(__APPLE__) #include <TargetConditionals.h> @@ -5504,30 +5500,20 @@ inline int sg_append_buffer(sg_buffer buf_id, const sg_range& data) { return sg_ #endif #if defined(TARGET_OS_IPHONE) && !TARGET_OS_IPHONE #include <OpenGL/gl3.h> - #define _SOKOL_GL_HAS_BASEVERTEX (1) #else #include <OpenGLES/ES3/gl.h> #include <OpenGLES/ES3/glext.h> - #define _SOKOL_GL_HAS_TEXSTORAGE (1) #endif #elif defined(__EMSCRIPTEN__) #if defined(SOKOL_GLES3) #include <GLES3/gl3.h> - #define _SOKOL_GL_HAS_TEXSTORAGE (1) #endif #elif defined(__ANDROID__) #include <GLES3/gl31.h> - #define _SOKOL_GL_HAS_COMPUTE (1) - #define _SOKOL_GL_HAS_TEXSTORAGE (1) #elif defined(__linux__) || defined(__unix__) - #define _SOKOL_GL_HAS_COMPUTE (1) - #define _SOKOL_GL_HAS_TEXSTORAGE (1) - #define _SOKOL_GL_HAS_BASEVERTEX (1) #if defined(SOKOL_GLCORE) #define GL_GLEXT_PROTOTYPES #include <GL/gl.h> - #define _SOKOL_GL_HAS_TEXVIEWS (1) - #define _SOKOL_GL_HAS_BASEINSTANCE (1) #else #include <GLES3/gl32.h> #include <GLES3/gl3ext.h> @@ -5535,6 +5521,50 @@ inline int sg_append_buffer(sg_buffer buf_id, const sg_range& data) { return sg_ #endif #endif + // broad GL feature availability defines (DON'T merge this into the above ifdef-block!) + #if defined(_WIN32) + #if defined(GL_VERSION_4_3) || defined(_SOKOL_USE_WIN32_GL_LOADER) + #define _SOKOL_GL_HAS_COMPUTE (1) + #define _SOKOL_GL_HAS_TEXVIEWS (1) + #endif + #if defined(GL_VERSION_4_2) || defined(_SOKOL_USE_WIN32_GL_LOADER) + #define _SOKOL_GL_HAS_TEXSTORAGE (1) + #define _SOKOL_GL_HAS_BASEINSTANCE (1) + #endif + #if defined(GL_VERSION_3_2) || defined(_SOKOL_USE_WIN32_GL_LOADER) + #define _SOKOL_GL_HAS_BASEVERTEX (1) + #endif + #elif defined(__APPLE__) + #if defined(TARGET_OS_IPHONE) && !TARGET_OS_IPHONE + #define _SOKOL_GL_HAS_BASEVERTEX (1) + #else + #define _SOKOL_GL_HAS_TEXSTORAGE (1) + #endif + #elif defined(__EMSCRIPTEN__) + #define _SOKOL_GL_HAS_TEXSTORAGE (1) + #elif defined(__ANDROID__) + #define _SOKOL_GL_HAS_COMPUTE (1) + #define _SOKOL_GL_HAS_TEXSTORAGE (1) + #elif defined(__linux__) || defined(__unix__) + #if defined(SOKOL_GLCORE) + #if defined(GL_VERSION_4_3) + #define _SOKOL_GL_HAS_COMPUTE (1) + #define _SOKOL_GL_HAS_TEXVIEWS (1) + #endif + #if defined(GL_VERSION_4_2) + #define _SOKOL_GL_HAS_TEXSTORAGE (1) + #define _SOKOL_GL_HAS_BASEINSTANCE (1) + #endif + #if defined(GL_VERSION_3_2) + #define _SOKOL_GL_HAS_BASEVERTEX (1) + #endif + #else + #define _SOKOL_GL_HAS_COMPUTE (1) + #define _SOKOL_GL_HAS_TEXSTORAGE (1) + #define _SOKOL_GL_HAS_BASEVERTEX (1) + #endif + #endif + // optional GL loader definitions (only on Win32) #if defined(_SOKOL_USE_WIN32_GL_LOADER) #define __gl_h_ 1 @@ -18378,15 +18408,10 @@ _SOKOL_PRIVATE void _sg_wgpu_commit(void) { _SOKOL_PRIVATE void _sg_wgpu_apply_viewport(int x, int y, int w, int h, bool origin_top_left) { SOKOL_ASSERT(_sg.wgpu.rpass_enc); - // FIXME FIXME FIXME: CLIPPING THE VIEWPORT HERE IS WRONG!!! - // (but currently required because WebGPU insists that the viewport rectangle must be - // fully contained inside the framebuffer, but this doesn't make any sense, and also - // isn't required by the backend APIs) - const _sg_recti_t clip = _sg_clipi(x, y, w, h, _sg.cur_pass.dim.width, _sg.cur_pass.dim.height); - float xf = (float) clip.x; - float yf = (float) (origin_top_left ? clip.y : (_sg.cur_pass.dim.height - (clip.y + clip.h))); - float wf = (float) clip.w; - float hf = (float) clip.h; + float xf = (float) x; + float yf = (float) (origin_top_left ? y : (_sg.cur_pass.dim.height - (y + h))); + float wf = (float) w; + float hf = (float) h; wgpuRenderPassEncoderSetViewport(_sg.wgpu.rpass_enc, xf, yf, wf, hf, 0.0f, 1.0f); } @@ -23075,7 +23100,7 @@ _SOKOL_PRIVATE bool _sg_validate_begin_pass(const sg_pass* pass) { } else { _SG_VALIDATE(color_width == _sg_image_view_dim(view).width, VALIDATE_BEGINPASS_COLORATTACHMENTVIEW_SIZES); _SG_VALIDATE(color_height == _sg_image_view_dim(view).height, VALIDATE_BEGINPASS_COLORATTACHMENTVIEW_SIZES); - _SG_VALIDATE(color_sample_count == img->cmn.sample_count, VALIDATE_BEGINPASS_COLORATTACHMENTVIEW_SAMPLECOUNTS); + _SG_VALIDATE(color_sample_count == img->cmn.sample_count, VALIDATE_BEGINPASS_COLORATTACHMENTVIEW_SAMPLECOUNTS_EQUAL); } } } @@ -23104,6 +23129,7 @@ _SOKOL_PRIVATE bool _sg_validate_begin_pass(const sg_pass* pass) { _SG_VALIDATE(img->slot.state == SG_RESOURCESTATE_VALID, VALIDATE_BEGINPASS_RESOLVEATTACHMENTVIEW_IMAGE_VALID); if (img->slot.state == SG_RESOURCESTATE_VALID) { if (color_width != -1) { + _SG_VALIDATE(color_sample_count > 1, VALIDATE_BEGINPASS_COLORATTACHMENTVIEW_SAMPLECOUNT); _SG_VALIDATE(color_width == _sg_image_view_dim(view).width, VALIDATE_BEGINPASS_RESOLVEATTACHMENTVIEW_SIZES); _SG_VALIDATE(color_height == _sg_image_view_dim(view).height, VALIDATE_BEGINPASS_RESOLVEATTACHMENTVIEW_SIZES); } diff --git a/tests/functional/sokol_args_test.c b/tests/functional/sokol_args_test.c index e2928d10..affa3bc0 100644 --- a/tests/functional/sokol_args_test.c +++ b/tests/functional/sokol_args_test.c @@ -253,7 +253,7 @@ UTEST(sokol_args, escape_sequence) { sargs_shutdown(); } -static char* argv_11[] = { "exe_name", "kvp0 kvp1", "kvp2 = val2", "kvp3", "kvp4=val4" }; +static char* argv_11[] = { "exe_name", "kvp0 kvp\\1", "kvp2 = val2", "kvp3", "kvp4=val4" }; UTEST(sokol_args, key_only_args) { sargs_setup(&(sargs_desc){ .argc = NUM_ARGS(argv_11), @@ -262,7 +262,7 @@ UTEST(sokol_args, key_only_args) { T(sargs_isvalid()); T(sargs_num_args() == 5); T(0 == sargs_find("kvp0")); - T(1 == sargs_find("kvp1")); + T(1 == sargs_find("kvp\\1")); T(2 == sargs_find("kvp2")); T(3 == sargs_find("kvp3")); T(4 == sargs_find("kvp4")) @@ -270,25 +270,25 @@ UTEST(sokol_args, key_only_args) { T(-1 == sargs_find("val2")); T(-1 == sargs_find("val4")); T(sargs_exists("kvp0")); - T(sargs_exists("kvp1")); + T(sargs_exists("kvp\\1")); T(sargs_exists("kvp2")); T(sargs_exists("kvp3")); T(sargs_exists("kvp4")); T(!sargs_exists("kvp5")); TSTR(sargs_value("kvp0"), ""); - TSTR(sargs_value("kvp1"), ""); + TSTR(sargs_value("kvp\\1"), ""); TSTR(sargs_value("kvp2"), "val2"); TSTR(sargs_value("kvp3"), ""); TSTR(sargs_value("kvp4"), "val4"); TSTR(sargs_value("kvp5"), ""); TSTR(sargs_value_def("kvp0", "bla0"), "bla0"); - TSTR(sargs_value_def("kvp1", "bla1"), "bla1"); + TSTR(sargs_value_def("kvp\\1", "bla1"), "bla1"); TSTR(sargs_value_def("kvp2", "bla2"), "val2"); TSTR(sargs_value_def("kvp3", "bla3"), "bla3"); TSTR(sargs_value_def("kvp4", "bla4"), "val4"); TSTR(sargs_value_def("kvp5", "bla5"), "bla5"); TSTR(sargs_key_at(0), "kvp0"); - TSTR(sargs_key_at(1), "kvp1"); + TSTR(sargs_key_at(1), "kvp\\1"); TSTR(sargs_key_at(2), "kvp2"); TSTR(sargs_key_at(3), "kvp3"); TSTR(sargs_key_at(4), "kvp4"); diff --git a/util/sokol_gfx_imgui.h b/util/sokol_gfx_imgui.h index fd025087..58481cee 100644 --- a/util/sokol_gfx_imgui.h +++ b/util/sokol_gfx_imgui.h @@ -4488,7 +4488,8 @@ _SOKOL_PRIVATE void _sgimgui_draw_capture_panel(sgimgui_t* ctx) { } _SOKOL_PRIVATE void _sgimgui_draw_caps_panel(void) { - _sgimgui_igtext("Backend: %s\n\n", _sgimgui_backend_string(sg_query_backend())); + _sgimgui_igtext("Backend: %s\n", _sgimgui_backend_string(sg_query_backend())); + _sgimgui_igtext("Dear ImGui Version: %s\n\n", IMGUI_VERSION); sg_features f = sg_query_features(); _sgimgui_igtext("Features:"); _sgimgui_igtext(" origin_top_left: %s", _sgimgui_bool_string(f.origin_top_left)); @@ -4500,6 +4501,7 @@ _SOKOL_PRIVATE void _sgimgui_draw_caps_panel(void) { _sgimgui_igtext(" separate_buffer_types: %s", _sgimgui_bool_string(f.separate_buffer_types)); _sgimgui_igtext(" draw_base_vertex: %s", _sgimgui_bool_string(f.draw_base_vertex)); _sgimgui_igtext(" draw_base_instance: %s", _sgimgui_bool_string(f.draw_base_instance)); + _sgimgui_igtext(" gl_texture_views: %s", _sgimgui_bool_string(f.gl_texture_views)); sg_limits l = sg_query_limits(); _sgimgui_igtext("\nLimits:\n"); _sgimgui_igtext(" max_image_size_2d: %d", l.max_image_size_2d); diff --git a/util/sokol_imgui.h b/util/sokol_imgui.h index a1fd4d34..89c47890 100644 --- a/util/sokol_imgui.h +++ b/util/sokol_imgui.h @@ -3145,9 +3145,12 @@ SOKOL_API_IMPL void simgui_new_frame(const simgui_frame_desc_t* desc) { static sg_pipeline _simgui_bind_texture_sampler(sg_bindings* bindings, ImTextureID imtex_id) { const sg_view tex_view = simgui_texture_view_from_imtextureid(imtex_id); + SOKOL_ASSERT(tex_view.id != SG_INVALID_ID); const sg_image img = sg_query_view_image(tex_view); + SOKOL_ASSERT(img.id != SG_INVALID_ID); bindings->views[0] = tex_view; bindings->samplers[0] = simgui_sampler_from_imtextureid(imtex_id); + SOKOL_ASSERT(bindings->samplers[0].id != SG_INVALID_ID); if (sg_query_pixelformat(sg_query_image_pixelformat(img)).filter) { return _simgui.def_pip; } else { diff --git a/util/sokol_spine.h b/util/sokol_spine.h index f8f1e0e1..ec142545 100644 --- a/util/sokol_spine.h +++ b/util/sokol_spine.h @@ -4097,10 +4097,11 @@ static sspine_resource_state _sspine_init_context(_sspine_context_t* ctx, const pip_desc.label = "sspine-pip-normal/additive"; ctx->pip.normal_additive = sg_make_pipeline(&pip_desc); - pip_desc.colors[0].blend.src_factor_rgb = SG_BLENDFACTOR_ZERO; - pip_desc.colors[0].blend.dst_factor_rgb = SG_BLENDFACTOR_SRC_COLOR; - pip_desc.colors[0].blend.src_factor_alpha = SG_BLENDFACTOR_ZERO; - pip_desc.colors[0].blend.dst_factor_alpha = SG_BLENDFACTOR_ONE; + pip_desc.colors[0].blend.src_factor_rgb = SG_BLENDFACTOR_DST_COLOR; + pip_desc.colors[0].blend.dst_factor_rgb = SG_BLENDFACTOR_ONE_MINUS_SRC_COLOR; + pip_desc.colors[0].blend.src_factor_alpha = SG_BLENDFACTOR_DST_ALPHA; + pip_desc.colors[0].blend.dst_factor_alpha = SG_BLENDFACTOR_ONE_MINUS_SRC_ALPHA; + pip_desc.label = "sspine-pip-multiply"; ctx->pip.multiply = sg_make_pipeline(&pip_desc); @@ -5257,6 +5258,7 @@ static void _sspine_draw_layer(_sspine_context_t* ctx, int layer, const sspine_l sg_apply_pipeline(cmd->pip); cur_pip_id = cmd->pip.id; sg_apply_uniforms(0, &vsparams_range); + sg_apply_uniforms(1, &fsparams_range); cur_view_id = SG_INVALID_ID; } if ((cur_view_id != cmd->view.id) || (cur_smp_id != cmd->smp.id)) { |