Merge remote-tracking branch 'origin/dev'
This commit is contained in:
commit
4747252187
|
@ -15,7 +15,7 @@ jobs:
|
|||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
submodules: true
|
||||
submodules: recursive
|
||||
|
||||
- uses: actions/setup-java@v4
|
||||
with:
|
||||
|
|
|
@ -16,10 +16,10 @@ jobs:
|
|||
version: '14.0'
|
||||
pkginstall: sudo pkg install -y alsa-lib ccache cmake evdev-proto git libao libevdev libudev-devd libzip miniupnpc ninja pkgconf pulseaudio sdl2
|
||||
- operating_system: netbsd
|
||||
version: '9.3'
|
||||
version: '10.0'
|
||||
pkginstall: sudo pkgin update && sudo pkgin -y install alsa-lib ccache cmake gcc12 git libao libzip miniupnpc ninja-build pkgconf pulseaudio SDL2 && export PATH=/usr/pkg/gcc12/bin:$PATH
|
||||
- operating_system: openbsd
|
||||
version: '7.4'
|
||||
version: '7.5'
|
||||
pkginstall: sudo pkg_add ccache cmake git libao libzip miniupnpc ninja pkgconf pulseaudio sdl2
|
||||
exclude:
|
||||
- architecture: arm64
|
||||
|
@ -36,7 +36,7 @@ jobs:
|
|||
key: ccache-${{ matrix.operating_system }}-${{ matrix.architecture }}-${{ github.sha }}
|
||||
restore-keys: ccache-${{ matrix.operating_system }}-${{ matrix.architecture }}-
|
||||
|
||||
- uses: cross-platform-actions/action@v0.23.0
|
||||
- uses: cross-platform-actions/action@v0.24.0
|
||||
with:
|
||||
operating_system: ${{ matrix.operating_system }}
|
||||
architecture: ${{ matrix.architecture }}
|
||||
|
|
|
@ -18,11 +18,11 @@ jobs:
|
|||
matrix:
|
||||
config:
|
||||
- {name: i686-pc-windows-msvc, os: windows-latest, shell: cmd, arch: x86, cmakeArgs: -G Ninja, buildType: Release}
|
||||
- {name: apple-darwin, os: macos-latest, shell: sh, cmakeArgs: -G Xcode -DAPPLE_BREAKPAD=ON, destDir: osx, buildType: RelWithDebInfo}
|
||||
- {name: apple-darwin, os: macos-latest, shell: sh, cmakeArgs: -G Xcode -DAPPLE_BREAKPAD=ON -DUSE_DISCORD=ON, destDir: osx, buildType: RelWithDebInfo}
|
||||
- {name: apple-ios, os: macos-latest, shell: sh, cmakeArgs: -DCMAKE_SYSTEM_NAME=iOS -G Xcode, destDir: ios, buildType: Release}
|
||||
- {name: x86_64-pc-linux-gnu, os: ubuntu-20.04, shell: sh, cmakeArgs: -G Ninja, destDir: linux, buildType: RelWithDebInfo}
|
||||
- {name: x86_64-pc-windows-msvc, os: windows-latest, shell: cmd, arch: x64, cmakeArgs: -G Ninja, buildType: Release}
|
||||
- {name: x86_64-w64-mingw32, os: windows-latest, shell: 'msys2 {0}', cmakeArgs: -G Ninja, destDir: win, buildType: RelWithDebInfo}
|
||||
- {name: x86_64-pc-linux-gnu, os: ubuntu-20.04, shell: sh, cmakeArgs: -G Ninja -DUSE_DISCORD=ON, destDir: linux, buildType: RelWithDebInfo}
|
||||
- {name: x86_64-pc-windows-msvc, os: windows-latest, shell: cmd, arch: x64, cmakeArgs: -G Ninja -DUSE_DISCORD=ON, buildType: Release}
|
||||
- {name: x86_64-w64-mingw32, os: windows-latest, shell: 'msys2 {0}', cmakeArgs: -G Ninja -DUSE_DISCORD=ON, destDir: win, buildType: RelWithDebInfo}
|
||||
- {name: libretro-x86_64-pc-linux-gnu, os: ubuntu-latest, shell: sh, cmakeArgs: -DLIBRETRO=ON -DCMAKE_POSITION_INDEPENDENT_CODE=TRUE -G Ninja, buildType: Release}
|
||||
- {name: libretro-x86_64-w64-mingw32, os: windows-latest, shell: 'msys2 {0}', cmakeArgs: -DLIBRETRO=ON -G Ninja, buildType: Release}
|
||||
|
||||
|
@ -70,7 +70,7 @@ jobs:
|
|||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
submodules: true
|
||||
submodules: recursive
|
||||
|
||||
- name: Compile a universal OpenMP (macOS)
|
||||
run: HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1 brew reinstall --build-from-source --formula ./shell/apple/libomp.rb
|
||||
|
|
|
@ -29,3 +29,12 @@
|
|||
[submodule "core/deps/Spout"]
|
||||
path = core/deps/Spout
|
||||
url = https://github.com/vkedwardli/Spout2.git
|
||||
[submodule "core/deps/discord-rpc"]
|
||||
path = core/deps/discord-rpc
|
||||
url = https://github.com/flyinghead/discord-rpc
|
||||
[submodule "core/deps/libadrenotools"]
|
||||
path = core/deps/libadrenotools
|
||||
url = https://github.com/bylaws/libadrenotools
|
||||
[submodule "core/deps/rcheevos"]
|
||||
path = core/deps/rcheevos
|
||||
url = https://github.com/RetroAchievements/rcheevos.git
|
||||
|
|
126
CMakeLists.txt
126
CMakeLists.txt
|
@ -69,6 +69,7 @@ option(APPLE_BREAKPAD "macOS: Build breakpad client and dump symbols" OFF)
|
|||
option(ENABLE_GDB_SERVER "Build with GDB debugging support" OFF)
|
||||
option(ENABLE_DC_PROFILER "Build with support for target machine (SH4) profiler" OFF)
|
||||
option(ENABLE_FC_PROFILER "Build with support for host app (Flycast) profiler" OFF)
|
||||
option(USE_DISCORD "Use Discord Presence API" OFF)
|
||||
|
||||
if(IOS AND NOT LIBRETRO)
|
||||
set(USE_VULKAN OFF CACHE BOOL "Force vulkan off" FORCE)
|
||||
|
@ -534,6 +535,7 @@ if(UNIX AND NOT APPLE AND NOT ANDROID)
|
|||
if(USE_GLES2)
|
||||
target_compile_definitions(${PROJECT_NAME} PRIVATE GLES GLES2)
|
||||
if(USE_VIDEOCORE)
|
||||
target_compile_definitions(${PROJECT_NAME} PRIVATE TARGET_VIDEOCORE USE_OMX)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE "-lbrcmGLESv2")
|
||||
target_link_directories(${PROJECT_NAME} PRIVATE "/opt/vc/lib")
|
||||
endif()
|
||||
|
@ -704,12 +706,13 @@ target_sources(${PROJECT_NAME} PRIVATE core/deps/lzma/7zArcIn.c core/deps/lzma/7
|
|||
add_subdirectory(core/deps/libelf)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE elf)
|
||||
if(NOT LIBRETRO)
|
||||
target_compile_definitions(${PROJECT_NAME} PRIVATE IMGUI_DISABLE_DEMO_WINDOWS)
|
||||
target_compile_definitions(${PROJECT_NAME} PRIVATE IMGUI_DISABLE_DEMO_WINDOWS IMGUI_DEFINE_MATH_OPERATORS)
|
||||
target_include_directories(${PROJECT_NAME} PRIVATE core/deps/imgui core/deps/imgui/backends)
|
||||
target_sources(${PROJECT_NAME} PRIVATE
|
||||
core/deps/imgui/imgui.cpp
|
||||
core/deps/imgui/imgui_demo.cpp
|
||||
core/deps/imgui/imgui_draw.cpp
|
||||
core/deps/imgui/imgui_stdlib.cpp
|
||||
core/deps/imgui/imgui_tables.cpp
|
||||
core/deps/imgui/imgui_widgets.cpp)
|
||||
|
||||
|
@ -725,6 +728,15 @@ endif()
|
|||
target_sources(${PROJECT_NAME} PRIVATE core/deps/xbrz/xbrz.cpp)
|
||||
target_sources(${PROJECT_NAME} PRIVATE core/deps/md5/md5.cpp)
|
||||
|
||||
if(USE_DISCORD AND NOT LIBRETRO)
|
||||
option(BUILD_EXAMPLES "Build example apps" OFF)
|
||||
add_subdirectory(core/deps/discord-rpc)
|
||||
target_include_directories(${PROJECT_NAME} PRIVATE core/deps/discord-rpc/include)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE discord-rpc)
|
||||
target_compile_definitions(${PROJECT_NAME} PRIVATE USE_DISCORD)
|
||||
target_sources(${PROJECT_NAME} PRIVATE core/ui/discord.cpp)
|
||||
endif()
|
||||
|
||||
cmrc_add_resource_library(flycast-resources ALIAS flycast::res NAMESPACE flycast)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE flycast::res)
|
||||
|
||||
|
@ -1001,7 +1013,10 @@ cmrc_add_resources(flycast-resources
|
|||
fonts/printer_kanji24x24.bin.zip)
|
||||
|
||||
if(NOT LIBRETRO)
|
||||
cmrc_add_resources(flycast-resources fonts/Roboto-Medium.ttf.zip)
|
||||
cmrc_add_resources(flycast-resources
|
||||
fonts/Roboto-Medium.ttf.zip
|
||||
fonts/Roboto-Regular.ttf.zip
|
||||
fonts/fa-solid-900.ttf.zip)
|
||||
if(ANDROID)
|
||||
cmrc_add_resources(flycast-resources
|
||||
WHENCE resources
|
||||
|
@ -1048,19 +1063,18 @@ else()
|
|||
core/linux/unwind_info.cpp)
|
||||
if(NINTENDO_SWITCH)
|
||||
target_sources(${PROJECT_NAME} PRIVATE
|
||||
core/linux/libnx_vmem.cpp
|
||||
shell/switch/libnx_vmem.cpp
|
||||
shell/switch/stubs.c
|
||||
shell/switch/context_switch.S
|
||||
shell/switch/nswitch.h
|
||||
shell/switch/switch_gamepad.h
|
||||
shell/switch/switch_main.cpp
|
||||
shell/switch/ucontext.h)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(NOT LIBRETRO)
|
||||
target_sources(${PROJECT_NAME} PRIVATE
|
||||
core/linux-dist/dispmanx.cpp
|
||||
core/linux-dist/dispmanx.h
|
||||
core/linux-dist/evdev.cpp
|
||||
core/linux-dist/evdev.h
|
||||
core/linux-dist/icon.h
|
||||
|
@ -1119,6 +1133,8 @@ if(NOT LIBRETRO)
|
|||
core/audio/audiobackend_pulseaudio.cpp
|
||||
core/audio/audiobackend_sdl2.cpp
|
||||
core/audio/audiostream.cpp
|
||||
core/oslib/http_client.cpp
|
||||
core/oslib/http_client.h
|
||||
core/oslib/oslib.cpp)
|
||||
endif()
|
||||
|
||||
|
@ -1163,6 +1179,44 @@ target_sources(${PROJECT_NAME} PRIVATE
|
|||
core/reios/reios_elf.h)
|
||||
cmrc_add_resources(flycast-resources fonts/biosfont.bin.zip)
|
||||
|
||||
target_sources(${PROJECT_NAME} PRIVATE
|
||||
core/achievements/achievements.cpp
|
||||
core/achievements/achievements.h)
|
||||
if(NOT LIBRETRO)
|
||||
target_sources(${PROJECT_NAME} PRIVATE
|
||||
core/deps/rcheevos/src/rc_client_raintegration.c
|
||||
core/deps/rcheevos/src/rc_client.c
|
||||
core/deps/rcheevos/src/rc_compat.c
|
||||
core/deps/rcheevos/src/rc_util.c
|
||||
core/deps/rcheevos/src/rc_version.c
|
||||
core/deps/rcheevos/src/rapi/rc_api_common.c
|
||||
core/deps/rcheevos/src/rapi/rc_api_editor.c
|
||||
core/deps/rcheevos/src/rapi/rc_api_info.c
|
||||
core/deps/rcheevos/src/rapi/rc_api_runtime.c
|
||||
core/deps/rcheevos/src/rapi/rc_api_user.c
|
||||
core/deps/rcheevos/src/rcheevos/alloc.c
|
||||
core/deps/rcheevos/src/rcheevos/condition.c
|
||||
core/deps/rcheevos/src/rcheevos/condset.c
|
||||
core/deps/rcheevos/src/rcheevos/consoleinfo.c
|
||||
core/deps/rcheevos/src/rcheevos/format.c
|
||||
core/deps/rcheevos/src/rcheevos/lboard.c
|
||||
core/deps/rcheevos/src/rcheevos/memref.c
|
||||
core/deps/rcheevos/src/rcheevos/operand.c
|
||||
core/deps/rcheevos/src/rcheevos/rc_validate.c
|
||||
core/deps/rcheevos/src/rcheevos/richpresence.c
|
||||
core/deps/rcheevos/src/rcheevos/runtime_progress.c
|
||||
core/deps/rcheevos/src/rcheevos/runtime.c
|
||||
core/deps/rcheevos/src/rcheevos/trigger.c
|
||||
core/deps/rcheevos/src/rcheevos/value.c
|
||||
core/deps/rcheevos/src/rhash/aes.c
|
||||
core/deps/rcheevos/src/rhash/cdreader.c
|
||||
core/deps/rcheevos/src/rhash/hash.c
|
||||
core/deps/rcheevos/src/rhash/md5.c
|
||||
core/deps/rcheevos/src/rurl/url.c)
|
||||
target_include_directories(${PROJECT_NAME} PRIVATE core/deps/rcheevos/include)
|
||||
target_compile_definitions(${PROJECT_NAME} PRIVATE USE_RACHIEVEMENTS RC_DISABLE_LUA)
|
||||
endif()
|
||||
|
||||
target_sources(${PROJECT_NAME} PRIVATE
|
||||
core/wsi/context.h
|
||||
core/wsi/libretro.cpp
|
||||
|
@ -1238,26 +1292,26 @@ target_sources(${PROJECT_NAME} PRIVATE
|
|||
core/rend/norend/norend.cpp)
|
||||
if(NOT LIBRETRO)
|
||||
target_sources(${PROJECT_NAME} PRIVATE
|
||||
core/rend/game_scanner.h
|
||||
core/rend/imgui_driver.h
|
||||
core/rend/gui.cpp
|
||||
core/rend/gui.h
|
||||
core/rend/gui_android.cpp
|
||||
core/rend/gui_android.h
|
||||
core/rend/gui_chat.h
|
||||
core/rend/gui_cheats.cpp
|
||||
core/rend/gui_util.cpp
|
||||
core/rend/gui_util.h
|
||||
core/rend/mainui.cpp
|
||||
core/rend/mainui.h
|
||||
core/rend/boxart/boxart.cpp
|
||||
core/rend/boxart/boxart.h
|
||||
core/rend/boxart/gamesdb.cpp
|
||||
core/rend/boxart/gamesdb.h
|
||||
core/rend/boxart/http_client.cpp
|
||||
core/rend/boxart/http_client.h
|
||||
core/rend/boxart/scraper.cpp
|
||||
core/rend/boxart/scraper.h)
|
||||
core/ui/game_scanner.cpp
|
||||
core/ui/game_scanner.h
|
||||
core/ui/imgui_driver.h
|
||||
core/ui/gui.cpp
|
||||
core/ui/gui.h
|
||||
core/ui/gui_achievements.cpp
|
||||
core/ui/gui_android.cpp
|
||||
core/ui/gui_android.h
|
||||
core/ui/gui_chat.h
|
||||
core/ui/gui_cheats.cpp
|
||||
core/ui/gui_util.cpp
|
||||
core/ui/gui_util.h
|
||||
core/ui/mainui.cpp
|
||||
core/ui/mainui.h
|
||||
core/ui/boxart/boxart.cpp
|
||||
core/ui/boxart/boxart.h
|
||||
core/ui/boxart/gamesdb.cpp
|
||||
core/ui/boxart/gamesdb.h
|
||||
core/ui/boxart/scraper.cpp
|
||||
core/ui/boxart/scraper.h)
|
||||
endif()
|
||||
|
||||
if(USE_VULKAN)
|
||||
|
@ -1281,6 +1335,11 @@ if(USE_VULKAN)
|
|||
target_compile_options(VulkanMemoryAllocator INTERFACE $<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CXX_COMPILER_ID:AppleClang,Clang>>:-Wno-nullability-completeness>)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE GPUOpen::VulkanMemoryAllocator)
|
||||
|
||||
if(ANDROID AND NOT LIBRETRO AND "arm64" IN_LIST ARCHITECTURE)
|
||||
add_subdirectory(core/deps/libadrenotools)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE adrenotools)
|
||||
endif()
|
||||
|
||||
target_compile_definitions(${PROJECT_NAME} PRIVATE USE_VULKAN HAVE_VULKAN)
|
||||
target_sources(${PROJECT_NAME} PRIVATE
|
||||
core/rend/vulkan/oit/oit_buffer.h
|
||||
|
@ -1293,6 +1352,7 @@ if(USE_VULKAN)
|
|||
core/rend/vulkan/oit/oit_renderpass.h
|
||||
core/rend/vulkan/oit/oit_shaders.cpp
|
||||
core/rend/vulkan/oit/oit_shaders.h
|
||||
core/rend/vulkan/adreno.cpp
|
||||
core/rend/vulkan/buffer.cpp
|
||||
core/rend/vulkan/buffer.h
|
||||
core/rend/vulkan/commandpool.cpp
|
||||
|
@ -1496,7 +1556,7 @@ endif()
|
|||
if((USE_OPENGL OR USE_GLES2 OR USE_GLES) AND NOT LIBRETRO)
|
||||
add_library(glad STATIC core/deps/glad/src/gl.c)
|
||||
if(NOT APPLE AND NOT WIN32 AND NOT SDL2_FOUND)
|
||||
# When SDL2 is not found, we can use EGL with ANativeWindow (Android), DispmanX (Raspberry Pi) or X11
|
||||
# When SDL2 is not found, we can use EGL with ANativeWindow (Android) or X11
|
||||
target_sources(glad PRIVATE core/deps/glad/src/egl.c)
|
||||
endif()
|
||||
target_include_directories(glad PUBLIC core/deps/glad/include)
|
||||
|
@ -1560,6 +1620,7 @@ if(NOT LIBRETRO)
|
|||
|
||||
target_sources(${PROJECT_NAME} PRIVATE
|
||||
shell/apple/common/http_client.mm
|
||||
shell/apple/common/util.mm
|
||||
shell/apple/emulator-ios/emulator/AppDelegate.h
|
||||
shell/apple/emulator-ios/emulator/AppDelegate.mm
|
||||
shell/apple/emulator-ios/emulator/ios_main.mm
|
||||
|
@ -1655,6 +1716,7 @@ if(NOT LIBRETRO)
|
|||
|
||||
target_sources(${PROJECT_NAME} PRIVATE
|
||||
shell/apple/common/http_client.mm
|
||||
shell/apple/common/util.mm
|
||||
shell/apple/emulator-osx/emulator-osx/SDLApplicationDelegate.h
|
||||
shell/apple/emulator-osx/emulator-osx/SDLApplicationDelegate.mm
|
||||
shell/apple/emulator-osx/emulator-osx/osx-main.mm)
|
||||
|
@ -1710,18 +1772,18 @@ if(NOT LIBRETRO)
|
|||
${CMAKE_CURRENT_BINARY_DIR}/Flycast.app/Contents/Frameworks/libvulkan.dylib)
|
||||
endif()
|
||||
endif()
|
||||
elseif(UNIX OR NINTENDO_SWITCH)
|
||||
elseif(UNIX)
|
||||
if(NOT BUILD_TESTING)
|
||||
target_sources(${PROJECT_NAME} PRIVATE
|
||||
core/linux-dist/main.cpp)
|
||||
endif()
|
||||
elseif(WIN32)
|
||||
target_sources(${PROJECT_NAME} PRIVATE
|
||||
core/windows/clock.c
|
||||
core/windows/rawinput.cpp
|
||||
core/windows/rawinput.h)
|
||||
if(NOT BUILD_TESTING)
|
||||
target_sources(${PROJECT_NAME} PRIVATE
|
||||
core/windows/clock.c
|
||||
core/windows/rawinput.cpp
|
||||
core/windows/rawinput.h
|
||||
core/windows/winmain.cpp)
|
||||
target_sources(${PROJECT_NAME} PRIVATE core/windows/winmain.cpp)
|
||||
endif()
|
||||
if(WINDOWS_STORE)
|
||||
file(READ shell/uwp/Package.appxmanifest MANIFEST)
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
This file is part of Flycast.
|
||||
|
||||
Flycast is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Flycast is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Flycast. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include "types.h"
|
||||
#include <future>
|
||||
#include <vector>
|
||||
|
||||
namespace achievements
|
||||
{
|
||||
#ifdef USE_RACHIEVEMENTS
|
||||
|
||||
struct Game
|
||||
{
|
||||
std::string image;
|
||||
std::string title;
|
||||
u32 unlockedAchievements;
|
||||
u32 totalAchievements;
|
||||
u32 points;
|
||||
u32 totalPoints;
|
||||
};
|
||||
|
||||
struct Achievement
|
||||
{
|
||||
Achievement() = default;
|
||||
Achievement(const std::string& image, const std::string& title, const std::string& description, const std::string& category, const std::string& status)
|
||||
: image(image), title(title), description(description), category(category), status(status) {}
|
||||
std::string image;
|
||||
std::string title;
|
||||
std::string description;
|
||||
std::string category;
|
||||
std::string status;
|
||||
};
|
||||
|
||||
bool init();
|
||||
void term();
|
||||
std::future<void> login(const char *username, const char *password);
|
||||
void logout();
|
||||
bool isLoggedOn();
|
||||
bool isActive();
|
||||
Game getCurrentGame();
|
||||
std::vector<Achievement> getAchievementList();
|
||||
|
||||
#else
|
||||
|
||||
static inline bool isActive() {
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void serialize(Serializer& ser);
|
||||
void deserialize(Deserializer& deser);
|
||||
|
||||
}
|
|
@ -47,7 +47,7 @@ ArchiveFile* ZipArchive::OpenFile(const char* name)
|
|||
return nullptr;
|
||||
zip_stat_t stat;
|
||||
zip_stat(zip, name, 0, &stat);
|
||||
return new ZipArchiveFile(zip_file, stat.size);
|
||||
return new ZipArchiveFile(zip_file, stat.size, stat.name);
|
||||
}
|
||||
|
||||
static zip_file *zip_fopen_by_crc(zip_t *za, u32 crc, int flags, zip_uint64_t& index)
|
||||
|
@ -77,7 +77,7 @@ ArchiveFile* ZipArchive::OpenFileByCrc(u32 crc)
|
|||
zip_stat_t stat;
|
||||
zip_stat_index(zip, index, 0, &stat);
|
||||
|
||||
return new ZipArchiveFile(zip_file, stat.size);
|
||||
return new ZipArchiveFile(zip_file, stat.size, stat.name);
|
||||
}
|
||||
|
||||
u32 ZipArchiveFile::Read(void* buffer, u32 length)
|
||||
|
@ -104,5 +104,15 @@ ArchiveFile *ZipArchive::OpenFirstFile()
|
|||
return nullptr;
|
||||
zip_stat_t stat;
|
||||
zip_stat_index(zip, 0, 0, &stat);
|
||||
return new ZipArchiveFile(zipFile, stat.size);
|
||||
return new ZipArchiveFile(zipFile, stat.size, stat.name);
|
||||
}
|
||||
|
||||
ArchiveFile *ZipArchive::OpenFileByIndex(size_t index)
|
||||
{
|
||||
zip_file_t *zipFile = zip_fopen_index(zip, index, 0);
|
||||
if (zipFile == nullptr)
|
||||
return nullptr;
|
||||
zip_stat_t stat;
|
||||
zip_stat_index(zip, index, 0, &stat);
|
||||
return new ZipArchiveFile(zipFile, stat.size, stat.name);
|
||||
}
|
||||
|
|
|
@ -31,11 +31,11 @@ public:
|
|||
ArchiveFile* OpenFile(const char* name) override;
|
||||
ArchiveFile* OpenFileByCrc(u32 crc) override;
|
||||
|
||||
bool Open(const void *data, size_t size);
|
||||
ArchiveFile *OpenFirstFile();
|
||||
|
||||
protected:
|
||||
bool Open(FILE *file) override;
|
||||
bool Open(const void *data, size_t size);
|
||||
|
||||
ArchiveFile *OpenFirstFile();
|
||||
ArchiveFile *OpenFileByIndex(size_t index);
|
||||
|
||||
private:
|
||||
zip_t *zip = nullptr;
|
||||
|
@ -44,8 +44,8 @@ private:
|
|||
class ZipArchiveFile : public ArchiveFile
|
||||
{
|
||||
public:
|
||||
ZipArchiveFile(zip_file_t *zip_file, size_t length)
|
||||
: zip_file(zip_file), _length(length) {}
|
||||
ZipArchiveFile(zip_file_t *zip_file, size_t length, const char *name)
|
||||
: zip_file(zip_file), _length(length), name(name) {}
|
||||
~ZipArchiveFile() override {
|
||||
zip_fclose(zip_file);
|
||||
}
|
||||
|
@ -53,8 +53,12 @@ public:
|
|||
size_t length() override {
|
||||
return _length;
|
||||
}
|
||||
const char *getName() override {
|
||||
return name;
|
||||
}
|
||||
|
||||
private:
|
||||
zip_file_t *zip_file;
|
||||
size_t _length;
|
||||
const char *name;
|
||||
};
|
||||
|
|
|
@ -28,6 +28,7 @@ public:
|
|||
virtual ~ArchiveFile() = default;
|
||||
virtual u32 Read(void *buffer, u32 length) = 0;
|
||||
virtual size_t length() = 0;
|
||||
virtual const char *getName() { return nullptr; }
|
||||
};
|
||||
|
||||
class Archive
|
||||
|
|
|
@ -23,14 +23,11 @@
|
|||
|
||||
const u8 RZipHeader[8] = { '#', 'R', 'Z', 'I', 'P', 'v', 1, '#' };
|
||||
|
||||
bool RZipFile::Open(const std::string& path, bool write)
|
||||
bool RZipFile::Open(FILE *file, bool write)
|
||||
{
|
||||
verify(file == nullptr);
|
||||
this->write = write;
|
||||
|
||||
file = nowide::fopen(path.c_str(), write ? "wb" : "rb");
|
||||
if (file == nullptr)
|
||||
return false;
|
||||
verify(this->file == nullptr);
|
||||
verify(file != nullptr);
|
||||
startOffset = std::ftell(file);
|
||||
if (!write)
|
||||
{
|
||||
u8 header[sizeof(RZipHeader)];
|
||||
|
@ -39,7 +36,7 @@ bool RZipFile::Open(const std::string& path, bool write)
|
|||
|| std::fread(&maxChunkSize, sizeof(maxChunkSize), 1, file) != 1
|
||||
|| std::fread(&size, sizeof(size), 1, file) != 1)
|
||||
{
|
||||
Close();
|
||||
std::fseek(file, startOffset, SEEK_SET);
|
||||
return false;
|
||||
}
|
||||
// savestates created on 32-bit platforms used to have a 32-bit size
|
||||
|
@ -59,11 +56,24 @@ bool RZipFile::Open(const std::string& path, bool write)
|
|||
|| std::fwrite(&maxChunkSize, sizeof(maxChunkSize), 1, file) != 1
|
||||
|| std::fwrite(&size, sizeof(size), 1, file) != 1)
|
||||
{
|
||||
Close();
|
||||
std::fseek(file, startOffset, SEEK_SET);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
this->write = write;
|
||||
this->file = file;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RZipFile::Open(const std::string& path, bool write)
|
||||
{
|
||||
FILE *f = nowide::fopen(path.c_str(), write ? "wb" : "rb");
|
||||
if (f == nullptr)
|
||||
return false;
|
||||
if (!Open(f, write)) {
|
||||
Close();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -73,7 +83,7 @@ void RZipFile::Close()
|
|||
{
|
||||
if (write)
|
||||
{
|
||||
std::fseek(file, sizeof(RZipHeader) + sizeof(maxChunkSize), SEEK_SET);
|
||||
std::fseek(file, startOffset + sizeof(RZipHeader) + sizeof(maxChunkSize), SEEK_SET);
|
||||
std::fwrite(&size, sizeof(size), 1, file);
|
||||
}
|
||||
std::fclose(file);
|
||||
|
|
|
@ -28,6 +28,7 @@ public:
|
|||
~RZipFile() { Close(); }
|
||||
|
||||
bool Open(const std::string& path, bool write);
|
||||
bool Open(FILE *file, bool write);
|
||||
void Close();
|
||||
size_t Size() const { return size; }
|
||||
size_t Read(void *data, size_t length);
|
||||
|
@ -42,4 +43,5 @@ private:
|
|||
u32 chunkSize = 0;
|
||||
u32 chunkIndex = 0;
|
||||
bool write = false;
|
||||
long startOffset = 0;
|
||||
};
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include <thread>
|
||||
#include "stdclass.h"
|
||||
#include "windows/comptr.h"
|
||||
#include "oslib/oslib.h"
|
||||
|
||||
HWND getNativeHwnd();
|
||||
#define verifyc(x) verify(!FAILED(x))
|
||||
|
@ -46,6 +47,7 @@ class DirectSoundBackend : public AudioBackend
|
|||
|
||||
void audioThreadMain()
|
||||
{
|
||||
ThreadName _("FlyDirectSound");
|
||||
audioThreadRunning = true;
|
||||
while (true)
|
||||
{
|
||||
|
|
|
@ -108,6 +108,7 @@ Option<int> PerPixelLayers("rend.PerPixelLayers", 32);
|
|||
Option<bool> NativeDepthInterpolation("rend.NativeDepthInterpolation", false);
|
||||
Option<bool> EmulateFramebuffer("rend.EmulateFramebuffer", false);
|
||||
Option<bool> FixUpscaleBleedingEdge("rend.FixUpscaleBleedingEdge", true);
|
||||
Option<bool> CustomGpuDriver("rend.CustomGpuDriver", false);
|
||||
#ifdef VIDEO_ROUTING
|
||||
Option<bool, false> VideoRouting("rend.VideoRouting", false);
|
||||
Option<bool, false> VideoRoutingScale("rend.VideoRoutingScale", false);
|
||||
|
@ -130,6 +131,7 @@ Option<bool> OpenGlChecks("OpenGlChecks", false, "validate");
|
|||
Option<std::vector<std::string>, false> ContentPath("Dreamcast.ContentPath");
|
||||
Option<bool, false> HideLegacyNaomiRoms("Dreamcast.HideLegacyNaomiRoms", true);
|
||||
Option<bool, false> UploadCrashLogs("UploadCrashLogs", true);
|
||||
Option<bool, false> DiscordPresence("DiscordPresence", true);
|
||||
|
||||
// Profiler
|
||||
Option<bool> ProfilerEnabled("Profiler.Enabled");
|
||||
|
@ -157,10 +159,6 @@ Option<bool> NetworkOutput("NetworkOutput", false, "network");
|
|||
Option<int> MultiboardSlaves("MultiboardSlaves", 1, "network");
|
||||
Option<bool> BattleCableEnable("BattleCable", false, "network");
|
||||
|
||||
#ifdef SUPPORT_DISPMANX
|
||||
Option<bool> DispmanxMaintainAspect("maintain_aspect", true, "dispmanx");
|
||||
#endif
|
||||
|
||||
#ifdef USE_OMX
|
||||
Option<int> OmxAudioLatency("audio_latency", 100, "omx");
|
||||
Option<bool> OmxAudioHdmi("audio_hdmi", true, "omx");
|
||||
|
@ -199,4 +197,11 @@ Option<bool, false> UseRawInput("RawInput", false, "input");
|
|||
Option<std::string, false> LuaFileName("LuaFileName", "flycast.lua");
|
||||
#endif
|
||||
|
||||
// RetroAchievements
|
||||
|
||||
Option<bool> EnableAchievements("Enabled", false, "achievements");
|
||||
Option<bool> AchievementsHardcoreMode("HardcoreMode", false, "achievements");
|
||||
OptionString AchievementsUserName("UserName", "", "achievements");
|
||||
OptionString AchievementsToken("Token", "", "achievements");
|
||||
|
||||
} // namespace config
|
||||
|
|
|
@ -474,6 +474,7 @@ extern Option<bool> DupeFrames;
|
|||
extern Option<bool> NativeDepthInterpolation;
|
||||
extern Option<bool> EmulateFramebuffer;
|
||||
extern Option<bool> FixUpscaleBleedingEdge;
|
||||
extern Option<bool> CustomGpuDriver;
|
||||
#ifdef VIDEO_ROUTING
|
||||
extern Option<bool, false> VideoRouting;
|
||||
extern Option<bool, false> VideoRoutingScale;
|
||||
|
@ -496,6 +497,7 @@ extern Option<bool> OpenGlChecks;
|
|||
extern Option<std::vector<std::string>, false> ContentPath;
|
||||
extern Option<bool, false> HideLegacyNaomiRoms;
|
||||
extern Option<bool, false> UploadCrashLogs;
|
||||
extern Option<bool, false> DiscordPresence;
|
||||
|
||||
// Profiling
|
||||
extern Option<bool> ProfilerEnabled;
|
||||
|
@ -523,10 +525,6 @@ extern Option<bool> NetworkOutput;
|
|||
extern Option<int> MultiboardSlaves;
|
||||
extern Option<bool> BattleCableEnable;
|
||||
|
||||
#ifdef SUPPORT_DISPMANX
|
||||
extern Option<bool> DispmanxMaintainAspect;
|
||||
#endif
|
||||
|
||||
#ifdef USE_OMX
|
||||
extern Option<int> OmxAudioLatency;
|
||||
extern Option<bool> OmxAudioHdmi;
|
||||
|
@ -549,4 +547,11 @@ constexpr bool UseRawInput = false;
|
|||
extern Option<std::string, false> LuaFileName;
|
||||
#endif
|
||||
|
||||
// RetroAchievements
|
||||
|
||||
extern Option<bool> EnableAchievements;
|
||||
extern Option<bool> AchievementsHardcoreMode;
|
||||
extern OptionString AchievementsUserName;
|
||||
extern OptionString AchievementsToken;
|
||||
|
||||
} // namespace config
|
||||
|
|
|
@ -432,9 +432,12 @@ void CheatManager::reset(const std::string& gameId)
|
|||
setActive(false);
|
||||
this->gameId = gameId;
|
||||
#ifndef LIBRETRO
|
||||
std::string cheatFile = cfgLoadStr("cheats", gameId, "");
|
||||
if (!cheatFile.empty())
|
||||
loadCheatFile(cheatFile);
|
||||
if (!settings.raHardcoreMode)
|
||||
{
|
||||
std::string cheatFile = cfgLoadStr("cheats", gameId, "");
|
||||
if (!cheatFile.empty())
|
||||
loadCheatFile(cheatFile);
|
||||
}
|
||||
#endif
|
||||
size_t cheatCount = cheats.size();
|
||||
if (gameId == "Fixed BOOT strapper") // Extreme Hunting 2
|
||||
|
@ -492,7 +495,7 @@ void CheatManager::reset(const std::string& gameId)
|
|||
if (cheats.size() > cheatCount)
|
||||
setActive(true);
|
||||
}
|
||||
if (config::WidescreenGameHacks)
|
||||
if (config::WidescreenGameHacks && !settings.raHardcoreMode)
|
||||
{
|
||||
if (settings.platform.isConsole())
|
||||
{
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "debug_agent.h"
|
||||
#include "network/net_platform.h"
|
||||
#include "cfg/option.h"
|
||||
#include "oslib/oslib.h"
|
||||
#include <stdexcept>
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
|
@ -140,6 +141,7 @@ private:
|
|||
|
||||
void serverThread()
|
||||
{
|
||||
ThreadName _("GdbServer");
|
||||
while (!stopRequested)
|
||||
{
|
||||
fd_set fds;
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit f461d91cd265d7b9a44b4d472b1df0c0ad2855a0
|
||||
Subproject commit fb1497566c5a05e2babdcf45ef0ab5c7cca2c4ae
|
|
@ -0,0 +1 @@
|
|||
Subproject commit c1197e1a1e2ff09c077e84541bd88cf90581648c
|
|
@ -59,7 +59,8 @@ struct ImGui_ImplDX11_Data
|
|||
ID3D11PixelShader* pPixelShader;
|
||||
ID3D11SamplerState* pFontSampler;
|
||||
ID3D11SamplerState* pTextureSampler;
|
||||
ID3D11ShaderResourceView* pFontTextureView;
|
||||
ID3D11SamplerState* pPointSampler;
|
||||
ImTextureDX11 FontTexture;
|
||||
ID3D11RasterizerState* pRasterizerState;
|
||||
ID3D11BlendState* pBlendState;
|
||||
ID3D11DepthStencilState* pDepthStencilState;
|
||||
|
@ -279,11 +280,17 @@ void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data)
|
|||
ctx->RSSetScissorRects(1, &r);
|
||||
|
||||
// Bind texture, Draw
|
||||
ID3D11ShaderResourceView* texture_srv = (ID3D11ShaderResourceView*)pcmd->GetTexID();
|
||||
if (pcmd->TextureId != (ImTextureID)bd->pFontTextureView)
|
||||
ctx->PSSetSamplers(0, 1, &bd->pTextureSampler);
|
||||
ImTextureDX11 *tex = (ImTextureDX11 *)pcmd->GetTexID();
|
||||
if (tex != &bd->FontTexture)
|
||||
{
|
||||
if (tex->pointSampling)
|
||||
ctx->PSSetSamplers(0, 1, &bd->pPointSampler);
|
||||
else
|
||||
ctx->PSSetSamplers(0, 1, &bd->pTextureSampler);
|
||||
}
|
||||
else
|
||||
ctx->PSSetSamplers(0, 1, &bd->pFontSampler);
|
||||
ID3D11ShaderResourceView* texture_srv = tex->shaderResourceView;
|
||||
ctx->PSSetShaderResources(0, 1, &texture_srv);
|
||||
ctx->DrawIndexed(pcmd->ElemCount, pcmd->IdxOffset + global_idx_offset, pcmd->VtxOffset + global_vtx_offset);
|
||||
}
|
||||
|
@ -350,12 +357,12 @@ static void ImGui_ImplDX11_CreateFontsTexture()
|
|||
srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
|
||||
srvDesc.Texture2D.MipLevels = desc.MipLevels;
|
||||
srvDesc.Texture2D.MostDetailedMip = 0;
|
||||
bd->pd3dDevice->CreateShaderResourceView(pTexture, &srvDesc, &bd->pFontTextureView);
|
||||
bd->pd3dDevice->CreateShaderResourceView(pTexture, &srvDesc, &bd->FontTexture.shaderResourceView);
|
||||
pTexture->Release();
|
||||
}
|
||||
|
||||
// Store our identifier
|
||||
io.Fonts->SetTexID((ImTextureID)bd->pFontTextureView);
|
||||
io.Fonts->SetTexID((ImTextureID)&bd->FontTexture);
|
||||
|
||||
// Create texture samplers
|
||||
// (Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling)
|
||||
|
@ -375,6 +382,9 @@ static void ImGui_ImplDX11_CreateFontsTexture()
|
|||
desc.AddressU = D3D11_TEXTURE_ADDRESS_BORDER;
|
||||
desc.AddressV = D3D11_TEXTURE_ADDRESS_BORDER;
|
||||
bd->pd3dDevice->CreateSamplerState(&desc, &bd->pTextureSampler);
|
||||
|
||||
desc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT;
|
||||
bd->pd3dDevice->CreateSamplerState(&desc, &bd->pPointSampler);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -540,7 +550,13 @@ void ImGui_ImplDX11_InvalidateDeviceObjects()
|
|||
|
||||
if (bd->pFontSampler) { bd->pFontSampler->Release(); bd->pFontSampler = nullptr; }
|
||||
if (bd->pTextureSampler) { bd->pTextureSampler->Release(); bd->pTextureSampler = nullptr; }
|
||||
if (bd->pFontTextureView) { bd->pFontTextureView->Release(); bd->pFontTextureView = nullptr; ImGui::GetIO().Fonts->SetTexID(0); } // We copied data->pFontTextureView to io.Fonts->TexID so let's clear that as well.
|
||||
if (bd->pPointSampler) { bd->pPointSampler->Release(); bd->pPointSampler = nullptr; }
|
||||
if (bd->FontTexture.shaderResourceView) {
|
||||
bd->FontTexture.shaderResourceView->Release();
|
||||
bd->FontTexture.shaderResourceView = nullptr;
|
||||
// We copied data->FontTexture.shaderResourceView to io.Fonts->TexID so let's clear that as well.
|
||||
ImGui::GetIO().Fonts->SetTexID(0);
|
||||
}
|
||||
if (bd->pIB) { bd->pIB->Release(); bd->pIB = nullptr; }
|
||||
if (bd->pVB) { bd->pVB->Release(); bd->pVB = nullptr; }
|
||||
if (bd->pBlendState) { bd->pBlendState->Release(); bd->pBlendState = nullptr; }
|
||||
|
@ -603,7 +619,7 @@ void ImGui_ImplDX11_Shutdown()
|
|||
void ImGui_ImplDX11_NewFrame()
|
||||
{
|
||||
ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData();
|
||||
IM_ASSERT(bd != nullptr && "Did you call ImGui_ImplDX11_Init()?");
|
||||
IM_ASSERT(bd != nullptr && "Context or backend not initialized! Did you call ImGui_ImplDX11_Init()?");
|
||||
|
||||
if (!bd->pFontSampler)
|
||||
ImGui_ImplDX11_CreateDeviceObjects();
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
struct ID3D11Device;
|
||||
struct ID3D11DeviceContext;
|
||||
struct ID3D11ShaderResourceView;
|
||||
|
||||
IMGUI_IMPL_API bool ImGui_ImplDX11_Init(ID3D11Device* device, ID3D11DeviceContext* device_context);
|
||||
IMGUI_IMPL_API void ImGui_ImplDX11_Shutdown();
|
||||
|
@ -29,4 +30,11 @@ IMGUI_IMPL_API void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data);
|
|||
IMGUI_IMPL_API void ImGui_ImplDX11_InvalidateDeviceObjects();
|
||||
IMGUI_IMPL_API bool ImGui_ImplDX11_CreateDeviceObjects();
|
||||
|
||||
// ImTextureID should be a pointer to this struct
|
||||
struct ImTextureDX11
|
||||
{
|
||||
ID3D11ShaderResourceView *shaderResourceView;
|
||||
bool pointSampling;
|
||||
};
|
||||
|
||||
#endif // #ifndef IMGUI_DISABLE
|
||||
|
|
|
@ -48,7 +48,7 @@ struct ImGui_ImplDX9_Data
|
|||
LPDIRECT3DDEVICE9 pd3dDevice;
|
||||
LPDIRECT3DVERTEXBUFFER9 pVB;
|
||||
LPDIRECT3DINDEXBUFFER9 pIB;
|
||||
LPDIRECT3DTEXTURE9 FontTexture;
|
||||
ImTextureDX9 FontTexture;
|
||||
int VertexBufferSize;
|
||||
int IndexBufferSize;
|
||||
|
||||
|
@ -244,17 +244,30 @@ void ImGui_ImplDX9_RenderDrawData(ImDrawData* draw_data)
|
|||
|
||||
// Apply Scissor/clipping rectangle, Bind texture, Draw
|
||||
const RECT r = { (LONG)clip_min.x, (LONG)clip_min.y, (LONG)clip_max.x, (LONG)clip_max.y };
|
||||
const LPDIRECT3DTEXTURE9 texture = (LPDIRECT3DTEXTURE9)pcmd->GetTexID();
|
||||
const ImTextureDX9 *tex = (const ImTextureDX9 *)pcmd->GetTexID();
|
||||
const LPDIRECT3DTEXTURE9 texture = tex->d3dTexture;
|
||||
bd->pd3dDevice->SetTexture(0, texture);
|
||||
if (texture != bd->FontTexture)
|
||||
if (tex != &bd->FontTexture)
|
||||
{
|
||||
bd->pd3dDevice->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_BORDER);
|
||||
bd->pd3dDevice->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_BORDER);
|
||||
if (tex->pointSampling)
|
||||
{
|
||||
bd->pd3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT);
|
||||
bd->pd3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT);
|
||||
}
|
||||
else
|
||||
{
|
||||
bd->pd3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
|
||||
bd->pd3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
bd->pd3dDevice->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP);
|
||||
bd->pd3dDevice->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP);
|
||||
bd->pd3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
|
||||
bd->pd3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
|
||||
}
|
||||
bd->pd3dDevice->SetScissorRect(&r);
|
||||
bd->pd3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, pcmd->VtxOffset + global_vtx_offset, 0, (UINT)cmd_list->VtxBuffer.Size, pcmd->IdxOffset + global_idx_offset, pcmd->ElemCount / 3);
|
||||
|
@ -338,18 +351,18 @@ static bool ImGui_ImplDX9_CreateFontsTexture()
|
|||
#endif
|
||||
|
||||
// Upload texture to graphics system
|
||||
bd->FontTexture = nullptr;
|
||||
if (bd->pd3dDevice->CreateTexture(width, height, 1, D3DUSAGE_DYNAMIC, rgba_support ? D3DFMT_A8B8G8R8 : D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &bd->FontTexture, nullptr) < 0)
|
||||
bd->FontTexture.d3dTexture = nullptr;
|
||||
if (bd->pd3dDevice->CreateTexture(width, height, 1, D3DUSAGE_DYNAMIC, rgba_support ? D3DFMT_A8B8G8R8 : D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &bd->FontTexture.d3dTexture, nullptr) < 0)
|
||||
return false;
|
||||
D3DLOCKED_RECT tex_locked_rect;
|
||||
if (bd->FontTexture->LockRect(0, &tex_locked_rect, nullptr, 0) != D3D_OK)
|
||||
if (bd->FontTexture.d3dTexture->LockRect(0, &tex_locked_rect, nullptr, 0) != D3D_OK)
|
||||
return false;
|
||||
for (int y = 0; y < height; y++)
|
||||
memcpy((unsigned char*)tex_locked_rect.pBits + (size_t)tex_locked_rect.Pitch * y, pixels + (size_t)width * bytes_per_pixel * y, (size_t)width * bytes_per_pixel);
|
||||
bd->FontTexture->UnlockRect(0);
|
||||
bd->FontTexture.d3dTexture->UnlockRect(0);
|
||||
|
||||
// Store our identifier
|
||||
io.Fonts->SetTexID((ImTextureID)bd->FontTexture);
|
||||
io.Fonts->SetTexID((ImTextureID)&bd->FontTexture);
|
||||
|
||||
#ifndef IMGUI_USE_BGRA_PACKED_COLOR
|
||||
if (!rgba_support && io.Fonts->TexPixelsUseColors)
|
||||
|
@ -376,15 +389,21 @@ void ImGui_ImplDX9_InvalidateDeviceObjects()
|
|||
return;
|
||||
if (bd->pVB) { bd->pVB->Release(); bd->pVB = nullptr; }
|
||||
if (bd->pIB) { bd->pIB->Release(); bd->pIB = nullptr; }
|
||||
if (bd->FontTexture) { bd->FontTexture->Release(); bd->FontTexture = nullptr; ImGui::GetIO().Fonts->SetTexID(0); } // We copied bd->pFontTextureView to io.Fonts->TexID so let's clear that as well.
|
||||
if (bd->FontTexture.d3dTexture)
|
||||
{
|
||||
bd->FontTexture.d3dTexture->Release();
|
||||
bd->FontTexture.d3dTexture = nullptr;
|
||||
// We copied bd->FontTexture to io.Fonts->TexID so let's clear that as well.
|
||||
ImGui::GetIO().Fonts->SetTexID(0);
|
||||
}
|
||||
}
|
||||
|
||||
void ImGui_ImplDX9_NewFrame()
|
||||
{
|
||||
ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData();
|
||||
IM_ASSERT(bd != nullptr && "Did you call ImGui_ImplDX9_Init()?");
|
||||
IM_ASSERT(bd != nullptr && "Context or backend not initialized! Did you call ImGui_ImplDX9_Init()?");
|
||||
|
||||
if (!bd->FontTexture)
|
||||
if (!bd->FontTexture.d3dTexture)
|
||||
ImGui_ImplDX9_CreateDeviceObjects();
|
||||
}
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#ifndef IMGUI_DISABLE
|
||||
|
||||
struct IDirect3DDevice9;
|
||||
struct IDirect3DTexture9;
|
||||
|
||||
IMGUI_IMPL_API bool ImGui_ImplDX9_Init(IDirect3DDevice9* device);
|
||||
IMGUI_IMPL_API void ImGui_ImplDX9_Shutdown();
|
||||
|
@ -28,4 +29,11 @@ IMGUI_IMPL_API void ImGui_ImplDX9_RenderDrawData(ImDrawData* draw_data);
|
|||
IMGUI_IMPL_API bool ImGui_ImplDX9_CreateDeviceObjects();
|
||||
IMGUI_IMPL_API void ImGui_ImplDX9_InvalidateDeviceObjects();
|
||||
|
||||
// ImTextureID should be a pointer to this struct
|
||||
struct ImTextureDX9
|
||||
{
|
||||
IDirect3DTexture9 *d3dTexture;
|
||||
bool pointSampling;
|
||||
};
|
||||
|
||||
#endif // #ifndef IMGUI_DISABLE
|
||||
|
|
|
@ -66,9 +66,7 @@
|
|||
#include "TargetConditionals.h"
|
||||
#endif
|
||||
|
||||
#include "wsi/gl_context.h"
|
||||
#include "rend/gles/glcache.h"
|
||||
#include "hw/pvr/Renderer_if.h"
|
||||
|
||||
// OpenGL Data
|
||||
static char g_GlslVersionString[32] = "";
|
||||
|
@ -81,7 +79,6 @@ static unsigned int g_VboHandle = 0, g_ElementsHandle = 0;
|
|||
// Functions
|
||||
static bool ImGui_ImplOpenGL3_CreateDeviceObjects();
|
||||
static void ImGui_ImplOpenGL3_DestroyDeviceObjects();
|
||||
static void ImGui_ImplOpenGL3_DrawBackground();
|
||||
|
||||
bool ImGui_ImplOpenGL3_Init()
|
||||
{
|
||||
|
@ -114,7 +111,6 @@ void ImGui_ImplOpenGL3_NewFrame()
|
|||
{
|
||||
if (!g_FontTexture)
|
||||
ImGui_ImplOpenGL3_CreateDeviceObjects();
|
||||
ImGui_ImplOpenGL3_DrawBackground();
|
||||
}
|
||||
|
||||
// OpenGL3 Render function.
|
||||
|
@ -489,15 +485,3 @@ static void ImGui_ImplOpenGL3_DestroyDeviceObjects()
|
|||
|
||||
ImGui_ImplOpenGL3_DestroyFontsTexture();
|
||||
}
|
||||
|
||||
static void ImGui_ImplOpenGL3_DrawBackground()
|
||||
{
|
||||
#ifndef TARGET_IPHONE
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
#endif
|
||||
glcache.Disable(GL_SCISSOR_TEST);
|
||||
glcache.ClearColor(0, 0, 0, 0);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
if (renderer != nullptr)
|
||||
renderer->RenderLastFrame();
|
||||
}
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
|
||||
// CHANGELOG
|
||||
// (minor and older changes stripped away, please see git history for details)
|
||||
// 2024-04-19: Vulkan: Added convenience support for Volk via IMGUI_IMPL_VULKAN_USE_VOLK define (you can also use IMGUI_IMPL_VULKAN_NO_PROTOTYPES + wrap Volk via ImGui_ImplVulkan_LoadFunctions().)
|
||||
// 2024-02-14: *BREAKING CHANGE*: Moved RenderPass parameter from ImGui_ImplVulkan_Init() function to ImGui_ImplVulkan_InitInfo structure. Not required when using dynamic rendering.
|
||||
// 2024-02-12: *BREAKING CHANGE*: Dynamic rendering now require filling PipelineRenderingCreateInfo structure.
|
||||
// 2024-01-19: Vulkan: Fixed vkAcquireNextImageKHR() validation errors in VulkanSDK 1.3.275 by allocating one extra semaphore than in-flight frames. (#7236)
|
||||
|
@ -108,12 +109,13 @@ void ImGui_ImplVulkanH_CreateWindowCommandBuffers(VkPhysicalDevice physical_devi
|
|||
|
||||
// Vulkan prototypes for use with custom loaders
|
||||
// (see description of IMGUI_IMPL_VULKAN_NO_PROTOTYPES in imgui_impl_vulkan.h
|
||||
#ifdef VK_NO_PROTOTYPES
|
||||
#if defined(VK_NO_PROTOTYPES) && !defined(VOLK_H_)
|
||||
#define IMGUI_IMPL_VULKAN_USE_LOADER
|
||||
static bool g_FunctionsLoaded = false;
|
||||
#else
|
||||
static bool g_FunctionsLoaded = true;
|
||||
#endif
|
||||
#ifdef VK_NO_PROTOTYPES
|
||||
#ifdef IMGUI_IMPL_VULKAN_USE_LOADER
|
||||
#define IMGUI_VULKAN_FUNC_MAP(IMGUI_VULKAN_FUNC_MAP_MACRO) \
|
||||
IMGUI_VULKAN_FUNC_MAP_MACRO(vkAllocateCommandBuffers) \
|
||||
IMGUI_VULKAN_FUNC_MAP_MACRO(vkAllocateDescriptorSets) \
|
||||
|
@ -184,7 +186,7 @@ static bool g_FunctionsLoaded = true;
|
|||
#define IMGUI_VULKAN_FUNC_DEF(func) static PFN_##func func;
|
||||
IMGUI_VULKAN_FUNC_MAP(IMGUI_VULKAN_FUNC_DEF)
|
||||
#undef IMGUI_VULKAN_FUNC_DEF
|
||||
#endif // VK_NO_PROTOTYPES
|
||||
#endif // IMGUI_IMPL_VULKAN_USE_LOADER
|
||||
|
||||
#ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING
|
||||
static PFN_vkCmdBeginRenderingKHR ImGuiImplVulkanFuncs_vkCmdBeginRenderingKHR;
|
||||
|
@ -1048,8 +1050,8 @@ bool ImGui_ImplVulkan_LoadFunctions(PFN_vkVoidFunction(*loader_func)(const ch
|
|||
// Load function pointers
|
||||
// You can use the default Vulkan loader using:
|
||||
// ImGui_ImplVulkan_LoadFunctions([](const char* function_name, void*) { return vkGetInstanceProcAddr(your_vk_isntance, function_name); });
|
||||
// But this would be equivalent to not setting VK_NO_PROTOTYPES.
|
||||
#ifdef VK_NO_PROTOTYPES
|
||||
// But this would be roughly equivalent to not setting VK_NO_PROTOTYPES.
|
||||
#ifdef IMGUI_IMPL_VULKAN_USE_LOADER
|
||||
#define IMGUI_VULKAN_FUNC_LOAD(func) \
|
||||
func = reinterpret_cast<decltype(func)>(loader_func(#func, user_data)); \
|
||||
if (func == nullptr) \
|
||||
|
@ -1078,7 +1080,7 @@ bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info)
|
|||
if (info->UseDynamicRendering)
|
||||
{
|
||||
#ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING
|
||||
#ifndef VK_NO_PROTOTYPES
|
||||
#ifndef IMGUI_IMPL_VULKAN_USE_LOADER
|
||||
ImGuiImplVulkanFuncs_vkCmdBeginRenderingKHR = reinterpret_cast<PFN_vkCmdBeginRenderingKHR>(vkGetInstanceProcAddr(info->Instance, "vkCmdBeginRenderingKHR"));
|
||||
ImGuiImplVulkanFuncs_vkCmdEndRenderingKHR = reinterpret_cast<PFN_vkCmdEndRenderingKHR>(vkGetInstanceProcAddr(info->Instance, "vkCmdEndRenderingKHR"));
|
||||
#endif
|
||||
|
@ -1131,7 +1133,7 @@ void ImGui_ImplVulkan_Shutdown()
|
|||
void ImGui_ImplVulkan_NewFrame()
|
||||
{
|
||||
ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData();
|
||||
IM_ASSERT(bd != nullptr && "Did you call ImGui_ImplVulkan_Init()?");
|
||||
IM_ASSERT(bd != nullptr && "Context or backend not initialized! Did you call ImGui_ImplVulkan_Init()?");
|
||||
|
||||
if (!bd->FontDescriptorSet)
|
||||
ImGui_ImplVulkan_CreateFontsTexture();
|
||||
|
|
|
@ -42,13 +42,20 @@
|
|||
// If you have no idea what this is, leave it alone!
|
||||
//#define IMGUI_IMPL_VULKAN_NO_PROTOTYPES
|
||||
|
||||
// Vulkan includes
|
||||
// Convenience support for Volk
|
||||
// (you can also technically use IMGUI_IMPL_VULKAN_NO_PROTOTYPES + wrap Volk via ImGui_ImplVulkan_LoadFunctions().)
|
||||
//#define IMGUI_IMPL_VULKAN_USE_VOLK
|
||||
|
||||
#if defined(IMGUI_IMPL_VULKAN_NO_PROTOTYPES) && !defined(VK_NO_PROTOTYPES)
|
||||
#define VK_NO_PROTOTYPES
|
||||
#endif
|
||||
#if defined(VK_USE_PLATFORM_WIN32_KHR) && !defined(NOMINMAX)
|
||||
#define NOMINMAX
|
||||
#include <vulkan/vulkan.h>
|
||||
#endif
|
||||
|
||||
// Vulkan includes
|
||||
#ifdef IMGUI_IMPL_VULKAN_USE_VOLK
|
||||
#include <Volk/volk.h>
|
||||
#else
|
||||
#include <vulkan/vulkan.h>
|
||||
#endif
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// dear imgui, v1.90.4
|
||||
// dear imgui, v1.90.6
|
||||
// (main code and documentation)
|
||||
|
||||
// Help:
|
||||
|
@ -7,15 +7,19 @@
|
|||
// - Read top of imgui.cpp for more details, links and comments.
|
||||
|
||||
// Resources:
|
||||
// - FAQ https://dearimgui.com/faq
|
||||
// - Getting Started https://dearimgui.com/getting-started
|
||||
// - Homepage https://github.com/ocornut/imgui
|
||||
// - Releases & changelog https://github.com/ocornut/imgui/releases
|
||||
// - Gallery https://github.com/ocornut/imgui/issues/6897 (please post your screenshots/video there!)
|
||||
// - Wiki https://github.com/ocornut/imgui/wiki (lots of good stuff there)
|
||||
// - Glossary https://github.com/ocornut/imgui/wiki/Glossary
|
||||
// - Issues & support https://github.com/ocornut/imgui/issues
|
||||
// - Tests & Automation https://github.com/ocornut/imgui_test_engine
|
||||
// - FAQ ........................ https://dearimgui.com/faq (in repository as docs/FAQ.md)
|
||||
// - Homepage ................... https://github.com/ocornut/imgui
|
||||
// - Releases & changelog ....... https://github.com/ocornut/imgui/releases
|
||||
// - Gallery .................... https://github.com/ocornut/imgui/issues/7503 (please post your screenshots/video there!)
|
||||
// - Wiki ....................... https://github.com/ocornut/imgui/wiki (lots of good stuff there)
|
||||
// - Getting Started https://github.com/ocornut/imgui/wiki/Getting-Started (how to integrate in an existing app by adding ~25 lines of code)
|
||||
// - Third-party Extensions https://github.com/ocornut/imgui/wiki/Useful-Extensions (ImPlot & many more)
|
||||
// - Bindings/Backends https://github.com/ocornut/imgui/wiki/Bindings (language bindings, backends for various tech/engines)
|
||||
// - Glossary https://github.com/ocornut/imgui/wiki/Glossary
|
||||
// - Debug Tools https://github.com/ocornut/imgui/wiki/Debug-Tools
|
||||
// - Software using Dear ImGui https://github.com/ocornut/imgui/wiki/Software-using-dear-imgui
|
||||
// - Issues & support ........... https://github.com/ocornut/imgui/issues
|
||||
// - Test Engine & Automation ... https://github.com/ocornut/imgui_test_engine (test suite, test engine to automate your apps)
|
||||
|
||||
// For first-time users having issues compiling/linking/running/loading fonts:
|
||||
// please post in https://github.com/ocornut/imgui/discussions if you cannot find a solution in resources above.
|
||||
|
@ -26,7 +30,7 @@
|
|||
// See LICENSE.txt for copyright and licensing details (standard MIT License).
|
||||
// This library is free but needs your support to sustain development and maintenance.
|
||||
// Businesses: you can support continued development via B2B invoiced technical support, maintenance and sponsoring contracts.
|
||||
// PLEASE reach out at omar AT dearimgui DOT com. See https://github.com/ocornut/imgui/wiki/Sponsors
|
||||
// PLEASE reach out at omar AT dearimgui DOT com. See https://github.com/ocornut/imgui/wiki/Funding
|
||||
// Businesses: you can also purchase licenses for the Dear ImGui Automation/Test Engine.
|
||||
|
||||
// It is recommended that you don't modify imgui.cpp! It will become difficult for you to update the library.
|
||||
|
@ -73,6 +77,7 @@ CODE
|
|||
// [SECTION] RENDER HELPERS
|
||||
// [SECTION] INITIALIZATION, SHUTDOWN
|
||||
// [SECTION] MAIN CODE (most of the code! lots of stuff, needs tidying up!)
|
||||
// [SECTION] ID STACK
|
||||
// [SECTION] INPUTS
|
||||
// [SECTION] ERROR CHECKING
|
||||
// [SECTION] ITEM SUBMISSION
|
||||
|
@ -425,6 +430,15 @@ CODE
|
|||
When you are not sure about an old symbol or function name, try using the Search/Find function of your IDE to look for comments or references in all imgui files.
|
||||
You can read releases logs https://github.com/ocornut/imgui/releases for more details.
|
||||
|
||||
- 2024/04/18 (1.90.6) - TreeNode: Fixed a layout inconsistency when using an empty/hidden label followed by a SameLine() call. (#7505, #282)
|
||||
- old: TreeNode("##Hidden"); SameLine(); Text("Hello"); // <-- This was actually incorrect! BUT appeared to look ok with the default style where ItemSpacing.x == FramePadding.x * 2 (it didn't look aligned otherwise).
|
||||
- new: TreeNode("##Hidden"); SameLine(0, 0); Text("Hello"); // <-- This is correct for all styles values.
|
||||
with the fix, IF you were successfully using TreeNode("")+SameLine(); you will now have extra spacing between your TreeNode and the following item.
|
||||
You'll need to change the SameLine() call to SameLine(0,0) to remove this extraneous spacing. This seemed like the more sensible fix that's not making things less consistent.
|
||||
(Note: when using this idiom you are likely to also use ImGuiTreeNodeFlags_SpanAvailWidth).
|
||||
- 2024/03/18 (1.90.5) - merged the radius_x/radius_y parameters in ImDrawList::AddEllipse(), AddEllipseFilled() and PathEllipticalArcTo() into a single ImVec2 parameter. Exceptionally, because those functions were added in 1.90, we are not adding inline redirection functions. The transition is easy and should affect few users. (#2743, #7417)
|
||||
- 2024/03/08 (1.90.5) - inputs: more formally obsoleted GetKeyIndex() when IMGUI_DISABLE_OBSOLETE_FUNCTIONS is set. It has been unnecessary and a no-op since 1.87 (it returns the same value as passed when used with a 1.87+ backend using io.AddKeyEvent() function). (#4921)
|
||||
- IsKeyPressed(GetKeyIndex(ImGuiKey_XXX)) -> use IsKeyPressed(ImGuiKey_XXX)
|
||||
- 2024/01/15 (1.90.2) - commented out obsolete ImGuiIO::ImeWindowHandle marked obsolete in 1.87, favor of writing to 'void* ImGuiViewport::PlatformHandleRaw'.
|
||||
- 2023/12/19 (1.90.1) - commented out obsolete ImGuiKey_KeyPadEnter redirection to ImGuiKey_KeypadEnter.
|
||||
- 2023/11/06 (1.90.1) - removed CalcListClipping() marked obsolete in 1.86. Prefer using ImGuiListClipper which can return non-contiguous ranges.
|
||||
|
@ -935,7 +949,7 @@ CODE
|
|||
A: - Businesses: please reach out to "omar AT dearimgui DOT com" if you work in a place using Dear ImGui!
|
||||
We can discuss ways for your company to fund development via invoiced technical support, maintenance or sponsoring contacts.
|
||||
This is among the most useful thing you can do for Dear ImGui. With increased funding, we sustain and grow work on this project.
|
||||
Also see https://github.com/ocornut/imgui/wiki/Sponsors
|
||||
>>> See https://github.com/ocornut/imgui/wiki/Funding
|
||||
- Businesses: you can also purchase licenses for the Dear ImGui Automation/Test Engine.
|
||||
- If you are experienced with Dear ImGui and C++, look at the GitHub issues, look at the Wiki, and see how you want to help and can help!
|
||||
- Disclose your usage of Dear ImGui via a dev blog post, a tweet, a screenshot, a mention somewhere etc.
|
||||
|
@ -1026,6 +1040,7 @@ CODE
|
|||
#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" // warning: zero as null pointer constant // some standard header variations use #define NULL 0
|
||||
#pragma clang diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function // using printf() is a misery with this as C++ va_arg ellipsis changes float to double.
|
||||
#pragma clang diagnostic ignored "-Wimplicit-int-float-conversion" // warning: implicit conversion from 'xxx' to 'float' may lose precision
|
||||
#pragma clang diagnostic ignored "-Wunsafe-buffer-usage" // warning: 'xxx' is an unsafe pointer used for buffer access
|
||||
#elif defined(__GNUC__)
|
||||
// We disable -Wpragmas because GCC doesn't provide a has_warning equivalent and some forks/patches may not follow the warning/version association.
|
||||
#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind
|
||||
|
@ -1124,6 +1139,7 @@ static void RenderWindowDecorations(ImGuiWindow* window, const ImRec
|
|||
static void RenderWindowTitleBarContents(ImGuiWindow* window, const ImRect& title_bar_rect, const char* name, bool* p_open);
|
||||
static void RenderDimmedBackgroundBehindWindow(ImGuiWindow* window, ImU32 col);
|
||||
static void RenderDimmedBackgrounds();
|
||||
static void SetLastItemDataForWindow(ImGuiWindow* window, const ImRect& rect);
|
||||
|
||||
// Viewports
|
||||
const ImGuiID IMGUI_VIEWPORT_DEFAULT_ID = 0x11111111; // Using an arbitrary constant instead of e.g. ImHashStr("ViewportDefault", 0); so it's easier to spot in the debugger. The exact value doesn't matter.
|
||||
|
@ -1179,58 +1195,59 @@ static void* GImAllocatorUserData = NULL;
|
|||
|
||||
ImGuiStyle::ImGuiStyle()
|
||||
{
|
||||
Alpha = 1.0f; // Global alpha applies to everything in Dear ImGui.
|
||||
DisabledAlpha = 0.60f; // Additional alpha multiplier applied by BeginDisabled(). Multiply over current value of Alpha.
|
||||
WindowPadding = ImVec2(8,8); // Padding within a window
|
||||
WindowRounding = 0.0f; // Radius of window corners rounding. Set to 0.0f to have rectangular windows. Large values tend to lead to variety of artifacts and are not recommended.
|
||||
WindowBorderSize = 1.0f; // Thickness of border around windows. Generally set to 0.0f or 1.0f. Other values not well tested.
|
||||
WindowMinSize = ImVec2(32,32); // Minimum window size
|
||||
WindowTitleAlign = ImVec2(0.0f,0.5f);// Alignment for title bar text
|
||||
WindowMenuButtonPosition= ImGuiDir_Left; // Position of the collapsing/docking button in the title bar (left/right). Defaults to ImGuiDir_Left.
|
||||
ChildRounding = 0.0f; // Radius of child window corners rounding. Set to 0.0f to have rectangular child windows
|
||||
ChildBorderSize = 1.0f; // Thickness of border around child windows. Generally set to 0.0f or 1.0f. Other values not well tested.
|
||||
PopupRounding = 0.0f; // Radius of popup window corners rounding. Set to 0.0f to have rectangular child windows
|
||||
PopupBorderSize = 1.0f; // Thickness of border around popup or tooltip windows. Generally set to 0.0f or 1.0f. Other values not well tested.
|
||||
FramePadding = ImVec2(4,3); // Padding within a framed rectangle (used by most widgets)
|
||||
FrameRounding = 0.0f; // Radius of frame corners rounding. Set to 0.0f to have rectangular frames (used by most widgets).
|
||||
FrameBorderSize = 0.0f; // Thickness of border around frames. Generally set to 0.0f or 1.0f. Other values not well tested.
|
||||
ItemSpacing = ImVec2(8,4); // Horizontal and vertical spacing between widgets/lines
|
||||
ItemInnerSpacing = ImVec2(4,4); // Horizontal and vertical spacing between within elements of a composed widget (e.g. a slider and its label)
|
||||
CellPadding = ImVec2(4,2); // Padding within a table cell. CellPadding.y may be altered between different rows.
|
||||
TouchExtraPadding = ImVec2(0,0); // Expand reactive bounding box for touch-based system where touch position is not accurate enough. Unfortunately we don't sort widgets so priority on overlap will always be given to the first widget. So don't grow this too much!
|
||||
IndentSpacing = 21.0f; // Horizontal spacing when e.g. entering a tree node. Generally == (FontSize + FramePadding.x*2).
|
||||
ColumnsMinSpacing = 6.0f; // Minimum horizontal spacing between two columns. Preferably > (FramePadding.x + 1).
|
||||
ScrollbarSize = 14.0f; // Width of the vertical scrollbar, Height of the horizontal scrollbar
|
||||
ScrollbarRounding = 9.0f; // Radius of grab corners rounding for scrollbar
|
||||
GrabMinSize = 12.0f; // Minimum width/height of a grab box for slider/scrollbar
|
||||
GrabRounding = 0.0f; // Radius of grabs corners rounding. Set to 0.0f to have rectangular slider grabs.
|
||||
LogSliderDeadzone = 4.0f; // The size in pixels of the dead-zone around zero on logarithmic sliders that cross zero.
|
||||
TabRounding = 4.0f; // Radius of upper corners of a tab. Set to 0.0f to have rectangular tabs.
|
||||
TabBorderSize = 0.0f; // Thickness of border around tabs.
|
||||
TabMinWidthForCloseButton = 0.0f; // Minimum width for close button to appear on an unselected tab when hovered. Set to 0.0f to always show when hovering, set to FLT_MAX to never show close button unless selected.
|
||||
TabBarBorderSize = 1.0f; // Thickness of tab-bar separator, which takes on the tab active color to denote focus.
|
||||
TableAngledHeadersAngle = 35.0f * (IM_PI / 180.0f); // Angle of angled headers (supported values range from -50 degrees to +50 degrees).
|
||||
ColorButtonPosition = ImGuiDir_Right; // Side of the color button in the ColorEdit4 widget (left/right). Defaults to ImGuiDir_Right.
|
||||
ButtonTextAlign = ImVec2(0.5f,0.5f);// Alignment of button text when button is larger than text.
|
||||
SelectableTextAlign = ImVec2(0.0f,0.0f);// Alignment of selectable text. Defaults to (0.0f, 0.0f) (top-left aligned). It's generally important to keep this left-aligned if you want to lay multiple items on a same line.
|
||||
SeparatorTextBorderSize = 3.0f; // Thickkness of border in SeparatorText()
|
||||
SeparatorTextAlign = ImVec2(0.0f,0.5f);// Alignment of text within the separator. Defaults to (0.0f, 0.5f) (left aligned, center).
|
||||
SeparatorTextPadding = ImVec2(20.0f,3.f);// Horizontal offset of text from each edge of the separator + spacing on other axis. Generally small values. .y is recommended to be == FramePadding.y.
|
||||
DisplayWindowPadding = ImVec2(19,19); // Window position are clamped to be visible within the display area or monitors by at least this amount. Only applies to regular windows.
|
||||
DisplaySafeAreaPadding = ImVec2(3,3); // If you cannot see the edge of your screen (e.g. on a TV) increase the safe area padding. Covers popups/tooltips as well regular windows.
|
||||
MouseCursorScale = 1.0f; // Scale software rendered mouse cursor (when io.MouseDrawCursor is enabled). May be removed later.
|
||||
AntiAliasedLines = true; // Enable anti-aliased lines/borders. Disable if you are really tight on CPU/GPU.
|
||||
AntiAliasedLinesUseTex = true; // Enable anti-aliased lines/borders using textures where possible. Require backend to render with bilinear filtering (NOT point/nearest filtering).
|
||||
AntiAliasedFill = true; // Enable anti-aliased filled shapes (rounded rectangles, circles, etc.).
|
||||
CurveTessellationTol = 1.25f; // Tessellation tolerance when using PathBezierCurveTo() without a specific number of segments. Decrease for highly tessellated curves (higher quality, more polygons), increase to reduce quality.
|
||||
CircleTessellationMaxError = 0.30f; // Maximum error (in pixels) allowed when using AddCircle()/AddCircleFilled() or drawing rounded corner rectangles with no explicit segment count specified. Decrease for higher quality but more geometry.
|
||||
Alpha = 1.0f; // Global alpha applies to everything in Dear ImGui.
|
||||
DisabledAlpha = 0.60f; // Additional alpha multiplier applied by BeginDisabled(). Multiply over current value of Alpha.
|
||||
WindowPadding = ImVec2(8,8); // Padding within a window
|
||||
WindowRounding = 0.0f; // Radius of window corners rounding. Set to 0.0f to have rectangular windows. Large values tend to lead to variety of artifacts and are not recommended.
|
||||
WindowBorderSize = 1.0f; // Thickness of border around windows. Generally set to 0.0f or 1.0f. Other values not well tested.
|
||||
WindowMinSize = ImVec2(32,32); // Minimum window size
|
||||
WindowTitleAlign = ImVec2(0.0f,0.5f);// Alignment for title bar text
|
||||
WindowMenuButtonPosition = ImGuiDir_Left; // Position of the collapsing/docking button in the title bar (left/right). Defaults to ImGuiDir_Left.
|
||||
ChildRounding = 0.0f; // Radius of child window corners rounding. Set to 0.0f to have rectangular child windows
|
||||
ChildBorderSize = 1.0f; // Thickness of border around child windows. Generally set to 0.0f or 1.0f. Other values not well tested.
|
||||
PopupRounding = 0.0f; // Radius of popup window corners rounding. Set to 0.0f to have rectangular child windows
|
||||
PopupBorderSize = 1.0f; // Thickness of border around popup or tooltip windows. Generally set to 0.0f or 1.0f. Other values not well tested.
|
||||
FramePadding = ImVec2(4,3); // Padding within a framed rectangle (used by most widgets)
|
||||
FrameRounding = 0.0f; // Radius of frame corners rounding. Set to 0.0f to have rectangular frames (used by most widgets).
|
||||
FrameBorderSize = 0.0f; // Thickness of border around frames. Generally set to 0.0f or 1.0f. Other values not well tested.
|
||||
ItemSpacing = ImVec2(8,4); // Horizontal and vertical spacing between widgets/lines
|
||||
ItemInnerSpacing = ImVec2(4,4); // Horizontal and vertical spacing between within elements of a composed widget (e.g. a slider and its label)
|
||||
CellPadding = ImVec2(4,2); // Padding within a table cell. Cellpadding.x is locked for entire table. CellPadding.y may be altered between different rows.
|
||||
TouchExtraPadding = ImVec2(0,0); // Expand reactive bounding box for touch-based system where touch position is not accurate enough. Unfortunately we don't sort widgets so priority on overlap will always be given to the first widget. So don't grow this too much!
|
||||
IndentSpacing = 21.0f; // Horizontal spacing when e.g. entering a tree node. Generally == (FontSize + FramePadding.x*2).
|
||||
ColumnsMinSpacing = 6.0f; // Minimum horizontal spacing between two columns. Preferably > (FramePadding.x + 1).
|
||||
ScrollbarSize = 14.0f; // Width of the vertical scrollbar, Height of the horizontal scrollbar
|
||||
ScrollbarRounding = 9.0f; // Radius of grab corners rounding for scrollbar
|
||||
GrabMinSize = 12.0f; // Minimum width/height of a grab box for slider/scrollbar
|
||||
GrabRounding = 0.0f; // Radius of grabs corners rounding. Set to 0.0f to have rectangular slider grabs.
|
||||
LogSliderDeadzone = 4.0f; // The size in pixels of the dead-zone around zero on logarithmic sliders that cross zero.
|
||||
TabRounding = 4.0f; // Radius of upper corners of a tab. Set to 0.0f to have rectangular tabs.
|
||||
TabBorderSize = 0.0f; // Thickness of border around tabs.
|
||||
TabMinWidthForCloseButton = 0.0f; // Minimum width for close button to appear on an unselected tab when hovered. Set to 0.0f to always show when hovering, set to FLT_MAX to never show close button unless selected.
|
||||
TabBarBorderSize = 1.0f; // Thickness of tab-bar separator, which takes on the tab active color to denote focus.
|
||||
TableAngledHeadersAngle = 35.0f * (IM_PI / 180.0f); // Angle of angled headers (supported values range from -50 degrees to +50 degrees).
|
||||
TableAngledHeadersTextAlign = ImVec2(0.5f,0.0f);// Alignment of angled headers within the cell
|
||||
ColorButtonPosition = ImGuiDir_Right; // Side of the color button in the ColorEdit4 widget (left/right). Defaults to ImGuiDir_Right.
|
||||
ButtonTextAlign = ImVec2(0.5f,0.5f);// Alignment of button text when button is larger than text.
|
||||
SelectableTextAlign = ImVec2(0.0f,0.0f);// Alignment of selectable text. Defaults to (0.0f, 0.0f) (top-left aligned). It's generally important to keep this left-aligned if you want to lay multiple items on a same line.
|
||||
SeparatorTextBorderSize = 3.0f; // Thickkness of border in SeparatorText()
|
||||
SeparatorTextAlign = ImVec2(0.0f,0.5f);// Alignment of text within the separator. Defaults to (0.0f, 0.5f) (left aligned, center).
|
||||
SeparatorTextPadding = ImVec2(20.0f,3.f);// Horizontal offset of text from each edge of the separator + spacing on other axis. Generally small values. .y is recommended to be == FramePadding.y.
|
||||
DisplayWindowPadding = ImVec2(19,19); // Window position are clamped to be visible within the display area or monitors by at least this amount. Only applies to regular windows.
|
||||
DisplaySafeAreaPadding = ImVec2(3,3); // If you cannot see the edge of your screen (e.g. on a TV) increase the safe area padding. Covers popups/tooltips as well regular windows.
|
||||
MouseCursorScale = 1.0f; // Scale software rendered mouse cursor (when io.MouseDrawCursor is enabled). May be removed later.
|
||||
AntiAliasedLines = true; // Enable anti-aliased lines/borders. Disable if you are really tight on CPU/GPU.
|
||||
AntiAliasedLinesUseTex = true; // Enable anti-aliased lines/borders using textures where possible. Require backend to render with bilinear filtering (NOT point/nearest filtering).
|
||||
AntiAliasedFill = true; // Enable anti-aliased filled shapes (rounded rectangles, circles, etc.).
|
||||
CurveTessellationTol = 1.25f; // Tessellation tolerance when using PathBezierCurveTo() without a specific number of segments. Decrease for highly tessellated curves (higher quality, more polygons), increase to reduce quality.
|
||||
CircleTessellationMaxError = 0.30f; // Maximum error (in pixels) allowed when using AddCircle()/AddCircleFilled() or drawing rounded corner rectangles with no explicit segment count specified. Decrease for higher quality but more geometry.
|
||||
|
||||
// Behaviors
|
||||
HoverStationaryDelay = 0.15f; // Delay for IsItemHovered(ImGuiHoveredFlags_Stationary). Time required to consider mouse stationary.
|
||||
HoverDelayShort = 0.15f; // Delay for IsItemHovered(ImGuiHoveredFlags_DelayShort). Usually used along with HoverStationaryDelay.
|
||||
HoverDelayNormal = 0.40f; // Delay for IsItemHovered(ImGuiHoveredFlags_DelayNormal). "
|
||||
HoverFlagsForTooltipMouse = ImGuiHoveredFlags_Stationary | ImGuiHoveredFlags_DelayShort | ImGuiHoveredFlags_AllowWhenDisabled; // Default flags when using IsItemHovered(ImGuiHoveredFlags_ForTooltip) or BeginItemTooltip()/SetItemTooltip() while using mouse.
|
||||
HoverFlagsForTooltipNav = ImGuiHoveredFlags_NoSharedDelay | ImGuiHoveredFlags_DelayNormal | ImGuiHoveredFlags_AllowWhenDisabled; // Default flags when using IsItemHovered(ImGuiHoveredFlags_ForTooltip) or BeginItemTooltip()/SetItemTooltip() while using keyboard/gamepad.
|
||||
HoverStationaryDelay = 0.15f; // Delay for IsItemHovered(ImGuiHoveredFlags_Stationary). Time required to consider mouse stationary.
|
||||
HoverDelayShort = 0.15f; // Delay for IsItemHovered(ImGuiHoveredFlags_DelayShort). Usually used along with HoverStationaryDelay.
|
||||
HoverDelayNormal = 0.40f; // Delay for IsItemHovered(ImGuiHoveredFlags_DelayNormal). "
|
||||
HoverFlagsForTooltipMouse = ImGuiHoveredFlags_Stationary | ImGuiHoveredFlags_DelayShort | ImGuiHoveredFlags_AllowWhenDisabled; // Default flags when using IsItemHovered(ImGuiHoveredFlags_ForTooltip) or BeginItemTooltip()/SetItemTooltip() while using mouse.
|
||||
HoverFlagsForTooltipNav = ImGuiHoveredFlags_NoSharedDelay | ImGuiHoveredFlags_DelayNormal | ImGuiHoveredFlags_AllowWhenDisabled; // Default flags when using IsItemHovered(ImGuiHoveredFlags_ForTooltip) or BeginItemTooltip()/SetItemTooltip() while using keyboard/gamepad.
|
||||
|
||||
// Default theme
|
||||
ImGui::StyleColorsDark(this);
|
||||
|
@ -2318,6 +2335,20 @@ const char* ImTextFindPreviousUtf8Codepoint(const char* in_text_start, const cha
|
|||
return in_text_start;
|
||||
}
|
||||
|
||||
int ImTextCountLines(const char* in_text, const char* in_text_end)
|
||||
{
|
||||
if (in_text_end == NULL)
|
||||
in_text_end = in_text + strlen(in_text); // FIXME-OPT: Not optimal approach, discourage use for now.
|
||||
int count = 0;
|
||||
while (in_text < in_text_end)
|
||||
{
|
||||
const char* line_end = (const char*)memchr(in_text, '\n', in_text_end - in_text);
|
||||
in_text = line_end ? line_end + 1 : in_text_end;
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
IM_MSVC_RUNTIME_CHECKS_RESTORE
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -3100,35 +3131,38 @@ void ImGui::PopStyleColor(int count)
|
|||
|
||||
static const ImGuiDataVarInfo GStyleVarInfo[] =
|
||||
{
|
||||
{ ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, Alpha) }, // ImGuiStyleVar_Alpha
|
||||
{ ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, DisabledAlpha) }, // ImGuiStyleVar_DisabledAlpha
|
||||
{ ImGuiDataType_Float, 2, (ImU32)offsetof(ImGuiStyle, WindowPadding) }, // ImGuiStyleVar_WindowPadding
|
||||
{ ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, WindowRounding) }, // ImGuiStyleVar_WindowRounding
|
||||
{ ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, WindowBorderSize) }, // ImGuiStyleVar_WindowBorderSize
|
||||
{ ImGuiDataType_Float, 2, (ImU32)offsetof(ImGuiStyle, WindowMinSize) }, // ImGuiStyleVar_WindowMinSize
|
||||
{ ImGuiDataType_Float, 2, (ImU32)offsetof(ImGuiStyle, WindowTitleAlign) }, // ImGuiStyleVar_WindowTitleAlign
|
||||
{ ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, ChildRounding) }, // ImGuiStyleVar_ChildRounding
|
||||
{ ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, ChildBorderSize) }, // ImGuiStyleVar_ChildBorderSize
|
||||
{ ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, PopupRounding) }, // ImGuiStyleVar_PopupRounding
|
||||
{ ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, PopupBorderSize) }, // ImGuiStyleVar_PopupBorderSize
|
||||
{ ImGuiDataType_Float, 2, (ImU32)offsetof(ImGuiStyle, FramePadding) }, // ImGuiStyleVar_FramePadding
|
||||
{ ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, FrameRounding) }, // ImGuiStyleVar_FrameRounding
|
||||
{ ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, FrameBorderSize) }, // ImGuiStyleVar_FrameBorderSize
|
||||
{ ImGuiDataType_Float, 2, (ImU32)offsetof(ImGuiStyle, ItemSpacing) }, // ImGuiStyleVar_ItemSpacing
|
||||
{ ImGuiDataType_Float, 2, (ImU32)offsetof(ImGuiStyle, ItemInnerSpacing) }, // ImGuiStyleVar_ItemInnerSpacing
|
||||
{ ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, IndentSpacing) }, // ImGuiStyleVar_IndentSpacing
|
||||
{ ImGuiDataType_Float, 2, (ImU32)offsetof(ImGuiStyle, CellPadding) }, // ImGuiStyleVar_CellPadding
|
||||
{ ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, ScrollbarSize) }, // ImGuiStyleVar_ScrollbarSize
|
||||
{ ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, ScrollbarRounding) }, // ImGuiStyleVar_ScrollbarRounding
|
||||
{ ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, GrabMinSize) }, // ImGuiStyleVar_GrabMinSize
|
||||
{ ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, GrabRounding) }, // ImGuiStyleVar_GrabRounding
|
||||
{ ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, TabRounding) }, // ImGuiStyleVar_TabRounding
|
||||
{ ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, TabBarBorderSize) }, // ImGuiStyleVar_TabBarBorderSize
|
||||
{ ImGuiDataType_Float, 2, (ImU32)offsetof(ImGuiStyle, ButtonTextAlign) }, // ImGuiStyleVar_ButtonTextAlign
|
||||
{ ImGuiDataType_Float, 2, (ImU32)offsetof(ImGuiStyle, SelectableTextAlign) }, // ImGuiStyleVar_SelectableTextAlign
|
||||
{ ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, SeparatorTextBorderSize)},// ImGuiStyleVar_SeparatorTextBorderSize
|
||||
{ ImGuiDataType_Float, 2, (ImU32)offsetof(ImGuiStyle, SeparatorTextAlign) }, // ImGuiStyleVar_SeparatorTextAlign
|
||||
{ ImGuiDataType_Float, 2, (ImU32)offsetof(ImGuiStyle, SeparatorTextPadding) }, // ImGuiStyleVar_SeparatorTextPadding
|
||||
{ ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, Alpha) }, // ImGuiStyleVar_Alpha
|
||||
{ ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, DisabledAlpha) }, // ImGuiStyleVar_DisabledAlpha
|
||||
{ ImGuiDataType_Float, 2, (ImU32)offsetof(ImGuiStyle, WindowPadding) }, // ImGuiStyleVar_WindowPadding
|
||||
{ ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, WindowRounding) }, // ImGuiStyleVar_WindowRounding
|
||||
{ ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, WindowBorderSize) }, // ImGuiStyleVar_WindowBorderSize
|
||||
{ ImGuiDataType_Float, 2, (ImU32)offsetof(ImGuiStyle, WindowMinSize) }, // ImGuiStyleVar_WindowMinSize
|
||||
{ ImGuiDataType_Float, 2, (ImU32)offsetof(ImGuiStyle, WindowTitleAlign) }, // ImGuiStyleVar_WindowTitleAlign
|
||||
{ ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, ChildRounding) }, // ImGuiStyleVar_ChildRounding
|
||||
{ ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, ChildBorderSize) }, // ImGuiStyleVar_ChildBorderSize
|
||||
{ ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, PopupRounding) }, // ImGuiStyleVar_PopupRounding
|
||||
{ ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, PopupBorderSize) }, // ImGuiStyleVar_PopupBorderSize
|
||||
{ ImGuiDataType_Float, 2, (ImU32)offsetof(ImGuiStyle, FramePadding) }, // ImGuiStyleVar_FramePadding
|
||||
{ ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, FrameRounding) }, // ImGuiStyleVar_FrameRounding
|
||||
{ ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, FrameBorderSize) }, // ImGuiStyleVar_FrameBorderSize
|
||||
{ ImGuiDataType_Float, 2, (ImU32)offsetof(ImGuiStyle, ItemSpacing) }, // ImGuiStyleVar_ItemSpacing
|
||||
{ ImGuiDataType_Float, 2, (ImU32)offsetof(ImGuiStyle, ItemInnerSpacing) }, // ImGuiStyleVar_ItemInnerSpacing
|
||||
{ ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, IndentSpacing) }, // ImGuiStyleVar_IndentSpacing
|
||||
{ ImGuiDataType_Float, 2, (ImU32)offsetof(ImGuiStyle, CellPadding) }, // ImGuiStyleVar_CellPadding
|
||||
{ ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, ScrollbarSize) }, // ImGuiStyleVar_ScrollbarSize
|
||||
{ ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, ScrollbarRounding) }, // ImGuiStyleVar_ScrollbarRounding
|
||||
{ ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, GrabMinSize) }, // ImGuiStyleVar_GrabMinSize
|
||||
{ ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, GrabRounding) }, // ImGuiStyleVar_GrabRounding
|
||||
{ ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, TabRounding) }, // ImGuiStyleVar_TabRounding
|
||||
{ ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, TabBorderSize) }, // ImGuiStyleVar_TabBorderSize
|
||||
{ ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, TabBarBorderSize) }, // ImGuiStyleVar_TabBarBorderSize
|
||||
{ ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, TableAngledHeadersAngle)}, // ImGuiStyleVar_TableAngledHeadersAngle
|
||||
{ ImGuiDataType_Float, 2, (ImU32)offsetof(ImGuiStyle, TableAngledHeadersTextAlign)},// ImGuiStyleVar_TableAngledHeadersTextAlign
|
||||
{ ImGuiDataType_Float, 2, (ImU32)offsetof(ImGuiStyle, ButtonTextAlign) }, // ImGuiStyleVar_ButtonTextAlign
|
||||
{ ImGuiDataType_Float, 2, (ImU32)offsetof(ImGuiStyle, SelectableTextAlign) }, // ImGuiStyleVar_SelectableTextAlign
|
||||
{ ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, SeparatorTextBorderSize)}, // ImGuiStyleVar_SeparatorTextBorderSize
|
||||
{ ImGuiDataType_Float, 2, (ImU32)offsetof(ImGuiStyle, SeparatorTextAlign) }, // ImGuiStyleVar_SeparatorTextAlign
|
||||
{ ImGuiDataType_Float, 2, (ImU32)offsetof(ImGuiStyle, SeparatorTextPadding) }, // ImGuiStyleVar_SeparatorTextPadding
|
||||
};
|
||||
|
||||
const ImGuiDataVarInfo* ImGui::GetStyleVarInfo(ImGuiStyleVar idx)
|
||||
|
@ -3773,45 +3807,6 @@ ImGuiWindow::~ImGuiWindow()
|
|||
ColumnsStorage.clear_destruct();
|
||||
}
|
||||
|
||||
ImGuiID ImGuiWindow::GetID(const char* str, const char* str_end)
|
||||
{
|
||||
ImGuiID seed = IDStack.back();
|
||||
ImGuiID id = ImHashStr(str, str_end ? (str_end - str) : 0, seed);
|
||||
ImGuiContext& g = *Ctx;
|
||||
if (g.DebugHookIdInfo == id)
|
||||
ImGui::DebugHookIdInfo(id, ImGuiDataType_String, str, str_end);
|
||||
return id;
|
||||
}
|
||||
|
||||
ImGuiID ImGuiWindow::GetID(const void* ptr)
|
||||
{
|
||||
ImGuiID seed = IDStack.back();
|
||||
ImGuiID id = ImHashData(&ptr, sizeof(void*), seed);
|
||||
ImGuiContext& g = *Ctx;
|
||||
if (g.DebugHookIdInfo == id)
|
||||
ImGui::DebugHookIdInfo(id, ImGuiDataType_Pointer, ptr, NULL);
|
||||
return id;
|
||||
}
|
||||
|
||||
ImGuiID ImGuiWindow::GetID(int n)
|
||||
{
|
||||
ImGuiID seed = IDStack.back();
|
||||
ImGuiID id = ImHashData(&n, sizeof(n), seed);
|
||||
ImGuiContext& g = *Ctx;
|
||||
if (g.DebugHookIdInfo == id)
|
||||
ImGui::DebugHookIdInfo(id, ImGuiDataType_S32, (void*)(intptr_t)n, NULL);
|
||||
return id;
|
||||
}
|
||||
|
||||
// This is only used in rare/specific situations to manufacture an ID out of nowhere.
|
||||
ImGuiID ImGuiWindow::GetIDFromRectangle(const ImRect& r_abs)
|
||||
{
|
||||
ImGuiID seed = IDStack.back();
|
||||
ImRect r_rel = ImGui::WindowRectAbsToRel(this, r_abs);
|
||||
ImGuiID id = ImHashData(&r_rel, sizeof(r_rel), seed);
|
||||
return id;
|
||||
}
|
||||
|
||||
static void SetCurrentWindow(ImGuiWindow* window)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
|
@ -4554,6 +4549,27 @@ void ImGui::UpdateHoveredWindowAndCaptureFlags()
|
|||
io.WantTextInput = (g.WantTextInputNextFrame != -1) ? (g.WantTextInputNextFrame != 0) : false;
|
||||
}
|
||||
|
||||
// Calling SetupDrawListSharedData() is followed by SetCurrentFont() which sets up the remaining data.
|
||||
static void SetupDrawListSharedData()
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
ImRect virtual_space(FLT_MAX, FLT_MAX, -FLT_MAX, -FLT_MAX);
|
||||
for (ImGuiViewportP* viewport : g.Viewports)
|
||||
virtual_space.Add(viewport->GetMainRect());
|
||||
g.DrawListSharedData.ClipRectFullscreen = virtual_space.ToVec4();
|
||||
g.DrawListSharedData.CurveTessellationTol = g.Style.CurveTessellationTol;
|
||||
g.DrawListSharedData.SetCircleTessellationMaxError(g.Style.CircleTessellationMaxError);
|
||||
g.DrawListSharedData.InitialFlags = ImDrawListFlags_None;
|
||||
if (g.Style.AntiAliasedLines)
|
||||
g.DrawListSharedData.InitialFlags |= ImDrawListFlags_AntiAliasedLines;
|
||||
if (g.Style.AntiAliasedLinesUseTex && !(g.IO.Fonts->Flags & ImFontAtlasFlags_NoBakedLines))
|
||||
g.DrawListSharedData.InitialFlags |= ImDrawListFlags_AntiAliasedLinesUseTex;
|
||||
if (g.Style.AntiAliasedFill)
|
||||
g.DrawListSharedData.InitialFlags |= ImDrawListFlags_AntiAliasedFill;
|
||||
if (g.IO.BackendFlags & ImGuiBackendFlags_RendererHasVtxOffset)
|
||||
g.DrawListSharedData.InitialFlags |= ImDrawListFlags_AllowVtxOffset;
|
||||
}
|
||||
|
||||
void ImGui::NewFrame()
|
||||
{
|
||||
IM_ASSERT(GImGui != NULL && "No current context. Did you call ImGui::CreateContext() and ImGui::SetCurrentContext() ?");
|
||||
|
@ -4596,23 +4612,9 @@ void ImGui::NewFrame()
|
|||
|
||||
// Setup current font and draw list shared data
|
||||
g.IO.Fonts->Locked = true;
|
||||
SetupDrawListSharedData();
|
||||
SetCurrentFont(GetDefaultFont());
|
||||
IM_ASSERT(g.Font->IsLoaded());
|
||||
ImRect virtual_space(FLT_MAX, FLT_MAX, -FLT_MAX, -FLT_MAX);
|
||||
for (ImGuiViewportP* viewport : g.Viewports)
|
||||
virtual_space.Add(viewport->GetMainRect());
|
||||
g.DrawListSharedData.ClipRectFullscreen = virtual_space.ToVec4();
|
||||
g.DrawListSharedData.CurveTessellationTol = g.Style.CurveTessellationTol;
|
||||
g.DrawListSharedData.SetCircleTessellationMaxError(g.Style.CircleTessellationMaxError);
|
||||
g.DrawListSharedData.InitialFlags = ImDrawListFlags_None;
|
||||
if (g.Style.AntiAliasedLines)
|
||||
g.DrawListSharedData.InitialFlags |= ImDrawListFlags_AntiAliasedLines;
|
||||
if (g.Style.AntiAliasedLinesUseTex && !(g.Font->ContainerAtlas->Flags & ImFontAtlasFlags_NoBakedLines))
|
||||
g.DrawListSharedData.InitialFlags |= ImDrawListFlags_AntiAliasedLinesUseTex;
|
||||
if (g.Style.AntiAliasedFill)
|
||||
g.DrawListSharedData.InitialFlags |= ImDrawListFlags_AntiAliasedFill;
|
||||
if (g.IO.BackendFlags & ImGuiBackendFlags_RendererHasVtxOffset)
|
||||
g.DrawListSharedData.InitialFlags |= ImDrawListFlags_AllowVtxOffset;
|
||||
|
||||
// Mark rendering data as invalid to prevent user who may have a handle on it to use it.
|
||||
for (ImGuiViewportP* viewport : g.Viewports)
|
||||
|
@ -5893,7 +5895,7 @@ static int ImGui::UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& si
|
|||
|
||||
int ret_auto_fit_mask = 0x00;
|
||||
const float grip_draw_size = IM_TRUNC(ImMax(g.FontSize * 1.35f, window->WindowRounding + 1.0f + g.FontSize * 0.2f));
|
||||
const float grip_hover_inner_size = IM_TRUNC(grip_draw_size * 0.75f);
|
||||
const float grip_hover_inner_size = (resize_grip_count > 0) ? IM_TRUNC(grip_draw_size * 0.75f) : 0.0f;
|
||||
const float grip_hover_outer_size = g.IO.ConfigWindowsResizeFromEdges ? WINDOWS_HOVER_PADDING : 0.0f;
|
||||
|
||||
ImRect clamp_rect = visibility_rect;
|
||||
|
@ -6021,10 +6023,13 @@ static int ImGui::UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& si
|
|||
border_target = ImClamp(border_target, clamp_min, clamp_max);
|
||||
if (flags & ImGuiWindowFlags_ChildWindow) // Clamp resizing of childs within parent
|
||||
{
|
||||
if ((flags & (ImGuiWindowFlags_HorizontalScrollbar | ImGuiWindowFlags_AlwaysHorizontalScrollbar)) == 0 || (flags & ImGuiWindowFlags_NoScrollbar))
|
||||
border_target.x = ImClamp(border_target.x, window->ParentWindow->InnerClipRect.Min.x, window->ParentWindow->InnerClipRect.Max.x);
|
||||
if (flags & ImGuiWindowFlags_NoScrollbar)
|
||||
border_target.y = ImClamp(border_target.y, window->ParentWindow->InnerClipRect.Min.y, window->ParentWindow->InnerClipRect.Max.y);
|
||||
ImGuiWindowFlags parent_flags = window->ParentWindow->Flags;
|
||||
ImRect border_limit_rect = window->ParentWindow->InnerRect;
|
||||
border_limit_rect.Expand(ImVec2(-ImMax(window->WindowPadding.x, window->WindowBorderSize), -ImMax(window->WindowPadding.y, window->WindowBorderSize)));
|
||||
if ((parent_flags & (ImGuiWindowFlags_HorizontalScrollbar | ImGuiWindowFlags_AlwaysHorizontalScrollbar)) == 0 || (parent_flags & ImGuiWindowFlags_NoScrollbar))
|
||||
border_target.x = ImClamp(border_target.x, border_limit_rect.Min.x, border_limit_rect.Max.x);
|
||||
if (parent_flags & ImGuiWindowFlags_NoScrollbar)
|
||||
border_target.y = ImClamp(border_target.y, border_limit_rect.Min.y, border_limit_rect.Max.y);
|
||||
}
|
||||
if (!ignore_resize)
|
||||
CalcResizePosSizeFromAnyCorner(window, border_target, ImMin(def.SegmentN1, def.SegmentN2), &pos_target, &size_target);
|
||||
|
@ -6330,6 +6335,30 @@ void ImGui::UpdateWindowParentAndRootLinks(ImGuiWindow* window, ImGuiWindowFlags
|
|||
}
|
||||
}
|
||||
|
||||
// [EXPERIMENTAL] Called by Begin(). NextWindowData is valid at this point.
|
||||
// This is designed as a toy/test-bed for
|
||||
void ImGui::UpdateWindowSkipRefresh(ImGuiWindow* window)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
window->SkipRefresh = false;
|
||||
if ((g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasRefreshPolicy) == 0)
|
||||
return;
|
||||
if (g.NextWindowData.RefreshFlagsVal & ImGuiWindowRefreshFlags_TryToAvoidRefresh)
|
||||
{
|
||||
// FIXME-IDLE: Tests for e.g. mouse clicks or keyboard while focused.
|
||||
if (window->Appearing) // If currently appearing
|
||||
return;
|
||||
if (window->Hidden) // If was hidden (previous frame)
|
||||
return;
|
||||
if ((g.NextWindowData.RefreshFlagsVal & ImGuiWindowRefreshFlags_RefreshOnHover) && g.HoveredWindow && window->RootWindow == g.HoveredWindow->RootWindow)
|
||||
return;
|
||||
if ((g.NextWindowData.RefreshFlagsVal & ImGuiWindowRefreshFlags_RefreshOnFocus) && g.NavWindow && window->RootWindow == g.NavWindow->RootWindow)
|
||||
return;
|
||||
window->DrawList = NULL;
|
||||
window->SkipRefresh = true;
|
||||
}
|
||||
}
|
||||
|
||||
// When a modal popup is open, newly created windows that want focus (i.e. are not popups and do not specify ImGuiWindowFlags_NoFocusOnAppearing)
|
||||
// should be positioned behind that modal window, unless the window was created inside the modal begin-stack.
|
||||
// In case of multiple stacked modals newly created window honors begin stack order and does not go below its own modal parent.
|
||||
|
@ -6464,7 +6493,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
|
|||
PushFocusScope((flags & ImGuiWindowFlags_NavFlattened) ? g.CurrentFocusScopeId : window->ID);
|
||||
window->NavRootFocusScopeId = g.CurrentFocusScopeId;
|
||||
|
||||
// Add to popup stack
|
||||
// Add to popup stacks: update OpenPopupStack[] data, push to BeginPopupStack[]
|
||||
if (flags & ImGuiWindowFlags_Popup)
|
||||
{
|
||||
ImGuiPopupData& popup_ref = g.OpenPopupStack[g.BeginPopupStack.Size];
|
||||
|
@ -6528,11 +6557,14 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
|
|||
if (window->Appearing)
|
||||
SetWindowConditionAllowFlags(window, ImGuiCond_Appearing, false);
|
||||
|
||||
// [EXPERIMENTAL] Skip Refresh mode
|
||||
UpdateWindowSkipRefresh(window);
|
||||
|
||||
// We intentionally set g.CurrentWindow to NULL to prevent usage until when the viewport is set, then will call SetCurrentWindow()
|
||||
g.CurrentWindow = NULL;
|
||||
|
||||
// When reusing window again multiple times a frame, just append content (don't need to setup again)
|
||||
if (first_begin_of_the_frame)
|
||||
if (first_begin_of_the_frame && !window->SkipRefresh)
|
||||
{
|
||||
// Initialize
|
||||
const bool window_is_child_tooltip = (flags & ImGuiWindowFlags_ChildWindow) && (flags & ImGuiWindowFlags_Tooltip); // FIXME-WIP: Undocumented behavior of Child+Tooltip for pinned tooltip (#1345)
|
||||
|
@ -6611,8 +6643,14 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
|
|||
window->DC.MenuBarOffset.x = ImMax(ImMax(window->WindowPadding.x, style.ItemSpacing.x), g.NextWindowData.MenuBarOffsetMinVal.x);
|
||||
window->DC.MenuBarOffset.y = g.NextWindowData.MenuBarOffsetMinVal.y;
|
||||
|
||||
// Depending on condition we use previous or current window size to compare against contents size to decide if a scrollbar should be visible.
|
||||
// Those flags will be altered further down in the function depending on more conditions.
|
||||
bool use_current_size_for_scrollbar_x = window_just_created;
|
||||
bool use_current_size_for_scrollbar_y = window_just_created;
|
||||
if (window_size_x_set_by_api && window->ContentSizeExplicit.x != 0.0f)
|
||||
use_current_size_for_scrollbar_x = true;
|
||||
if (window_size_y_set_by_api && window->ContentSizeExplicit.y != 0.0f) // #7252
|
||||
use_current_size_for_scrollbar_y = true;
|
||||
|
||||
// Collapse window by double-clicking on title bar
|
||||
// At this point we don't have a clipping rectangle setup yet, so we can use the title bar area for hit detection and drawing
|
||||
|
@ -6620,8 +6658,9 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
|
|||
{
|
||||
// We don't use a regular button+id to test for double-click on title bar (mostly due to legacy reason, could be fixed), so verify that we don't have items over the title bar.
|
||||
ImRect title_bar_rect = window->TitleBarRect();
|
||||
if (g.HoveredWindow == window && g.HoveredId == 0 && g.HoveredIdPreviousFrame == 0 && IsMouseHoveringRect(title_bar_rect.Min, title_bar_rect.Max) && g.IO.MouseClickedCount[0] == 2)
|
||||
window->WantCollapseToggle = true;
|
||||
if (g.HoveredWindow == window && g.HoveredId == 0 && g.HoveredIdPreviousFrame == 0 && IsMouseHoveringRect(title_bar_rect.Min, title_bar_rect.Max))
|
||||
if (g.IO.MouseClickedCount[0] == 2 && GetKeyOwner(ImGuiKey_MouseLeft) == ImGuiKeyOwner_None)
|
||||
window->WantCollapseToggle = true;
|
||||
if (window->WantCollapseToggle)
|
||||
{
|
||||
window->Collapsed = !window->Collapsed;
|
||||
|
@ -6827,17 +6866,19 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
|
|||
window->InnerRect.Max.y = window->Pos.y + window->Size.y - window->DecoOuterSizeY2;
|
||||
|
||||
// Inner clipping rectangle.
|
||||
// Will extend a little bit outside the normal work region.
|
||||
// This is to allow e.g. Selectable or CollapsingHeader or some separators to cover that space.
|
||||
// Force round operator last to ensure that e.g. (int)(max.x-min.x) in user's render code produce correct result.
|
||||
// - Extend a outside of normal work region up to borders.
|
||||
// - This is to allow e.g. Selectable or CollapsingHeader or some separators to cover that space.
|
||||
// - It also makes clipped items be more noticeable.
|
||||
// - And is consistent on both axis (prior to 2024/05/03 ClipRect used WindowPadding.x * 0.5f on left and right edge), see #3312
|
||||
// - Force round operator last to ensure that e.g. (int)(max.x-min.x) in user's render code produce correct result.
|
||||
// Note that if our window is collapsed we will end up with an inverted (~null) clipping rectangle which is the correct behavior.
|
||||
// Affected by window/frame border size. Used by:
|
||||
// - Begin() initial clip rect
|
||||
float top_border_size = (((flags & ImGuiWindowFlags_MenuBar) || !(flags & ImGuiWindowFlags_NoTitleBar)) ? style.FrameBorderSize : window->WindowBorderSize);
|
||||
window->InnerClipRect.Min.x = ImTrunc(0.5f + window->InnerRect.Min.x + ImMax(ImTrunc(window->WindowPadding.x * 0.5f), window->WindowBorderSize));
|
||||
window->InnerClipRect.Min.y = ImTrunc(0.5f + window->InnerRect.Min.y + top_border_size);
|
||||
window->InnerClipRect.Max.x = ImTrunc(0.5f + window->InnerRect.Max.x - ImMax(ImTrunc(window->WindowPadding.x * 0.5f), window->WindowBorderSize));
|
||||
window->InnerClipRect.Max.y = ImTrunc(0.5f + window->InnerRect.Max.y - window->WindowBorderSize);
|
||||
window->InnerClipRect.Min.x = ImFloor(0.5f + window->InnerRect.Min.x + window->WindowBorderSize);
|
||||
window->InnerClipRect.Min.y = ImFloor(0.5f + window->InnerRect.Min.y + top_border_size);
|
||||
window->InnerClipRect.Max.x = ImFloor(0.5f + window->InnerRect.Max.x - window->WindowBorderSize);
|
||||
window->InnerClipRect.Max.y = ImFloor(0.5f + window->InnerRect.Max.y - window->WindowBorderSize);
|
||||
window->InnerClipRect.ClipWithFull(host_rect);
|
||||
|
||||
// Default item width. Make it proportional to window size if window manually resizes
|
||||
|
@ -6998,7 +7039,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
|
|||
|
||||
// We fill last item data based on Title Bar/Tab, in order for IsItemHovered() and IsItemActive() to be usable after Begin().
|
||||
// This is useful to allow creating context menus on title bar only, etc.
|
||||
SetLastItemData(window->MoveId, g.CurrentItemFlags, IsMouseHoveringRect(title_bar_rect.Min, title_bar_rect.Max, false) ? ImGuiItemStatusFlags_HoveredRect : 0, title_bar_rect);
|
||||
SetLastItemDataForWindow(window, title_bar_rect);
|
||||
|
||||
// [DEBUG]
|
||||
#ifndef IMGUI_DISABLE_DEBUG_TOOLS
|
||||
|
@ -7014,11 +7055,17 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
|
|||
}
|
||||
else
|
||||
{
|
||||
// Skip refresh always mark active
|
||||
if (window->SkipRefresh)
|
||||
window->Active = true;
|
||||
|
||||
// Append
|
||||
SetCurrentWindow(window);
|
||||
SetLastItemDataForWindow(window, window->TitleBarRect());
|
||||
}
|
||||
|
||||
PushClipRect(window->InnerClipRect.Min, window->InnerClipRect.Max, true);
|
||||
if (!window->SkipRefresh)
|
||||
PushClipRect(window->InnerClipRect.Min, window->InnerClipRect.Max, true);
|
||||
|
||||
// Clear 'accessed' flag last thing (After PushClipRect which will set the flag. We want the flag to stay false when the default "Debug" window is unused)
|
||||
window->WriteAccessed = false;
|
||||
|
@ -7026,7 +7073,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
|
|||
g.NextWindowData.ClearFlags();
|
||||
|
||||
// Update visibility
|
||||
if (first_begin_of_the_frame)
|
||||
if (first_begin_of_the_frame && !window->SkipRefresh)
|
||||
{
|
||||
if ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_ChildMenu))
|
||||
{
|
||||
|
@ -7072,6 +7119,11 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
|
|||
skip_items = true;
|
||||
window->SkipItems = skip_items;
|
||||
}
|
||||
else if (first_begin_of_the_frame)
|
||||
{
|
||||
// Skip refresh mode
|
||||
window->SkipItems = true;
|
||||
}
|
||||
|
||||
// [DEBUG] io.ConfigDebugBeginReturnValue override return value to test Begin/End and BeginChild/EndChild behaviors.
|
||||
// (The implicit fallback window is NOT automatically ended allowing it to always be able to receive commands without crashing)
|
||||
|
@ -7088,6 +7140,12 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
|
|||
return !window->SkipItems;
|
||||
}
|
||||
|
||||
static void ImGui::SetLastItemDataForWindow(ImGuiWindow* window, const ImRect& rect)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
SetLastItemData(window->MoveId, g.CurrentItemFlags, IsMouseHoveringRect(rect.Min, rect.Max, false) ? ImGuiItemStatusFlags_HoveredRect : 0, rect);
|
||||
}
|
||||
|
||||
void ImGui::End()
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
|
@ -7108,9 +7166,16 @@ void ImGui::End()
|
|||
// Close anything that is open
|
||||
if (window->DC.CurrentColumns)
|
||||
EndColumns();
|
||||
PopClipRect(); // Inner window clip rectangle
|
||||
if (!window->SkipRefresh)
|
||||
PopClipRect(); // Inner window clip rectangle
|
||||
PopFocusScope();
|
||||
|
||||
if (window->SkipRefresh)
|
||||
{
|
||||
IM_ASSERT(window->DrawList == NULL);
|
||||
window->DrawList = &window->DrawListInst;
|
||||
}
|
||||
|
||||
// Stop logging
|
||||
if (!(window->Flags & ImGuiWindowFlags_ChildWindow)) // FIXME: add more options for scope of logging
|
||||
LogFinish();
|
||||
|
@ -7795,6 +7860,14 @@ void ImGui::SetNextWindowBgAlpha(float alpha)
|
|||
g.NextWindowData.BgAlphaVal = alpha;
|
||||
}
|
||||
|
||||
// This is experimental and meant to be a toy for exploring a future/wider range of features.
|
||||
void ImGui::SetNextWindowRefreshPolicy(ImGuiWindowRefreshFlags flags)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasRefreshPolicy;
|
||||
g.NextWindowData.RefreshFlagsVal = flags;
|
||||
}
|
||||
|
||||
ImDrawList* ImGui::GetWindowDrawList()
|
||||
{
|
||||
ImGuiWindow* window = GetCurrentWindow();
|
||||
|
@ -7965,6 +8038,69 @@ ImGuiStorage* ImGui::GetStateStorage()
|
|||
return window->DC.StateStorage;
|
||||
}
|
||||
|
||||
bool ImGui::IsRectVisible(const ImVec2& size)
|
||||
{
|
||||
ImGuiWindow* window = GImGui->CurrentWindow;
|
||||
return window->ClipRect.Overlaps(ImRect(window->DC.CursorPos, window->DC.CursorPos + size));
|
||||
}
|
||||
|
||||
bool ImGui::IsRectVisible(const ImVec2& rect_min, const ImVec2& rect_max)
|
||||
{
|
||||
ImGuiWindow* window = GImGui->CurrentWindow;
|
||||
return window->ClipRect.Overlaps(ImRect(rect_min, rect_max));
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// [SECTION] ID STACK
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// This is one of the very rare legacy case where we use ImGuiWindow methods,
|
||||
// it should ideally be flattened at some point but it's been used a lots by widgets.
|
||||
ImGuiID ImGuiWindow::GetID(const char* str, const char* str_end)
|
||||
{
|
||||
ImGuiID seed = IDStack.back();
|
||||
ImGuiID id = ImHashStr(str, str_end ? (str_end - str) : 0, seed);
|
||||
#ifndef IMGUI_DISABLE_DEBUG_TOOLS
|
||||
ImGuiContext& g = *Ctx;
|
||||
if (g.DebugHookIdInfo == id)
|
||||
ImGui::DebugHookIdInfo(id, ImGuiDataType_String, str, str_end);
|
||||
#endif
|
||||
return id;
|
||||
}
|
||||
|
||||
ImGuiID ImGuiWindow::GetID(const void* ptr)
|
||||
{
|
||||
ImGuiID seed = IDStack.back();
|
||||
ImGuiID id = ImHashData(&ptr, sizeof(void*), seed);
|
||||
#ifndef IMGUI_DISABLE_DEBUG_TOOLS
|
||||
ImGuiContext& g = *Ctx;
|
||||
if (g.DebugHookIdInfo == id)
|
||||
ImGui::DebugHookIdInfo(id, ImGuiDataType_Pointer, ptr, NULL);
|
||||
#endif
|
||||
return id;
|
||||
}
|
||||
|
||||
ImGuiID ImGuiWindow::GetID(int n)
|
||||
{
|
||||
ImGuiID seed = IDStack.back();
|
||||
ImGuiID id = ImHashData(&n, sizeof(n), seed);
|
||||
#ifndef IMGUI_DISABLE_DEBUG_TOOLS
|
||||
ImGuiContext& g = *Ctx;
|
||||
if (g.DebugHookIdInfo == id)
|
||||
ImGui::DebugHookIdInfo(id, ImGuiDataType_S32, (void*)(intptr_t)n, NULL);
|
||||
#endif
|
||||
return id;
|
||||
}
|
||||
|
||||
// This is only used in rare/specific situations to manufacture an ID out of nowhere.
|
||||
ImGuiID ImGuiWindow::GetIDFromRectangle(const ImRect& r_abs)
|
||||
{
|
||||
ImGuiID seed = IDStack.back();
|
||||
ImRect r_rel = ImGui::WindowRectAbsToRel(this, r_abs);
|
||||
ImGuiID id = ImHashData(&r_rel, sizeof(r_rel), seed);
|
||||
return id;
|
||||
}
|
||||
|
||||
void ImGui::PushID(const char* str_id)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
|
@ -8002,8 +8138,10 @@ void ImGui::PushOverrideID(ImGuiID id)
|
|||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
ImGuiWindow* window = g.CurrentWindow;
|
||||
#ifndef IMGUI_DISABLE_DEBUG_TOOLS
|
||||
if (g.DebugHookIdInfo == id)
|
||||
DebugHookIdInfo(id, ImGuiDataType_ID, NULL, NULL);
|
||||
#endif
|
||||
window->IDStack.push_back(id);
|
||||
}
|
||||
|
||||
|
@ -8013,18 +8151,22 @@ void ImGui::PushOverrideID(ImGuiID id)
|
|||
ImGuiID ImGui::GetIDWithSeed(const char* str, const char* str_end, ImGuiID seed)
|
||||
{
|
||||
ImGuiID id = ImHashStr(str, str_end ? (str_end - str) : 0, seed);
|
||||
#ifndef IMGUI_DISABLE_DEBUG_TOOLS
|
||||
ImGuiContext& g = *GImGui;
|
||||
if (g.DebugHookIdInfo == id)
|
||||
DebugHookIdInfo(id, ImGuiDataType_String, str, str_end);
|
||||
#endif
|
||||
return id;
|
||||
}
|
||||
|
||||
ImGuiID ImGui::GetIDWithSeed(int n, ImGuiID seed)
|
||||
{
|
||||
ImGuiID id = ImHashData(&n, sizeof(n), seed);
|
||||
#ifndef IMGUI_DISABLE_DEBUG_TOOLS
|
||||
ImGuiContext& g = *GImGui;
|
||||
if (g.DebugHookIdInfo == id)
|
||||
DebugHookIdInfo(id, ImGuiDataType_S32, (void*)(intptr_t)n, NULL);
|
||||
#endif
|
||||
return id;
|
||||
}
|
||||
|
||||
|
@ -8053,19 +8195,6 @@ ImGuiID ImGui::GetID(const void* ptr_id)
|
|||
return window->GetID(ptr_id);
|
||||
}
|
||||
|
||||
bool ImGui::IsRectVisible(const ImVec2& size)
|
||||
{
|
||||
ImGuiWindow* window = GImGui->CurrentWindow;
|
||||
return window->ClipRect.Overlaps(ImRect(window->DC.CursorPos, window->DC.CursorPos + size));
|
||||
}
|
||||
|
||||
bool ImGui::IsRectVisible(const ImVec2& rect_min, const ImVec2& rect_max)
|
||||
{
|
||||
ImGuiWindow* window = GImGui->CurrentWindow;
|
||||
return window->ClipRect.Overlaps(ImRect(rect_min, rect_max));
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// [SECTION] INPUTS
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -9196,7 +9325,7 @@ void ImGui::SetNextFrameWantCaptureMouse(bool want_capture_mouse)
|
|||
#ifndef IMGUI_DISABLE_DEBUG_TOOLS
|
||||
static const char* GetInputSourceName(ImGuiInputSource source)
|
||||
{
|
||||
const char* input_source_names[] = { "None", "Mouse", "Keyboard", "Gamepad", "Clipboard" };
|
||||
const char* input_source_names[] = { "None", "Mouse", "Keyboard", "Gamepad" };
|
||||
IM_ASSERT(IM_ARRAYSIZE(input_source_names) == ImGuiInputSource_COUNT && source >= 0 && source < ImGuiInputSource_COUNT);
|
||||
return input_source_names[source];
|
||||
}
|
||||
|
@ -9512,13 +9641,15 @@ bool ImGui::Shortcut(ImGuiKeyChord key_chord, ImGuiID owner_id, ImGuiInputFlags
|
|||
//-----------------------------------------------------------------------------
|
||||
|
||||
// Helper function to verify ABI compatibility between caller code and compiled version of Dear ImGui.
|
||||
// This is called by IMGUI_CHECKVERSION().
|
||||
// Verify that the type sizes are matching between the calling file's compilation unit and imgui.cpp's compilation unit
|
||||
// If this triggers you have an issue:
|
||||
// - Most commonly: mismatched headers and compiled code version.
|
||||
// - Or: mismatched configuration #define, compilation settings, packing pragma etc.
|
||||
// The configuration settings mentioned in imconfig.h must be set for all compilation units involved with Dear ImGui,
|
||||
// which is way it is required you put them in your imconfig file (and not just before including imgui.h).
|
||||
// Otherwise it is possible that different compilation units would see different structure layout
|
||||
// If this triggers you have mismatched headers and compiled code versions.
|
||||
// - It could be because of a build issue (using new headers with old compiled code)
|
||||
// - It could be because of mismatched configuration #define, compilation settings, packing pragma etc.
|
||||
// THE CONFIGURATION SETTINGS MENTIONED IN imconfig.h MUST BE SET FOR ALL COMPILATION UNITS INVOLVED WITH DEAR IMGUI.
|
||||
// Which is why it is required you put them in your imconfig file (and NOT only before including imgui.h).
|
||||
// Otherwise it is possible that different compilation units would see different structure layout.
|
||||
// If you don't want to modify imconfig.h you can use the IMGUI_USER_CONFIG define to change filename.
|
||||
bool ImGui::DebugCheckVersionAndDataLayout(const char* version, size_t sz_io, size_t sz_style, size_t sz_vec2, size_t sz_vec4, size_t sz_vert, size_t sz_idx)
|
||||
{
|
||||
bool error = false;
|
||||
|
@ -10775,7 +10906,7 @@ void ImGui::OpenPopupEx(ImGuiID id, ImGuiPopupFlags popup_flags)
|
|||
ImGuiPopupData popup_ref; // Tagged as new ref as Window will be set back to NULL if we write this into OpenPopupStack.
|
||||
popup_ref.PopupId = id;
|
||||
popup_ref.Window = NULL;
|
||||
popup_ref.BackupNavWindow = g.NavWindow; // When popup closes focus may be restored to NavWindow (depend on window type).
|
||||
popup_ref.RestoreNavWindow = g.NavWindow; // When popup closes focus may be restored to NavWindow (depend on window type).
|
||||
popup_ref.OpenFrameCount = g.FrameCount;
|
||||
popup_ref.OpenParentId = parent_window->IDStack.back();
|
||||
popup_ref.OpenPopupPos = NavCalcPreferredRefPos();
|
||||
|
@ -10824,6 +10955,7 @@ void ImGui::ClosePopupsOverWindow(ImGuiWindow* ref_window, bool restore_focus_to
|
|||
return;
|
||||
|
||||
// Don't close our own child popup windows.
|
||||
//IMGUI_DEBUG_LOG_POPUP("[popup] ClosePopupsOverWindow(\"%s\") restore_under=%d\n", ref_window ? ref_window->Name : "<NULL>", restore_focus_to_window_under_popup);
|
||||
int popup_count_to_keep = 0;
|
||||
if (ref_window)
|
||||
{
|
||||
|
@ -10880,18 +11012,19 @@ void ImGui::ClosePopupsExceptModals()
|
|||
void ImGui::ClosePopupToLevel(int remaining, bool restore_focus_to_window_under_popup)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
IMGUI_DEBUG_LOG_POPUP("[popup] ClosePopupToLevel(%d), restore_focus_to_window_under_popup=%d\n", remaining, restore_focus_to_window_under_popup);
|
||||
IMGUI_DEBUG_LOG_POPUP("[popup] ClosePopupToLevel(%d), restore_under=%d\n", remaining, restore_focus_to_window_under_popup);
|
||||
IM_ASSERT(remaining >= 0 && remaining < g.OpenPopupStack.Size);
|
||||
|
||||
// Trim open popup stack
|
||||
ImGuiWindow* popup_window = g.OpenPopupStack[remaining].Window;
|
||||
ImGuiWindow* popup_backup_nav_window = g.OpenPopupStack[remaining].BackupNavWindow;
|
||||
ImGuiPopupData prev_popup = g.OpenPopupStack[remaining];
|
||||
g.OpenPopupStack.resize(remaining);
|
||||
|
||||
if (restore_focus_to_window_under_popup)
|
||||
// Restore focus (unless popup window was not yet submitted, and didn't have a chance to take focus anyhow. See #7325 for an edge case)
|
||||
if (restore_focus_to_window_under_popup && prev_popup.Window)
|
||||
{
|
||||
ImGuiWindow* focus_window = (popup_window && popup_window->Flags & ImGuiWindowFlags_ChildMenu) ? popup_window->ParentWindow : popup_backup_nav_window;
|
||||
if (focus_window && !focus_window->WasActive && popup_window)
|
||||
ImGuiWindow* popup_window = prev_popup.Window;
|
||||
ImGuiWindow* focus_window = (popup_window->Flags & ImGuiWindowFlags_ChildMenu) ? popup_window->ParentWindow : prev_popup.RestoreNavWindow;
|
||||
if (focus_window && !focus_window->WasActive)
|
||||
FocusTopMostWindowUnderOne(popup_window, NULL, NULL, ImGuiFocusRequestFlags_RestoreFocusedChild); // Fallback
|
||||
else
|
||||
FocusWindow(focus_window, (g.NavLayer == ImGuiNavLayer_Main) ? ImGuiFocusRequestFlags_RestoreFocusedChild : ImGuiFocusRequestFlags_None);
|
||||
|
@ -12283,8 +12416,10 @@ void ImGui::NavMoveRequestApplyResult()
|
|||
g.NavLastValidSelectionUserData = ImGuiSelectionUserData_Invalid;
|
||||
}
|
||||
|
||||
// FIXME: Could become optional e.g. ImGuiNavMoveFlags_NoClearActiveId if we later want to apply navigation requests without altering active input.
|
||||
if (g.ActiveId != result->ID)
|
||||
// Clear active id unless requested not to
|
||||
// FIXME: ImGuiNavMoveFlags_NoClearActiveId is currently unused as we don't have a clear strategy to preserve active id after interaction,
|
||||
// so this is mostly provided as a gateway for further experiments (see #1418, #2890)
|
||||
if (g.ActiveId != result->ID && (g.NavMoveFlags & ImGuiNavMoveFlags_NoClearActiveId) == 0)
|
||||
ClearActiveID();
|
||||
|
||||
// Don't set NavJustMovedToId if just landed on the same spot (which may happen with ImGuiNavMoveFlags_AllowCurrentNavId)
|
||||
|
@ -12918,6 +13053,7 @@ bool ImGui::BeginDragDropSource(ImGuiDragDropFlags flags)
|
|||
source_drag_active = true;
|
||||
}
|
||||
|
||||
IM_ASSERT(g.DragDropWithinTarget == false); // Can't nest BeginDragDropSource() and BeginDragDropTarget()
|
||||
if (source_drag_active)
|
||||
{
|
||||
if (!g.DragDropActive)
|
||||
|
@ -13033,7 +13169,7 @@ bool ImGui::BeginDragDropTargetCustom(const ImRect& bb, ImGuiID id)
|
|||
if (window->SkipItems)
|
||||
return false;
|
||||
|
||||
IM_ASSERT(g.DragDropWithinTarget == false);
|
||||
IM_ASSERT(g.DragDropWithinTarget == false && g.DragDropWithinSource == false); // Can't nest BeginDragDropSource() and BeginDragDropTarget()
|
||||
g.DragDropTargetRect = bb;
|
||||
g.DragDropTargetClipRect = window->ClipRect; // May want to be overriden by user depending on use case?
|
||||
g.DragDropTargetId = id;
|
||||
|
@ -13068,7 +13204,7 @@ bool ImGui::BeginDragDropTarget()
|
|||
if (g.DragDropPayload.SourceId == id)
|
||||
return false;
|
||||
|
||||
IM_ASSERT(g.DragDropWithinTarget == false);
|
||||
IM_ASSERT(g.DragDropWithinTarget == false && g.DragDropWithinSource == false); // Can't nest BeginDragDropSource() and BeginDragDropTarget()
|
||||
g.DragDropTargetRect = display_rect;
|
||||
g.DragDropTargetClipRect = (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_HasClipRect) ? g.LastItemData.ClipRect : window->ClipRect;
|
||||
g.DragDropTargetId = id;
|
||||
|
@ -14455,9 +14591,9 @@ void ImGui::ShowMetricsWindow(bool* p_open)
|
|||
{
|
||||
// As it's difficult to interact with tree nodes while popups are open, we display everything inline.
|
||||
ImGuiWindow* window = popup_data.Window;
|
||||
BulletText("PopupID: %08x, Window: '%s' (%s%s), BackupNavWindow '%s', ParentWindow '%s'",
|
||||
BulletText("PopupID: %08x, Window: '%s' (%s%s), RestoreNavWindow '%s', ParentWindow '%s'",
|
||||
popup_data.PopupId, window ? window->Name : "NULL", window && (window->Flags & ImGuiWindowFlags_ChildWindow) ? "Child;" : "", window && (window->Flags & ImGuiWindowFlags_ChildMenu) ? "Menu;" : "",
|
||||
popup_data.BackupNavWindow ? popup_data.BackupNavWindow->Name : "NULL", window && window->ParentWindow ? window->ParentWindow->Name : "NULL");
|
||||
popup_data.RestoreNavWindow ? popup_data.RestoreNavWindow->Name : "NULL", window && window->ParentWindow ? window->ParentWindow->Name : "NULL");
|
||||
}
|
||||
TreePop();
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// dear imgui, v1.90.4
|
||||
// dear imgui, v1.90.6 WIP
|
||||
// (headers)
|
||||
|
||||
// Help:
|
||||
|
@ -7,15 +7,19 @@
|
|||
// - Read top of imgui.cpp for more details, links and comments.
|
||||
|
||||
// Resources:
|
||||
// - FAQ https://dearimgui.com/faq
|
||||
// - Getting Started https://dearimgui.com/getting-started
|
||||
// - Homepage https://github.com/ocornut/imgui
|
||||
// - Releases & changelog https://github.com/ocornut/imgui/releases
|
||||
// - Gallery https://github.com/ocornut/imgui/issues/6897 (please post your screenshots/video there!)
|
||||
// - Wiki https://github.com/ocornut/imgui/wiki (lots of good stuff there)
|
||||
// - Glossary https://github.com/ocornut/imgui/wiki/Glossary
|
||||
// - Issues & support https://github.com/ocornut/imgui/issues
|
||||
// - Tests & Automation https://github.com/ocornut/imgui_test_engine
|
||||
// - FAQ ........................ https://dearimgui.com/faq (in repository as docs/FAQ.md)
|
||||
// - Homepage ................... https://github.com/ocornut/imgui
|
||||
// - Releases & changelog ....... https://github.com/ocornut/imgui/releases
|
||||
// - Gallery .................... https://github.com/ocornut/imgui/issues/7503 (please post your screenshots/video there!)
|
||||
// - Wiki ....................... https://github.com/ocornut/imgui/wiki (lots of good stuff there)
|
||||
// - Getting Started https://github.com/ocornut/imgui/wiki/Getting-Started (how to integrate in an existing app by adding ~25 lines of code)
|
||||
// - Third-party Extensions https://github.com/ocornut/imgui/wiki/Useful-Extensions (ImPlot & many more)
|
||||
// - Bindings/Backends https://github.com/ocornut/imgui/wiki/Bindings (language bindings, backends for various tech/engines)
|
||||
// - Glossary https://github.com/ocornut/imgui/wiki/Glossary
|
||||
// - Debug Tools https://github.com/ocornut/imgui/wiki/Debug-Tools
|
||||
// - Software using Dear ImGui https://github.com/ocornut/imgui/wiki/Software-using-dear-imgui
|
||||
// - Issues & support ........... https://github.com/ocornut/imgui/issues
|
||||
// - Test Engine & Automation ... https://github.com/ocornut/imgui_test_engine (test suite, test engine to automate your apps)
|
||||
|
||||
// For first-time users having issues compiling/linking/running/loading fonts:
|
||||
// please post in https://github.com/ocornut/imgui/discussions if you cannot find a solution in resources above.
|
||||
|
@ -23,8 +27,8 @@
|
|||
|
||||
// Library Version
|
||||
// (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345')
|
||||
#define IMGUI_VERSION "1.90.4"
|
||||
#define IMGUI_VERSION_NUM 19040
|
||||
#define IMGUI_VERSION "1.90.6"
|
||||
#define IMGUI_VERSION_NUM 19060
|
||||
#define IMGUI_HAS_TABLE
|
||||
|
||||
/*
|
||||
|
@ -126,6 +130,7 @@ Index of this file:
|
|||
#pragma clang diagnostic ignored "-Wfloat-equal" // warning: comparing floating point with == or != is unsafe
|
||||
#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant"
|
||||
#pragma clang diagnostic ignored "-Wreserved-identifier" // warning: identifier '_Xxx' is reserved because it starts with '_' followed by a capital letter
|
||||
#pragma clang diagnostic ignored "-Wunsafe-buffer-usage" // warning: 'xxx' is an unsafe pointer used for buffer access
|
||||
#elif defined(__GNUC__)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind
|
||||
|
@ -171,8 +176,9 @@ struct ImGuiViewport; // A Platform Window (always only one in 'ma
|
|||
// Enumerations
|
||||
// - We don't use strongly typed enums much because they add constraints (can't extend in private code, can't store typed in bit fields, extra casting on iteration)
|
||||
// - Tip: Use your programming IDE navigation facilities on the names in the _central column_ below to find the actual flags/enum lists!
|
||||
// In Visual Studio IDE: CTRL+comma ("Edit.GoToAll") can follow symbols in comments, whereas CTRL+F12 ("Edit.GoToImplementation") cannot.
|
||||
// With Visual Assist installed: ALT+G ("VAssistX.GoToImplementation") can also follow symbols in comments.
|
||||
// - In Visual Studio: CTRL+comma ("Edit.GoToAll") can follow symbols inside comments, whereas CTRL+F12 ("Edit.GoToImplementation") cannot.
|
||||
// - In Visual Studio w/ Visual Assist installed: ALT+G ("VAssistX.GoToImplementation") can also follow symbols inside comments.
|
||||
// - In VS Code, CLion, etc.: CTRL+click can follow symbols inside comments.
|
||||
enum ImGuiKey : int; // -> enum ImGuiKey // Enum: A key identifier (ImGuiKey_XXX or ImGuiMod_XXX value)
|
||||
enum ImGuiMouseSource : int; // -> enum ImGuiMouseSource // Enum; A mouse input source identifier (Mouse, TouchScreen, Pen)
|
||||
typedef int ImGuiCol; // -> enum ImGuiCol_ // Enum: A color identifier for styling
|
||||
|
@ -187,8 +193,9 @@ typedef int ImGuiTableBgTarget; // -> enum ImGuiTableBgTarget_ // Enum: A
|
|||
|
||||
// Flags (declared as int to allow using as flags without overhead, and to not pollute the top of this file)
|
||||
// - Tip: Use your programming IDE navigation facilities on the names in the _central column_ below to find the actual flags/enum lists!
|
||||
// In Visual Studio IDE: CTRL+comma ("Edit.GoToAll") can follow symbols in comments, whereas CTRL+F12 ("Edit.GoToImplementation") cannot.
|
||||
// With Visual Assist installed: ALT+G ("VAssistX.GoToImplementation") can also follow symbols in comments.
|
||||
// - In Visual Studio: CTRL+comma ("Edit.GoToAll") can follow symbols inside comments, whereas CTRL+F12 ("Edit.GoToImplementation") cannot.
|
||||
// - In Visual Studio w/ Visual Assist installed: ALT+G ("VAssistX.GoToImplementation") can also follow symbols inside comments.
|
||||
// - In VS Code, CLion, etc.: CTRL+click can follow symbols inside comments.
|
||||
typedef int ImDrawFlags; // -> enum ImDrawFlags_ // Flags: for ImDrawList functions
|
||||
typedef int ImDrawListFlags; // -> enum ImDrawListFlags_ // Flags: for ImDrawList instance
|
||||
typedef int ImFontAtlasFlags; // -> enum ImFontAtlasFlags_ // Flags: for ImFontAtlas build
|
||||
|
@ -1096,11 +1103,12 @@ enum ImGuiTreeNodeFlags_
|
|||
ImGuiTreeNodeFlags_Leaf = 1 << 8, // No collapsing, no arrow (use as a convenience for leaf nodes).
|
||||
ImGuiTreeNodeFlags_Bullet = 1 << 9, // Display a bullet instead of arrow. IMPORTANT: node can still be marked open/close if you don't set the _Leaf flag!
|
||||
ImGuiTreeNodeFlags_FramePadding = 1 << 10, // Use FramePadding (even for an unframed text node) to vertically align text baseline to regular widget height. Equivalent to calling AlignTextToFramePadding().
|
||||
ImGuiTreeNodeFlags_SpanAvailWidth = 1 << 11, // Extend hit box to the right-most edge, even if not framed. This is not the default in order to allow adding other items on the same line. In the future we may refactor the hit system to be front-to-back, allowing natural overlaps and then this can become the default.
|
||||
ImGuiTreeNodeFlags_SpanFullWidth = 1 << 12, // Extend hit box to the left-most and right-most edges (bypass the indented area).
|
||||
ImGuiTreeNodeFlags_SpanAllColumns = 1 << 13, // Frame will span all columns of its container table (text will still fit in current column)
|
||||
ImGuiTreeNodeFlags_NavLeftJumpsBackHere = 1 << 14, // (WIP) Nav: left direction may move to this TreeNode() from any of its child (items submitted between TreeNode and TreePop)
|
||||
//ImGuiTreeNodeFlags_NoScrollOnOpen = 1 << 15, // FIXME: TODO: Disable automatic scroll on TreePop() if node got just open and contents is not visible
|
||||
ImGuiTreeNodeFlags_SpanAvailWidth = 1 << 11, // Extend hit box to the right-most edge, even if not framed. This is not the default in order to allow adding other items on the same line without using AllowOverlap mode.
|
||||
ImGuiTreeNodeFlags_SpanFullWidth = 1 << 12, // Extend hit box to the left-most and right-most edges (cover the indent area).
|
||||
ImGuiTreeNodeFlags_SpanTextWidth = 1 << 13, // Narrow hit box + narrow hovering highlight, will only cover the label text.
|
||||
ImGuiTreeNodeFlags_SpanAllColumns = 1 << 14, // Frame will span all columns of its container table (text will still fit in current column)
|
||||
ImGuiTreeNodeFlags_NavLeftJumpsBackHere = 1 << 15, // (WIP) Nav: left direction may move to this TreeNode() from any of its child (items submitted between TreeNode and TreePop)
|
||||
//ImGuiTreeNodeFlags_NoScrollOnOpen = 1 << 16, // FIXME: TODO: Disable automatic scroll on TreePop() if node got just open and contents is not visible
|
||||
ImGuiTreeNodeFlags_CollapsingHeader = ImGuiTreeNodeFlags_Framed | ImGuiTreeNodeFlags_NoTreePushOnOpen | ImGuiTreeNodeFlags_NoAutoOpenOnLog,
|
||||
|
||||
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
|
||||
|
@ -1544,41 +1552,45 @@ enum ImGuiCol_
|
|||
// - The enum only refers to fields of ImGuiStyle which makes sense to be pushed/popped inside UI code.
|
||||
// During initialization or between frames, feel free to just poke into ImGuiStyle directly.
|
||||
// - Tip: Use your programming IDE navigation facilities on the names in the _second column_ below to find the actual members and their description.
|
||||
// In Visual Studio IDE: CTRL+comma ("Edit.GoToAll") can follow symbols in comments, whereas CTRL+F12 ("Edit.GoToImplementation") cannot.
|
||||
// With Visual Assist installed: ALT+G ("VAssistX.GoToImplementation") can also follow symbols in comments.
|
||||
// - In Visual Studio: CTRL+comma ("Edit.GoToAll") can follow symbols inside comments, whereas CTRL+F12 ("Edit.GoToImplementation") cannot.
|
||||
// - In Visual Studio w/ Visual Assist installed: ALT+G ("VAssistX.GoToImplementation") can also follow symbols inside comments.
|
||||
// - In VS Code, CLion, etc.: CTRL+click can follow symbols inside comments.
|
||||
// - When changing this enum, you need to update the associated internal table GStyleVarInfo[] accordingly. This is where we link enum values to members offset/type.
|
||||
enum ImGuiStyleVar_
|
||||
{
|
||||
// Enum name --------------------- // Member in ImGuiStyle structure (see ImGuiStyle for descriptions)
|
||||
ImGuiStyleVar_Alpha, // float Alpha
|
||||
ImGuiStyleVar_DisabledAlpha, // float DisabledAlpha
|
||||
ImGuiStyleVar_WindowPadding, // ImVec2 WindowPadding
|
||||
ImGuiStyleVar_WindowRounding, // float WindowRounding
|
||||
ImGuiStyleVar_WindowBorderSize, // float WindowBorderSize
|
||||
ImGuiStyleVar_WindowMinSize, // ImVec2 WindowMinSize
|
||||
ImGuiStyleVar_WindowTitleAlign, // ImVec2 WindowTitleAlign
|
||||
ImGuiStyleVar_ChildRounding, // float ChildRounding
|
||||
ImGuiStyleVar_ChildBorderSize, // float ChildBorderSize
|
||||
ImGuiStyleVar_PopupRounding, // float PopupRounding
|
||||
ImGuiStyleVar_PopupBorderSize, // float PopupBorderSize
|
||||
ImGuiStyleVar_FramePadding, // ImVec2 FramePadding
|
||||
ImGuiStyleVar_FrameRounding, // float FrameRounding
|
||||
ImGuiStyleVar_FrameBorderSize, // float FrameBorderSize
|
||||
ImGuiStyleVar_ItemSpacing, // ImVec2 ItemSpacing
|
||||
ImGuiStyleVar_ItemInnerSpacing, // ImVec2 ItemInnerSpacing
|
||||
ImGuiStyleVar_IndentSpacing, // float IndentSpacing
|
||||
ImGuiStyleVar_CellPadding, // ImVec2 CellPadding
|
||||
ImGuiStyleVar_ScrollbarSize, // float ScrollbarSize
|
||||
ImGuiStyleVar_ScrollbarRounding, // float ScrollbarRounding
|
||||
ImGuiStyleVar_GrabMinSize, // float GrabMinSize
|
||||
ImGuiStyleVar_GrabRounding, // float GrabRounding
|
||||
ImGuiStyleVar_TabRounding, // float TabRounding
|
||||
ImGuiStyleVar_TabBarBorderSize, // float TabBarBorderSize
|
||||
ImGuiStyleVar_ButtonTextAlign, // ImVec2 ButtonTextAlign
|
||||
ImGuiStyleVar_SelectableTextAlign, // ImVec2 SelectableTextAlign
|
||||
ImGuiStyleVar_SeparatorTextBorderSize,// float SeparatorTextBorderSize
|
||||
ImGuiStyleVar_SeparatorTextAlign, // ImVec2 SeparatorTextAlign
|
||||
ImGuiStyleVar_SeparatorTextPadding,// ImVec2 SeparatorTextPadding
|
||||
// Enum name -------------------------- // Member in ImGuiStyle structure (see ImGuiStyle for descriptions)
|
||||
ImGuiStyleVar_Alpha, // float Alpha
|
||||
ImGuiStyleVar_DisabledAlpha, // float DisabledAlpha
|
||||
ImGuiStyleVar_WindowPadding, // ImVec2 WindowPadding
|
||||
ImGuiStyleVar_WindowRounding, // float WindowRounding
|
||||
ImGuiStyleVar_WindowBorderSize, // float WindowBorderSize
|
||||
ImGuiStyleVar_WindowMinSize, // ImVec2 WindowMinSize
|
||||
ImGuiStyleVar_WindowTitleAlign, // ImVec2 WindowTitleAlign
|
||||
ImGuiStyleVar_ChildRounding, // float ChildRounding
|
||||
ImGuiStyleVar_ChildBorderSize, // float ChildBorderSize
|
||||
ImGuiStyleVar_PopupRounding, // float PopupRounding
|
||||
ImGuiStyleVar_PopupBorderSize, // float PopupBorderSize
|
||||
ImGuiStyleVar_FramePadding, // ImVec2 FramePadding
|
||||
ImGuiStyleVar_FrameRounding, // float FrameRounding
|
||||
ImGuiStyleVar_FrameBorderSize, // float FrameBorderSize
|
||||
ImGuiStyleVar_ItemSpacing, // ImVec2 ItemSpacing
|
||||
ImGuiStyleVar_ItemInnerSpacing, // ImVec2 ItemInnerSpacing
|
||||
ImGuiStyleVar_IndentSpacing, // float IndentSpacing
|
||||
ImGuiStyleVar_CellPadding, // ImVec2 CellPadding
|
||||
ImGuiStyleVar_ScrollbarSize, // float ScrollbarSize
|
||||
ImGuiStyleVar_ScrollbarRounding, // float ScrollbarRounding
|
||||
ImGuiStyleVar_GrabMinSize, // float GrabMinSize
|
||||
ImGuiStyleVar_GrabRounding, // float GrabRounding
|
||||
ImGuiStyleVar_TabRounding, // float TabRounding
|
||||
ImGuiStyleVar_TabBorderSize, // float TabBorderSize
|
||||
ImGuiStyleVar_TabBarBorderSize, // float TabBarBorderSize
|
||||
ImGuiStyleVar_TableAngledHeadersAngle, // float TableAngledHeadersAngle
|
||||
ImGuiStyleVar_TableAngledHeadersTextAlign,// ImVec2 TableAngledHeadersTextAlign
|
||||
ImGuiStyleVar_ButtonTextAlign, // ImVec2 ButtonTextAlign
|
||||
ImGuiStyleVar_SelectableTextAlign, // ImVec2 SelectableTextAlign
|
||||
ImGuiStyleVar_SeparatorTextBorderSize, // float SeparatorTextBorderSize
|
||||
ImGuiStyleVar_SeparatorTextAlign, // ImVec2 SeparatorTextAlign
|
||||
ImGuiStyleVar_SeparatorTextPadding, // ImVec2 SeparatorTextPadding
|
||||
ImGuiStyleVar_COUNT
|
||||
};
|
||||
|
||||
|
@ -1993,7 +2005,7 @@ struct ImGuiStyle
|
|||
float FrameBorderSize; // Thickness of border around frames. Generally set to 0.0f or 1.0f. (Other values are not well tested and more CPU/GPU costly).
|
||||
ImVec2 ItemSpacing; // Horizontal and vertical spacing between widgets/lines.
|
||||
ImVec2 ItemInnerSpacing; // Horizontal and vertical spacing between within elements of a composed widget (e.g. a slider and its label).
|
||||
ImVec2 CellPadding; // Padding within a table cell. CellPadding.y may be altered between different rows.
|
||||
ImVec2 CellPadding; // Padding within a table cell. Cellpadding.x is locked for entire table. CellPadding.y may be altered between different rows.
|
||||
ImVec2 TouchExtraPadding; // Expand reactive bounding box for touch-based system where touch position is not accurate enough. Unfortunately we don't sort widgets so priority on overlap will always be given to the first widget. So don't grow this too much!
|
||||
float IndentSpacing; // Horizontal indentation when e.g. entering a tree node. Generally == (FontSize + FramePadding.x*2).
|
||||
float ColumnsMinSpacing; // Minimum horizontal spacing between two columns. Preferably > (FramePadding.x + 1).
|
||||
|
@ -2007,6 +2019,7 @@ struct ImGuiStyle
|
|||
float TabMinWidthForCloseButton; // Minimum width for close button to appear on an unselected tab when hovered. Set to 0.0f to always show when hovering, set to FLT_MAX to never show close button unless selected.
|
||||
float TabBarBorderSize; // Thickness of tab-bar separator, which takes on the tab active color to denote focus.
|
||||
float TableAngledHeadersAngle; // Angle of angled headers (supported values range from -50.0f degrees to +50.0f degrees).
|
||||
ImVec2 TableAngledHeadersTextAlign;// Alignment of angled headers within the cell
|
||||
ImGuiDir ColorButtonPosition; // Side of the color button in the ColorEdit4 widget (left/right). Defaults to ImGuiDir_Right.
|
||||
ImVec2 ButtonTextAlign; // Alignment of button text when button is larger than text. Defaults to (0.5f, 0.5f) (centered).
|
||||
ImVec2 SelectableTextAlign; // Alignment of selectable text. Defaults to (0.0f, 0.0f) (top-left aligned). It's generally important to keep this left-aligned if you want to lay multiple items on a same line.
|
||||
|
@ -2040,6 +2053,9 @@ struct ImGuiStyle
|
|||
//-----------------------------------------------------------------------------
|
||||
// Communicate most settings and inputs/outputs to Dear ImGui using this structure.
|
||||
// Access via ImGui::GetIO(). Read 'Programmer guide' section in .cpp file for general usage.
|
||||
// It is generally expected that:
|
||||
// - initialization: backends and user code writes to ImGuiIO.
|
||||
// - main loop: backends writes to ImGuiIO, user code and imgui code reads from ImGuiIO.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// [Internal] Storage used by IsKeyDown(), IsKeyPressed() etc functions.
|
||||
|
@ -2186,16 +2202,6 @@ struct ImGuiIO
|
|||
int MetricsActiveWindows; // Number of active windows
|
||||
ImVec2 MouseDelta; // Mouse delta. Note that this is zero if either current or previous position are invalid (-FLT_MAX,-FLT_MAX), so a disappearing/reappearing mouse won't have a huge delta.
|
||||
|
||||
// Legacy: before 1.87, we required backend to fill io.KeyMap[] (imgui->native map) during initialization and io.KeysDown[] (native indices) every frame.
|
||||
// This is still temporarily supported as a legacy feature. However the new preferred scheme is for backend to call io.AddKeyEvent().
|
||||
// Old (<1.87): ImGui::IsKeyPressed(ImGui::GetIO().KeyMap[ImGuiKey_Space]) --> New (1.87+) ImGui::IsKeyPressed(ImGuiKey_Space)
|
||||
#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO
|
||||
int KeyMap[ImGuiKey_COUNT]; // [LEGACY] Input: map of indices into the KeysDown[512] entries array which represent your "native" keyboard state. The first 512 are now unused and should be kept zero. Legacy backend will write into KeyMap[] using ImGuiKey_ indices which are always >512.
|
||||
bool KeysDown[ImGuiKey_COUNT]; // [LEGACY] Input: Keyboard keys that are pressed (ideally left in the "native" order your engine has access to keyboard keys, so you can use your own defines/enums for keys). This used to be [512] sized. It is now ImGuiKey_COUNT to allow legacy io.KeysDown[GetKeyIndex(...)] to work without an overflow.
|
||||
float NavInputs[ImGuiNavInput_COUNT]; // [LEGACY] Since 1.88, NavInputs[] was removed. Backends from 1.60 to 1.86 won't build. Feed gamepad inputs via io.AddKeyEvent() and ImGuiKey_GamepadXXX enums.
|
||||
//void* ImeWindowHandle; // [Obsoleted in 1.87] Set ImGuiViewport::PlatformHandleRaw instead. Set this to your HWND to get automatic IME cursor positioning.
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// [Internal] Dear ImGui will maintain those fields. Forward compatibility not guaranteed!
|
||||
//------------------------------------------------------------------
|
||||
|
@ -2241,6 +2247,16 @@ struct ImGuiIO
|
|||
ImWchar16 InputQueueSurrogate; // For AddInputCharacterUTF16()
|
||||
ImVector<ImWchar> InputQueueCharacters; // Queue of _characters_ input (obtained by platform backend). Fill using AddInputCharacter() helper.
|
||||
|
||||
// Legacy: before 1.87, we required backend to fill io.KeyMap[] (imgui->native map) during initialization and io.KeysDown[] (native indices) every frame.
|
||||
// This is still temporarily supported as a legacy feature. However the new preferred scheme is for backend to call io.AddKeyEvent().
|
||||
// Old (<1.87): ImGui::IsKeyPressed(ImGui::GetIO().KeyMap[ImGuiKey_Space]) --> New (1.87+) ImGui::IsKeyPressed(ImGuiKey_Space)
|
||||
#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO
|
||||
int KeyMap[ImGuiKey_COUNT]; // [LEGACY] Input: map of indices into the KeysDown[512] entries array which represent your "native" keyboard state. The first 512 are now unused and should be kept zero. Legacy backend will write into KeyMap[] using ImGuiKey_ indices which are always >512.
|
||||
bool KeysDown[ImGuiKey_COUNT]; // [LEGACY] Input: Keyboard keys that are pressed (ideally left in the "native" order your engine has access to keyboard keys, so you can use your own defines/enums for keys). This used to be [512] sized. It is now ImGuiKey_COUNT to allow legacy io.KeysDown[GetKeyIndex(...)] to work without an overflow.
|
||||
float NavInputs[ImGuiNavInput_COUNT]; // [LEGACY] Since 1.88, NavInputs[] was removed. Backends from 1.60 to 1.86 won't build. Feed gamepad inputs via io.AddKeyEvent() and ImGuiKey_GamepadXXX enums.
|
||||
//void* ImeWindowHandle; // [Obsoleted in 1.87] Set ImGuiViewport::PlatformHandleRaw instead. Set this to your HWND to get automatic IME cursor positioning.
|
||||
#endif
|
||||
|
||||
IMGUI_API ImGuiIO();
|
||||
};
|
||||
|
||||
|
@ -2265,6 +2281,8 @@ struct ImGuiInputTextCallbackData
|
|||
void* UserData; // What user passed to InputText() // Read-only
|
||||
|
||||
// Arguments for the different callback events
|
||||
// - During Resize callback, Buf will be same as your input buffer.
|
||||
// - However, during Completion/History/Always callback, Buf always points to our own internal data (it is not the same as your buffer)! Changes to it will be reflected into your own buffer shortly after the callback.
|
||||
// - To modify the text buffer in a callback, prefer using the InsertChars() / DeleteChars() function. InsertChars() will take care of calling the resize callback if necessary.
|
||||
// - If you know your edits are not going to resize the underlying buffer allocation, you may modify the contents of 'Buf[]' directly. You need to update 'BufTextLen' accordingly (0 <= BufTextLen < BufSize) and set 'BufDirty'' to true so InputText can update its internal state.
|
||||
ImWchar EventChar; // Character input // Read-write // [CharFilter] Replace character with another one, or set to zero to drop. return 1 is equivalent to setting EventChar=0;
|
||||
|
@ -2708,15 +2726,15 @@ struct ImDrawList
|
|||
// [Internal, used while building lists]
|
||||
unsigned int _VtxCurrentIdx; // [Internal] generally == VtxBuffer.Size unless we are past 64K vertices, in which case this gets reset to 0.
|
||||
ImDrawListSharedData* _Data; // Pointer to shared draw data (you can use ImGui::GetDrawListSharedData() to get the one from current ImGui context)
|
||||
const char* _OwnerName; // Pointer to owner window's name for debugging
|
||||
ImDrawVert* _VtxWritePtr; // [Internal] point within VtxBuffer.Data after each add command (to avoid using the ImVector<> operators too much)
|
||||
ImDrawIdx* _IdxWritePtr; // [Internal] point within IdxBuffer.Data after each add command (to avoid using the ImVector<> operators too much)
|
||||
ImVector<ImVec4> _ClipRectStack; // [Internal]
|
||||
ImVector<ImTextureID> _TextureIdStack; // [Internal]
|
||||
ImVector<ImVec2> _Path; // [Internal] current path building
|
||||
ImDrawCmdHeader _CmdHeader; // [Internal] template of active commands. Fields should match those of CmdBuffer.back().
|
||||
ImDrawListSplitter _Splitter; // [Internal] for channels api (note: prefer using your own persistent instance of ImDrawListSplitter!)
|
||||
ImVector<ImVec4> _ClipRectStack; // [Internal]
|
||||
ImVector<ImTextureID> _TextureIdStack; // [Internal]
|
||||
float _FringeScale; // [Internal] anti-alias fringe is scaled by this value, this helps to keep things sharp while zooming at vertex buffer content
|
||||
const char* _OwnerName; // Pointer to owner window's name for debugging
|
||||
|
||||
// If you want to create ImDrawList instances, pass them ImGui::GetDrawListSharedData() or create and use your own ImDrawListSharedData (so you can use ImDrawList without ImGui)
|
||||
ImDrawList(ImDrawListSharedData* shared_data) { memset(this, 0, sizeof(*this)); _Data = shared_data; }
|
||||
|
@ -2749,15 +2767,20 @@ struct ImDrawList
|
|||
IMGUI_API void AddCircleFilled(const ImVec2& center, float radius, ImU32 col, int num_segments = 0);
|
||||
IMGUI_API void AddNgon(const ImVec2& center, float radius, ImU32 col, int num_segments, float thickness = 1.0f);
|
||||
IMGUI_API void AddNgonFilled(const ImVec2& center, float radius, ImU32 col, int num_segments);
|
||||
IMGUI_API void AddEllipse(const ImVec2& center, float radius_x, float radius_y, ImU32 col, float rot = 0.0f, int num_segments = 0, float thickness = 1.0f);
|
||||
IMGUI_API void AddEllipseFilled(const ImVec2& center, float radius_x, float radius_y, ImU32 col, float rot = 0.0f, int num_segments = 0);
|
||||
IMGUI_API void AddEllipse(const ImVec2& center, const ImVec2& radius, ImU32 col, float rot = 0.0f, int num_segments = 0, float thickness = 1.0f);
|
||||
IMGUI_API void AddEllipseFilled(const ImVec2& center, const ImVec2& radius, ImU32 col, float rot = 0.0f, int num_segments = 0);
|
||||
IMGUI_API void AddText(const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end = NULL);
|
||||
IMGUI_API void AddText(const ImFont* font, float font_size, const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end = NULL, float wrap_width = 0.0f, const ImVec4* cpu_fine_clip_rect = NULL);
|
||||
IMGUI_API void AddPolyline(const ImVec2* points, int num_points, ImU32 col, ImDrawFlags flags, float thickness);
|
||||
IMGUI_API void AddConvexPolyFilled(const ImVec2* points, int num_points, ImU32 col);
|
||||
IMGUI_API void AddBezierCubic(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, ImU32 col, float thickness, int num_segments = 0); // Cubic Bezier (4 control points)
|
||||
IMGUI_API void AddBezierQuadratic(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, ImU32 col, float thickness, int num_segments = 0); // Quadratic Bezier (3 control points)
|
||||
|
||||
// General polygon
|
||||
// - Only simple polygons are supported by filling functions (no self-intersections, no holes).
|
||||
// - Concave polygon fill is more expensive than convex one: it has O(N^2) complexity. Provided as a convenience fo user but not used by main library.
|
||||
IMGUI_API void AddPolyline(const ImVec2* points, int num_points, ImU32 col, ImDrawFlags flags, float thickness);
|
||||
IMGUI_API void AddConvexPolyFilled(const ImVec2* points, int num_points, ImU32 col);
|
||||
IMGUI_API void AddConcavePolyFilled(const ImVec2* points, int num_points, ImU32 col);
|
||||
|
||||
// Image primitives
|
||||
// - Read FAQ to understand what ImTextureID is.
|
||||
// - "p_min" and "p_max" represent the upper-left and lower-right corners of the rectangle.
|
||||
|
@ -2773,10 +2796,11 @@ struct ImDrawList
|
|||
inline void PathLineTo(const ImVec2& pos) { _Path.push_back(pos); }
|
||||
inline void PathLineToMergeDuplicate(const ImVec2& pos) { if (_Path.Size == 0 || memcmp(&_Path.Data[_Path.Size - 1], &pos, 8) != 0) _Path.push_back(pos); }
|
||||
inline void PathFillConvex(ImU32 col) { AddConvexPolyFilled(_Path.Data, _Path.Size, col); _Path.Size = 0; }
|
||||
inline void PathFillConcave(ImU32 col) { AddConcavePolyFilled(_Path.Data, _Path.Size, col); _Path.Size = 0; }
|
||||
inline void PathStroke(ImU32 col, ImDrawFlags flags = 0, float thickness = 1.0f) { AddPolyline(_Path.Data, _Path.Size, col, flags, thickness); _Path.Size = 0; }
|
||||
IMGUI_API void PathArcTo(const ImVec2& center, float radius, float a_min, float a_max, int num_segments = 0);
|
||||
IMGUI_API void PathArcToFast(const ImVec2& center, float radius, int a_min_of_12, int a_max_of_12); // Use precomputed angles for a 12 steps circle
|
||||
IMGUI_API void PathEllipticalArcTo(const ImVec2& center, float radius_x, float radius_y, float rot, float a_min, float a_max, int num_segments = 0); // Ellipse
|
||||
IMGUI_API void PathEllipticalArcTo(const ImVec2& center, const ImVec2& radius, float rot, float a_min, float a_max, int num_segments = 0); // Ellipse
|
||||
IMGUI_API void PathBezierCubicCurveTo(const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, int num_segments = 0); // Cubic Bezier (4 control points)
|
||||
IMGUI_API void PathBezierQuadraticCurveTo(const ImVec2& p2, const ImVec2& p3, int num_segments = 0); // Quadratic Bezier (3 control points)
|
||||
IMGUI_API void PathRect(const ImVec2& rect_min, const ImVec2& rect_max, float rounding = 0.0f, ImDrawFlags flags = 0);
|
||||
|
@ -2809,6 +2833,9 @@ struct ImDrawList
|
|||
inline void PrimVtx(const ImVec2& pos, const ImVec2& uv, ImU32 col) { PrimWriteIdx((ImDrawIdx)_VtxCurrentIdx); PrimWriteVtx(pos, uv, col); } // Write vertex with unique index
|
||||
|
||||
// Obsolete names
|
||||
//inline void AddEllipse(const ImVec2& center, float radius_x, float radius_y, ImU32 col, float rot = 0.0f, int num_segments = 0, float thickness = 1.0f) { AddEllipse(center, ImVec2(radius_x, radius_y), col, rot, num_segments, thickness); } // OBSOLETED in 1.90.5 (Mar 2024)
|
||||
//inline void AddEllipseFilled(const ImVec2& center, float radius_x, float radius_y, ImU32 col, float rot = 0.0f, int num_segments = 0) { AddEllipseFilled(center, ImVec2(radius_x, radius_y), col, rot, num_segments); } // OBSOLETED in 1.90.5 (Mar 2024)
|
||||
//inline void PathEllipticalArcTo(const ImVec2& center, float radius_x, float radius_y, float rot, float a_min, float a_max, int num_segments = 0) { PathEllipticalArcTo(center, ImVec2(radius_x, radius_y), rot, a_min, a_max, num_segments); } // OBSOLETED in 1.90.5 (Mar 2024)
|
||||
//inline void AddBezierCurve(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, ImU32 col, float thickness, int num_segments = 0) { AddBezierCubic(p1, p2, p3, p4, col, thickness, num_segments); } // OBSOLETED in 1.80 (Jan 2021)
|
||||
//inline void PathBezierCurveTo(const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, int num_segments = 0) { PathBezierCubicCurveTo(p2, p3, p4, num_segments); } // OBSOLETED in 1.80 (Jan 2021)
|
||||
|
||||
|
@ -3163,15 +3190,6 @@ struct ImGuiPlatformImeData
|
|||
// Please keep your copy of dear imgui up to date! Occasionally set '#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS' in imconfig.h to stay ahead.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
namespace ImGui
|
||||
{
|
||||
#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO
|
||||
IMGUI_API ImGuiKey GetKeyIndex(ImGuiKey key); // map ImGuiKey_* values into legacy native key index. == io.KeyMap[key]
|
||||
#else
|
||||
static inline ImGuiKey GetKeyIndex(ImGuiKey key) { IM_ASSERT(key >= ImGuiKey_NamedKey_BEGIN && key < ImGuiKey_NamedKey_END && "ImGuiKey and native_index was merged together and native_index is disabled by IMGUI_DISABLE_OBSOLETE_KEYIO. Please switch to ImGuiKey."); return key; }
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
|
||||
namespace ImGui
|
||||
{
|
||||
|
@ -3193,6 +3211,9 @@ namespace ImGui
|
|||
// OBSOLETED in 1.88 (from May 2022)
|
||||
static inline void CaptureKeyboardFromApp(bool want_capture_keyboard = true) { SetNextFrameWantCaptureKeyboard(want_capture_keyboard); } // Renamed as name was misleading + removed default value.
|
||||
static inline void CaptureMouseFromApp(bool want_capture_mouse = true) { SetNextFrameWantCaptureMouse(want_capture_mouse); } // Renamed as name was misleading + removed default value.
|
||||
// OBSOLETED in 1.87 (from February 2022)
|
||||
IMGUI_API ImGuiKey GetKeyIndex(ImGuiKey key); // Map ImGuiKey_* values into legacy native key index. == io.KeyMap[key]. When using a 1.87+ backend using io.AddKeyEvent(), calling GetKeyIndex() with ANY ImGuiKey_XXXX values will return the same value!
|
||||
//static inline ImGuiKey GetKeyIndex(ImGuiKey key) { IM_ASSERT(key >= ImGuiKey_NamedKey_BEGIN && key < ImGuiKey_NamedKey_END); return key; }
|
||||
|
||||
// Some of the older obsolete names along with their replacement (commented out so they are not reported in IDE)
|
||||
//-- OBSOLETED in 1.86 (from November 2021)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// dear imgui, v1.90.4
|
||||
// dear imgui, v1.90.6
|
||||
// (demo code)
|
||||
|
||||
// Help:
|
||||
|
@ -7,9 +7,14 @@
|
|||
// - Need help integrating Dear ImGui in your codebase?
|
||||
// - Read Getting Started https://github.com/ocornut/imgui/wiki/Getting-Started
|
||||
// - Read 'Programmer guide' in imgui.cpp for notes on how to setup Dear ImGui in your codebase.
|
||||
// Read imgui.cpp for more details, documentation and comments.
|
||||
// Read top of imgui.cpp and imgui.h for many details, documentation, comments, links.
|
||||
// Get the latest version at https://github.com/ocornut/imgui
|
||||
|
||||
// How to easily locate code?
|
||||
// - Use the Item Picker to debug break in code by clicking any widgets: https://github.com/ocornut/imgui/wiki/Debug-Tools
|
||||
// - Browse an online version the demo with code linked to hovered widgets: https://pthom.github.io/imgui_manual_online/manual/imgui_manual.html
|
||||
// - Find a visible string and search for it in the code!
|
||||
|
||||
//---------------------------------------------------
|
||||
// PLEASE DO NOT REMOVE THIS FILE FROM YOUR PROJECT!
|
||||
//---------------------------------------------------
|
||||
|
@ -54,8 +59,9 @@
|
|||
// Because we can't assume anything about your support of maths operators, we cannot use them in imgui_demo.cpp.
|
||||
|
||||
// Navigating this file:
|
||||
// - In Visual Studio: CTRL+comma ("Edit.GoToAll") can follow symbols in comments, whereas CTRL+F12 ("Edit.GoToImplementation") cannot.
|
||||
// - With Visual Assist installed: ALT+G ("VAssistX.GoToImplementation") can also follow symbols in comments.
|
||||
// - In Visual Studio: CTRL+comma ("Edit.GoToAll") can follow symbols inside comments, whereas CTRL+F12 ("Edit.GoToImplementation") cannot.
|
||||
// - In Visual Studio w/ Visual Assist installed: ALT+G ("VAssistX.GoToImplementation") can also follow symbols inside comments.
|
||||
// - In VS Code, CLion, etc.: CTRL+click can follow symbols inside comments.
|
||||
|
||||
/*
|
||||
|
||||
|
@ -130,6 +136,7 @@ Index of this file:
|
|||
#pragma clang diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function // using printf() is a misery with this as C++ va_arg ellipsis changes float to double.
|
||||
#pragma clang diagnostic ignored "-Wreserved-id-macro" // warning: macro name is a reserved identifier
|
||||
#pragma clang diagnostic ignored "-Wimplicit-int-float-conversion" // warning: implicit conversion from 'xxx' to 'float' may lose precision
|
||||
#pragma clang diagnostic ignored "-Wunsafe-buffer-usage" // warning: 'xxx' is an unsafe pointer used for buffer access
|
||||
#elif defined(__GNUC__)
|
||||
#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind
|
||||
#pragma GCC diagnostic ignored "-Wint-to-pointer-cast" // warning: cast to pointer from integer of different size
|
||||
|
@ -899,13 +906,18 @@ static void ShowDemoWindowWidgets()
|
|||
if (i == 0)
|
||||
ImGui::SetNextItemOpen(true, ImGuiCond_Once);
|
||||
|
||||
if (ImGui::TreeNode((void*)(intptr_t)i, "Child %d", i))
|
||||
// Here we use PushID() to generate a unique base ID, and then the "" used as TreeNode id won't conflict.
|
||||
// An alternative to using 'PushID() + TreeNode("", ...)' to generate a unique ID is to use 'TreeNode((void*)(intptr_t)i, ...)',
|
||||
// aka generate a dummy pointer-sized value to be hashed. The demo below uses that technique. Both are fine.
|
||||
ImGui::PushID(i);
|
||||
if (ImGui::TreeNode("", "Child %d", i))
|
||||
{
|
||||
ImGui::Text("blah blah");
|
||||
ImGui::SameLine();
|
||||
if (ImGui::SmallButton("button")) {}
|
||||
ImGui::TreePop();
|
||||
}
|
||||
ImGui::PopID();
|
||||
}
|
||||
ImGui::TreePop();
|
||||
}
|
||||
|
@ -923,7 +935,10 @@ static void ShowDemoWindowWidgets()
|
|||
ImGui::CheckboxFlags("ImGuiTreeNodeFlags_OpenOnDoubleClick", &base_flags, ImGuiTreeNodeFlags_OpenOnDoubleClick);
|
||||
ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanAvailWidth", &base_flags, ImGuiTreeNodeFlags_SpanAvailWidth); ImGui::SameLine(); HelpMarker("Extend hit area to all available width instead of allowing more items to be laid out after the node.");
|
||||
ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanFullWidth", &base_flags, ImGuiTreeNodeFlags_SpanFullWidth);
|
||||
ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanTextWidth", &base_flags, ImGuiTreeNodeFlags_SpanTextWidth); ImGui::SameLine(); HelpMarker("Reduce hit area to the text label and a bit of margin.");
|
||||
ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanAllColumns", &base_flags, ImGuiTreeNodeFlags_SpanAllColumns); ImGui::SameLine(); HelpMarker("For use in Tables only.");
|
||||
ImGui::CheckboxFlags("ImGuiTreeNodeFlags_AllowOverlap", &base_flags, ImGuiTreeNodeFlags_AllowOverlap);
|
||||
ImGui::CheckboxFlags("ImGuiTreeNodeFlags_Framed", &base_flags, ImGuiTreeNodeFlags_Framed); ImGui::SameLine(); HelpMarker("Draw frame with background (e.g. for CollapsingHeader)");
|
||||
ImGui::Checkbox("Align label with current X position", &align_label_with_current_x_position);
|
||||
ImGui::Checkbox("Test tree node as drag source", &test_drag_and_drop);
|
||||
ImGui::Text("Hello!");
|
||||
|
@ -956,6 +971,12 @@ static void ShowDemoWindowWidgets()
|
|||
ImGui::Text("This is a drag and drop source");
|
||||
ImGui::EndDragDropSource();
|
||||
}
|
||||
if (i == 2)
|
||||
{
|
||||
// Item 2 has an additional inline button to help demonstrate SpanTextWidth.
|
||||
ImGui::SameLine();
|
||||
if (ImGui::SmallButton("button")) {}
|
||||
}
|
||||
if (node_open)
|
||||
{
|
||||
ImGui::BulletText("Blah blah\nBlah Blah");
|
||||
|
@ -1288,6 +1309,7 @@ static void ShowDemoWindowWidgets()
|
|||
}
|
||||
ImGui::EndListBox();
|
||||
}
|
||||
ImGui::SameLine(); HelpMarker("Here we are sharing selection state between both boxes.");
|
||||
|
||||
// Custom size: use all width, 5 items tall
|
||||
ImGui::Text("Full-width:");
|
||||
|
@ -1818,10 +1840,10 @@ static void ShowDemoWindowWidgets()
|
|||
ImGui::Checkbox("Animate", &animate);
|
||||
|
||||
// Plot as lines and plot as histogram
|
||||
IMGUI_DEMO_MARKER("Widgets/Plotting/PlotLines, PlotHistogram");
|
||||
static float arr[] = { 0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f };
|
||||
ImGui::PlotLines("Frame Times", arr, IM_ARRAYSIZE(arr));
|
||||
ImGui::PlotHistogram("Histogram", arr, IM_ARRAYSIZE(arr), 0, NULL, 0.0f, 1.0f, ImVec2(0, 80.0f));
|
||||
//ImGui::SameLine(); HelpMarker("Consider using ImPlot instead!");
|
||||
|
||||
// Fill an array of contiguous float values to plot
|
||||
// Tip: If your float aren't contiguous but part of a structure, you can pass a pointer to your first float
|
||||
|
@ -1871,15 +1893,17 @@ static void ShowDemoWindowWidgets()
|
|||
ImGui::PlotHistogram("Histogram", func, NULL, display_count, 0, NULL, -1.0f, 1.0f, ImVec2(0, 80));
|
||||
ImGui::Separator();
|
||||
|
||||
ImGui::TreePop();
|
||||
}
|
||||
|
||||
IMGUI_DEMO_MARKER("Widgets/Progress Bars");
|
||||
if (ImGui::TreeNode("Progress Bars"))
|
||||
{
|
||||
// Animate a simple progress bar
|
||||
IMGUI_DEMO_MARKER("Widgets/Plotting/ProgressBar");
|
||||
static float progress = 0.0f, progress_dir = 1.0f;
|
||||
if (animate)
|
||||
{
|
||||
progress += progress_dir * 0.4f * ImGui::GetIO().DeltaTime;
|
||||
if (progress >= +1.1f) { progress = +1.1f; progress_dir *= -1.0f; }
|
||||
if (progress <= -0.1f) { progress = -0.1f; progress_dir *= -1.0f; }
|
||||
}
|
||||
progress += progress_dir * 0.4f * ImGui::GetIO().DeltaTime;
|
||||
if (progress >= +1.1f) { progress = +1.1f; progress_dir *= -1.0f; }
|
||||
if (progress <= -0.1f) { progress = -0.1f; progress_dir *= -1.0f; }
|
||||
|
||||
// Typically we would use ImVec2(-1.0f,0.0f) or ImVec2(-FLT_MIN,0.0f) to use all available width,
|
||||
// or ImVec2(width,0.0f) for a specified width. ImVec2(0.0f,0.0f) uses ItemWidth.
|
||||
|
@ -1891,6 +1915,13 @@ static void ShowDemoWindowWidgets()
|
|||
char buf[32];
|
||||
sprintf(buf, "%d/%d", (int)(progress_saturated * 1753), 1753);
|
||||
ImGui::ProgressBar(progress, ImVec2(0.f, 0.f), buf);
|
||||
|
||||
// Pass an animated negative value, e.g. -1.0f * (float)ImGui::GetTime() is the recommended value.
|
||||
// Adjust the factor if you want to adjust the animation speed.
|
||||
ImGui::ProgressBar(-1.0f * (float)ImGui::GetTime(), ImVec2(0.0f, 0.0f), "Searching..");
|
||||
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
||||
ImGui::Text("Indeterminate");
|
||||
|
||||
ImGui::TreePop();
|
||||
}
|
||||
|
||||
|
@ -2481,9 +2512,7 @@ static void ShowDemoWindowWidgets()
|
|||
{
|
||||
IM_UNUSED(payload);
|
||||
ImGui::SetMouseCursor(ImGuiMouseCursor_NotAllowed);
|
||||
ImGui::BeginTooltip();
|
||||
ImGui::Text("Cannot drop here!");
|
||||
ImGui::EndTooltip();
|
||||
ImGui::SetTooltip("Cannot drop here!");
|
||||
}
|
||||
ImGui::EndDragDropTarget();
|
||||
}
|
||||
|
@ -5139,7 +5168,8 @@ static void ShowDemoWindowTables()
|
|||
static ImGuiTableFlags flags = ImGuiTableFlags_BordersV | ImGuiTableFlags_BordersOuterH | ImGuiTableFlags_Resizable | ImGuiTableFlags_RowBg | ImGuiTableFlags_NoBordersInBody;
|
||||
|
||||
static ImGuiTreeNodeFlags tree_node_flags = ImGuiTreeNodeFlags_SpanAllColumns;
|
||||
ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanFullWidth", &tree_node_flags, ImGuiTreeNodeFlags_SpanFullWidth);
|
||||
ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanFullWidth", &tree_node_flags, ImGuiTreeNodeFlags_SpanFullWidth);
|
||||
ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanTextWidth", &tree_node_flags, ImGuiTreeNodeFlags_SpanTextWidth);
|
||||
ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanAllColumns", &tree_node_flags, ImGuiTreeNodeFlags_SpanAllColumns);
|
||||
|
||||
HelpMarker("See \"Columns flags\" section to configure how indentation is applied to individual columns.");
|
||||
|
@ -5328,6 +5358,17 @@ static void ShowDemoWindowTables()
|
|||
ImGui::SliderInt("Frozen rows", &frozen_rows, 0, 2);
|
||||
ImGui::CheckboxFlags("Disable header contributing to column width", &column_flags, ImGuiTableColumnFlags_NoHeaderWidth);
|
||||
|
||||
if (ImGui::TreeNode("Style settings"))
|
||||
{
|
||||
ImGui::SameLine();
|
||||
HelpMarker("Giving access to some ImGuiStyle value in this demo for convenience.");
|
||||
ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8);
|
||||
ImGui::SliderAngle("style.TableAngledHeadersAngle", &ImGui::GetStyle().TableAngledHeadersAngle, -50.0f, +50.0f);
|
||||
ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8);
|
||||
ImGui::SliderFloat2("style.TableAngledHeadersTextAlign", (float*)&ImGui::GetStyle().TableAngledHeadersTextAlign, 0.0f, 1.0f, "%.2f");
|
||||
ImGui::TreePop();
|
||||
}
|
||||
|
||||
if (ImGui::BeginTable("table_angled_headers", columns_count, table_flags, ImVec2(0.0f, TEXT_BASE_HEIGHT * 12)))
|
||||
{
|
||||
ImGui::TableSetupColumn(column_names[0], ImGuiTableColumnFlags_NoHide | ImGuiTableColumnFlags_NoReorder);
|
||||
|
@ -5479,6 +5520,7 @@ static void ShowDemoWindowTables()
|
|||
HelpMarker("Multiple tables with the same identifier will share their settings, width, visibility, order etc.");
|
||||
|
||||
static ImGuiTableFlags flags = ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Borders | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_NoSavedSettings;
|
||||
ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags, ImGuiTableFlags_Resizable);
|
||||
ImGui::CheckboxFlags("ImGuiTableFlags_ScrollY", &flags, ImGuiTableFlags_ScrollY);
|
||||
ImGui::CheckboxFlags("ImGuiTableFlags_SizingFixedFit", &flags, ImGuiTableFlags_SizingFixedFit);
|
||||
ImGui::CheckboxFlags("ImGuiTableFlags_HighlightHoveredColumn", &flags, ImGuiTableFlags_HighlightHoveredColumn);
|
||||
|
@ -6351,7 +6393,7 @@ void ImGui::ShowAboutWindow(bool* p_open)
|
|||
ImGui::Separator();
|
||||
ImGui::Text("By Omar Cornut and all Dear ImGui contributors.");
|
||||
ImGui::Text("Dear ImGui is licensed under the MIT License, see LICENSE for more information.");
|
||||
ImGui::Text("If your company uses this, please consider sponsoring the project!");
|
||||
ImGui::Text("If your company uses this, please consider funding the project.");
|
||||
|
||||
static bool show_config_info = false;
|
||||
ImGui::Checkbox("Config/Build Information", &show_config_info);
|
||||
|
@ -6616,6 +6658,7 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref)
|
|||
ImGui::SeparatorText("Tables");
|
||||
ImGui::SliderFloat2("CellPadding", (float*)&style.CellPadding, 0.0f, 20.0f, "%.0f");
|
||||
ImGui::SliderAngle("TableAngledHeadersAngle", &style.TableAngledHeadersAngle, -50.0f, +50.0f);
|
||||
ImGui::SliderFloat2("TableAngledHeadersTextAlign", (float*)&style.TableAngledHeadersTextAlign, 0.0f, 1.0f, "%.2f");
|
||||
|
||||
ImGui::SeparatorText("Widgets");
|
||||
ImGui::SliderFloat2("WindowTitleAlign", (float*)&style.WindowTitleAlign, 0.0f, 1.0f, "%.2f");
|
||||
|
@ -7789,7 +7832,7 @@ static void ShowExampleAppConstrainedResize(bool* p_open)
|
|||
if (type == 2) ImGui::SetNextWindowSizeConstraints(ImVec2(-1, 0), ImVec2(-1, FLT_MAX)); // Resize vertical + lock current width
|
||||
if (type == 3) ImGui::SetNextWindowSizeConstraints(ImVec2(0, -1), ImVec2(FLT_MAX, -1)); // Resize horizontal + lock current height
|
||||
if (type == 4) ImGui::SetNextWindowSizeConstraints(ImVec2(400, -1), ImVec2(500, -1)); // Width Between and 400 and 500
|
||||
if (type == 5) ImGui::SetNextWindowSizeConstraints(ImVec2(-1, 500), ImVec2(-1, FLT_MAX)); // Height at least 400
|
||||
if (type == 5) ImGui::SetNextWindowSizeConstraints(ImVec2(-1, 400), ImVec2(-1, FLT_MAX)); // Height at least 400
|
||||
if (type == 6) ImGui::SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(FLT_MAX, FLT_MAX), CustomConstraints::AspectRatio, (void*)&aspect_ratio); // Aspect ratio
|
||||
if (type == 7) ImGui::SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(FLT_MAX, FLT_MAX), CustomConstraints::Square); // Always Square
|
||||
if (type == 8) ImGui::SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(FLT_MAX, FLT_MAX), CustomConstraints::Step, (void*)&fixed_step); // Fixed Step
|
||||
|
@ -7964,6 +8007,14 @@ static void ShowExampleAppWindowTitles(bool*)
|
|||
// [SECTION] Example App: Custom Rendering using ImDrawList API / ShowExampleAppCustomRendering()
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// Add a |_| looking shape
|
||||
static void PathConcaveShape(ImDrawList* draw_list, float x, float y, float sz)
|
||||
{
|
||||
const ImVec2 pos_norms[] = { { 0.0f, 0.0f }, { 0.3f, 0.0f }, { 0.3f, 0.7f }, { 0.7f, 0.7f }, { 0.7f, 0.0f }, { 1.0f, 0.0f }, { 1.0f, 1.0f }, { 0.0f, 1.0f } };
|
||||
for (const ImVec2& p : pos_norms)
|
||||
draw_list->PathLineTo(ImVec2(x + 0.5f + (int)(sz * p.x), y + 0.5f + (int)(sz * p.y)));
|
||||
}
|
||||
|
||||
// Demonstrate using the low-level ImDrawList to draw custom shapes.
|
||||
static void ShowExampleAppCustomRendering(bool* p_open)
|
||||
{
|
||||
|
@ -8047,12 +8098,14 @@ static void ShowExampleAppCustomRendering(bool* p_open)
|
|||
float th = (n == 0) ? 1.0f : thickness;
|
||||
draw_list->AddNgon(ImVec2(x + sz*0.5f, y + sz*0.5f), sz*0.5f, col, ngon_sides, th); x += sz + spacing; // N-gon
|
||||
draw_list->AddCircle(ImVec2(x + sz*0.5f, y + sz*0.5f), sz*0.5f, col, circle_segments, th); x += sz + spacing; // Circle
|
||||
draw_list->AddEllipse(ImVec2(x + sz*0.5f, y + sz*0.5f), sz*0.5f, sz*0.3f, col, -0.3f, circle_segments, th); x += sz + spacing; // Ellipse
|
||||
draw_list->AddEllipse(ImVec2(x + sz*0.5f, y + sz*0.5f), ImVec2(sz*0.5f, sz*0.3f), col, -0.3f, circle_segments, th); x += sz + spacing; // Ellipse
|
||||
draw_list->AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, 0.0f, ImDrawFlags_None, th); x += sz + spacing; // Square
|
||||
draw_list->AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, rounding, ImDrawFlags_None, th); x += sz + spacing; // Square with all rounded corners
|
||||
draw_list->AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, rounding, corners_tl_br, th); x += sz + spacing; // Square with two rounded corners
|
||||
draw_list->AddTriangle(ImVec2(x+sz*0.5f,y), ImVec2(x+sz, y+sz-0.5f), ImVec2(x, y+sz-0.5f), col, th);x += sz + spacing; // Triangle
|
||||
//draw_list->AddTriangle(ImVec2(x+sz*0.2f,y), ImVec2(x, y+sz-0.5f), ImVec2(x+sz*0.4f, y+sz-0.5f), col, th);x+= sz*0.4f + spacing; // Thin triangle
|
||||
PathConcaveShape(draw_list, x, y, sz); draw_list->PathStroke(col, ImDrawFlags_Closed, th); x += sz + spacing; // Concave Shape
|
||||
//draw_list->AddPolyline(concave_shape, IM_ARRAYSIZE(concave_shape), col, ImDrawFlags_Closed, th);
|
||||
draw_list->AddLine(ImVec2(x, y), ImVec2(x + sz, y), col, th); x += sz + spacing; // Horizontal line (note: drawing a filled rectangle will be faster!)
|
||||
draw_list->AddLine(ImVec2(x, y), ImVec2(x, y + sz), col, th); x += spacing; // Vertical line (note: drawing a filled rectangle will be faster!)
|
||||
draw_list->AddLine(ImVec2(x, y), ImVec2(x + sz, y + sz), col, th); x += sz + spacing; // Diagonal line
|
||||
|
@ -8076,12 +8129,13 @@ static void ShowExampleAppCustomRendering(bool* p_open)
|
|||
// Filled shapes
|
||||
draw_list->AddNgonFilled(ImVec2(x + sz * 0.5f, y + sz * 0.5f), sz * 0.5f, col, ngon_sides); x += sz + spacing; // N-gon
|
||||
draw_list->AddCircleFilled(ImVec2(x + sz * 0.5f, y + sz * 0.5f), sz * 0.5f, col, circle_segments); x += sz + spacing; // Circle
|
||||
draw_list->AddEllipseFilled(ImVec2(x + sz * 0.5f, y + sz * 0.5f), sz * 0.5f, sz * 0.3f, col, -0.3f, circle_segments); x += sz + spacing;// Ellipse
|
||||
draw_list->AddEllipseFilled(ImVec2(x + sz * 0.5f, y + sz * 0.5f), ImVec2(sz * 0.5f, sz * 0.3f), col, -0.3f, circle_segments); x += sz + spacing;// Ellipse
|
||||
draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + sz), col); x += sz + spacing; // Square
|
||||
draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + sz), col, 10.0f); x += sz + spacing; // Square with all rounded corners
|
||||
draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + sz), col, 10.0f, corners_tl_br); x += sz + spacing; // Square with two rounded corners
|
||||
draw_list->AddTriangleFilled(ImVec2(x+sz*0.5f,y), ImVec2(x+sz, y+sz-0.5f), ImVec2(x, y+sz-0.5f), col); x += sz + spacing; // Triangle
|
||||
//draw_list->AddTriangleFilled(ImVec2(x+sz*0.2f,y), ImVec2(x, y+sz-0.5f), ImVec2(x+sz*0.4f, y+sz-0.5f), col); x += sz*0.4f + spacing; // Thin triangle
|
||||
PathConcaveShape(draw_list, x, y, sz); draw_list->PathFillConcave(col); x += sz + spacing; // Concave shape
|
||||
draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + thickness), col); x += sz + spacing; // Horizontal line (faster than AddLine, but only handle integer thickness)
|
||||
draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + thickness, y + sz), col); x += spacing * 2.0f;// Vertical line (faster than AddLine, but only handle integer thickness)
|
||||
draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + 1, y + 1), col); x += sz; // Pixel (faster than AddLine)
|
||||
|
@ -8097,15 +8151,10 @@ static void ShowExampleAppCustomRendering(bool* p_open)
|
|||
draw_list->PathFillConvex(col);
|
||||
x += sz + spacing;
|
||||
|
||||
// Cubic Bezier Curve (4 control points): this is concave so not drawing it yet
|
||||
//draw_list->PathLineTo(ImVec2(x + cp4[0].x, y + cp4[0].y));
|
||||
//draw_list->PathBezierCubicCurveTo(ImVec2(x + cp4[1].x, y + cp4[1].y), ImVec2(x + cp4[2].x, y + cp4[2].y), ImVec2(x + cp4[3].x, y + cp4[3].y), curve_segments);
|
||||
//draw_list->PathFillConvex(col);
|
||||
//x += sz + spacing;
|
||||
|
||||
draw_list->AddRectFilledMultiColor(ImVec2(x, y), ImVec2(x + sz, y + sz), IM_COL32(0, 0, 0, 255), IM_COL32(255, 0, 0, 255), IM_COL32(255, 255, 0, 255), IM_COL32(0, 255, 0, 255));
|
||||
x += sz + spacing;
|
||||
|
||||
ImGui::Dummy(ImVec2((sz + spacing) * 12.2f, (sz + spacing) * 3.0f));
|
||||
ImGui::Dummy(ImVec2((sz + spacing) * 13.2f, (sz + spacing) * 3.0f));
|
||||
ImGui::PopItemWidth();
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// dear imgui, v1.90.4
|
||||
// dear imgui, v1.90.6
|
||||
// (drawing and font code)
|
||||
|
||||
/*
|
||||
|
@ -8,6 +8,7 @@ Index of this file:
|
|||
// [SECTION] STB libraries implementation
|
||||
// [SECTION] Style functions
|
||||
// [SECTION] ImDrawList
|
||||
// [SECTION] ImTriangulator, ImDrawList concave polygon fill
|
||||
// [SECTION] ImDrawListSplitter
|
||||
// [SECTION] ImDrawData
|
||||
// [SECTION] Helpers ShadeVertsXXX functions
|
||||
|
@ -64,6 +65,7 @@ Index of this file:
|
|||
#pragma clang diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function // using printf() is a misery with this as C++ va_arg ellipsis changes float to double.
|
||||
#pragma clang diagnostic ignored "-Wimplicit-int-float-conversion" // warning: implicit conversion from 'xxx' to 'float' may lose precision
|
||||
#pragma clang diagnostic ignored "-Wreserved-identifier" // warning: identifier '_Xxx' is reserved because it starts with '_' followed by a capital letter
|
||||
#pragma clang diagnostic ignored "-Wunsafe-buffer-usage" // warning: 'xxx' is an unsafe pointer used for buffer access
|
||||
#elif defined(__GNUC__)
|
||||
#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind
|
||||
#pragma GCC diagnostic ignored "-Wunused-function" // warning: 'xxxx' defined but not used
|
||||
|
@ -383,6 +385,7 @@ void ImDrawListSharedData::SetCircleTessellationMaxError(float max_error)
|
|||
}
|
||||
|
||||
// Initialize before use in a new frame. We always have a command ready in the buffer.
|
||||
// In the majority of cases, you would want to call PushClipRect() and PushTextureID() after this.
|
||||
void ImDrawList::_ResetForNewFrame()
|
||||
{
|
||||
// Verify that the ImDrawCmd fields we want to memcmp() are contiguous in memory.
|
||||
|
@ -1217,10 +1220,10 @@ void ImDrawList::PathArcTo(const ImVec2& center, float radius, float a_min, floa
|
|||
}
|
||||
}
|
||||
|
||||
void ImDrawList::PathEllipticalArcTo(const ImVec2& center, float radius_x, float radius_y, float rot, float a_min, float a_max, int num_segments)
|
||||
void ImDrawList::PathEllipticalArcTo(const ImVec2& center, const ImVec2& radius, float rot, float a_min, float a_max, int num_segments)
|
||||
{
|
||||
if (num_segments <= 0)
|
||||
num_segments = _CalcCircleAutoSegmentCount(ImMax(radius_x, radius_y)); // A bit pessimistic, maybe there's a better computation to do here.
|
||||
num_segments = _CalcCircleAutoSegmentCount(ImMax(radius.x, radius.y)); // A bit pessimistic, maybe there's a better computation to do here.
|
||||
|
||||
_Path.reserve(_Path.Size + (num_segments + 1));
|
||||
|
||||
|
@ -1229,11 +1232,10 @@ void ImDrawList::PathEllipticalArcTo(const ImVec2& center, float radius_x, float
|
|||
for (int i = 0; i <= num_segments; i++)
|
||||
{
|
||||
const float a = a_min + ((float)i / (float)num_segments) * (a_max - a_min);
|
||||
ImVec2 point(ImCos(a) * radius_x, ImSin(a) * radius_y);
|
||||
const float rel_x = (point.x * cos_rot) - (point.y * sin_rot);
|
||||
const float rel_y = (point.x * sin_rot) + (point.y * cos_rot);
|
||||
point.x = rel_x + center.x;
|
||||
point.y = rel_y + center.y;
|
||||
ImVec2 point(ImCos(a) * radius.x, ImSin(a) * radius.y);
|
||||
const ImVec2 rel((point.x * cos_rot) - (point.y * sin_rot), (point.x * sin_rot) + (point.y * cos_rot));
|
||||
point.x = rel.x + center.x;
|
||||
point.y = rel.y + center.y;
|
||||
_Path.push_back(point);
|
||||
}
|
||||
}
|
||||
|
@ -1558,31 +1560,31 @@ void ImDrawList::AddNgonFilled(const ImVec2& center, float radius, ImU32 col, in
|
|||
}
|
||||
|
||||
// Ellipse
|
||||
void ImDrawList::AddEllipse(const ImVec2& center, float radius_x, float radius_y, ImU32 col, float rot, int num_segments, float thickness)
|
||||
void ImDrawList::AddEllipse(const ImVec2& center, const ImVec2& radius, ImU32 col, float rot, int num_segments, float thickness)
|
||||
{
|
||||
if ((col & IM_COL32_A_MASK) == 0)
|
||||
return;
|
||||
|
||||
if (num_segments <= 0)
|
||||
num_segments = _CalcCircleAutoSegmentCount(ImMax(radius_x, radius_y)); // A bit pessimistic, maybe there's a better computation to do here.
|
||||
num_segments = _CalcCircleAutoSegmentCount(ImMax(radius.x, radius.y)); // A bit pessimistic, maybe there's a better computation to do here.
|
||||
|
||||
// Because we are filling a closed shape we remove 1 from the count of segments/points
|
||||
const float a_max = IM_PI * 2.0f * ((float)num_segments - 1.0f) / (float)num_segments;
|
||||
PathEllipticalArcTo(center, radius_x, radius_y, rot, 0.0f, a_max, num_segments - 1);
|
||||
PathEllipticalArcTo(center, radius, rot, 0.0f, a_max, num_segments - 1);
|
||||
PathStroke(col, true, thickness);
|
||||
}
|
||||
|
||||
void ImDrawList::AddEllipseFilled(const ImVec2& center, float radius_x, float radius_y, ImU32 col, float rot, int num_segments)
|
||||
void ImDrawList::AddEllipseFilled(const ImVec2& center, const ImVec2& radius, ImU32 col, float rot, int num_segments)
|
||||
{
|
||||
if ((col & IM_COL32_A_MASK) == 0)
|
||||
return;
|
||||
|
||||
if (num_segments <= 0)
|
||||
num_segments = _CalcCircleAutoSegmentCount(ImMax(radius_x, radius_y)); // A bit pessimistic, maybe there's a better computation to do here.
|
||||
num_segments = _CalcCircleAutoSegmentCount(ImMax(radius.x, radius.y)); // A bit pessimistic, maybe there's a better computation to do here.
|
||||
|
||||
// Because we are filling a closed shape we remove 1 from the count of segments/points
|
||||
const float a_max = IM_PI * 2.0f * ((float)num_segments - 1.0f) / (float)num_segments;
|
||||
PathEllipticalArcTo(center, radius_x, radius_y, rot, 0.0f, a_max, num_segments - 1);
|
||||
PathEllipticalArcTo(center, radius, rot, 0.0f, a_max, num_segments - 1);
|
||||
PathFillConvex(col);
|
||||
}
|
||||
|
||||
|
@ -1613,10 +1615,11 @@ void ImDrawList::AddText(const ImFont* font, float font_size, const ImVec2& pos,
|
|||
if ((col & IM_COL32_A_MASK) == 0)
|
||||
return;
|
||||
|
||||
// Accept null ranges
|
||||
if (text_begin == text_end || text_begin[0] == 0)
|
||||
return;
|
||||
if (text_end == NULL)
|
||||
text_end = text_begin + strlen(text_begin);
|
||||
if (text_begin == text_end)
|
||||
return;
|
||||
|
||||
// Pull default font/size from the shared ImDrawListSharedData instance
|
||||
if (font == NULL)
|
||||
|
@ -1700,6 +1703,316 @@ void ImDrawList::AddImageRounded(ImTextureID user_texture_id, const ImVec2& p_mi
|
|||
PopTextureID();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// [SECTION] ImTriangulator, ImDrawList concave polygon fill
|
||||
//-----------------------------------------------------------------------------
|
||||
// Triangulate concave polygons. Based on "Triangulation by Ear Clipping" paper, O(N^2) complexity.
|
||||
// Reference: https://www.geometrictools.com/Documentation/TriangulationByEarClipping.pdf
|
||||
// Provided as a convenience for user but not used by main library.
|
||||
//-----------------------------------------------------------------------------
|
||||
// - ImTriangulator [Internal]
|
||||
// - AddConcavePolyFilled()
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
enum ImTriangulatorNodeType
|
||||
{
|
||||
ImTriangulatorNodeType_Convex,
|
||||
ImTriangulatorNodeType_Ear,
|
||||
ImTriangulatorNodeType_Reflex
|
||||
};
|
||||
|
||||
struct ImTriangulatorNode
|
||||
{
|
||||
ImTriangulatorNodeType Type;
|
||||
int Index;
|
||||
ImVec2 Pos;
|
||||
ImTriangulatorNode* Next;
|
||||
ImTriangulatorNode* Prev;
|
||||
|
||||
void Unlink() { Next->Prev = Prev; Prev->Next = Next; }
|
||||
};
|
||||
|
||||
struct ImTriangulatorNodeSpan
|
||||
{
|
||||
ImTriangulatorNode** Data = NULL;
|
||||
int Size = 0;
|
||||
|
||||
void push_back(ImTriangulatorNode* node) { Data[Size++] = node; }
|
||||
void find_erase_unsorted(int idx) { for (int i = Size - 1; i >= 0; i--) if (Data[i]->Index == idx) { Data[i] = Data[Size - 1]; Size--; return; } }
|
||||
};
|
||||
|
||||
struct ImTriangulator
|
||||
{
|
||||
static int EstimateTriangleCount(int points_count) { return (points_count < 3) ? 0 : points_count - 2; }
|
||||
static int EstimateScratchBufferSize(int points_count) { return sizeof(ImTriangulatorNode) * points_count + sizeof(ImTriangulatorNode*) * points_count * 2; }
|
||||
|
||||
void Init(const ImVec2* points, int points_count, void* scratch_buffer);
|
||||
void GetNextTriangle(unsigned int out_triangle[3]); // Return relative indexes for next triangle
|
||||
|
||||
// Internal functions
|
||||
void BuildNodes(const ImVec2* points, int points_count);
|
||||
void BuildReflexes();
|
||||
void BuildEars();
|
||||
void FlipNodeList();
|
||||
bool IsEar(int i0, int i1, int i2, const ImVec2& v0, const ImVec2& v1, const ImVec2& v2) const;
|
||||
void ReclassifyNode(ImTriangulatorNode* node);
|
||||
|
||||
// Internal members
|
||||
int _TrianglesLeft = 0;
|
||||
ImTriangulatorNode* _Nodes = NULL;
|
||||
ImTriangulatorNodeSpan _Ears;
|
||||
ImTriangulatorNodeSpan _Reflexes;
|
||||
};
|
||||
|
||||
// Distribute storage for nodes, ears and reflexes.
|
||||
// FIXME-OPT: if everything is convex, we could report it to caller and let it switch to an convex renderer
|
||||
// (this would require first building reflexes to bail to convex if empty, without even building nodes)
|
||||
void ImTriangulator::Init(const ImVec2* points, int points_count, void* scratch_buffer)
|
||||
{
|
||||
IM_ASSERT(scratch_buffer != NULL && points_count >= 3);
|
||||
_TrianglesLeft = EstimateTriangleCount(points_count);
|
||||
_Nodes = (ImTriangulatorNode*)scratch_buffer; // points_count x Node
|
||||
_Ears.Data = (ImTriangulatorNode**)(_Nodes + points_count); // points_count x Node*
|
||||
_Reflexes.Data = (ImTriangulatorNode**)(_Nodes + points_count) + points_count; // points_count x Node*
|
||||
BuildNodes(points, points_count);
|
||||
BuildReflexes();
|
||||
BuildEars();
|
||||
}
|
||||
|
||||
void ImTriangulator::BuildNodes(const ImVec2* points, int points_count)
|
||||
{
|
||||
for (int i = 0; i < points_count; i++)
|
||||
{
|
||||
_Nodes[i].Type = ImTriangulatorNodeType_Convex;
|
||||
_Nodes[i].Index = i;
|
||||
_Nodes[i].Pos = points[i];
|
||||
_Nodes[i].Next = _Nodes + i + 1;
|
||||
_Nodes[i].Prev = _Nodes + i - 1;
|
||||
}
|
||||
_Nodes[0].Prev = _Nodes + points_count - 1;
|
||||
_Nodes[points_count - 1].Next = _Nodes;
|
||||
}
|
||||
|
||||
void ImTriangulator::BuildReflexes()
|
||||
{
|
||||
ImTriangulatorNode* n1 = _Nodes;
|
||||
for (int i = _TrianglesLeft; i >= 0; i--, n1 = n1->Next)
|
||||
{
|
||||
if (ImTriangleIsClockwise(n1->Prev->Pos, n1->Pos, n1->Next->Pos))
|
||||
continue;
|
||||
n1->Type = ImTriangulatorNodeType_Reflex;
|
||||
_Reflexes.push_back(n1);
|
||||
}
|
||||
}
|
||||
|
||||
void ImTriangulator::BuildEars()
|
||||
{
|
||||
ImTriangulatorNode* n1 = _Nodes;
|
||||
for (int i = _TrianglesLeft; i >= 0; i--, n1 = n1->Next)
|
||||
{
|
||||
if (n1->Type != ImTriangulatorNodeType_Convex)
|
||||
continue;
|
||||
if (!IsEar(n1->Prev->Index, n1->Index, n1->Next->Index, n1->Prev->Pos, n1->Pos, n1->Next->Pos))
|
||||
continue;
|
||||
n1->Type = ImTriangulatorNodeType_Ear;
|
||||
_Ears.push_back(n1);
|
||||
}
|
||||
}
|
||||
|
||||
void ImTriangulator::GetNextTriangle(unsigned int out_triangle[3])
|
||||
{
|
||||
if (_Ears.Size == 0)
|
||||
{
|
||||
FlipNodeList();
|
||||
|
||||
ImTriangulatorNode* node = _Nodes;
|
||||
for (int i = _TrianglesLeft; i >= 0; i--, node = node->Next)
|
||||
node->Type = ImTriangulatorNodeType_Convex;
|
||||
_Reflexes.Size = 0;
|
||||
BuildReflexes();
|
||||
BuildEars();
|
||||
|
||||
// If we still don't have ears, it means geometry is degenerated.
|
||||
if (_Ears.Size == 0)
|
||||
{
|
||||
// Return first triangle available, mimicking the behavior of convex fill.
|
||||
IM_ASSERT(_TrianglesLeft > 0); // Geometry is degenerated
|
||||
_Ears.Data[0] = _Nodes;
|
||||
_Ears.Size = 1;
|
||||
}
|
||||
}
|
||||
|
||||
ImTriangulatorNode* ear = _Ears.Data[--_Ears.Size];
|
||||
out_triangle[0] = ear->Prev->Index;
|
||||
out_triangle[1] = ear->Index;
|
||||
out_triangle[2] = ear->Next->Index;
|
||||
|
||||
ear->Unlink();
|
||||
if (ear == _Nodes)
|
||||
_Nodes = ear->Next;
|
||||
|
||||
ReclassifyNode(ear->Prev);
|
||||
ReclassifyNode(ear->Next);
|
||||
_TrianglesLeft--;
|
||||
}
|
||||
|
||||
void ImTriangulator::FlipNodeList()
|
||||
{
|
||||
ImTriangulatorNode* prev = _Nodes;
|
||||
ImTriangulatorNode* temp = _Nodes;
|
||||
ImTriangulatorNode* current = _Nodes->Next;
|
||||
prev->Next = prev;
|
||||
prev->Prev = prev;
|
||||
while (current != _Nodes)
|
||||
{
|
||||
temp = current->Next;
|
||||
|
||||
current->Next = prev;
|
||||
prev->Prev = current;
|
||||
_Nodes->Next = current;
|
||||
current->Prev = _Nodes;
|
||||
|
||||
prev = current;
|
||||
current = temp;
|
||||
}
|
||||
_Nodes = prev;
|
||||
}
|
||||
|
||||
// A triangle is an ear is no other vertex is inside it. We can test reflexes vertices only (see reference algorithm)
|
||||
bool ImTriangulator::IsEar(int i0, int i1, int i2, const ImVec2& v0, const ImVec2& v1, const ImVec2& v2) const
|
||||
{
|
||||
ImTriangulatorNode** p_end = _Reflexes.Data + _Reflexes.Size;
|
||||
for (ImTriangulatorNode** p = _Reflexes.Data; p < p_end; p++)
|
||||
{
|
||||
ImTriangulatorNode* reflex = *p;
|
||||
if (reflex->Index != i0 && reflex->Index != i1 && reflex->Index != i2)
|
||||
if (ImTriangleContainsPoint(v0, v1, v2, reflex->Pos))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void ImTriangulator::ReclassifyNode(ImTriangulatorNode* n1)
|
||||
{
|
||||
// Classify node
|
||||
ImTriangulatorNodeType type;
|
||||
const ImTriangulatorNode* n0 = n1->Prev;
|
||||
const ImTriangulatorNode* n2 = n1->Next;
|
||||
if (!ImTriangleIsClockwise(n0->Pos, n1->Pos, n2->Pos))
|
||||
type = ImTriangulatorNodeType_Reflex;
|
||||
else if (IsEar(n0->Index, n1->Index, n2->Index, n0->Pos, n1->Pos, n2->Pos))
|
||||
type = ImTriangulatorNodeType_Ear;
|
||||
else
|
||||
type = ImTriangulatorNodeType_Convex;
|
||||
|
||||
// Update lists when a type changes
|
||||
if (type == n1->Type)
|
||||
return;
|
||||
if (n1->Type == ImTriangulatorNodeType_Reflex)
|
||||
_Reflexes.find_erase_unsorted(n1->Index);
|
||||
else if (n1->Type == ImTriangulatorNodeType_Ear)
|
||||
_Ears.find_erase_unsorted(n1->Index);
|
||||
if (type == ImTriangulatorNodeType_Reflex)
|
||||
_Reflexes.push_back(n1);
|
||||
else if (type == ImTriangulatorNodeType_Ear)
|
||||
_Ears.push_back(n1);
|
||||
n1->Type = type;
|
||||
}
|
||||
|
||||
// Use ear-clipping algorithm to triangulate a simple polygon (no self-interaction, no holes).
|
||||
// (Reminder: we don't perform any coarse clipping/culling in ImDrawList layer!
|
||||
// It is up to caller to ensure not making costly calls that will be outside of visible area.
|
||||
// As concave fill is noticeably more expensive than other primitives, be mindful of this...
|
||||
// Caller can build AABB of points, and avoid filling if 'draw_list->_CmdHeader.ClipRect.Overlays(points_bb) == false')
|
||||
void ImDrawList::AddConcavePolyFilled(const ImVec2* points, const int points_count, ImU32 col)
|
||||
{
|
||||
if (points_count < 3 || (col & IM_COL32_A_MASK) == 0)
|
||||
return;
|
||||
|
||||
const ImVec2 uv = _Data->TexUvWhitePixel;
|
||||
ImTriangulator triangulator;
|
||||
unsigned int triangle[3];
|
||||
if (Flags & ImDrawListFlags_AntiAliasedFill)
|
||||
{
|
||||
// Anti-aliased Fill
|
||||
const float AA_SIZE = _FringeScale;
|
||||
const ImU32 col_trans = col & ~IM_COL32_A_MASK;
|
||||
const int idx_count = (points_count - 2) * 3 + points_count * 6;
|
||||
const int vtx_count = (points_count * 2);
|
||||
PrimReserve(idx_count, vtx_count);
|
||||
|
||||
// Add indexes for fill
|
||||
unsigned int vtx_inner_idx = _VtxCurrentIdx;
|
||||
unsigned int vtx_outer_idx = _VtxCurrentIdx + 1;
|
||||
|
||||
_Data->TempBuffer.reserve_discard((ImTriangulator::EstimateScratchBufferSize(points_count) + sizeof(ImVec2)) / sizeof(ImVec2));
|
||||
triangulator.Init(points, points_count, _Data->TempBuffer.Data);
|
||||
while (triangulator._TrianglesLeft > 0)
|
||||
{
|
||||
triangulator.GetNextTriangle(triangle);
|
||||
_IdxWritePtr[0] = (ImDrawIdx)(vtx_inner_idx + (triangle[0] << 1)); _IdxWritePtr[1] = (ImDrawIdx)(vtx_inner_idx + (triangle[1] << 1)); _IdxWritePtr[2] = (ImDrawIdx)(vtx_inner_idx + (triangle[2] << 1));
|
||||
_IdxWritePtr += 3;
|
||||
}
|
||||
|
||||
// Compute normals
|
||||
_Data->TempBuffer.reserve_discard(points_count);
|
||||
ImVec2* temp_normals = _Data->TempBuffer.Data;
|
||||
for (int i0 = points_count - 1, i1 = 0; i1 < points_count; i0 = i1++)
|
||||
{
|
||||
const ImVec2& p0 = points[i0];
|
||||
const ImVec2& p1 = points[i1];
|
||||
float dx = p1.x - p0.x;
|
||||
float dy = p1.y - p0.y;
|
||||
IM_NORMALIZE2F_OVER_ZERO(dx, dy);
|
||||
temp_normals[i0].x = dy;
|
||||
temp_normals[i0].y = -dx;
|
||||
}
|
||||
|
||||
for (int i0 = points_count - 1, i1 = 0; i1 < points_count; i0 = i1++)
|
||||
{
|
||||
// Average normals
|
||||
const ImVec2& n0 = temp_normals[i0];
|
||||
const ImVec2& n1 = temp_normals[i1];
|
||||
float dm_x = (n0.x + n1.x) * 0.5f;
|
||||
float dm_y = (n0.y + n1.y) * 0.5f;
|
||||
IM_FIXNORMAL2F(dm_x, dm_y);
|
||||
dm_x *= AA_SIZE * 0.5f;
|
||||
dm_y *= AA_SIZE * 0.5f;
|
||||
|
||||
// Add vertices
|
||||
_VtxWritePtr[0].pos.x = (points[i1].x - dm_x); _VtxWritePtr[0].pos.y = (points[i1].y - dm_y); _VtxWritePtr[0].uv = uv; _VtxWritePtr[0].col = col; // Inner
|
||||
_VtxWritePtr[1].pos.x = (points[i1].x + dm_x); _VtxWritePtr[1].pos.y = (points[i1].y + dm_y); _VtxWritePtr[1].uv = uv; _VtxWritePtr[1].col = col_trans; // Outer
|
||||
_VtxWritePtr += 2;
|
||||
|
||||
// Add indexes for fringes
|
||||
_IdxWritePtr[0] = (ImDrawIdx)(vtx_inner_idx + (i1 << 1)); _IdxWritePtr[1] = (ImDrawIdx)(vtx_inner_idx + (i0 << 1)); _IdxWritePtr[2] = (ImDrawIdx)(vtx_outer_idx + (i0 << 1));
|
||||
_IdxWritePtr[3] = (ImDrawIdx)(vtx_outer_idx + (i0 << 1)); _IdxWritePtr[4] = (ImDrawIdx)(vtx_outer_idx + (i1 << 1)); _IdxWritePtr[5] = (ImDrawIdx)(vtx_inner_idx + (i1 << 1));
|
||||
_IdxWritePtr += 6;
|
||||
}
|
||||
_VtxCurrentIdx += (ImDrawIdx)vtx_count;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Non Anti-aliased Fill
|
||||
const int idx_count = (points_count - 2) * 3;
|
||||
const int vtx_count = points_count;
|
||||
PrimReserve(idx_count, vtx_count);
|
||||
for (int i = 0; i < vtx_count; i++)
|
||||
{
|
||||
_VtxWritePtr[0].pos = points[i]; _VtxWritePtr[0].uv = uv; _VtxWritePtr[0].col = col;
|
||||
_VtxWritePtr++;
|
||||
}
|
||||
_Data->TempBuffer.reserve_discard((ImTriangulator::EstimateScratchBufferSize(points_count) + sizeof(ImVec2)) / sizeof(ImVec2));
|
||||
triangulator.Init(points, points_count, _Data->TempBuffer.Data);
|
||||
while (triangulator._TrianglesLeft > 0)
|
||||
{
|
||||
triangulator.GetNextTriangle(triangle);
|
||||
_IdxWritePtr[0] = (ImDrawIdx)(_VtxCurrentIdx + triangle[0]); _IdxWritePtr[1] = (ImDrawIdx)(_VtxCurrentIdx + triangle[1]); _IdxWritePtr[2] = (ImDrawIdx)(_VtxCurrentIdx + triangle[2]);
|
||||
_IdxWritePtr += 3;
|
||||
}
|
||||
_VtxCurrentIdx += (ImDrawIdx)vtx_count;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// [SECTION] ImDrawListSplitter
|
||||
|
@ -2672,8 +2985,8 @@ static bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas)
|
|||
int unscaled_ascent, unscaled_descent, unscaled_line_gap;
|
||||
stbtt_GetFontVMetrics(&src_tmp.FontInfo, &unscaled_ascent, &unscaled_descent, &unscaled_line_gap);
|
||||
|
||||
const float ascent = ImTrunc(unscaled_ascent * font_scale + ((unscaled_ascent > 0.0f) ? +1 : -1));
|
||||
const float descent = ImTrunc(unscaled_descent * font_scale + ((unscaled_descent > 0.0f) ? +1 : -1));
|
||||
const float ascent = ImCeil(unscaled_ascent * font_scale);
|
||||
const float descent = ImFloor(unscaled_descent * font_scale);
|
||||
ImFontAtlasBuildSetupFont(atlas, dst_font, &cfg, ascent, descent);
|
||||
const float font_off_x = cfg.GlyphOffset.x;
|
||||
const float font_off_y = cfg.GlyphOffset.y + IM_ROUND(dst_font->Ascent);
|
||||
|
@ -3768,6 +4081,8 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, const ImVec2& pos, Im
|
|||
{
|
||||
x = start_x;
|
||||
y += line_height;
|
||||
if (y > clip_rect.w)
|
||||
break; // break out of main loop
|
||||
word_wrap_eol = NULL;
|
||||
s = CalcWordWrapNextLineStartA(s, text_end); // Wrapping skips upcoming blanks
|
||||
continue;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// dear imgui, v1.90.4
|
||||
// dear imgui, v1.90.6
|
||||
// (internal structures/api)
|
||||
|
||||
// You may use this file to debug, understand or extend Dear ImGui features but we don't provide any guarantee of forward compatibility.
|
||||
|
@ -87,6 +87,8 @@ Index of this file:
|
|||
#pragma clang diagnostic ignored "-Wdouble-promotion"
|
||||
#pragma clang diagnostic ignored "-Wimplicit-int-float-conversion" // warning: implicit conversion from 'xxx' to 'float' may lose precision
|
||||
#pragma clang diagnostic ignored "-Wmissing-noreturn" // warning: function 'xxx' could be declared with attribute 'noreturn'
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-enum-enum-conversion"// warning: bitwise operation between different enumeration types ('XXXFlags_' and 'XXXFlagsPrivate_') is deprecated
|
||||
#pragma clang diagnostic ignored "-Wunsafe-buffer-usage" // warning: 'xxx' is an unsafe pointer used for buffer access
|
||||
#elif defined(__GNUC__)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind
|
||||
|
@ -124,7 +126,7 @@ struct ImDrawListSharedData; // Data shared between all ImDrawList instan
|
|||
struct ImGuiColorMod; // Stacked color modifier, backup of modified data so we can restore it
|
||||
struct ImGuiContext; // Main Dear ImGui context
|
||||
struct ImGuiContextHook; // Hook for extensions like ImGuiTestEngine
|
||||
struct ImGuiDataVarInfo; // Variable information (e.g. to avoid style variables from an enum)
|
||||
struct ImGuiDataVarInfo; // Variable information (e.g. to access style variables from an enum)
|
||||
struct ImGuiDataTypeInfo; // Type information associated to a ImGuiDataType enum
|
||||
struct ImGuiGroupData; // Stacked storage data for BeginGroup()/EndGroup()
|
||||
struct ImGuiInputTextState; // Internal state of the currently focused/edited text input box
|
||||
|
@ -146,6 +148,7 @@ struct ImGuiStyleMod; // Stacked style modifier, backup of modifie
|
|||
struct ImGuiTabBar; // Storage for a tab bar
|
||||
struct ImGuiTabItem; // Storage for a tab item (within a tab bar)
|
||||
struct ImGuiTable; // Storage for a table
|
||||
struct ImGuiTableHeaderData; // Storage for TableAngledHeadersRow()
|
||||
struct ImGuiTableColumn; // Storage for one column of a table
|
||||
struct ImGuiTableInstanceData; // Storage for one instance of a same table
|
||||
struct ImGuiTableTempData; // Temporary storage for one table (one per table in the stack), shared between tables.
|
||||
|
@ -179,6 +182,7 @@ typedef int ImGuiSeparatorFlags; // -> enum ImGuiSeparatorFlags_ // F
|
|||
typedef int ImGuiTextFlags; // -> enum ImGuiTextFlags_ // Flags: for TextEx()
|
||||
typedef int ImGuiTooltipFlags; // -> enum ImGuiTooltipFlags_ // Flags: for BeginTooltipEx()
|
||||
typedef int ImGuiTypingSelectFlags; // -> enum ImGuiTypingSelectFlags_ // Flags: for GetTypingSelectRequest()
|
||||
typedef int ImGuiWindowRefreshFlags; // -> enum ImGuiWindowRefreshFlags_ // Flags: for SetNextWindowRefreshPolicy()
|
||||
|
||||
typedef void (*ImGuiErrorLogCallback)(void* user_data, const char* fmt, ...);
|
||||
|
||||
|
@ -404,6 +408,7 @@ IMGUI_API int ImTextCountCharsFromUtf8(const char* in_text, const char
|
|||
IMGUI_API int ImTextCountUtf8BytesFromChar(const char* in_text, const char* in_text_end); // return number of bytes to express one char in UTF-8
|
||||
IMGUI_API int ImTextCountUtf8BytesFromStr(const ImWchar* in_text, const ImWchar* in_text_end); // return number of bytes to express string in UTF-8
|
||||
IMGUI_API const char* ImTextFindPreviousUtf8Codepoint(const char* in_text_start, const char* in_text_curr); // return previous UTF-8 code-point.
|
||||
IMGUI_API int ImTextCountLines(const char* in_text, const char* in_text_end); // return number of lines taken by text. trailing carriage return doesn't count as an extra line.
|
||||
|
||||
// Helpers: File System
|
||||
#ifdef IMGUI_DISABLE_FILE_FUNCTIONS
|
||||
|
@ -498,7 +503,8 @@ IMGUI_API ImVec2 ImLineClosestPoint(const ImVec2& a, const ImVec2& b, const
|
|||
IMGUI_API bool ImTriangleContainsPoint(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p);
|
||||
IMGUI_API ImVec2 ImTriangleClosestPoint(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p);
|
||||
IMGUI_API void ImTriangleBarycentricCoords(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p, float& out_u, float& out_v, float& out_w);
|
||||
inline float ImTriangleArea(const ImVec2& a, const ImVec2& b, const ImVec2& c) { return ImFabs((a.x * (b.y - c.y)) + (b.x * (c.y - a.y)) + (c.x * (a.y - b.y))) * 0.5f; }
|
||||
inline float ImTriangleArea(const ImVec2& a, const ImVec2& b, const ImVec2& c) { return ImFabs((a.x * (b.y - c.y)) + (b.x * (c.y - a.y)) + (c.x * (a.y - b.y))) * 0.5f; }
|
||||
inline bool ImTriangleIsClockwise(const ImVec2& a, const ImVec2& b, const ImVec2& c) { return ((b.x - a.x) * (c.y - b.y)) - ((c.x - b.x) * (b.y - a.y)) > 0.0f; }
|
||||
|
||||
// Helper: ImVec1 (1D vector)
|
||||
// (this odd construct is used to facilitate the transition between 1D and 2D, and the maintenance of some branches/patches)
|
||||
|
@ -863,6 +869,7 @@ enum ImGuiInputTextFlagsPrivate_
|
|||
ImGuiInputTextFlags_Multiline = 1 << 26, // For internal use by InputTextMultiline()
|
||||
ImGuiInputTextFlags_NoMarkEdited = 1 << 27, // For internal use by functions using InputText() before reformatting data
|
||||
ImGuiInputTextFlags_MergedItem = 1 << 28, // For internal use by TempInputText(), will skip calling ItemAdd(). Require bounding-box to strictly match.
|
||||
ImGuiInputTextFlags_LocalizeDecimalPoint= 1 << 29, // For internal use by InputScalar() and TempInputScalar()
|
||||
};
|
||||
|
||||
// Extend ImGuiButtonFlags_
|
||||
|
@ -1111,6 +1118,15 @@ struct IMGUI_API ImGuiInputTextState
|
|||
|
||||
};
|
||||
|
||||
enum ImGuiWindowRefreshFlags_
|
||||
{
|
||||
ImGuiWindowRefreshFlags_None = 0,
|
||||
ImGuiWindowRefreshFlags_TryToAvoidRefresh = 1 << 0, // [EXPERIMENTAL] Try to keep existing contents, USER MUST NOT HONOR BEGIN() RETURNING FALSE AND NOT APPEND.
|
||||
ImGuiWindowRefreshFlags_RefreshOnHover = 1 << 1, // [EXPERIMENTAL] Always refresh on hover
|
||||
ImGuiWindowRefreshFlags_RefreshOnFocus = 1 << 2, // [EXPERIMENTAL] Always refresh on focus
|
||||
// Refresh policy/frequency, Load Balancing etc.
|
||||
};
|
||||
|
||||
enum ImGuiNextWindowDataFlags_
|
||||
{
|
||||
ImGuiNextWindowDataFlags_None = 0,
|
||||
|
@ -1123,6 +1139,7 @@ enum ImGuiNextWindowDataFlags_
|
|||
ImGuiNextWindowDataFlags_HasBgAlpha = 1 << 6,
|
||||
ImGuiNextWindowDataFlags_HasScroll = 1 << 7,
|
||||
ImGuiNextWindowDataFlags_HasChildFlags = 1 << 8,
|
||||
ImGuiNextWindowDataFlags_HasRefreshPolicy = 1 << 9,
|
||||
};
|
||||
|
||||
// Storage for SetNexWindow** functions
|
||||
|
@ -1144,6 +1161,7 @@ struct ImGuiNextWindowData
|
|||
void* SizeCallbackUserData;
|
||||
float BgAlphaVal; // Override background alpha
|
||||
ImVec2 MenuBarOffsetMinVal; // (Always on) This is not exposed publicly, so we don't clear it and it doesn't have a corresponding flag (could we? for consistency?)
|
||||
ImGuiWindowRefreshFlags RefreshFlagsVal;
|
||||
|
||||
ImGuiNextWindowData() { memset(this, 0, sizeof(*this)); }
|
||||
inline void ClearFlags() { Flags = ImGuiNextWindowDataFlags_None; }
|
||||
|
@ -1292,7 +1310,7 @@ struct ImGuiPopupData
|
|||
{
|
||||
ImGuiID PopupId; // Set on OpenPopup()
|
||||
ImGuiWindow* Window; // Resolved on BeginPopup() - may stay unresolved if user never calls OpenPopup()
|
||||
ImGuiWindow* BackupNavWindow;// Set on OpenPopup(), a NavWindow that will be restored on popup close
|
||||
ImGuiWindow* RestoreNavWindow;// Set on OpenPopup(), a NavWindow that will be restored on popup close
|
||||
int ParentNavLayer; // Resolved on BeginPopup(). Actually a ImGuiNavLayer type (declared down below), initialized to -1 which is not part of an enum, but serves well-enough as "not any of layers" value
|
||||
int OpenFrameCount; // Set on OpenPopup()
|
||||
ImGuiID OpenParentId; // Set on OpenPopup(), we need this to differentiate multiple menu sets from each others (e.g. inside menu bar vs loose menu items)
|
||||
|
@ -1349,7 +1367,6 @@ enum ImGuiInputSource
|
|||
ImGuiInputSource_Mouse, // Note: may be Mouse or TouchScreen or Pen. See io.MouseSource to distinguish them.
|
||||
ImGuiInputSource_Keyboard,
|
||||
ImGuiInputSource_Gamepad,
|
||||
ImGuiInputSource_Clipboard, // Currently only used by InputText()
|
||||
ImGuiInputSource_COUNT
|
||||
};
|
||||
|
||||
|
@ -1578,6 +1595,7 @@ enum ImGuiNavMoveFlags_
|
|||
ImGuiNavMoveFlags_Activate = 1 << 12, // Activate/select target item.
|
||||
ImGuiNavMoveFlags_NoSelect = 1 << 13, // Don't trigger selection by not setting g.NavJustMovedTo
|
||||
ImGuiNavMoveFlags_NoSetNavHighlight = 1 << 14, // Do not alter the visible state of keyboard vs mouse nav highlight
|
||||
ImGuiNavMoveFlags_NoClearActiveId = 1 << 15, // (Experimental) Do not clear active id when applying move result
|
||||
};
|
||||
|
||||
enum ImGuiNavLayer
|
||||
|
@ -1594,10 +1612,10 @@ struct ImGuiNavItemData
|
|||
ImGuiID FocusScopeId; // Init,Move // Best candidate focus scope ID
|
||||
ImRect RectRel; // Init,Move // Best candidate bounding box in window relative space
|
||||
ImGuiItemFlags InFlags; // ????,Move // Best candidate item flags
|
||||
ImGuiSelectionUserData SelectionUserData;//I+Mov // Best candidate SetNextItemSelectionData() value.
|
||||
float DistBox; // Move // Best candidate box distance to current NavId
|
||||
float DistCenter; // Move // Best candidate center distance to current NavId
|
||||
float DistAxial; // Move // Best candidate axial distance to current NavId
|
||||
ImGuiSelectionUserData SelectionUserData;//I+Mov // Best candidate SetNextItemSelectionData() value.
|
||||
|
||||
ImGuiNavItemData() { Clear(); }
|
||||
void Clear() { Window = NULL; ID = FocusScopeId = 0; InFlags = 0; SelectionUserData = -1; DistBox = DistCenter = DistAxial = FLT_MAX; }
|
||||
|
@ -2530,6 +2548,7 @@ struct IMGUI_API ImGuiWindow
|
|||
bool Collapsed; // Set when collapsing window to become only title-bar
|
||||
bool WantCollapseToggle;
|
||||
bool SkipItems; // Set when items can safely be all clipped (e.g. window not visible or collapsed)
|
||||
bool SkipRefresh; // [EXPERIMENTAL] Reuse previous frame drawn contents, Begin() returns false.
|
||||
bool Appearing; // Set during the frame where the window is appearing (or re-appearing)
|
||||
bool Hidden; // Do not display (== HiddenFrames*** > 0)
|
||||
bool IsFallbackWindow; // Set on the "Debug##Default" window.
|
||||
|
@ -2769,13 +2788,24 @@ struct ImGuiTableColumn
|
|||
};
|
||||
|
||||
// Transient cell data stored per row.
|
||||
// sizeof() ~ 6
|
||||
// sizeof() ~ 6 bytes
|
||||
struct ImGuiTableCellData
|
||||
{
|
||||
ImU32 BgColor; // Actual color
|
||||
ImGuiTableColumnIdx Column; // Column number
|
||||
};
|
||||
|
||||
// Parameters for TableAngledHeadersRowEx()
|
||||
// This may end up being refactored for more general purpose.
|
||||
// sizeof() ~ 12 bytes
|
||||
struct ImGuiTableHeaderData
|
||||
{
|
||||
ImGuiTableColumnIdx Index; // Column index
|
||||
ImU32 TextColor;
|
||||
ImU32 BgColor0;
|
||||
ImU32 BgColor1;
|
||||
};
|
||||
|
||||
// Per-instance data that needs preserving across frames (seemingly most others do not need to be preserved aside from debug needs. Does that means they could be moved to ImGuiTableTempData?)
|
||||
// sizeof() ~ 24 bytes
|
||||
struct ImGuiTableInstanceData
|
||||
|
@ -2861,7 +2891,7 @@ struct IMGUI_API ImGuiTable
|
|||
ImGuiTableSortSpecs SortSpecs; // Public facing sorts specs, this is what we return in TableGetSortSpecs()
|
||||
ImGuiTableColumnIdx SortSpecsCount;
|
||||
ImGuiTableColumnIdx ColumnsEnabledCount; // Number of enabled columns (<= ColumnsCount)
|
||||
ImGuiTableColumnIdx ColumnsEnabledFixedCount; // Number of enabled columns (<= ColumnsCount)
|
||||
ImGuiTableColumnIdx ColumnsEnabledFixedCount; // Number of enabled columns using fixed width (<= ColumnsCount)
|
||||
ImGuiTableColumnIdx DeclColumnsCount; // Count calls to TableSetupColumn()
|
||||
ImGuiTableColumnIdx AngledHeadersCount; // Count columns with angled headers
|
||||
ImGuiTableColumnIdx HoveredColumnBody; // Index of column whose visible region is being hovered. Important: == ColumnsCount when hovering empty region after the right-most column!
|
||||
|
@ -2914,12 +2944,13 @@ struct IMGUI_API ImGuiTable
|
|||
// Transient data that are only needed between BeginTable() and EndTable(), those buffers are shared (1 per level of stacked table).
|
||||
// - Accessing those requires chasing an extra pointer so for very frequently used data we leave them in the main table structure.
|
||||
// - We also leave out of this structure data that tend to be particularly useful for debugging/metrics.
|
||||
// sizeof() ~ 120 bytes.
|
||||
// sizeof() ~ 136 bytes.
|
||||
struct IMGUI_API ImGuiTableTempData
|
||||
{
|
||||
int TableIndex; // Index in g.Tables.Buf[] pool
|
||||
float LastTimeActive; // Last timestamp this structure was used
|
||||
float AngledHeadersExtraWidth; // Used in EndTable()
|
||||
ImVector<ImGuiTableHeaderData> AngledHeadersRequests; // Used in TableAngledHeadersRow()
|
||||
|
||||
ImVec2 UserOuterSize; // outer_size.x passed to BeginTable()
|
||||
ImDrawListSplitter DrawSplitter;
|
||||
|
@ -2991,6 +3022,7 @@ namespace ImGui
|
|||
IMGUI_API ImGuiWindow* FindWindowByID(ImGuiID id);
|
||||
IMGUI_API ImGuiWindow* FindWindowByName(const char* name);
|
||||
IMGUI_API void UpdateWindowParentAndRootLinks(ImGuiWindow* window, ImGuiWindowFlags flags, ImGuiWindow* parent_window);
|
||||
IMGUI_API void UpdateWindowSkipRefresh(ImGuiWindow* window);
|
||||
IMGUI_API ImVec2 CalcWindowNextAutoFitSize(ImGuiWindow* window);
|
||||
IMGUI_API bool IsWindowChildOf(ImGuiWindow* window, ImGuiWindow* potential_parent, bool popup_hierarchy);
|
||||
IMGUI_API bool IsWindowWithinBeginStackOf(ImGuiWindow* window, ImGuiWindow* potential_parent);
|
||||
|
@ -3016,6 +3048,9 @@ namespace ImGui
|
|||
IMGUI_API int FindWindowDisplayIndex(ImGuiWindow* window);
|
||||
IMGUI_API ImGuiWindow* FindBottomMostVisibleWindowWithinBeginStack(ImGuiWindow* window);
|
||||
|
||||
// Windows: Idle, Refresh Policies [EXPERIMENTAL]
|
||||
IMGUI_API void SetNextWindowRefreshPolicy(ImGuiWindowRefreshFlags flags);
|
||||
|
||||
// Fonts, drawing
|
||||
IMGUI_API void SetCurrentFont(ImFont* font);
|
||||
inline ImFont* GetDefaultFont() { ImGuiContext& g = *GImGui; return g.IO.FontDefault ? g.IO.FontDefault : g.IO.Fonts->Fonts[0]; }
|
||||
|
@ -3303,7 +3338,7 @@ namespace ImGui
|
|||
IMGUI_API float TableGetHeaderAngledMaxLabelWidth();
|
||||
IMGUI_API void TablePushBackgroundChannel();
|
||||
IMGUI_API void TablePopBackgroundChannel();
|
||||
IMGUI_API void TableAngledHeadersRowEx(float angle, float max_label_width = 0.0f);
|
||||
IMGUI_API void TableAngledHeadersRowEx(ImGuiID row_id, float angle, float max_label_width, const ImGuiTableHeaderData* data, int data_count);
|
||||
|
||||
// Tables: Internals
|
||||
inline ImGuiTable* GetCurrentTable() { ImGuiContext& g = *GImGui; return g.CurrentTable; }
|
||||
|
|
|
@ -0,0 +1,85 @@
|
|||
// dear imgui: wrappers for C++ standard library (STL) types (std::string, etc.)
|
||||
// This is also an example of how you may wrap your own similar types.
|
||||
|
||||
// Changelog:
|
||||
// - v0.10: Initial version. Added InputText() / InputTextMultiline() calls with std::string
|
||||
|
||||
// See more C++ related extension (fmt, RAII, syntaxis sugar) on Wiki:
|
||||
// https://github.com/ocornut/imgui/wiki/Useful-Extensions#cness
|
||||
|
||||
#include "imgui.h"
|
||||
#include "imgui_stdlib.h"
|
||||
|
||||
// Clang warnings with -Weverything
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wsign-conversion" // warning: implicit conversion changes signedness
|
||||
#endif
|
||||
|
||||
struct InputTextCallback_UserData
|
||||
{
|
||||
std::string* Str;
|
||||
ImGuiInputTextCallback ChainCallback;
|
||||
void* ChainCallbackUserData;
|
||||
};
|
||||
|
||||
static int InputTextCallback(ImGuiInputTextCallbackData* data)
|
||||
{
|
||||
InputTextCallback_UserData* user_data = (InputTextCallback_UserData*)data->UserData;
|
||||
if (data->EventFlag == ImGuiInputTextFlags_CallbackResize)
|
||||
{
|
||||
// Resize string callback
|
||||
// If for some reason we refuse the new length (BufTextLen) and/or capacity (BufSize) we need to set them back to what we want.
|
||||
std::string* str = user_data->Str;
|
||||
IM_ASSERT(data->Buf == str->c_str());
|
||||
str->resize(data->BufTextLen);
|
||||
data->Buf = (char*)str->c_str();
|
||||
}
|
||||
else if (user_data->ChainCallback)
|
||||
{
|
||||
// Forward to user callback, if any
|
||||
data->UserData = user_data->ChainCallbackUserData;
|
||||
return user_data->ChainCallback(data);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool ImGui::InputText(const char* label, std::string* str, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data)
|
||||
{
|
||||
IM_ASSERT((flags & ImGuiInputTextFlags_CallbackResize) == 0);
|
||||
flags |= ImGuiInputTextFlags_CallbackResize;
|
||||
|
||||
InputTextCallback_UserData cb_user_data;
|
||||
cb_user_data.Str = str;
|
||||
cb_user_data.ChainCallback = callback;
|
||||
cb_user_data.ChainCallbackUserData = user_data;
|
||||
return InputText(label, (char*)str->c_str(), str->capacity() + 1, flags, InputTextCallback, &cb_user_data);
|
||||
}
|
||||
|
||||
bool ImGui::InputTextMultiline(const char* label, std::string* str, const ImVec2& size, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data)
|
||||
{
|
||||
IM_ASSERT((flags & ImGuiInputTextFlags_CallbackResize) == 0);
|
||||
flags |= ImGuiInputTextFlags_CallbackResize;
|
||||
|
||||
InputTextCallback_UserData cb_user_data;
|
||||
cb_user_data.Str = str;
|
||||
cb_user_data.ChainCallback = callback;
|
||||
cb_user_data.ChainCallbackUserData = user_data;
|
||||
return InputTextMultiline(label, (char*)str->c_str(), str->capacity() + 1, size, flags, InputTextCallback, &cb_user_data);
|
||||
}
|
||||
|
||||
bool ImGui::InputTextWithHint(const char* label, const char* hint, std::string* str, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data)
|
||||
{
|
||||
IM_ASSERT((flags & ImGuiInputTextFlags_CallbackResize) == 0);
|
||||
flags |= ImGuiInputTextFlags_CallbackResize;
|
||||
|
||||
InputTextCallback_UserData cb_user_data;
|
||||
cb_user_data.Str = str;
|
||||
cb_user_data.ChainCallback = callback;
|
||||
cb_user_data.ChainCallbackUserData = user_data;
|
||||
return InputTextWithHint(label, hint, (char*)str->c_str(), str->capacity() + 1, flags, InputTextCallback, &cb_user_data);
|
||||
}
|
||||
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
|
@ -0,0 +1,21 @@
|
|||
// dear imgui: wrappers for C++ standard library (STL) types (std::string, etc.)
|
||||
// This is also an example of how you may wrap your own similar types.
|
||||
|
||||
// Changelog:
|
||||
// - v0.10: Initial version. Added InputText() / InputTextMultiline() calls with std::string
|
||||
|
||||
// See more C++ related extension (fmt, RAII, syntaxis sugar) on Wiki:
|
||||
// https://github.com/ocornut/imgui/wiki/Useful-Extensions#cness
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace ImGui
|
||||
{
|
||||
// ImGui::InputText() with std::string
|
||||
// Because text input needs dynamic resizing, we need to setup a callback to grow the capacity
|
||||
IMGUI_API bool InputText(const char* label, std::string* str, ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = nullptr, void* user_data = nullptr);
|
||||
IMGUI_API bool InputTextMultiline(const char* label, std::string* str, const ImVec2& size = ImVec2(0, 0), ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = nullptr, void* user_data = nullptr);
|
||||
IMGUI_API bool InputTextWithHint(const char* label, const char* hint, std::string* str, ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = nullptr, void* user_data = nullptr);
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
// dear imgui, v1.90.4
|
||||
// dear imgui, v1.90.6
|
||||
// (tables and columns code)
|
||||
|
||||
/*
|
||||
|
@ -24,8 +24,9 @@ Index of this file:
|
|||
*/
|
||||
|
||||
// Navigating this file:
|
||||
// - In Visual Studio IDE: CTRL+comma ("Edit.GoToAll") can follow symbols in comments, whereas CTRL+F12 ("Edit.GoToImplementation") cannot.
|
||||
// - With Visual Assist installed: ALT+G ("VAssistX.GoToImplementation") can also follow symbols in comments.
|
||||
// - In Visual Studio: CTRL+comma ("Edit.GoToAll") can follow symbols inside comments, whereas CTRL+F12 ("Edit.GoToImplementation") cannot.
|
||||
// - In Visual Studio w/ Visual Assist installed: ALT+G ("VAssistX.GoToImplementation") can also follow symbols inside comments.
|
||||
// - In VS Code, CLion, etc.: CTRL+click can follow symbols inside comments.
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// [SECTION] Commentary
|
||||
|
@ -227,6 +228,7 @@ Index of this file:
|
|||
#pragma clang diagnostic ignored "-Wenum-enum-conversion" // warning: bitwise operation between different enumeration types ('XXXFlags_' and 'XXXFlagsPrivate_')
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-enum-enum-conversion"// warning: bitwise operation between different enumeration types ('XXXFlags_' and 'XXXFlagsPrivate_') is deprecated
|
||||
#pragma clang diagnostic ignored "-Wimplicit-int-float-conversion" // warning: implicit conversion from 'xxx' to 'float' may lose precision
|
||||
#pragma clang diagnostic ignored "-Wunsafe-buffer-usage" // warning: 'xxx' is an unsafe pointer used for buffer access
|
||||
#elif defined(__GNUC__)
|
||||
#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind
|
||||
#pragma GCC diagnostic ignored "-Wformat-nonliteral" // warning: format not a string literal, format string not checked
|
||||
|
@ -498,6 +500,7 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG
|
|||
table->DeclColumnsCount = table->AngledHeadersCount = 0;
|
||||
if (previous_frame_active + 1 < g.FrameCount)
|
||||
table->IsActiveIdInTable = false;
|
||||
table->AngledHeadersHeight = 0.0f;
|
||||
temp_data->AngledHeadersExtraWidth = 0.0f;
|
||||
|
||||
// Using opaque colors facilitate overlapping lines of the grid, otherwise we'd need to improve TableDrawBorders()
|
||||
|
@ -1066,6 +1069,7 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
|
|||
// - ClipRect.Max.x: using WorkMaxX instead of MaxX (aka including padding) makes things more consistent when resizing down, tho slightly detrimental to visibility in very-small column.
|
||||
// - ClipRect.Max.x: using MaxX makes it easier for header to receive hover highlight with no discontinuity and display sorting arrow.
|
||||
// - FIXME-TABLE: We want equal width columns to have equal (ClipRect.Max.x - WorkMinX) width, which means ClipRect.max.x cannot stray off host_clip_rect.Max.x else right-most column may appear shorter.
|
||||
const float previous_instance_work_min_x = column->WorkMinX;
|
||||
column->WorkMinX = column->MinX + table->CellPaddingX + table->CellSpacingX1;
|
||||
column->WorkMaxX = column->MaxX - table->CellPaddingX - table->CellSpacingX2; // Expected max
|
||||
column->ItemWidth = ImTrunc(column->WidthGiven * 0.65f);
|
||||
|
@ -1118,8 +1122,22 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
|
|||
// column->WorkMinX = ImLerp(column->WorkMinX, ImMax(column->StartX, column->MaxX - column->ContentWidthRowsUnfrozen), 0.5f);
|
||||
|
||||
// Reset content width variables
|
||||
column->ContentMaxXFrozen = column->ContentMaxXUnfrozen = column->WorkMinX;
|
||||
column->ContentMaxXHeadersUsed = column->ContentMaxXHeadersIdeal = column->WorkMinX;
|
||||
if (table->InstanceCurrent == 0)
|
||||
{
|
||||
column->ContentMaxXFrozen = column->WorkMinX;
|
||||
column->ContentMaxXUnfrozen = column->WorkMinX;
|
||||
column->ContentMaxXHeadersUsed = column->WorkMinX;
|
||||
column->ContentMaxXHeadersIdeal = column->WorkMinX;
|
||||
}
|
||||
else
|
||||
{
|
||||
// As we store an absolute value to make per-cell updates faster, we need to offset values used for width computation.
|
||||
const float offset_from_previous_instance = column->WorkMinX - previous_instance_work_min_x;
|
||||
column->ContentMaxXFrozen += offset_from_previous_instance;
|
||||
column->ContentMaxXUnfrozen += offset_from_previous_instance;
|
||||
column->ContentMaxXHeadersUsed += offset_from_previous_instance;
|
||||
column->ContentMaxXHeadersIdeal += offset_from_previous_instance;
|
||||
}
|
||||
|
||||
// Don't decrement auto-fit counters until container window got a chance to submit its items
|
||||
if (table->HostSkipItems == false)
|
||||
|
@ -1240,7 +1258,7 @@ void ImGui::TableUpdateBorders(ImGuiTable* table)
|
|||
ImGuiTableInstanceData* table_instance = TableGetInstanceData(table, table->InstanceCurrent);
|
||||
const float hit_half_width = TABLE_RESIZE_SEPARATOR_HALF_THICKNESS;
|
||||
const float hit_y1 = (table->FreezeRowsCount >= 1 ? table->OuterRect.Min.y : table->WorkRect.Min.y) + table->AngledHeadersHeight;
|
||||
const float hit_y2_body = ImMax(table->OuterRect.Max.y, hit_y1 + table_instance->LastOuterHeight);
|
||||
const float hit_y2_body = ImMax(table->OuterRect.Max.y, hit_y1 + table_instance->LastOuterHeight - table->AngledHeadersHeight);
|
||||
const float hit_y2_head = hit_y1 + table_instance->LastTopHeadersRowHeight;
|
||||
|
||||
for (int order_n = 0; order_n < table->ColumnsCount; order_n++)
|
||||
|
@ -1890,7 +1908,7 @@ void ImGui::TableEndRow(ImGuiTable* table)
|
|||
if (is_visible)
|
||||
{
|
||||
// Update data for TableGetHoveredRow()
|
||||
if (table->HoveredColumnBody != -1 && g.IO.MousePos.y >= bg_y1 && g.IO.MousePos.y < bg_y2)
|
||||
if (table->HoveredColumnBody != -1 && g.IO.MousePos.y >= bg_y1 && g.IO.MousePos.y < bg_y2 && table_instance->HoveredRowNext < 0)
|
||||
table_instance->HoveredRowNext = table->CurrentRow;
|
||||
|
||||
// Decide of background color for the row
|
||||
|
@ -3153,15 +3171,43 @@ void ImGui::TableHeader(const char* label)
|
|||
}
|
||||
|
||||
// Unlike TableHeadersRow() it is not expected that you can reimplement or customize this with custom widgets.
|
||||
// FIXME: highlight without ImGuiTableFlags_HighlightHoveredColumn
|
||||
// FIXME: No hit-testing/button on the angled header.
|
||||
void ImGui::TableAngledHeadersRow()
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
TableAngledHeadersRowEx(g.Style.TableAngledHeadersAngle, 0.0f);
|
||||
ImGuiTable* table = g.CurrentTable;
|
||||
ImGuiTableTempData* temp_data = table->TempData;
|
||||
temp_data->AngledHeadersRequests.resize(0);
|
||||
temp_data->AngledHeadersRequests.reserve(table->ColumnsEnabledCount);
|
||||
|
||||
// Which column needs highlight?
|
||||
const ImGuiID row_id = GetID("##AngledHeaders");
|
||||
ImGuiTableInstanceData* table_instance = TableGetInstanceData(table, table->InstanceCurrent);
|
||||
int highlight_column_n = table->HighlightColumnHeader;
|
||||
if (highlight_column_n == -1 && table->HoveredColumnBody != -1)
|
||||
if (table_instance->HoveredRowLast == 0 && table->HoveredColumnBorder == -1 && (g.ActiveId == 0 || g.ActiveId == row_id || (table->IsActiveIdInTable || g.DragDropActive)))
|
||||
highlight_column_n = table->HoveredColumnBody;
|
||||
|
||||
// Build up request
|
||||
ImU32 col_header_bg = GetColorU32(ImGuiCol_TableHeaderBg);
|
||||
ImU32 col_text = GetColorU32(ImGuiCol_Text);
|
||||
for (int order_n = 0; order_n < table->ColumnsCount; order_n++)
|
||||
if (IM_BITARRAY_TESTBIT(table->EnabledMaskByDisplayOrder, order_n))
|
||||
{
|
||||
const int column_n = table->DisplayOrderToIndex[order_n];
|
||||
ImGuiTableColumn* column = &table->Columns[column_n];
|
||||
if ((column->Flags & ImGuiTableColumnFlags_AngledHeader) == 0) // Note: can't rely on ImGuiTableColumnFlags_IsVisible test here.
|
||||
continue;
|
||||
ImGuiTableHeaderData request = { (ImGuiTableColumnIdx)column_n, col_text, col_header_bg, (column_n == highlight_column_n) ? GetColorU32(ImGuiCol_Header) : 0 };
|
||||
temp_data->AngledHeadersRequests.push_back(request);
|
||||
}
|
||||
|
||||
// Render row
|
||||
TableAngledHeadersRowEx(row_id, g.Style.TableAngledHeadersAngle, 0.0f, temp_data->AngledHeadersRequests.Data, temp_data->AngledHeadersRequests.Size);
|
||||
}
|
||||
|
||||
void ImGui::TableAngledHeadersRowEx(float angle, float max_label_width)
|
||||
// Important: data must be fed left to right
|
||||
void ImGui::TableAngledHeadersRowEx(ImGuiID row_id, float angle, float max_label_width, const ImGuiTableHeaderData* data, int data_count)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
ImGuiTable* table = g.CurrentTable;
|
||||
|
@ -3185,7 +3231,7 @@ void ImGui::TableAngledHeadersRowEx(float angle, float max_label_width)
|
|||
// Calculate our base metrics and set angled headers data _before_ the first call to TableNextRow()
|
||||
// FIXME-STYLE: Would it be better for user to submit 'max_label_width' or 'row_height' ? One can be derived from the other.
|
||||
const float header_height = g.FontSize + g.Style.CellPadding.x * 2.0f;
|
||||
const float row_height = ImFabs(ImRotate(ImVec2(max_label_width, flip_label ? +header_height : -header_height), cos_a, sin_a).y);
|
||||
const float row_height = ImTrunc(ImFabs(ImRotate(ImVec2(max_label_width, flip_label ? +header_height : -header_height), cos_a, sin_a).y));
|
||||
table->AngledHeadersHeight = row_height;
|
||||
table->AngledHeadersSlope = (sin_a != 0.0f) ? (cos_a / sin_a) : 0.0f;
|
||||
const ImVec2 header_angled_vector = unit_right * (row_height / -sin_a); // vector from bottom-left to top-left, and from bottom-right to top-right
|
||||
|
@ -3203,28 +3249,22 @@ void ImGui::TableAngledHeadersRowEx(float angle, float max_label_width)
|
|||
draw_list->AddRectFilled(ImVec2(table->BgClipRect.Min.x, row_r.Min.y), ImVec2(table->BgClipRect.Max.x, row_r.Max.y), GetColorU32(ImGuiCol_TableHeaderBg, 0.25f)); // FIXME-STYLE: Change row background with an arbitrary color.
|
||||
PushClipRect(ImVec2(clip_rect_min_x, table->BgClipRect.Min.y), table->BgClipRect.Max, true); // Span all columns
|
||||
|
||||
const ImGuiID row_id = GetID("##AngledHeaders");
|
||||
ButtonBehavior(row_r, row_id, NULL, NULL);
|
||||
KeepAliveID(row_id);
|
||||
|
||||
ImGuiTableInstanceData* table_instance = TableGetInstanceData(table, table->InstanceCurrent);
|
||||
int highlight_column_n = table->HighlightColumnHeader;
|
||||
if (highlight_column_n == -1 && table->HoveredColumnBody != -1)
|
||||
if (table_instance->HoveredRowLast == 0 && table->HoveredColumnBorder == -1 && (g.ActiveId == 0 || g.ActiveId == row_id || (table->IsActiveIdInTable || g.DragDropActive)))
|
||||
highlight_column_n = table->HoveredColumnBody;
|
||||
const float ascent_scaled = g.Font->Ascent * (g.FontSize / g.Font->FontSize); // FIXME: Standardize those scaling factors better
|
||||
const float line_off_for_ascent_x = (ImMax((g.FontSize - ascent_scaled) * 0.5f, 0.0f) / -sin_a) * (flip_label ? -1.0f : 1.0f);
|
||||
const ImVec2 padding = g.Style.CellPadding; // We will always use swapped component
|
||||
const ImVec2 align = g.Style.TableAngledHeadersTextAlign;
|
||||
|
||||
// Draw background and labels in first pass, then all borders.
|
||||
float max_x = 0.0f;
|
||||
ImVec2 padding = g.Style.CellPadding; // We will always use swapped component
|
||||
for (int pass = 0; pass < 2; pass++)
|
||||
for (int order_n = 0; order_n < table->ColumnsCount; order_n++)
|
||||
for (int order_n = 0; order_n < data_count; order_n++)
|
||||
{
|
||||
if (!IM_BITARRAY_TESTBIT(table->EnabledMaskByDisplayOrder, order_n))
|
||||
continue;
|
||||
const int column_n = table->DisplayOrderToIndex[order_n];
|
||||
const ImGuiTableHeaderData* request = &data[order_n];
|
||||
const int column_n = request->Index;
|
||||
ImGuiTableColumn* column = &table->Columns[column_n];
|
||||
if ((column->Flags & ImGuiTableColumnFlags_AngledHeader) == 0) // Note: can't rely on ImGuiTableColumnFlags_IsVisible test here.
|
||||
continue;
|
||||
|
||||
ImVec2 bg_shape[4];
|
||||
bg_shape[0] = ImVec2(column->MaxX, row_r.Max.y);
|
||||
|
@ -3234,9 +3274,8 @@ void ImGui::TableAngledHeadersRowEx(float angle, float max_label_width)
|
|||
if (pass == 0)
|
||||
{
|
||||
// Draw shape
|
||||
draw_list->AddQuadFilled(bg_shape[0], bg_shape[1], bg_shape[2], bg_shape[3], GetColorU32(ImGuiCol_TableHeaderBg));
|
||||
if (column_n == highlight_column_n)
|
||||
draw_list->AddQuadFilled(bg_shape[0], bg_shape[1], bg_shape[2], bg_shape[3], GetColorU32(ImGuiCol_Header)); // Highlight on hover
|
||||
draw_list->AddQuadFilled(bg_shape[0], bg_shape[1], bg_shape[2], bg_shape[3], request->BgColor0);
|
||||
draw_list->AddQuadFilled(bg_shape[0], bg_shape[1], bg_shape[2], bg_shape[3], request->BgColor1); // Optional highlight
|
||||
max_x = ImMax(max_x, bg_shape[3].x);
|
||||
|
||||
// Draw label
|
||||
|
@ -3244,8 +3283,17 @@ void ImGui::TableAngledHeadersRowEx(float angle, float max_label_width)
|
|||
// - Handle multiple lines manually, as we want each lines to follow on the horizontal border, rather than see a whole block rotated.
|
||||
const char* label_name = TableGetColumnName(table, column_n);
|
||||
const char* label_name_end = FindRenderedTextEnd(label_name);
|
||||
const float line_off_step_x = g.FontSize / -sin_a;
|
||||
float line_off_curr_x = 0.0f;
|
||||
const float line_off_step_x = (g.FontSize / -sin_a);
|
||||
const int label_lines = ImTextCountLines(label_name, label_name_end);
|
||||
|
||||
// Left<>Right alignment
|
||||
float line_off_curr_x = flip_label ? (label_lines - 1) * line_off_step_x : 0.0f;
|
||||
float line_off_for_align_x = ImMax((((column->MaxX - column->MinX) - padding.x * 2.0f) - (label_lines * line_off_step_x)), 0.0f) * align.x;
|
||||
line_off_curr_x += line_off_for_align_x - line_off_for_ascent_x;
|
||||
|
||||
// Register header width
|
||||
column->ContentMaxXHeadersUsed = column->ContentMaxXHeadersIdeal = column->WorkMinX + ImCeil(label_lines * line_off_step_x - line_off_for_align_x);
|
||||
|
||||
while (label_name < label_name_end)
|
||||
{
|
||||
const char* label_name_eol = strchr(label_name, '\n');
|
||||
|
@ -3258,22 +3306,26 @@ void ImGui::TableAngledHeadersRowEx(float angle, float max_label_width)
|
|||
float clip_height = ImMin(label_size.y, column->ClipRect.Max.x - column->WorkMinX - line_off_curr_x);
|
||||
ImRect clip_r(window->ClipRect.Min, window->ClipRect.Min + ImVec2(clip_width, clip_height));
|
||||
int vtx_idx_begin = draw_list->_VtxCurrentIdx;
|
||||
PushStyleColor(ImGuiCol_Text, request->TextColor);
|
||||
RenderTextEllipsis(draw_list, clip_r.Min, clip_r.Max, clip_r.Max.x, clip_r.Max.x, label_name, label_name_eol, &label_size);
|
||||
PopStyleColor();
|
||||
int vtx_idx_end = draw_list->_VtxCurrentIdx;
|
||||
|
||||
// Up<>Down alignment
|
||||
const float available_space = ImMax(clip_width - label_size.x + ImAbs(padding.x * cos_a) * 2.0f - ImAbs(padding.y * sin_a) * 2.0f, 0.0f);
|
||||
const float vertical_offset = available_space * align.y * (flip_label ? -1.0f : 1.0f);
|
||||
|
||||
// Rotate and offset label
|
||||
ImVec2 pivot_in = ImVec2(window->ClipRect.Min.x, window->ClipRect.Min.y + label_size.y);
|
||||
ImVec2 pivot_in = ImVec2(window->ClipRect.Min.x - vertical_offset, window->ClipRect.Min.y + label_size.y);
|
||||
ImVec2 pivot_out = ImVec2(column->WorkMinX, row_r.Max.y);
|
||||
line_off_curr_x += line_off_step_x;
|
||||
line_off_curr_x += flip_label ? -line_off_step_x : line_off_step_x;
|
||||
pivot_out += unit_right * padding.y;
|
||||
if (flip_label)
|
||||
pivot_out += unit_right * (clip_width - ImMax(0.0f, clip_width - label_size.x));
|
||||
pivot_out.x += flip_label ? line_off_curr_x - line_off_step_x : line_off_curr_x;
|
||||
pivot_out.x += flip_label ? line_off_curr_x + line_off_step_x : line_off_curr_x;
|
||||
ShadeVertsTransformPos(draw_list, vtx_idx_begin, vtx_idx_end, pivot_in, label_cos_a, label_sin_a, pivot_out); // Rotate and offset
|
||||
//if (g.IO.KeyShift) { ImDrawList* fg_dl = GetForegroundDrawList(); vtx_idx_begin = fg_dl->_VtxCurrentIdx; fg_dl->AddRect(clip_r.Min, clip_r.Max, IM_COL32(0, 255, 0, 255), 0.0f, 0, 2.0f); ShadeVertsTransformPos(fg_dl, vtx_idx_begin, fg_dl->_VtxCurrentIdx, pivot_in, label_cos_a, label_sin_a, pivot_out); }
|
||||
//if (g.IO.KeyShift) { ImDrawList* fg_dl = GetForegroundDrawList(); vtx_idx_begin = fg_dl->_VtxCurrentIdx; fg_dl->AddRect(clip_r.Min, clip_r.Max, IM_COL32(0, 255, 0, 255), 0.0f, 0, 1.0f); ShadeVertsTransformPos(fg_dl, vtx_idx_begin, fg_dl->_VtxCurrentIdx, pivot_in, label_cos_a, label_sin_a, pivot_out); }
|
||||
|
||||
// Register header width
|
||||
column->ContentMaxXHeadersUsed = column->ContentMaxXHeadersIdeal = column->WorkMinX + ImCeil(line_off_curr_x);
|
||||
label_name = label_name_eol + 1;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// dear imgui, v1.90.4
|
||||
// dear imgui, v1.90.6
|
||||
// (widgets code)
|
||||
|
||||
/*
|
||||
|
@ -75,6 +75,7 @@ Index of this file:
|
|||
#pragma clang diagnostic ignored "-Wenum-enum-conversion" // warning: bitwise operation between different enumeration types ('XXXFlags_' and 'XXXFlagsPrivate_')
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-enum-enum-conversion"// warning: bitwise operation between different enumeration types ('XXXFlags_' and 'XXXFlagsPrivate_') is deprecated
|
||||
#pragma clang diagnostic ignored "-Wimplicit-int-float-conversion" // warning: implicit conversion from 'xxx' to 'float' may lose precision
|
||||
#pragma clang diagnostic ignored "-Wunsafe-buffer-usage" // warning: 'xxx' is an unsafe pointer used for buffer access
|
||||
#elif defined(__GNUC__)
|
||||
#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind
|
||||
#pragma GCC diagnostic ignored "-Wformat-nonliteral" // warning: format not a string literal, format string not checked
|
||||
|
@ -122,9 +123,9 @@ static const ImU64 IM_U64_MAX = (2ULL * 9223372036854775807LL + 1);
|
|||
//-------------------------------------------------------------------------
|
||||
|
||||
// For InputTextEx()
|
||||
static bool InputTextFilterCharacter(ImGuiContext* ctx, unsigned int* p_char, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data, ImGuiInputSource input_source);
|
||||
static int InputTextCalcTextLenAndLineCount(const char* text_begin, const char** out_text_end);
|
||||
static ImVec2 InputTextCalcTextSizeW(ImGuiContext* ctx, const ImWchar* text_begin, const ImWchar* text_end, const ImWchar** remaining = NULL, ImVec2* out_offset = NULL, bool stop_on_new_line = false);
|
||||
static bool InputTextFilterCharacter(ImGuiContext* ctx, unsigned int* p_char, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data, bool input_source_is_clipboard = false);
|
||||
static int InputTextCalcTextLenAndLineCount(const char* text_begin, const char** out_text_end);
|
||||
static ImVec2 InputTextCalcTextSizeW(ImGuiContext* ctx, const ImWchar* text_begin, const ImWchar* text_end, const ImWchar** remaining = NULL, ImVec2* out_offset = NULL, bool stop_on_new_line = false);
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// [SECTION] Widgets: Text, etc.
|
||||
|
@ -508,7 +509,7 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool
|
|||
|
||||
#ifdef IMGUI_ENABLE_TEST_ENGINE
|
||||
// Alternate registration spot, for when caller didn't use ItemAdd()
|
||||
if (id != 0 && g.LastItemData.ID != id)
|
||||
if (g.LastItemData.ID != id)
|
||||
IMGUI_TEST_ENGINE_ITEM_ADD(id, bb, NULL);
|
||||
#endif
|
||||
|
||||
|
@ -536,6 +537,8 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool
|
|||
const ImGuiID test_owner_id = (flags & ImGuiButtonFlags_NoTestKeyOwner) ? ImGuiKeyOwner_Any : id;
|
||||
if (hovered)
|
||||
{
|
||||
IM_ASSERT(id != 0); // Lazily check inside rare path.
|
||||
|
||||
// Poll mouse buttons
|
||||
// - 'mouse_button_clicked' is generally carried into ActiveIdMouseButton when setting ActiveId.
|
||||
// - Technically we only need some values in one code path, but since this is gated by hovered test this is fine.
|
||||
|
@ -1312,24 +1315,47 @@ void ImGui::ProgressBar(float fraction, const ImVec2& size_arg, const char* over
|
|||
if (!ItemAdd(bb, 0))
|
||||
return;
|
||||
|
||||
// Render
|
||||
fraction = ImSaturate(fraction);
|
||||
RenderFrame(bb.Min, bb.Max, GetColorU32(ImGuiCol_FrameBg), true, style.FrameRounding);
|
||||
bb.Expand(ImVec2(-style.FrameBorderSize, -style.FrameBorderSize));
|
||||
const ImVec2 fill_br = ImVec2(ImLerp(bb.Min.x, bb.Max.x, fraction), bb.Max.y);
|
||||
RenderRectFilledRangeH(window->DrawList, bb, GetColorU32(ImGuiCol_PlotHistogram), 0.0f, fraction, style.FrameRounding);
|
||||
// Fraction < 0.0f will display an indeterminate progress bar animation
|
||||
// The value must be animated along with time, so e.g. passing '-1.0f * ImGui::GetTime()' as fraction works.
|
||||
const bool is_indeterminate = (fraction < 0.0f);
|
||||
if (!is_indeterminate)
|
||||
fraction = ImSaturate(fraction);
|
||||
|
||||
// Default displaying the fraction as percentage string, but user can override it
|
||||
char overlay_buf[32];
|
||||
if (!overlay)
|
||||
// Out of courtesy we accept a NaN fraction without crashing
|
||||
float fill_n0 = 0.0f;
|
||||
float fill_n1 = (fraction == fraction) ? fraction : 0.0f;
|
||||
|
||||
if (is_indeterminate)
|
||||
{
|
||||
ImFormatString(overlay_buf, IM_ARRAYSIZE(overlay_buf), "%.0f%%", fraction * 100 + 0.01f);
|
||||
overlay = overlay_buf;
|
||||
const float fill_width_n = 0.2f;
|
||||
fill_n0 = ImFmod(-fraction, 1.0f) * (1.0f + fill_width_n) - fill_width_n;
|
||||
fill_n1 = ImSaturate(fill_n0 + fill_width_n);
|
||||
fill_n0 = ImSaturate(fill_n0);
|
||||
}
|
||||
|
||||
ImVec2 overlay_size = CalcTextSize(overlay, NULL);
|
||||
if (overlay_size.x > 0.0f)
|
||||
RenderTextClipped(ImVec2(ImClamp(fill_br.x + style.ItemSpacing.x, bb.Min.x, bb.Max.x - overlay_size.x - style.ItemInnerSpacing.x), bb.Min.y), bb.Max, overlay, NULL, &overlay_size, ImVec2(0.0f, 0.5f), &bb);
|
||||
// Render
|
||||
RenderFrame(bb.Min, bb.Max, GetColorU32(ImGuiCol_FrameBg), true, style.FrameRounding);
|
||||
bb.Expand(ImVec2(-style.FrameBorderSize, -style.FrameBorderSize));
|
||||
RenderRectFilledRangeH(window->DrawList, bb, GetColorU32(ImGuiCol_PlotHistogram), fill_n0, fill_n1, style.FrameRounding);
|
||||
|
||||
// Default displaying the fraction as percentage string, but user can override it
|
||||
// Don't display text for indeterminate bars by default
|
||||
char overlay_buf[32];
|
||||
if (!is_indeterminate || overlay != NULL)
|
||||
{
|
||||
if (!overlay)
|
||||
{
|
||||
ImFormatString(overlay_buf, IM_ARRAYSIZE(overlay_buf), "%.0f%%", fraction * 100 + 0.01f);
|
||||
overlay = overlay_buf;
|
||||
}
|
||||
|
||||
ImVec2 overlay_size = CalcTextSize(overlay, NULL);
|
||||
if (overlay_size.x > 0.0f)
|
||||
{
|
||||
float text_x = is_indeterminate ? (bb.Min.x + bb.Max.x - overlay_size.x) * 0.5f : ImLerp(bb.Min.x, bb.Max.x, fill_n1) + style.ItemSpacing.x;
|
||||
RenderTextClipped(ImVec2(ImClamp(text_x, bb.Min.x, bb.Max.x - overlay_size.x - style.ItemInnerSpacing.x), bb.Min.y), bb.Max, overlay, NULL, &overlay_size, ImVec2(0.0f, 0.5f), &bb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ImGui::Bullet()
|
||||
|
@ -3450,7 +3476,7 @@ bool ImGui::TempInputScalar(const ImRect& bb, ImGuiID id, const char* label, ImG
|
|||
DataTypeFormatString(data_buf, IM_ARRAYSIZE(data_buf), data_type, p_data, format);
|
||||
ImStrTrimBlanks(data_buf);
|
||||
|
||||
ImGuiInputTextFlags flags = ImGuiInputTextFlags_AutoSelectAll | (ImGuiInputTextFlags)ImGuiInputTextFlags_NoMarkEdited;
|
||||
ImGuiInputTextFlags flags = ImGuiInputTextFlags_AutoSelectAll | (ImGuiInputTextFlags)ImGuiInputTextFlags_NoMarkEdited | (ImGuiInputTextFlags)ImGuiInputTextFlags_LocalizeDecimalPoint;
|
||||
|
||||
bool value_changed = false;
|
||||
if (TempInputText(bb, id, label, data_buf, IM_ARRAYSIZE(data_buf), flags))
|
||||
|
@ -3495,6 +3521,7 @@ bool ImGui::InputScalar(const char* label, ImGuiDataType data_type, void* p_data
|
|||
DataTypeFormatString(buf, IM_ARRAYSIZE(buf), data_type, p_data, format);
|
||||
|
||||
flags |= ImGuiInputTextFlags_AutoSelectAll | (ImGuiInputTextFlags)ImGuiInputTextFlags_NoMarkEdited; // We call MarkItemEdited() ourselves by comparing the actual data rather than the string.
|
||||
flags |= (ImGuiInputTextFlags)ImGuiInputTextFlags_LocalizeDecimalPoint;
|
||||
|
||||
bool value_changed = false;
|
||||
if (p_step == NULL)
|
||||
|
@ -3940,9 +3967,8 @@ void ImGuiInputTextCallbackData::InsertChars(int pos, const char* new_text, cons
|
|||
}
|
||||
|
||||
// Return false to discard a character.
|
||||
static bool InputTextFilterCharacter(ImGuiContext* ctx, unsigned int* p_char, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data, ImGuiInputSource input_source)
|
||||
static bool InputTextFilterCharacter(ImGuiContext* ctx, unsigned int* p_char, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data, bool input_source_is_clipboard)
|
||||
{
|
||||
IM_ASSERT(input_source == ImGuiInputSource_Keyboard || input_source == ImGuiInputSource_Clipboard);
|
||||
unsigned int c = *p_char;
|
||||
|
||||
// Filter non-printable (NB: isprint is unreliable! see #2467)
|
||||
|
@ -3957,7 +3983,7 @@ static bool InputTextFilterCharacter(ImGuiContext* ctx, unsigned int* p_char, Im
|
|||
apply_named_filters = false; // Override named filters below so newline and tabs can still be inserted.
|
||||
}
|
||||
|
||||
if (input_source != ImGuiInputSource_Clipboard)
|
||||
if (input_source_is_clipboard == false)
|
||||
{
|
||||
// We ignore Ascii representation of delete (emitted from Backspace on OSX, see #2578, #2817)
|
||||
if (c == 127)
|
||||
|
@ -3973,7 +3999,7 @@ static bool InputTextFilterCharacter(ImGuiContext* ctx, unsigned int* p_char, Im
|
|||
return false;
|
||||
|
||||
// Generic named filters
|
||||
if (apply_named_filters && (flags & (ImGuiInputTextFlags_CharsDecimal | ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsUppercase | ImGuiInputTextFlags_CharsNoBlank | ImGuiInputTextFlags_CharsScientific)))
|
||||
if (apply_named_filters && (flags & (ImGuiInputTextFlags_CharsDecimal | ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsUppercase | ImGuiInputTextFlags_CharsNoBlank | ImGuiInputTextFlags_CharsScientific | (ImGuiInputTextFlags)ImGuiInputTextFlags_LocalizeDecimalPoint)))
|
||||
{
|
||||
// The libc allows overriding locale, with e.g. 'setlocale(LC_NUMERIC, "de_DE.UTF-8");' which affect the output/input of printf/scanf to use e.g. ',' instead of '.'.
|
||||
// The standard mandate that programs starts in the "C" locale where the decimal point is '.'.
|
||||
|
@ -3983,7 +4009,7 @@ static bool InputTextFilterCharacter(ImGuiContext* ctx, unsigned int* p_char, Im
|
|||
// Users of non-default decimal point (in particular ',') may be affected by word-selection logic (is_word_boundary_from_right/is_word_boundary_from_left) functions.
|
||||
ImGuiContext& g = *ctx;
|
||||
const unsigned c_decimal_point = (unsigned int)g.IO.PlatformLocaleDecimalPoint;
|
||||
if (flags & (ImGuiInputTextFlags_CharsDecimal | ImGuiInputTextFlags_CharsScientific))
|
||||
if (flags & (ImGuiInputTextFlags_CharsDecimal | ImGuiInputTextFlags_CharsScientific | (ImGuiInputTextFlags)ImGuiInputTextFlags_LocalizeDecimalPoint))
|
||||
if (c == '.' || c == ',')
|
||||
c = c_decimal_point;
|
||||
|
||||
|
@ -4442,7 +4468,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
|
|||
if (Shortcut(ImGuiKey_Tab, id, ImGuiInputFlags_Repeat))
|
||||
{
|
||||
unsigned int c = '\t'; // Insert TAB
|
||||
if (InputTextFilterCharacter(&g, &c, flags, callback, callback_user_data, ImGuiInputSource_Keyboard))
|
||||
if (InputTextFilterCharacter(&g, &c, flags, callback, callback_user_data))
|
||||
state->OnKeyPressed((int)c);
|
||||
}
|
||||
// FIXME: Implement Shift+Tab
|
||||
|
@ -4465,7 +4491,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
|
|||
unsigned int c = (unsigned int)io.InputQueueCharacters[n];
|
||||
if (c == '\t') // Skip Tab, see above.
|
||||
continue;
|
||||
if (InputTextFilterCharacter(&g, &c, flags, callback, callback_user_data, ImGuiInputSource_Keyboard))
|
||||
if (InputTextFilterCharacter(&g, &c, flags, callback, callback_user_data))
|
||||
state->OnKeyPressed((int)c);
|
||||
}
|
||||
|
||||
|
@ -4548,7 +4574,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
|
|||
else if (!is_readonly)
|
||||
{
|
||||
unsigned int c = '\n'; // Insert new line
|
||||
if (InputTextFilterCharacter(&g, &c, flags, callback, callback_user_data, ImGuiInputSource_Keyboard))
|
||||
if (InputTextFilterCharacter(&g, &c, flags, callback, callback_user_data))
|
||||
state->OnKeyPressed((int)c);
|
||||
}
|
||||
}
|
||||
|
@ -4615,7 +4641,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
|
|||
{
|
||||
unsigned int c;
|
||||
s += ImTextCharFromUtf8(&c, s, NULL);
|
||||
if (!InputTextFilterCharacter(&g, &c, flags, callback, callback_user_data, ImGuiInputSource_Clipboard))
|
||||
if (!InputTextFilterCharacter(&g, &c, flags, callback, callback_user_data, true))
|
||||
continue;
|
||||
clipboard_filtered[clipboard_filtered_len++] = (ImWchar)c;
|
||||
}
|
||||
|
@ -6203,13 +6229,17 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l
|
|||
label_end = FindRenderedTextEnd(label);
|
||||
const ImVec2 label_size = CalcTextSize(label, label_end, false);
|
||||
|
||||
const float text_offset_x = g.FontSize + (display_frame ? padding.x * 3 : padding.x * 2); // Collapsing arrow width + Spacing
|
||||
const float text_offset_y = ImMax(padding.y, window->DC.CurrLineTextBaseOffset); // Latch before ItemSize changes it
|
||||
const float text_width = g.FontSize + label_size.x + padding.x * 2; // Include collapsing arrow
|
||||
|
||||
// We vertically grow up to current line height up the typical widget height.
|
||||
const float frame_height = ImMax(ImMin(window->DC.CurrLineSize.y, g.FontSize + style.FramePadding.y * 2), label_size.y + padding.y * 2);
|
||||
const bool span_all_columns = (flags & ImGuiTreeNodeFlags_SpanAllColumns) != 0 && (g.CurrentTable != NULL);
|
||||
ImRect frame_bb;
|
||||
frame_bb.Min.x = span_all_columns ? window->ParentWorkRect.Min.x : (flags & ImGuiTreeNodeFlags_SpanFullWidth) ? window->WorkRect.Min.x : window->DC.CursorPos.x;
|
||||
frame_bb.Min.y = window->DC.CursorPos.y;
|
||||
frame_bb.Max.x = span_all_columns ? window->ParentWorkRect.Max.x : window->WorkRect.Max.x;
|
||||
frame_bb.Max.x = span_all_columns ? window->ParentWorkRect.Max.x : (flags & ImGuiTreeNodeFlags_SpanTextWidth) ? window->DC.CursorPos.x + text_width + padding.x : window->WorkRect.Max.x;
|
||||
frame_bb.Max.y = window->DC.CursorPos.y + frame_height;
|
||||
if (display_frame)
|
||||
{
|
||||
|
@ -6219,16 +6249,13 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l
|
|||
frame_bb.Max.x += IM_TRUNC(window->WindowPadding.x * 0.5f);
|
||||
}
|
||||
|
||||
const float text_offset_x = g.FontSize + (display_frame ? padding.x * 3 : padding.x * 2); // Collapsing arrow width + Spacing
|
||||
const float text_offset_y = ImMax(padding.y, window->DC.CurrLineTextBaseOffset); // Latch before ItemSize changes it
|
||||
const float text_width = g.FontSize + (label_size.x > 0.0f ? label_size.x + padding.x * 2 : 0.0f); // Include collapsing
|
||||
ImVec2 text_pos(window->DC.CursorPos.x + text_offset_x, window->DC.CursorPos.y + text_offset_y);
|
||||
ItemSize(ImVec2(text_width, frame_height), padding.y);
|
||||
|
||||
// For regular tree nodes, we arbitrary allow to click past 2 worth of ItemSpacing
|
||||
ImRect interact_bb = frame_bb;
|
||||
if (!display_frame && (flags & (ImGuiTreeNodeFlags_SpanAvailWidth | ImGuiTreeNodeFlags_SpanFullWidth | ImGuiTreeNodeFlags_SpanAllColumns)) == 0)
|
||||
interact_bb.Max.x = frame_bb.Min.x + text_width + style.ItemSpacing.x * 2.0f;
|
||||
if ((flags & (ImGuiTreeNodeFlags_Framed | ImGuiTreeNodeFlags_SpanAvailWidth | ImGuiTreeNodeFlags_SpanFullWidth | ImGuiTreeNodeFlags_SpanTextWidth | ImGuiTreeNodeFlags_SpanAllColumns)) == 0)
|
||||
interact_bb.Max.x = frame_bb.Min.x + text_width + (label_size.x > 0.0f ? style.ItemSpacing.x * 2.0f : 0.0f);
|
||||
|
||||
// Modify ClipRect for the ItemAdd(), faster than doing a PushColumnsBackground/PushTableBackgroundChannel for every Selectable..
|
||||
const float backup_clip_rect_min_x = window->ClipRect.Min.x;
|
||||
|
@ -6958,6 +6985,7 @@ bool ImGui::BeginListBox(const char* label, const ImVec2& size_arg)
|
|||
ImVec2 label_pos = ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y);
|
||||
RenderText(label_pos, label);
|
||||
window->DC.CursorMaxPos = ImMax(window->DC.CursorMaxPos, label_pos + label_size);
|
||||
AlignTextToFramePadding();
|
||||
}
|
||||
|
||||
BeginChild(id, frame_bb.GetSize(), ImGuiChildFlags_FrameStyle);
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 5deac9f1ab2bd833ad664bc3386ac1e8998cecb3
|
|
@ -1 +1 @@
|
|||
Subproject commit 7239eab39c961a27959cfb58c8877cb2ab1fbf2d
|
||||
Subproject commit 86b272076d542287d3f03952e7d4efe283e815bf
|
|
@ -0,0 +1 @@
|
|||
Subproject commit e88f74992527b9ade48ae1591378ec2cf363bef9
|
|
@ -37,7 +37,6 @@
|
|||
#include "network/ggpo.h"
|
||||
#include "hw/mem/mem_watch.h"
|
||||
#include "network/net_handshake.h"
|
||||
#include "rend/gui.h"
|
||||
#include "network/naomi_network.h"
|
||||
#include "serialize.h"
|
||||
#include "hw/pvr/pvr.h"
|
||||
|
@ -45,6 +44,9 @@
|
|||
#include "oslib/storage.h"
|
||||
#include "wsi/context.h"
|
||||
#include <chrono>
|
||||
#ifndef LIBRETRO
|
||||
#include "ui/gui.h"
|
||||
#endif
|
||||
|
||||
settings_t settings;
|
||||
|
||||
|
@ -449,6 +451,8 @@ void Emulator::loadGame(const char *path, LoadProgress *progress)
|
|||
{
|
||||
hostfs::FileInfo info = hostfs::storage().getFileInfo(settings.content.path);
|
||||
settings.content.fileName = info.name;
|
||||
if (settings.content.title.empty())
|
||||
settings.content.title = get_file_basename(info.name);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -487,7 +491,7 @@ void Emulator::loadGame(const char *path, LoadProgress *progress)
|
|||
nvmem::loadHle();
|
||||
NOTICE_LOG(BOOT, "Did not load BIOS, using reios");
|
||||
if (!config::UseReios && config::UseReios.isReadOnly())
|
||||
gui_display_notification("This game requires a real BIOS", 15000);
|
||||
os_notify("This game requires a real BIOS", 15000);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -506,6 +510,8 @@ void Emulator::loadGame(const char *path, LoadProgress *progress)
|
|||
InitDrive("");
|
||||
}
|
||||
}
|
||||
if (settings.content.path.empty())
|
||||
settings.content.title = "Dreamcast BIOS";
|
||||
|
||||
if (progress)
|
||||
progress->progress = 1.0f;
|
||||
|
@ -526,10 +532,18 @@ void Emulator::loadGame(const char *path, LoadProgress *progress)
|
|||
// Must be done after the maple devices are created and EEPROM is accessible
|
||||
naomi_cart_ConfigureEEPROM();
|
||||
}
|
||||
#ifdef USE_RACHIEVEMENTS
|
||||
// RA probably isn't expecting to travel back in the past so disable it
|
||||
if (config::GGPOEnable)
|
||||
config::EnableAchievements.override(false);
|
||||
// Hardcore mode disables all cheats, under/overclocking, load state, lua and forces dynarec on
|
||||
settings.raHardcoreMode = config::EnableAchievements && config::AchievementsHardcoreMode
|
||||
&& !NaomiNetworkSupported();
|
||||
#endif
|
||||
cheatManager.reset(settings.content.gameId);
|
||||
if (cheatManager.isWidescreen())
|
||||
{
|
||||
gui_display_notification("Widescreen cheat activated", 1000);
|
||||
os_notify("Widescreen cheat activated", 2000);
|
||||
config::ScreenStretching.override(134); // 4:3 -> 16:9
|
||||
}
|
||||
// reload settings so that all settings can be overridden
|
||||
|
@ -538,10 +552,12 @@ void Emulator::loadGame(const char *path, LoadProgress *progress)
|
|||
settings.input.fastForwardMode = false;
|
||||
if (!settings.content.path.empty())
|
||||
{
|
||||
#ifndef LIBRETRO
|
||||
if (config::GGPOEnable)
|
||||
dc_loadstate(-1);
|
||||
else if (config::AutoLoadState && !NaomiNetworkSupported() && !settings.naomi.multiboard)
|
||||
dc_loadstate(config::SavestateSlot);
|
||||
#endif
|
||||
}
|
||||
EventManager::event(Event::Start);
|
||||
|
||||
|
@ -600,9 +616,11 @@ void Emulator::unloadGame()
|
|||
} catch (...) { }
|
||||
if (state == Loaded || state == Error)
|
||||
{
|
||||
#ifndef LIBRETRO
|
||||
if (state == Loaded && config::AutoSaveState && !settings.content.path.empty()
|
||||
&& !settings.naomi.multiboard && !config::GGPOEnable && !NaomiNetworkSupported())
|
||||
dc_savestate(config::SavestateSlot);
|
||||
gui_saveState(false);
|
||||
#endif
|
||||
try {
|
||||
dc_reset(true);
|
||||
} catch (const FlycastException& e) {
|
||||
|
@ -614,6 +632,7 @@ void Emulator::unloadGame()
|
|||
settings.content.path.clear();
|
||||
settings.content.gameId.clear();
|
||||
settings.content.fileName.clear();
|
||||
settings.content.title.clear();
|
||||
settings.platform.system = DC_PLATFORM_DREAMCAST;
|
||||
state = Init;
|
||||
EventManager::event(Event::Terminate);
|
||||
|
@ -686,6 +705,10 @@ void Emulator::requestReset()
|
|||
|
||||
void loadGameSpecificSettings()
|
||||
{
|
||||
// Graphics context isn't available yet in libretro
|
||||
if (GraphicsContext::Instance() != nullptr && GraphicsContext::Instance()->isAMD())
|
||||
config::NativeDepthInterpolation.override(true);
|
||||
|
||||
if (settings.platform.isConsole())
|
||||
{
|
||||
reios_disk_id();
|
||||
|
@ -703,8 +726,13 @@ void loadGameSpecificSettings()
|
|||
// Reload per-game settings
|
||||
config::Settings::instance().load(true);
|
||||
|
||||
if (config::GGPOEnable)
|
||||
if (config::GGPOEnable || settings.raHardcoreMode)
|
||||
config::Sh4Clock.override(200);
|
||||
if (settings.raHardcoreMode)
|
||||
{
|
||||
config::WidescreenGameHacks.override(false);
|
||||
config::DynarecEnabled.override(true);
|
||||
}
|
||||
}
|
||||
|
||||
void Emulator::step()
|
||||
|
@ -755,42 +783,30 @@ void Emulator::setNetworkState(bool online)
|
|||
config::Sh4Clock.override(200);
|
||||
sh4_cpu.ResetCache();
|
||||
}
|
||||
EventManager::event(Event::Network);
|
||||
}
|
||||
settings.input.fastForwardMode &= !online;
|
||||
}
|
||||
|
||||
EventManager EventManager::Instance;
|
||||
|
||||
void EventManager::registerEvent(Event event, Callback callback, void *param)
|
||||
{
|
||||
unregisterEvent(event, callback, param);
|
||||
auto it = callbacks.find(event);
|
||||
if (it != callbacks.end())
|
||||
it->second.push_back(std::make_pair(callback, param));
|
||||
else
|
||||
callbacks.insert({ event, { std::make_pair(callback, param) } });
|
||||
auto& vector = callbacks[static_cast<size_t>(event)];
|
||||
vector.push_back(std::make_pair(callback, param));
|
||||
}
|
||||
|
||||
void EventManager::unregisterEvent(Event event, Callback callback, void *param)
|
||||
{
|
||||
auto it = callbacks.find(event);
|
||||
if (it == callbacks.end())
|
||||
return;
|
||||
|
||||
auto it2 = std::find(it->second.begin(), it->second.end(), std::make_pair(callback, param));
|
||||
if (it2 == it->second.end())
|
||||
return;
|
||||
|
||||
it->second.erase(it2);
|
||||
auto& vector = callbacks[static_cast<size_t>(event)];
|
||||
auto it = std::find(vector.begin(), vector.end(), std::make_pair(callback, param));
|
||||
if (it != vector.end())
|
||||
vector.erase(it);
|
||||
}
|
||||
|
||||
void EventManager::broadcastEvent(Event event)
|
||||
{
|
||||
auto it = callbacks.find(event);
|
||||
if (it == callbacks.end())
|
||||
return;
|
||||
|
||||
for (auto& pair : it->second)
|
||||
auto& vector = callbacks[static_cast<size_t>(event)];
|
||||
for (auto& pair : vector)
|
||||
pair.first(event, pair.second);
|
||||
}
|
||||
|
||||
|
@ -842,6 +858,7 @@ void Emulator::start()
|
|||
{
|
||||
const std::lock_guard<std::mutex> lock(mutex);
|
||||
threadResult = std::async(std::launch::async, [this] {
|
||||
ThreadName _("Flycast-emu");
|
||||
InitAudio();
|
||||
|
||||
try {
|
||||
|
|
|
@ -23,10 +23,11 @@
|
|||
|
||||
#include <atomic>
|
||||
#include <future>
|
||||
#include <map>
|
||||
#include <array>
|
||||
#include <mutex>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <time.h>
|
||||
|
||||
void loadGameSpecificSettings();
|
||||
void SaveSettings();
|
||||
|
@ -35,9 +36,11 @@ int flycast_init(int argc, char* argv[]);
|
|||
void dc_reset(bool hard); // for tests only
|
||||
void flycast_term();
|
||||
void dc_exit();
|
||||
void dc_savestate(int index = 0);
|
||||
void dc_savestate(int index = 0, const u8 *pngData = nullptr, u32 pngSize = 0);
|
||||
void dc_loadstate(int index = 0);
|
||||
void dc_loadstate(Deserializer& deser);
|
||||
time_t dc_getStateCreationDate(int index);
|
||||
void dc_getStateScreenshot(int index, std::vector<u8>& pngData);
|
||||
|
||||
enum class Event {
|
||||
Start,
|
||||
|
@ -46,6 +49,9 @@ enum class Event {
|
|||
Terminate,
|
||||
LoadState,
|
||||
VBlank,
|
||||
Network,
|
||||
DiskChange,
|
||||
max = DiskChange
|
||||
};
|
||||
|
||||
class EventManager
|
||||
|
@ -54,26 +60,29 @@ public:
|
|||
using Callback = void (*)(Event, void *);
|
||||
|
||||
static void listen(Event event, Callback callback, void *param = nullptr) {
|
||||
Instance.registerEvent(event, callback, param);
|
||||
instance().registerEvent(event, callback, param);
|
||||
}
|
||||
|
||||
static void unlisten(Event event, Callback callback, void *param = nullptr) {
|
||||
Instance.unregisterEvent(event, callback, param);
|
||||
instance().unregisterEvent(event, callback, param);
|
||||
}
|
||||
|
||||
static void event(Event event) {
|
||||
Instance.broadcastEvent(event);
|
||||
instance().broadcastEvent(event);
|
||||
}
|
||||
|
||||
private:
|
||||
EventManager() = default;
|
||||
static EventManager& instance() {
|
||||
static EventManager _instance;
|
||||
return _instance;
|
||||
}
|
||||
|
||||
void registerEvent(Event event, Callback callback, void *param);
|
||||
void unregisterEvent(Event event, Callback callback, void *param);
|
||||
void broadcastEvent(Event event);
|
||||
|
||||
static EventManager Instance;
|
||||
std::map<Event, std::vector<std::pair<Callback, void *>>> callbacks;
|
||||
std::array<std::vector<std::pair<Callback, void *>>, static_cast<size_t>(Event::max) + 1> callbacks;
|
||||
};
|
||||
|
||||
struct LoadProgress
|
||||
|
|
|
@ -581,8 +581,7 @@ void deserialize(Deserializer& deser)
|
|||
deser >> VREG;
|
||||
deser >> ARMRST;
|
||||
deser >> rtc_EN;
|
||||
if (deser.version() >= Deserializer::V9)
|
||||
deser >> RealTimeClock;
|
||||
deser >> RealTimeClock;
|
||||
|
||||
deser >> aica_reg;
|
||||
|
||||
|
|
|
@ -149,80 +149,88 @@ class VmuBeep
|
|||
public:
|
||||
void init()
|
||||
{
|
||||
beepOn = 0;
|
||||
beepPeriod = 0;
|
||||
beepCounter = 0;
|
||||
beepValue = 0;
|
||||
active = false;
|
||||
att = 256;
|
||||
waveIdx.full = 0;
|
||||
waveStep = 0;
|
||||
}
|
||||
|
||||
void update(int on, int period)
|
||||
void update(int period, int on)
|
||||
{
|
||||
if (on == 0 || period == 0 || on < period)
|
||||
{
|
||||
beepOn = 0;
|
||||
beepPeriod = 0;
|
||||
if (on == 0 || period == 0 || on >= period) {
|
||||
active = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// The maple doc may be wrong on this. It looks like the raw values of T1LR and T1LC are set.
|
||||
// So the period is (256 - T1LR) / (32768 / 6)
|
||||
// and the duty cycle is (256 - T1LC) / (32768 / 6)
|
||||
beepOn = (256 - on) * 8;
|
||||
beepPeriod = (256 - period) * 8;
|
||||
beepCounter = 0;
|
||||
// on (duty cycle) is ignored
|
||||
active = true;
|
||||
// 6 MHz clock
|
||||
int freq = 6000000 / 6 / period;
|
||||
waveStep = freq * 1024 / 2698;
|
||||
}
|
||||
}
|
||||
|
||||
SampleType getSample()
|
||||
{
|
||||
constexpr int Slope = 500;
|
||||
if (beepPeriod == 0)
|
||||
{
|
||||
if (beepValue > 0)
|
||||
beepValue = std::max(0, beepValue - Slope);
|
||||
else if (beepValue < 0)
|
||||
beepValue = std::min(0, beepValue + Slope);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (beepCounter <= beepOn)
|
||||
beepValue = std::min(16383, beepValue + Slope);
|
||||
else
|
||||
beepValue = std::max(-16384, beepValue - Slope);
|
||||
beepCounter = (beepCounter + 1) % beepPeriod;
|
||||
}
|
||||
if (!active && att >= 256)
|
||||
return 0;
|
||||
|
||||
return beepValue;
|
||||
waveIdx.full += waveStep;
|
||||
waveIdx.ip %= std::size(wave);
|
||||
int nextIdx = (waveIdx.ip + 1) % std::size(wave);
|
||||
SampleType s = (FPMul(wave[waveIdx.ip], (int)(1024 - waveIdx.fp), 10) + FPMul(wave[nextIdx], (int)waveIdx.fp, 10)) * 2;
|
||||
|
||||
s = FPMul(s, tl_lut[att], 15);
|
||||
if (active)
|
||||
att = std::max(att - 2, 0);
|
||||
else
|
||||
att = std::min(att + 2, 256);
|
||||
return s;
|
||||
}
|
||||
|
||||
void serialize(Serializer& ser)
|
||||
{
|
||||
ser << beepOn;
|
||||
ser << beepPeriod;
|
||||
ser << beepCounter;
|
||||
ser << active;
|
||||
ser << att;
|
||||
ser << waveIdx;
|
||||
ser << waveStep;
|
||||
}
|
||||
|
||||
void deserialize(Deserializer& deser)
|
||||
{
|
||||
if (deser.version() >= Deserializer::V22)
|
||||
if (deser.version() < Deserializer::V49)
|
||||
{
|
||||
deser >> beepOn;
|
||||
deser >> beepPeriod;
|
||||
deser >> beepCounter;
|
||||
if (deser.version() >= Deserializer::V22)
|
||||
{
|
||||
deser.skip<int>(); // beepOn
|
||||
deser.skip<int>(); // beepPeriod
|
||||
deser.skip<int>(); // beepCounter
|
||||
}
|
||||
init();
|
||||
}
|
||||
else
|
||||
{
|
||||
beepOn = 0;
|
||||
beepPeriod = 0;
|
||||
beepCounter = 0;
|
||||
deser >> active;
|
||||
deser >> att;
|
||||
deser >> waveIdx;
|
||||
deser >> waveStep;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
int beepOn = 0;
|
||||
int beepPeriod = 0;
|
||||
int beepCounter = 0;
|
||||
SampleType beepValue = 0;
|
||||
bool active = false;
|
||||
int att = 256;
|
||||
fp_22_10 waveIdx {};
|
||||
int waveStep = 0;
|
||||
|
||||
// 2698 Hz
|
||||
static constexpr SampleType wave[] = { 503, -3519,
|
||||
-7540, -8214, -8209, -8214, -8209, -5199, -1172, 2843,
|
||||
6873, 8207, 8214, 8209, 8212, 5866, 1840, -2175,
|
||||
-6203, -8210, -8215, -8209, -8214, -6533, -2516, 1507,
|
||||
5526, 8212, 8210, 8212, 8210, 7206, 3187, -841,
|
||||
-4856, -8215, -8209, -8214, -8208, -7882, -3850, 162,
|
||||
4187, 8213, 8208, 8213, 8209, 8211, 4525 };
|
||||
};
|
||||
static VmuBeep beep;
|
||||
|
||||
|
|
|
@ -76,8 +76,7 @@ static void add_isp_to_nvmem(DCFlashChip *flash)
|
|||
for (u32 i = FLASH_USER_INET + 5; i <= 0xbf; i++)
|
||||
flash->WriteBlock(FLASH_PT_USER, i, block);
|
||||
|
||||
flash_isp1_block isp1;
|
||||
memset(&isp1, 0, sizeof(isp1));
|
||||
flash_isp1_block isp1{};
|
||||
isp1._unknown[3] = 1;
|
||||
memcpy(isp1.sega, "SEGA", 4);
|
||||
strcpy(isp1.username, "flycast1");
|
||||
|
@ -96,8 +95,7 @@ static void add_isp_to_nvmem(DCFlashChip *flash)
|
|||
block[60] = 1;
|
||||
flash->WriteBlock(FLASH_PT_USER, FLASH_USER_ISP1 + 5, block);
|
||||
|
||||
flash_isp2_block isp2;
|
||||
memset(&isp2, 0, sizeof(isp2));
|
||||
flash_isp2_block isp2{};
|
||||
memcpy(isp2.sega, "SEGA", 4);
|
||||
strcpy(isp2.username, "flycast2");
|
||||
strcpy(isp2.password, "password");
|
||||
|
@ -373,36 +371,8 @@ void serialize(Serializer& ser)
|
|||
|
||||
void deserialize(Deserializer& deser)
|
||||
{
|
||||
if (deser.version() <= Deserializer::VLAST_LIBRETRO)
|
||||
{
|
||||
deser.skip<u32>(); // size
|
||||
deser.skip<u32>(); // mask
|
||||
|
||||
// Legacy libretro savestate
|
||||
if (settings.platform.isArcade())
|
||||
sys_nvmem->Deserialize(deser);
|
||||
|
||||
deser.skip<u32>(); // sys_nvmem/sys_rom->size
|
||||
deser.skip<u32>(); // sys_nvmem/sys_rom->mask
|
||||
if (settings.platform.isConsole())
|
||||
{
|
||||
sys_nvmem->Deserialize(deser);
|
||||
}
|
||||
else if (settings.platform.isAtomiswave())
|
||||
{
|
||||
deser >> static_cast<DCFlashChip*>(sys_rom)->state;
|
||||
deser.deserialize(sys_rom->data, sys_rom->size);
|
||||
}
|
||||
else
|
||||
{
|
||||
deser.skip<u32>();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sys_rom->Deserialize(deser);
|
||||
sys_nvmem->Deserialize(deser);
|
||||
}
|
||||
sys_rom->Deserialize(deser);
|
||||
sys_nvmem->Deserialize(deser);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1412,8 +1412,6 @@ void deserialize(Deserializer& deser)
|
|||
deser.skip<u32>(Deserializer::V44); // set_mode_offset (repeat)
|
||||
deser >> ata_cmd;
|
||||
deser >> cdda;
|
||||
if (deser.version() < Deserializer::V10)
|
||||
cdda.status = (bool)cdda.status ? cdda_t::Playing : cdda_t::NoInfo;
|
||||
deser >> gd_state;
|
||||
deser >> gd_disk_type;
|
||||
deser >> data_write_mode;
|
||||
|
@ -1426,8 +1424,6 @@ void deserialize(Deserializer& deser)
|
|||
deser >> SecNumber;
|
||||
deser >> GDStatus;
|
||||
deser >> ByteCount;
|
||||
if (deser.version() <= Deserializer::VLAST_LIBRETRO)
|
||||
deser.skip<u32>(); // GDROM_TICK
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "emulator.h"
|
||||
#include "hw/bba/bba.h"
|
||||
#include "serialize.h"
|
||||
#include <map>
|
||||
|
||||
u32 sb_regs[0x540];
|
||||
HollyRegisters hollyRegs;
|
||||
|
@ -704,18 +705,7 @@ void sb_serialize(Serializer& ser)
|
|||
|
||||
void sb_deserialize(Deserializer& deser)
|
||||
{
|
||||
if (deser.version() <= Deserializer::VLAST_LIBRETRO)
|
||||
{
|
||||
for (u32& reg : sb_regs)
|
||||
{
|
||||
deser.skip<u32>(); // regs.data[i].flags
|
||||
deser >> reg;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
deser >> sb_regs;
|
||||
}
|
||||
deser >> sb_regs;
|
||||
if (deser.version() < Deserializer::V33)
|
||||
deser >> SB_ISTNRM;
|
||||
if (deser.version() >= Deserializer::V24)
|
||||
|
@ -729,9 +719,6 @@ void sb_deserialize(Deserializer& deser)
|
|||
deser.skip<u32>(); // SB_FFST_rc;
|
||||
deser.skip<u32>(); // SB_FFST;
|
||||
}
|
||||
if (deser.version() >= Deserializer::V15)
|
||||
deser >> SB_ADST;
|
||||
else
|
||||
SB_ADST = 0;
|
||||
deser >> SB_ADST;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
#include "oslib/oslib.h"
|
||||
#include "hw/aica/sgc_if.h"
|
||||
#include "cfg/option.h"
|
||||
#include "rend/gui.h"
|
||||
#include <zlib.h>
|
||||
#include <cerrno>
|
||||
#include <ctime>
|
||||
|
@ -154,7 +153,15 @@ struct maple_sega_controller: maple_base
|
|||
//2 (Maximum current consumption)
|
||||
w16(get_device_current(1));
|
||||
|
||||
return cmd == MDC_DeviceRequest ? MDRS_DeviceStatus : MDRS_DeviceStatusAll;
|
||||
if (cmd == MDC_AllStatusReq)
|
||||
{
|
||||
const char *extra = "Version 1.010,1998/09/28,315-6211-AB ,Analog Module : The 4th Edition.5/8 +DF";
|
||||
wptr(extra, strlen(extra));
|
||||
return MDRS_DeviceStatusAll;
|
||||
}
|
||||
else {
|
||||
return MDRS_DeviceStatus;
|
||||
}
|
||||
|
||||
//controller condition
|
||||
case MDCF_GetCondition:
|
||||
|
@ -441,7 +448,15 @@ struct maple_sega_vmu: maple_base
|
|||
//2
|
||||
w16(0x0082); // 13 mA
|
||||
|
||||
return cmd == MDC_DeviceRequest ? MDRS_DeviceStatus : MDRS_DeviceStatusAll;
|
||||
if (cmd == MDC_AllStatusReq)
|
||||
{
|
||||
const char *extra = "Version 1.005,1999/04/15,315-6208-03,SEGA Visual Memory System BIOS Produced by ";
|
||||
wptr(extra, strlen(extra));
|
||||
return MDRS_DeviceStatusAll;
|
||||
}
|
||||
else {
|
||||
return MDRS_DeviceStatus;
|
||||
}
|
||||
|
||||
//in[0] is function used
|
||||
//out[0] is function used
|
||||
|
@ -1730,7 +1745,7 @@ struct RFIDReaderWriter : maple_base
|
|||
cardLocked = false;
|
||||
cardInserted = false;
|
||||
NOTICE_LOG(MAPLE, "RFID card %d unlocked", player_num);
|
||||
gui_display_notification("Card ejected", 2000);
|
||||
os_notify("Card ejected", 2000);
|
||||
return (MapleDeviceRV)0xfe;
|
||||
|
||||
case 0xB1: // write to card
|
||||
|
|
|
@ -142,8 +142,7 @@ struct maple_device
|
|||
ser << player_num;
|
||||
}
|
||||
virtual void deserialize(Deserializer& deser) {
|
||||
if (deser.version() >= Deserializer::V14)
|
||||
deser >> player_num;
|
||||
deser >> player_num;
|
||||
}
|
||||
|
||||
virtual MapleDeviceType get_device_type() = 0;
|
||||
|
|
|
@ -28,10 +28,7 @@
|
|||
#include "network/picoppp.h"
|
||||
#include "serialize.h"
|
||||
#include "cfg/option.h"
|
||||
|
||||
#ifndef NDEBUG
|
||||
#include "oslib/oslib.h"
|
||||
#endif
|
||||
#include "stdclass.h"
|
||||
#include <cassert>
|
||||
|
||||
#define MODEM_COUNTRY_RES 0
|
||||
|
@ -127,7 +124,7 @@ static u64 last_dial_time;
|
|||
static bool data_sent;
|
||||
|
||||
#ifndef NDEBUG
|
||||
static double last_comm_stats;
|
||||
static u64 last_comm_stats;
|
||||
static int sent_bytes;
|
||||
static int recvd_bytes;
|
||||
static FILE *recv_fp;
|
||||
|
@ -137,7 +134,7 @@ static FILE *sent_fp;
|
|||
static int modem_sched_func(int tag, int cycles, int jitter, void *arg)
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
if (os_GetSeconds() - last_comm_stats >= 2)
|
||||
if (getTimeMs() - last_comm_stats >= 2000)
|
||||
{
|
||||
if (last_comm_stats != 0)
|
||||
{
|
||||
|
@ -147,7 +144,7 @@ static int modem_sched_func(int tag, int cycles, int jitter, void *arg)
|
|||
sent_bytes = 0;
|
||||
recvd_bytes = 0;
|
||||
}
|
||||
last_comm_stats = os_GetSeconds();
|
||||
last_comm_stats = getTimeMs();
|
||||
}
|
||||
#endif
|
||||
int callback_cycles = 0;
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
#include "hw/sh4/modules/modules.h"
|
||||
#include "hw/maple/maple_cfg.h"
|
||||
#include "hw/maple/maple_devs.h"
|
||||
#include "rend/gui.h"
|
||||
#include <deque>
|
||||
#include <memory>
|
||||
#include <cerrno>
|
||||
|
@ -288,7 +287,7 @@ protected:
|
|||
case CARD_EJECT:
|
||||
NOTICE_LOG(NAOMI, "Card ejected");
|
||||
if (cardInserted)
|
||||
gui_display_notification("Card ejected", 2000);
|
||||
os_notify("Card ejected", 2000);
|
||||
cardInserted = false;
|
||||
status1 = getStatus1();
|
||||
break;
|
||||
|
@ -582,7 +581,7 @@ private:
|
|||
case CARD_EJECT:
|
||||
NOTICE_LOG(NAOMI, "Card ejected");
|
||||
if (cardInserted)
|
||||
gui_display_notification("Card ejected", 2000);
|
||||
os_notify("Card ejected", 2000);
|
||||
cardInserted = false;
|
||||
break;
|
||||
case CARD_NEW:
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
#include "serialize.h"
|
||||
#include "network/output.h"
|
||||
#include "hw/sh4/modules/modules.h"
|
||||
#include "rend/gui.h"
|
||||
#include "oslib/oslib.h"
|
||||
#include "printer.h"
|
||||
#include "hw/flashrom/x76f100.h"
|
||||
|
||||
|
@ -409,10 +409,7 @@ void naomi_Deserialize(Deserializer& deser)
|
|||
deser.skip<u32>(); // reg_dimm_parameterh;
|
||||
deser.skip<u32>(); // reg_dimm_status;
|
||||
}
|
||||
if (deser.version() < Deserializer::V11)
|
||||
deser.skip<u8>();
|
||||
else if (deser.version() >= Deserializer::V14)
|
||||
deser >> aw_maple_devs;
|
||||
deser >> aw_maple_devs;
|
||||
if (deser.version() >= Deserializer::V20)
|
||||
{
|
||||
deser >> coin_chute_time;
|
||||
|
@ -515,7 +512,7 @@ struct DriveSimPipe : public SerialPort::Pipe
|
|||
{
|
||||
char message[16];
|
||||
sprintf(message, "Speed: %3d", speed);
|
||||
gui_display_notification(message, 1000);
|
||||
os_notify(message, 1000);
|
||||
}
|
||||
}
|
||||
buffer.clear();
|
||||
|
|
|
@ -68,7 +68,7 @@ static bool loadBios(const char *filename, Archive *child_archive, Archive *pare
|
|||
|
||||
const BIOS_t *bios = &BIOS[biosid];
|
||||
|
||||
std::string arch_name(filename);
|
||||
std::string arch_name(bios->filename != nullptr ? bios->filename : filename);
|
||||
std::string path = hostfs::findNaomiBios(arch_name + ".zip");
|
||||
if (path.empty())
|
||||
path = hostfs::findNaomiBios(arch_name + ".7z");
|
||||
|
@ -123,6 +123,7 @@ static bool loadBios(const char *filename, Archive *child_archive, Archive *pare
|
|||
break;
|
||||
case EepromBE16:
|
||||
{
|
||||
// FIXME memory leak
|
||||
naomi_default_eeprom = (u8 *)malloc(bios->blobs[romid].length);
|
||||
if (naomi_default_eeprom == nullptr)
|
||||
throw NaomiCartException("Memory allocation failed");
|
||||
|
@ -627,8 +628,10 @@ void naomi_cart_LoadRom(const std::string& path, const std::string& fileName, Lo
|
|||
bool systemSP = memcmp(bootId.boardName, "SystemSP", 8) == 0;
|
||||
std::string gameId = trim_trailing_ws(std::string(bootId.gameTitle[systemSP ? 1 : 0], &bootId.gameTitle[systemSP ? 1 : 0][32]));
|
||||
std::string romName;
|
||||
if (CurrentCartridge->game != nullptr)
|
||||
if (CurrentCartridge->game != nullptr) {
|
||||
romName = CurrentCartridge->game->name;
|
||||
settings.content.title = CurrentCartridge->game->description;
|
||||
}
|
||||
if (gameId == "SAMPLE GAME MAX LONG NAME-")
|
||||
{
|
||||
// Use better game names
|
||||
|
@ -775,7 +778,7 @@ void naomi_cart_serialize(Serializer& ser)
|
|||
|
||||
void naomi_cart_deserialize(Deserializer& deser)
|
||||
{
|
||||
if (CurrentCartridge != nullptr && (!settings.platform.isAtomiswave() || deser.version() >= Deserializer::V10_LIBRETRO))
|
||||
if (CurrentCartridge != nullptr)
|
||||
CurrentCartridge->Deserialize(deser);
|
||||
touchscreen::deserialize(deser);
|
||||
printer::deserialize(deser);
|
||||
|
@ -885,7 +888,7 @@ void* NaomiCartridge::GetDmaPtr(u32& size)
|
|||
{
|
||||
if ((DmaOffset & 0x1fffffff) >= RomSize)
|
||||
{
|
||||
INFO_LOG(NAOMI, "Error: DmaOffset >= RomSize");
|
||||
INFO_LOG(NAOMI, "Error: DmaOffset (%x) >= RomSize (%x)", DmaOffset, RomSize);
|
||||
size = 0;
|
||||
return nullptr;
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
#include "hw/sh4/sh4_mem.h"
|
||||
#include "network/naomi_network.h"
|
||||
#include "emulator.h"
|
||||
#include "rend/gui.h"
|
||||
#include "oslib/oslib.h"
|
||||
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
|
@ -72,7 +72,7 @@ void NaomiM3Comm::closeNetwork()
|
|||
|
||||
void NaomiM3Comm::connectNetwork()
|
||||
{
|
||||
gui_display_notification("Network started", 5000);
|
||||
os_notify("Network started", 5000);
|
||||
packet_number = 0;
|
||||
slot_count = naomiNetwork.getSlotCount();
|
||||
slot_id = naomiNetwork.getSlotId();
|
||||
|
|
|
@ -88,51 +88,51 @@ const BIOS_t BIOS[] =
|
|||
//ROM_SYSTEM_BIOS( 1, "bios1", "epr-21576g (Japan)" )
|
||||
{ 0, "epr-21576g.ic27", 0x000000, 0x200000, 0xd2a1c6bf },
|
||||
//ROM_SYSTEM_BIOS( 2, "bios2", "epr-21576e (Japan)" )
|
||||
//{ 0, "epr-21576e.ic27", 0x000000, 0x200000 },
|
||||
//{ 0, "epr-21576e.ic27", 0x000000, 0x200000, 0x08c0add7 },
|
||||
//ROM_SYSTEM_BIOS( 3, "bios3", "epr-21576d (Japan)" )
|
||||
//{ 0, "epr-21576d.ic27", 0x000000, 0x200000 },
|
||||
//{ 0, "epr-21576d.ic27", 0x000000, 0x200000, 0x3b2afa7b },
|
||||
//ROM_SYSTEM_BIOS( 4, "bios4", "epr-21576c (Japan)" )
|
||||
//{ 0, "epr-21576c.ic27", 0x000000, 0x200000 }, // BAD DUMP
|
||||
//{ 0, "epr-21576c.ic27", 0x000000, 0x200000, 0x4599ad13 }, // BAD DUMP
|
||||
//ROM_SYSTEM_BIOS( 5, "bios5", "epr-21576b (Japan)" )
|
||||
//{ 0, "epr-21576b.ic27", 0x000000, 0x200000 },
|
||||
//{ 0, "epr-21576b.ic27", 0x000000, 0x200000, 0x755a6e07 },
|
||||
//ROM_SYSTEM_BIOS( 6, "bios6", "epr-21576a (Japan)" )
|
||||
//{ 0, "epr-21576a.ic27", 0x000000, 0x200000 },
|
||||
//{ 0, "epr-21576a.ic27", 0x000000, 0x200000, 0xcedfe439 },
|
||||
//ROM_SYSTEM_BIOS( 7, "bios7", "epr-21576 (Japan)" )
|
||||
//{ 0, "epr-21576.ic27", 0x000000, 0x200000 },
|
||||
//{ 0, "epr-21576.ic27", 0x000000, 0x200000, 0x9dad3495 },
|
||||
//ROM_SYSTEM_BIOS( 8, "bios8", "epr-21578h (Export)" )
|
||||
{ 2, "epr-21578h.ic27", 0x000000, 0x200000, 0x7b452946 },
|
||||
//ROM_SYSTEM_BIOS( 9, "bios9", "epr-21578g (Export)" )
|
||||
{ 2, "epr-21578g.ic27", 0x000000, 0x200000, 0x55413214 },
|
||||
//ROM_SYSTEM_BIOS( 10, "bios10", "epr-21578f (Export)" )
|
||||
//{ 2, "epr-21578f.ic27", 0x000000, 0x200000 },
|
||||
//{ 2, "epr-21578f.ic27", 0x000000, 0x200000, 0x628a27fd },
|
||||
//ROM_SYSTEM_BIOS( 11, "bios11", "epr-21578e (Export)" )
|
||||
//{ 2, "epr-21578e.ic27", 0x000000, 0x200000 },
|
||||
//{ 2, "epr-21578e.ic27", 0x000000, 0x200000, 0x087f09a3 },
|
||||
//ROM_SYSTEM_BIOS( 12, "bios12", "epr-21578d (Export)" )
|
||||
//{ 2, "epr-21578d.ic27", 0x000000, 0x200000 },
|
||||
//{ 2, "epr-21578d.ic27", 0x000000, 0x200000, 0xdfd5f42a },
|
||||
//ROM_SYSTEM_BIOS( 13, "bios13", "epr-21578a (Export)" )
|
||||
//{ 2, "epr-21578a.ic27", 0x000000, 0x200000 },
|
||||
//{ 2, "epr-21578a.ic27", 0x000000, 0x200000, 0x6c9aad83 },
|
||||
//ROM_SYSTEM_BIOS( 14, "bios14", "epr-21577h (USA)" )
|
||||
{ 1, "epr-21577h.ic27", 0x000000, 0x200000, 0xfdf17452 },
|
||||
//ROM_SYSTEM_BIOS( 15, "bios15", "epr-21577g (USA)" )
|
||||
{ 1, "epr-21577g.ic27", 0x000000, 0x200000, 0x25f64af7 },
|
||||
//ROM_SYSTEM_BIOS( 16, "bios16", "epr-21577e (USA)" )
|
||||
//{ 1, "epr-21577e.ic27", 0x000000, 0x200000 },
|
||||
//{ 1, "epr-21577e.ic27", 0x000000, 0x200000, 0xcf36e97b },
|
||||
//ROM_SYSTEM_BIOS( 17, "bios17", "epr-21577d (USA)" )
|
||||
//{ 1, "epr-21577d.ic27", 0x000000, 0x200000 },
|
||||
//{ 1, "epr-21577d.ic27", 0x000000, 0x200000, 0x60ddcbbe },
|
||||
//ROM_SYSTEM_BIOS( 18, "bios18", "epr-21577a (USA)" )
|
||||
//{ 1, "epr-21577a.ic27", 0x000000, 0x200000 },
|
||||
//{ 1, "epr-21577a.ic27", 0x000000, 0x200000, 0x969dc491 },
|
||||
//ROM_SYSTEM_BIOS( 19, "bios19", "epr-21579d (Korea)" )
|
||||
{ 3, "epr-21579d.ic27", 0x000000, 0x200000, 0x33513691 },
|
||||
//ROM_SYSTEM_BIOS( 20, "bios20", "epr-21579 (Korea)" )
|
||||
//{ 3, "epr-21579.ic27", 0x000000, 0x200000 },
|
||||
//{ 3, "epr-21579.ic27", 0x000000, 0x200000, 0x71f9c918 },
|
||||
//ROM_SYSTEM_BIOS( 21, "bios21", "Set4 Dev BIOS" )
|
||||
//{ 3, "boot_rom_64b8.ic606", 0x000000, 0x080000 },
|
||||
//{ 3, "boot_rom_64b8.ic606", 0x000000, 0x080000, 0x7a50fab9 },
|
||||
//ROM_SYSTEM_BIOS( 22, "bios22", "Dev BIOS v1.10" )
|
||||
//{ 3, "develop110.ic27", 0x000000, 0x200000 },
|
||||
//{ 3, "develop110.ic27", 0x000000, 0x200000, 0xde7cfdb0 },
|
||||
//ROM_SYSTEM_BIOS( 23, "bios23", "Dev BIOS (Nov 1998)" )
|
||||
//{ 3, "develop.ic27", 0x000000, 0x200000 },
|
||||
//{ 3, "develop.ic27", 0x000000, 0x200000, 0x309a196a },
|
||||
//ROM_SYSTEM_BIOS( 24, "bios24", "Development ROM Board" )
|
||||
//{ 3, "zukinver0930.ic25", 0x000000, 0x200000 },
|
||||
//{ 3, "zukinver0930.ic25", 0x000000, 0x200000, 0x58e17c23 },
|
||||
//ROM_SYSTEM_BIOS( 25, "bios25", "epr-21576h (multi-region hack)" )
|
||||
// The default dipswitch configuration selects Korea for the multiregion hacked BIOS
|
||||
// See hw/maple/maple_jvs.cpp
|
||||
|
@ -176,6 +176,17 @@ const BIOS_t BIOS[] =
|
|||
{ 2, "mb_eeprom_exp.ic54s", 0x000, 0x800, 0x947ddfad, EepromBE16 },
|
||||
},
|
||||
},
|
||||
{
|
||||
"naomi-jp-d", // for marstv
|
||||
{
|
||||
//ROM_SYSTEM_BIOS( 3, "bios3", "epr-21576d (Japan)" )
|
||||
{ 0, "epr-21576d.ic27", 0x000000, 0x200000, 0x3b2afa7b },
|
||||
{ 1, "epr-21576d.ic27", 0x000000, 0x200000, 0x3b2afa7b },
|
||||
{ 2, "epr-21576d.ic27", 0x000000, 0x200000, 0x3b2afa7b },
|
||||
{ 3, "epr-21576d.ic27", 0x000000, 0x200000, 0x3b2afa7b },
|
||||
},
|
||||
"naomi",
|
||||
},
|
||||
{
|
||||
nullptr
|
||||
}
|
||||
|
@ -2375,11 +2386,11 @@ const Game Games[] =
|
|||
// Mars TV (JPN)
|
||||
{
|
||||
"marstv",
|
||||
NULL,
|
||||
nullptr,
|
||||
"Mars TV",
|
||||
0x08000000,
|
||||
0x280b8ef5,
|
||||
NULL,
|
||||
"naomi-jp-d",
|
||||
M2,
|
||||
ROT0,
|
||||
{
|
||||
|
@ -2400,7 +2411,6 @@ const Game Games[] =
|
|||
{ "mpr-22990.ic13s", 0x6800000, 0x800000 },
|
||||
{ "mpr-22991.ic14s", 0x7000000, 0x800000 },
|
||||
{ "mpr-22992.ic15s", 0x7800000, 0x800000 },
|
||||
{ NULL, 0, 0 },
|
||||
}
|
||||
},
|
||||
// Mazan: Flash of the Blade (MAZ2 Ver. A)
|
||||
|
|
|
@ -62,6 +62,7 @@ struct BIOS_t
|
|||
u32 crc;
|
||||
BlobType blob_type;
|
||||
} blobs[MAX_GAME_FILES];
|
||||
const char* filename; // if different from name
|
||||
};
|
||||
extern const BIOS_t BIOS[];
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
#include "stdclass.h"
|
||||
#include "printer.h"
|
||||
#include "serialize.h"
|
||||
#include "rend/gui.h"
|
||||
#include "oslib/oslib.h"
|
||||
#include <cassert>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
@ -827,11 +827,11 @@ private:
|
|||
state = Default;
|
||||
if (bitmapWriter && bitmapWriter->isDirty())
|
||||
{
|
||||
// TODO save to ~/Pictures instead
|
||||
std::string s = get_writable_data_path(settings.content.gameId + "-results.png");
|
||||
bitmapWriter->save(s);
|
||||
bitmapWriter.reset();
|
||||
s = "Print out saved to " + s;
|
||||
gui_display_notification(s.c_str(), 5000);
|
||||
os_notify("Print out saved", 5000, s.c_str());
|
||||
NOTICE_LOG(NAOMI, "%s", s.c_str());
|
||||
}
|
||||
break;
|
||||
|
@ -1198,7 +1198,7 @@ std::string get_writable_data_path(const std::string& s)
|
|||
return "./" + s;
|
||||
}
|
||||
|
||||
void gui_display_notification(char const*, int) {
|
||||
void os_notify(char const*, int, char const*) {
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
|
|
|
@ -1300,7 +1300,7 @@ class MedalIOManager : public DefaultIOManager
|
|||
}
|
||||
|
||||
// OUT-1 (CN10 17-24)
|
||||
void setCN10_17_24(u8 v)
|
||||
void setCN10_17_24(u8 v) override
|
||||
{
|
||||
// 0: sw.lamp c
|
||||
// 1: jp solenoid
|
||||
|
|
|
@ -536,11 +536,7 @@ void rend_serialize(Serializer& ser)
|
|||
}
|
||||
void rend_deserialize(Deserializer& deser)
|
||||
{
|
||||
if ((deser.version() >= Deserializer::V12_LIBRETRO && deser.version() <= Deserializer::VLAST_LIBRETRO)
|
||||
|| deser.version() >= Deserializer::V12)
|
||||
deser >> fb_w_cur;
|
||||
else
|
||||
fb_w_cur = 1;
|
||||
deser >> fb_w_cur;
|
||||
if (deser.version() >= Deserializer::V20)
|
||||
{
|
||||
deser >> render_called;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
#include "types.h"
|
||||
#include "ta_ctx.h"
|
||||
#include <vector>
|
||||
|
||||
extern u32 FrameCount;
|
||||
|
||||
|
@ -62,6 +63,11 @@ struct Renderer
|
|||
virtual bool Render() = 0;
|
||||
virtual void RenderFramebuffer(const FramebufferInfo& info) = 0;
|
||||
virtual bool RenderLastFrame() { return false; }
|
||||
// Get the last rendered frame pixel data in RGB format
|
||||
// The returned image is rotated and scaled (upward orientation and square pixels)
|
||||
// If both width and height are zero, the internal render resolution will be used.
|
||||
// Otherwise either width or height will be used as the maximum width or height respectively.
|
||||
virtual bool GetLastFrame(std::vector<u8>& data, int& width, int& height) { return false; }
|
||||
|
||||
virtual bool Present() { return true; }
|
||||
|
||||
|
|
|
@ -104,8 +104,7 @@ void deserialize(Deserializer& deser)
|
|||
deser >> taRenderPass;
|
||||
else
|
||||
taRenderPass = 0;
|
||||
if (deser.version() >= Deserializer::V11 || (deser.version() >= Deserializer::V10_LIBRETRO && deser.version() <= Deserializer::VLAST_LIBRETRO))
|
||||
DeserializeTAContext(deser);
|
||||
DeserializeTAContext(deser);
|
||||
|
||||
if (!deser.rollback())
|
||||
vram.deserialize(deser);
|
||||
|
|
|
@ -190,10 +190,7 @@ void YUV_deserialize(Deserializer& deser)
|
|||
deser >> YUV_y_curr;
|
||||
deser >> YUV_x_size;
|
||||
deser >> YUV_y_size;
|
||||
if (deser.version() >= Deserializer::V16)
|
||||
deser >> YUV_index;
|
||||
else
|
||||
YUV_index = 0;
|
||||
deser >> YUV_index;
|
||||
}
|
||||
|
||||
void YUV_reset()
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
#include <array>
|
||||
#include "spg.h"
|
||||
#include "hw/holly/holly_intc.h"
|
||||
#include "hw/holly/sb.h"
|
||||
#include "hw/sh4/sh4_sched.h"
|
||||
#include "oslib/oslib.h"
|
||||
#include "hw/maple/maple_if.h"
|
||||
#include "serialize.h"
|
||||
#include "network/ggpo.h"
|
||||
#include "hw/pvr/Renderer_if.h"
|
||||
#include "stdclass.h"
|
||||
#include <array>
|
||||
|
||||
#ifdef TEST_AUTOMATION
|
||||
#include "input/gamepad_device.h"
|
||||
|
@ -21,7 +21,7 @@ static u32 prv_cur_scanline = -1;
|
|||
|
||||
#if !defined(NDEBUG) || defined(DEBUGFAST)
|
||||
static u32 vblk_cnt;
|
||||
static float last_fps;
|
||||
static u64 last_fps;
|
||||
#endif
|
||||
|
||||
// 27 mhz pixel clock
|
||||
|
@ -156,17 +156,18 @@ static int spg_line_sched(int tag, int cycles, int jitter, void *arg)
|
|||
|
||||
rend_vblank();
|
||||
|
||||
double now = os_GetSeconds() * 1000000.0;
|
||||
u64 now = getTimeMs();
|
||||
cpu_time_idx = (cpu_time_idx + 1) % cpu_cycles.size();
|
||||
if (cpu_cycles[cpu_time_idx] != 0)
|
||||
{
|
||||
u32 cycle_span = (u32)(sh4_sched_now64() - cpu_cycles[cpu_time_idx]);
|
||||
double time_span = now - real_times[cpu_time_idx];
|
||||
double cpu_speed = ((double)cycle_span / time_span) / (SH4_MAIN_CLOCK / 100000000);
|
||||
SH4FastEnough = cpu_speed >= 85.0;
|
||||
u64 time_span = now - real_times[cpu_time_idx];
|
||||
float cpu_speed = ((float)cycle_span / time_span) / (SH4_MAIN_CLOCK / 100000);
|
||||
SH4FastEnough = cpu_speed >= 85.f;
|
||||
}
|
||||
else
|
||||
else {
|
||||
SH4FastEnough = false;
|
||||
}
|
||||
cpu_cycles[cpu_time_idx] = sh4_sched_now64();
|
||||
real_times[cpu_time_idx] = now;
|
||||
|
||||
|
@ -176,15 +177,15 @@ static int spg_line_sched(int tag, int cycles, int jitter, void *arg)
|
|||
|
||||
#if !defined(NDEBUG) || defined(DEBUGFAST)
|
||||
vblk_cnt++;
|
||||
if ((os_GetSeconds()-last_fps)>2)
|
||||
if (getTimeMs() - last_fps >= 2000)
|
||||
{
|
||||
static int Last_FC;
|
||||
double ts=os_GetSeconds()-last_fps;
|
||||
double spd_fps=(FrameCount-Last_FC)/ts;
|
||||
double spd_vbs=vblk_cnt/ts;
|
||||
double spd_cpu=spd_vbs*Frame_Cycles;
|
||||
spd_cpu/=1000000; //mrhz kthx
|
||||
double fullvbs=(spd_vbs/spd_cpu)*200;
|
||||
double ts = ((double)getTimeMs() - last_fps) / 1000.0;
|
||||
double spd_fps = (FrameCount - Last_FC) / ts;
|
||||
double spd_vbs = vblk_cnt / ts;
|
||||
double spd_cpu = spd_vbs * Frame_Cycles;
|
||||
spd_cpu /= 1000000.0; //mrhz kthx
|
||||
double fullvbs = (spd_vbs / spd_cpu) * 200.0;
|
||||
|
||||
Last_FC=FrameCount;
|
||||
|
||||
|
@ -210,13 +211,13 @@ static int spg_line_sched(int tag, int cycles, int jitter, void *arg)
|
|||
|
||||
double full_rps = spd_fps + fskip / ts;
|
||||
|
||||
INFO_LOG(COMMON, "%s/%c - %4.2f - %4.2f - V: %4.2f (%.2f, %s%s%4.2f) R: %4.2f+%4.2f",
|
||||
VER_SHORTNAME,'n',mspdf,spd_cpu*100/200,spd_vbs,
|
||||
spd_vbs/full_rps,mode,res,fullvbs,
|
||||
spd_fps,fskip/ts);
|
||||
INFO_LOG(COMMON, "SPG - %4.2f - %4.2f - V: %4.2f (%.2f, %s%s%4.2f) R: %4.2f+%4.2f",
|
||||
mspdf, spd_cpu * 100 / 200, spd_vbs,
|
||||
spd_vbs / full_rps, mode, res, fullvbs,
|
||||
spd_fps, fskip / ts);
|
||||
|
||||
fskip=0;
|
||||
last_fps=os_GetSeconds();
|
||||
fskip = 0;
|
||||
last_fps = getTimeMs();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -314,19 +315,11 @@ void spg_Deserialize(Deserializer& deser)
|
|||
if (deser.version() < Deserializer::V30)
|
||||
deser.skip<u32>(); // in_vblank
|
||||
deser >> clc_pvr_scanline;
|
||||
if (deser.version() >= Deserializer::V12)
|
||||
{
|
||||
deser >> maple_int_pending;
|
||||
if (deser.version() >= Deserializer::V14)
|
||||
{
|
||||
deser >> pvr_numscanlines;
|
||||
deser >> prv_cur_scanline;
|
||||
deser >> Line_Cycles;
|
||||
deser >> Frame_Cycles;
|
||||
deser >> lightgun_line;
|
||||
deser >> lightgun_hpos;
|
||||
}
|
||||
}
|
||||
if (deser.version() < Deserializer::V14)
|
||||
CalculateSync();
|
||||
deser >> maple_int_pending;
|
||||
deser >> pvr_numscanlines;
|
||||
deser >> prv_cur_scanline;
|
||||
deser >> Line_Cycles;
|
||||
deser >> Frame_Cycles;
|
||||
deser >> lightgun_line;
|
||||
deser >> lightgun_hpos;
|
||||
}
|
||||
|
|
|
@ -249,8 +249,7 @@ static void deserializeContext(Deserializer& deser, TA_context **pctx)
|
|||
tad_context& tad = (*pctx)->tad;
|
||||
deser.deserialize(tad.thd_root, size);
|
||||
tad.thd_data = tad.thd_root + size;
|
||||
if ((deser.version() >= Deserializer::V12 && deser.version() < Deserializer::V26)
|
||||
|| (deser.version() >= Deserializer::V12_LIBRETRO && deser.version() <= Deserializer::VLAST_LIBRETRO))
|
||||
if (deser.version() < Deserializer::V26)
|
||||
{
|
||||
u32 render_pass_count;
|
||||
deser >> render_pass_count;
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "hw/sh4/sh4_if.h"
|
||||
#include "hw/sh4/sh4_core.h"
|
||||
#include "types.h"
|
||||
#include "stdclass.h"
|
||||
|
||||
#ifdef FAST_MMU
|
||||
|
||||
|
@ -156,7 +157,7 @@ int main(int argc, char *argv[])
|
|||
addrs.push_back(random());
|
||||
asids.push_back(666);
|
||||
}
|
||||
double start = os_GetSeconds();
|
||||
u64 start = getTimeMs();
|
||||
int success = 0;
|
||||
const int loops = 100000;
|
||||
for (int i = 0; i < loops; i++)
|
||||
|
@ -170,8 +171,8 @@ int main(int argc, char *argv[])
|
|||
success++;
|
||||
}
|
||||
}
|
||||
double end = os_GetSeconds();
|
||||
printf("Lookup time: %f ms. Success rate %f max_len %d\n", (end - start) * 1000.0 / addrs.size(), (double)success / addrs.size() / loops, 0/*max_length*/);
|
||||
u64 end = getTimeMs();
|
||||
printf("Lookup time: %f ms. Success rate %f max_len %d\n", ((double)end - start) / addrs.size(), (double)success / addrs.size() / loops, 0/*max_length*/);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -591,8 +591,6 @@ void mmu_deserialize(Deserializer& deser)
|
|||
deser >> UTLB;
|
||||
deser >> ITLB;
|
||||
|
||||
if (deser.version() >= Deserializer::V11
|
||||
|| (deser.version() >= Deserializer::V11_LIBRETRO && deser.version() <= Deserializer::VLAST_LIBRETRO))
|
||||
deser >> sq_remap;
|
||||
deser >> sq_remap;
|
||||
deser.skip(64 * 4, Deserializer::V23); // ITLB_LRU_USE
|
||||
}
|
||||
|
|
|
@ -692,59 +692,24 @@ void serialize(Serializer& ser)
|
|||
sh4_sched_serialize(ser);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static void register_deserialize_libretro(T& regs, Deserializer& deser)
|
||||
{
|
||||
for (auto& reg : regs)
|
||||
{
|
||||
deser.skip<u32>(); // regs.data[i].flags
|
||||
deser >> reg;
|
||||
}
|
||||
}
|
||||
|
||||
void deserialize(Deserializer& deser)
|
||||
{
|
||||
deser >> OnChipRAM;
|
||||
|
||||
if (deser.version() <= Deserializer::VLAST_LIBRETRO)
|
||||
{
|
||||
register_deserialize_libretro(CCN, deser);
|
||||
register_deserialize_libretro(UBC, deser);
|
||||
register_deserialize_libretro(BSC, deser);
|
||||
register_deserialize_libretro(DMAC, deser);
|
||||
register_deserialize_libretro(CPG, deser);
|
||||
register_deserialize_libretro(RTC, deser);
|
||||
register_deserialize_libretro(INTC, deser);
|
||||
register_deserialize_libretro(TMU, deser);
|
||||
register_deserialize_libretro(SCI, deser);
|
||||
register_deserialize_libretro(SCIF, deser);
|
||||
}
|
||||
else
|
||||
{
|
||||
deser >> CCN;
|
||||
deser >> UBC;
|
||||
deser >> BSC;
|
||||
deser >> DMAC;
|
||||
deser >> CPG;
|
||||
deser >> RTC;
|
||||
deser >> INTC;
|
||||
deser >> TMU;
|
||||
deser >> SCI;
|
||||
deser >> SCIF;
|
||||
}
|
||||
deser >> CCN;
|
||||
deser >> UBC;
|
||||
deser >> BSC;
|
||||
deser >> DMAC;
|
||||
deser >> CPG;
|
||||
deser >> RTC;
|
||||
deser >> INTC;
|
||||
deser >> TMU;
|
||||
deser >> SCI;
|
||||
deser >> SCIF;
|
||||
|
||||
SCIFSerialPort::Instance().deserialize(deser);
|
||||
if (deser.version() >= Deserializer::V9
|
||||
// Note (lr): was added in V11 fa49de29 24/12/2020 but ver not updated until V12 (13/4/2021)
|
||||
|| (deser.version() >= Deserializer::V11_LIBRETRO && deser.version() <= Deserializer::VLAST_LIBRETRO))
|
||||
icache.Deserialize(deser);
|
||||
else
|
||||
icache.Reset(true);
|
||||
if (deser.version() >= Deserializer::V10
|
||||
// Note (lr): was added in V11 2eb66879 27/12/2020 but ver not updated until V12 (13/4/2021)
|
||||
|| (deser.version() >= Deserializer::V11_LIBRETRO && deser.version() <= Deserializer::VLAST_LIBRETRO))
|
||||
ocache.Deserialize(deser);
|
||||
else
|
||||
ocache.Reset(true);
|
||||
icache.Deserialize(deser);
|
||||
ocache.Deserialize(deser);
|
||||
|
||||
if (!deser.rollback())
|
||||
mem_b.deserialize(deser);
|
||||
|
@ -778,11 +743,7 @@ void deserialize2(Deserializer& deser)
|
|||
if (deser.version() <= Deserializer::V32)
|
||||
{
|
||||
deser >> SCIF_SCFSR2;
|
||||
if (deser.version() >= Deserializer::V11
|
||||
|| (deser.version() >= Deserializer::V11_LIBRETRO && deser.version() <= Deserializer::VLAST_LIBRETRO))
|
||||
deser >> SCIF_SCSCR2;
|
||||
else
|
||||
SCIF_SCSCR2.full = 0;
|
||||
deser >> SCIF_SCSCR2;
|
||||
deser >> BSC_PDTRA;
|
||||
}
|
||||
|
||||
|
|
|
@ -350,6 +350,7 @@ bool DiscSwap(const std::string& path)
|
|||
{
|
||||
if (!doDiscSwap(path))
|
||||
throw FlycastException("This media cannot be loaded");
|
||||
EventManager::event(Event::DiskChange);
|
||||
// Drive is busy after the lid was closed
|
||||
sns_asc = 4;
|
||||
sns_ascq = 1;
|
||||
|
|
|
@ -51,6 +51,7 @@ enum DreamcastKey
|
|||
EMU_BTN_LOADSTATE,
|
||||
EMU_BTN_SAVESTATE,
|
||||
EMU_BTN_BYPASS_KB,
|
||||
EMU_BTN_SCREENSHOT,
|
||||
|
||||
// Real axes
|
||||
DC_AXIS_TRIGGERS = 0x1000000,
|
||||
|
|
|
@ -19,8 +19,8 @@
|
|||
|
||||
#include "gamepad_device.h"
|
||||
#include "cfg/cfg.h"
|
||||
#include "oslib/oslib.h"
|
||||
#include "rend/gui.h"
|
||||
#include "stdclass.h"
|
||||
#include "ui/gui.h"
|
||||
#include "emulator.h"
|
||||
#include "hw/maple/maple_devs.h"
|
||||
#include "mouse.h"
|
||||
|
@ -99,6 +99,10 @@ bool GamepadDevice::handleButtonInput(int port, DreamcastKey key, bool pressed)
|
|||
if (pressed)
|
||||
gui_saveState();
|
||||
break;
|
||||
case EMU_BTN_SCREENSHOT:
|
||||
if (pressed)
|
||||
gui_takeScreenshot();
|
||||
break;
|
||||
case DC_AXIS_LT:
|
||||
if (port >= 0)
|
||||
lt[port] = pressed ? 0xffff : 0;
|
||||
|
@ -152,7 +156,7 @@ bool GamepadDevice::handleButtonInput(int port, DreamcastKey key, bool pressed)
|
|||
bool GamepadDevice::gamepad_btn_input(u32 code, bool pressed)
|
||||
{
|
||||
if (_input_detected != nullptr && _detecting_button
|
||||
&& os_GetSeconds() >= _detection_start_time && pressed)
|
||||
&& getTimeMs() >= _detection_start_time && pressed)
|
||||
{
|
||||
_input_detected(code, false, false);
|
||||
_input_detected = nullptr;
|
||||
|
@ -207,7 +211,7 @@ bool GamepadDevice::gamepad_axis_input(u32 code, int value)
|
|||
{
|
||||
bool positive = value >= 0;
|
||||
if (_input_detected != NULL && _detecting_axis
|
||||
&& os_GetSeconds() >= _detection_start_time && std::abs(value) >= 16384)
|
||||
&& getTimeMs() >= _detection_start_time && std::abs(value) >= 16384)
|
||||
{
|
||||
_input_detected(code, true, positive);
|
||||
_input_detected = nullptr;
|
||||
|
@ -505,7 +509,7 @@ void GamepadDevice::detect_btn_input(input_detected_cb button_pressed)
|
|||
_input_detected = button_pressed;
|
||||
_detecting_button = true;
|
||||
_detecting_axis = false;
|
||||
_detection_start_time = os_GetSeconds() + 0.2;
|
||||
_detection_start_time = getTimeMs() + 200;
|
||||
}
|
||||
|
||||
void GamepadDevice::detect_axis_input(input_detected_cb axis_moved)
|
||||
|
@ -513,7 +517,7 @@ void GamepadDevice::detect_axis_input(input_detected_cb axis_moved)
|
|||
_input_detected = axis_moved;
|
||||
_detecting_button = false;
|
||||
_detecting_axis = true;
|
||||
_detection_start_time = os_GetSeconds() + 0.2;
|
||||
_detection_start_time = getTimeMs() + 200;
|
||||
}
|
||||
|
||||
void GamepadDevice::detectButtonOrAxisInput(input_detected_cb input_changed)
|
||||
|
@ -521,7 +525,7 @@ void GamepadDevice::detectButtonOrAxisInput(input_detected_cb input_changed)
|
|||
_input_detected = input_changed;
|
||||
_detecting_button = true;
|
||||
_detecting_axis = true;
|
||||
_detection_start_time = os_GetSeconds() + 0.2;
|
||||
_detection_start_time = getTimeMs() + 200;
|
||||
}
|
||||
|
||||
#ifdef TEST_AUTOMATION
|
||||
|
|
|
@ -177,7 +177,7 @@ private:
|
|||
int _maple_port;
|
||||
bool _detecting_button = false;
|
||||
bool _detecting_axis = false;
|
||||
double _detection_start_time = 0.0;
|
||||
u64 _detection_start_time = 0;
|
||||
input_detected_cb _input_detected;
|
||||
bool _remappable;
|
||||
u32 digitalToAnalogState[4];
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
#include "types.h"
|
||||
#include "cfg/option.h"
|
||||
#include "gamepad_device.h"
|
||||
#include "rend/gui.h"
|
||||
#include "ui/gui.h"
|
||||
#include <memory>
|
||||
|
||||
extern u8 kb_key[4][6]; // normal keys pressed
|
||||
|
@ -61,6 +61,7 @@ public:
|
|||
set_button(DC_AXIS_LEFT, 13); // J
|
||||
set_button(DC_AXIS_RIGHT, 15); // L
|
||||
set_button(DC_BTN_D, 4); // Q (Coin)
|
||||
set_button(EMU_BTN_SCREENSHOT, 69); // F12
|
||||
|
||||
dirty = false;
|
||||
}
|
||||
|
|
|
@ -61,6 +61,7 @@ button_list[] =
|
|||
{ EMU_BTN_LOADSTATE, "emulator", "btn_jump_state" },
|
||||
{ EMU_BTN_SAVESTATE, "emulator", "btn_quick_save" },
|
||||
{ EMU_BTN_BYPASS_KB, "emulator", "btn_bypass_kb" },
|
||||
{ EMU_BTN_SCREENSHOT, "emulator", "btn_screenshot" },
|
||||
};
|
||||
|
||||
static struct
|
||||
|
|
|
@ -36,6 +36,7 @@ public:
|
|||
name = other.name;
|
||||
dead_zone = other.dead_zone;
|
||||
saturation = other.saturation;
|
||||
rumblePower = other.rumblePower;
|
||||
for (int port = 0; port < 4; port++)
|
||||
{
|
||||
buttons[port] = other.buttons[port];
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
*/
|
||||
#include "mouse.h"
|
||||
#include "cfg/option.h"
|
||||
#include "rend/gui.h"
|
||||
#include "ui/gui.h"
|
||||
|
||||
// Mouse buttons
|
||||
// bit 0: Button C
|
||||
|
|
|
@ -1,82 +0,0 @@
|
|||
#if defined(SUPPORT_DISPMANX)
|
||||
#include "dispmanx.h"
|
||||
#include "types.h"
|
||||
#include "wsi/context.h"
|
||||
#include "cfg/option.h"
|
||||
|
||||
#include <bcm_host.h>
|
||||
#include <EGL/egl.h>
|
||||
|
||||
void dispmanx_window_create()
|
||||
{
|
||||
DISPMANX_DISPLAY_HANDLE_T dispman_display;
|
||||
DISPMANX_UPDATE_HANDLE_T dispman_update;
|
||||
DISPMANX_ELEMENT_HANDLE_T dispman_element;
|
||||
VC_RECT_T src_rect;
|
||||
VC_RECT_T dst_rect;
|
||||
VC_DISPMANX_ALPHA_T dispman_alpha;
|
||||
uint32_t screen_width;
|
||||
uint32_t screen_height;
|
||||
uint32_t window_width;
|
||||
uint32_t window_height;
|
||||
|
||||
dispman_alpha.flags = DISPMANX_FLAGS_ALPHA_FIXED_ALL_PIXELS;
|
||||
dispman_alpha.opacity = 0xFF;
|
||||
dispman_alpha.mask = 0;
|
||||
|
||||
graphics_get_display_size(0 /* LCD */, &screen_width, &screen_height);
|
||||
|
||||
window_width = cfgLoadInt("window", "width", 0);
|
||||
window_height = cfgLoadInt("window", "height", 0);
|
||||
|
||||
if(window_width < 1)
|
||||
window_width = screen_width;
|
||||
if(window_height < 1)
|
||||
window_height = screen_height;
|
||||
|
||||
src_rect.x = 0;
|
||||
src_rect.y = 0;
|
||||
src_rect.width = window_width << 16;
|
||||
src_rect.height = window_height << 16;
|
||||
|
||||
if (config::DispmanxMaintainAspect)
|
||||
{
|
||||
float screen_aspect = (float)screen_width / screen_height;
|
||||
float window_aspect = (float)window_width / window_height;
|
||||
if(screen_aspect > window_aspect)
|
||||
{
|
||||
dst_rect.width = window_width * screen_height / window_height;
|
||||
dst_rect.height = screen_height;
|
||||
}
|
||||
else
|
||||
{
|
||||
dst_rect.width = screen_width;
|
||||
dst_rect.height = window_height * screen_width / window_width;
|
||||
}
|
||||
dst_rect.x = (screen_width - dst_rect.width) / 2;
|
||||
dst_rect.y = (screen_height - dst_rect.height) / 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
dst_rect.x = 0;
|
||||
dst_rect.y = 0;
|
||||
dst_rect.width = screen_width;
|
||||
dst_rect.height = screen_height;
|
||||
}
|
||||
|
||||
dispman_display = vc_dispmanx_display_open( 0 /* LCD */);
|
||||
dispman_update = vc_dispmanx_update_start( 0 );
|
||||
dispman_element = vc_dispmanx_element_add(dispman_update, dispman_display,
|
||||
0 /*layer*/, &dst_rect, 0 /*src*/,
|
||||
&src_rect, DISPMANX_PROTECTION_NONE,
|
||||
&dispman_alpha /*alpha*/, 0 /*clamp*/, (DISPMANX_TRANSFORM_T)0 /*transform*/);
|
||||
|
||||
static EGL_DISPMANX_WINDOW_T native_window;
|
||||
native_window.element = dispman_element;
|
||||
native_window.width = window_width;
|
||||
native_window.height = window_height;
|
||||
vc_dispmanx_update_submit_sync( dispman_update );
|
||||
|
||||
initRenderApi(&native_window, (void *)dispman_display);
|
||||
}
|
||||
#endif
|
|
@ -1,3 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
extern void dispmanx_window_create();
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
#include "evdev.h"
|
||||
#include "input/gamepad_device.h"
|
||||
#include "oslib/oslib.h"
|
||||
#include "stdclass.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <linux/input.h>
|
||||
|
@ -81,7 +81,7 @@ public:
|
|||
void rumble(float power, float inclination, u32 duration_ms) override
|
||||
{
|
||||
vib_inclination = inclination * power;
|
||||
vib_stop_time = os_GetSeconds() + duration_ms / 1000.0;
|
||||
vib_stop_time = getTimeMs() + duration_ms;
|
||||
|
||||
do_rumble(power, duration_ms);
|
||||
}
|
||||
|
@ -89,7 +89,7 @@ public:
|
|||
{
|
||||
if (vib_inclination > 0)
|
||||
{
|
||||
int rem_time = (vib_stop_time - os_GetSeconds()) * 1000;
|
||||
int rem_time = vib_stop_time - getTimeMs();
|
||||
if (rem_time <= 0)
|
||||
vib_inclination = 0;
|
||||
else
|
||||
|
@ -308,7 +308,7 @@ private:
|
|||
std::string _devnode;
|
||||
int _rumble_effect_id = -1;
|
||||
float vib_inclination = 0;
|
||||
double vib_stop_time = 0;
|
||||
u64 vib_stop_time = 0;
|
||||
std::map<u32, int> axis_min_values;
|
||||
std::map<u32, unsigned int> axis_ranges;
|
||||
static std::map<std::string, std::shared_ptr<EvdevGamepadDevice>> evdev_gamepads;
|
||||
|
|
|
@ -3,10 +3,10 @@
|
|||
#endif
|
||||
#include "types.h"
|
||||
|
||||
#if defined(__unix__) || defined(__SWITCH__)
|
||||
#if defined(__unix__)
|
||||
#include "log/LogManager.h"
|
||||
#include "emulator.h"
|
||||
#include "rend/mainui.h"
|
||||
#include "ui/mainui.h"
|
||||
#include "oslib/directory.h"
|
||||
#include "oslib/oslib.h"
|
||||
#include "stdclass.h"
|
||||
|
@ -16,14 +16,6 @@
|
|||
#include <unistd.h>
|
||||
#include <vector>
|
||||
|
||||
#if defined(__SWITCH__)
|
||||
#include "nswitch.h"
|
||||
#endif
|
||||
|
||||
#if defined(SUPPORT_DISPMANX)
|
||||
#include "dispmanx.h"
|
||||
#endif
|
||||
|
||||
#if defined(SUPPORT_X11)
|
||||
#include "x11.h"
|
||||
#endif
|
||||
|
@ -32,50 +24,10 @@
|
|||
#include "sdl/sdl.h"
|
||||
#endif
|
||||
|
||||
#if defined(USE_EVDEV)
|
||||
#include "evdev.h"
|
||||
#endif
|
||||
|
||||
#ifdef USE_BREAKPAD
|
||||
#include "breakpad/client/linux/handler/exception_handler.h"
|
||||
#endif
|
||||
|
||||
void os_SetupInput()
|
||||
{
|
||||
#if defined(USE_EVDEV)
|
||||
input_evdev_init();
|
||||
#endif
|
||||
|
||||
#if defined(SUPPORT_X11)
|
||||
input_x11_init();
|
||||
#endif
|
||||
|
||||
#if defined(USE_SDL)
|
||||
input_sdl_init();
|
||||
#endif
|
||||
}
|
||||
|
||||
void os_TermInput()
|
||||
{
|
||||
#if defined(USE_EVDEV)
|
||||
input_evdev_close();
|
||||
#endif
|
||||
#if defined(USE_SDL)
|
||||
input_sdl_quit();
|
||||
#endif
|
||||
}
|
||||
|
||||
void UpdateInputState()
|
||||
{
|
||||
#if defined(USE_EVDEV)
|
||||
input_evdev_handle();
|
||||
#endif
|
||||
|
||||
#if defined(USE_SDL)
|
||||
input_sdl_handle();
|
||||
#endif
|
||||
}
|
||||
|
||||
void os_DoEvents()
|
||||
{
|
||||
#if defined(SUPPORT_X11)
|
||||
|
@ -84,39 +36,12 @@ void os_DoEvents()
|
|||
#endif
|
||||
}
|
||||
|
||||
void os_SetWindowText(const char * text)
|
||||
{
|
||||
#if defined(SUPPORT_X11)
|
||||
x11_window_set_text(text);
|
||||
#endif
|
||||
#if defined(USE_SDL)
|
||||
sdl_window_set_text(text);
|
||||
#endif
|
||||
}
|
||||
|
||||
void os_CreateWindow()
|
||||
{
|
||||
#if defined(SUPPORT_DISPMANX)
|
||||
dispmanx_window_create();
|
||||
#endif
|
||||
#if defined(SUPPORT_X11)
|
||||
x11_window_create();
|
||||
#endif
|
||||
#if defined(USE_SDL)
|
||||
sdl_window_create();
|
||||
#endif
|
||||
}
|
||||
|
||||
void common_linux_setup();
|
||||
|
||||
// Find the user config directory.
|
||||
// $HOME/.config/flycast on linux
|
||||
std::string find_user_config_dir()
|
||||
static std::string find_user_config_dir()
|
||||
{
|
||||
#ifdef __SWITCH__
|
||||
flycast::mkdir("/flycast", 0755);
|
||||
return "/flycast/";
|
||||
#else
|
||||
std::string xdg_home;
|
||||
if (nowide::getenv("XDG_CONFIG_HOME") != nullptr)
|
||||
// If XDG_CONFIG_HOME is set explicitly, we'll use that instead of $HOME/.config
|
||||
|
@ -140,17 +65,12 @@ std::string find_user_config_dir()
|
|||
}
|
||||
// Unable to detect config dir, use the current folder
|
||||
return ".";
|
||||
#endif
|
||||
}
|
||||
|
||||
// Find the user data directory.
|
||||
// $HOME/.local/share/flycast on linux
|
||||
std::string find_user_data_dir()
|
||||
static std::string find_user_data_dir()
|
||||
{
|
||||
#ifdef __SWITCH__
|
||||
flycast::mkdir("/flycast/data", 0755);
|
||||
return "/flycast/data/";
|
||||
#else
|
||||
std::string xdg_home;
|
||||
if (nowide::getenv("XDG_DATA_HOME") != nullptr)
|
||||
// If XDG_DATA_HOME is set explicitly, we'll use that instead of $HOME/.local/share
|
||||
|
@ -174,10 +94,8 @@ std::string find_user_data_dir()
|
|||
}
|
||||
// Unable to detect data dir, use the current folder
|
||||
return ".";
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef __SWITCH__
|
||||
static void addDirectoriesFromPath(std::vector<std::string>& dirs, const std::string& path, const std::string& suffix)
|
||||
{
|
||||
std::string::size_type pos = 0;
|
||||
|
@ -193,7 +111,6 @@ static void addDirectoriesFromPath(std::vector<std::string>& dirs, const std::st
|
|||
if (pos < path.length())
|
||||
dirs.push_back(path.substr(pos) + suffix);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Find a file in the user and system config directories.
|
||||
// The following folders are checked in this order:
|
||||
|
@ -204,13 +121,10 @@ static void addDirectoriesFromPath(std::vector<std::string>& dirs, const std::st
|
|||
// /etc/flycast/
|
||||
// /etc/xdg/flycast/
|
||||
// .
|
||||
std::vector<std::string> find_system_config_dirs()
|
||||
static std::vector<std::string> find_system_config_dirs()
|
||||
{
|
||||
std::vector<std::string> dirs;
|
||||
|
||||
#ifdef __SWITCH__
|
||||
dirs.push_back("/flycast/");
|
||||
#else
|
||||
std::string xdg_home;
|
||||
if (nowide::getenv("XDG_CONFIG_HOME") != nullptr)
|
||||
// If XDG_CONFIG_HOME is set explicitly, we'll use that instead of $HOME/.config
|
||||
|
@ -235,7 +149,6 @@ std::vector<std::string> find_system_config_dirs()
|
|||
dirs.push_back("/etc/flycast/"); // This isn't part of the XDG spec, but much more common than /etc/xdg/
|
||||
dirs.push_back("/etc/xdg/flycast/");
|
||||
}
|
||||
#endif
|
||||
dirs.push_back("./");
|
||||
|
||||
return dirs;
|
||||
|
@ -252,13 +165,10 @@ std::vector<std::string> find_system_config_dirs()
|
|||
// <$FLYCAST_BIOS_PATH>
|
||||
// ./
|
||||
// ./data
|
||||
std::vector<std::string> find_system_data_dirs()
|
||||
static std::vector<std::string> find_system_data_dirs()
|
||||
{
|
||||
std::vector<std::string> dirs;
|
||||
|
||||
#ifdef __SWITCH__
|
||||
dirs.push_back("/flycast/data/");
|
||||
#else
|
||||
std::string xdg_home;
|
||||
if (nowide::getenv("XDG_DATA_HOME") != nullptr)
|
||||
// If XDG_DATA_HOME is set explicitly, we'll use that instead of $HOME/.local/share
|
||||
|
@ -288,7 +198,6 @@ std::vector<std::string> find_system_data_dirs()
|
|||
std::string path = (std::string)nowide::getenv("FLYCAST_BIOS_PATH");
|
||||
addDirectoriesFromPath(dirs, path, "/");
|
||||
}
|
||||
#endif
|
||||
dirs.push_back("./");
|
||||
dirs.push_back("data/");
|
||||
|
||||
|
@ -323,11 +232,6 @@ static bool dumpCallback(const google_breakpad::MinidumpDescriptor& descriptor,
|
|||
int main(int argc, char* argv[])
|
||||
{
|
||||
selfPath = argv[0];
|
||||
#if defined(__SWITCH__)
|
||||
socketInitializeDefault();
|
||||
nxlinkStdio();
|
||||
//appletSetFocusHandlingMode(AppletFocusHandlingMode_NoSuspend);
|
||||
#endif
|
||||
#if defined(USE_BREAKPAD)
|
||||
google_breakpad::MinidumpDescriptor descriptor("/tmp");
|
||||
google_breakpad::ExceptionHandler eh(descriptor, nullptr, dumpCallback, nullptr, true, -1);
|
||||
|
@ -353,9 +257,7 @@ int main(int argc, char* argv[])
|
|||
}
|
||||
#endif
|
||||
|
||||
#if defined(__unix__)
|
||||
common_linux_setup();
|
||||
#endif
|
||||
|
||||
if (flycast_init(argc, argv))
|
||||
die("Flycast initialization failed\n");
|
||||
|
@ -366,29 +268,16 @@ int main(int argc, char* argv[])
|
|||
|
||||
mainui_loop();
|
||||
|
||||
#if defined(SUPPORT_X11)
|
||||
x11_window_destroy();
|
||||
#endif
|
||||
#if defined(USE_SDL)
|
||||
sdl_window_destroy();
|
||||
#endif
|
||||
|
||||
flycast_term();
|
||||
os_UninstallFaultHandler();
|
||||
|
||||
#if defined(__SWITCH__)
|
||||
socketExit();
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(__unix__)
|
||||
[[noreturn]] void os_DebugBreak()
|
||||
{
|
||||
raise(SIGTRAP);
|
||||
std::abort();
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // __unix__ || __SWITCH__
|
||||
#endif // __unix__
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
#include "types.h"
|
||||
#include "cfg/cfg.h"
|
||||
#include "x11.h"
|
||||
#include "rend/gui.h"
|
||||
#include "ui/gui.h"
|
||||
#include "input/gamepad.h"
|
||||
#include "input/mouse.h"
|
||||
#include "icon.h"
|
||||
|
@ -21,6 +21,8 @@
|
|||
#define DEFAULT_WINDOW_WIDTH 640
|
||||
#define DEFAULT_WINDOW_HEIGHT 480
|
||||
|
||||
static void x11_window_set_text(const char *text);
|
||||
|
||||
static Window x11_win;
|
||||
Display *x11_disp;
|
||||
|
||||
|
@ -356,7 +358,7 @@ void x11_window_create()
|
|||
}
|
||||
}
|
||||
|
||||
void x11_window_set_text(const char* text)
|
||||
static void x11_window_set_text(const char* text)
|
||||
{
|
||||
if (x11_win)
|
||||
{
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
#pragma once
|
||||
|
||||
extern void input_x11_init();
|
||||
extern void event_x11_handle();
|
||||
extern void input_x11_handle();
|
||||
extern void x11_window_create();
|
||||
extern void x11_window_set_text(const char* text);
|
||||
extern void x11_window_destroy();
|
||||
void input_x11_init();
|
||||
void event_x11_handle();
|
||||
void input_x11_handle();
|
||||
void x11_window_create();
|
||||
void x11_window_destroy();
|
||||
|
||||
// numbers
|
||||
const int KEY_1 = 10;
|
||||
|
|
|
@ -11,10 +11,10 @@
|
|||
#if defined(__linux__) && !defined(__ANDROID__)
|
||||
#include <sys/personality.h>
|
||||
#endif
|
||||
#if !defined(TARGET_BSD) && !defined(__ANDROID__) && defined(TARGET_VIDEOCORE)
|
||||
#include <dlfcn.h>
|
||||
#endif
|
||||
#include <unistd.h>
|
||||
#ifdef __linux__
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
#include "oslib/host_context.h"
|
||||
|
||||
|
@ -22,6 +22,7 @@
|
|||
#include "rend/TexCache.h"
|
||||
#include "hw/mem/addrspace.h"
|
||||
#include "hw/mem/mem_watch.h"
|
||||
#include "emulator.h"
|
||||
|
||||
#ifdef __SWITCH__
|
||||
#include <ucontext.h>
|
||||
|
@ -119,14 +120,6 @@ void os_UninstallFaultHandler()
|
|||
}
|
||||
#endif // !defined(TARGET_NO_EXCEPTIONS)
|
||||
|
||||
double os_GetSeconds()
|
||||
{
|
||||
timeval a;
|
||||
gettimeofday (&a,0);
|
||||
static u64 tvs_base=a.tv_sec;
|
||||
return a.tv_sec-tvs_base+a.tv_usec/1000000.0;
|
||||
}
|
||||
|
||||
#if !defined(__unix__) && !defined(LIBRETRO) && !defined(__SWITCH__)
|
||||
[[noreturn]] void os_DebugBreak()
|
||||
{
|
||||
|
@ -134,11 +127,15 @@ double os_GetSeconds()
|
|||
}
|
||||
#endif
|
||||
|
||||
void enable_runfast()
|
||||
// RunFast mode is the combination of the following conditions:
|
||||
// * the VFP11 coprocessor is in flush-to-zero mode
|
||||
// * the VFP11 coprocessor is in default NaN mode
|
||||
// * all exception enable bits are cleared.
|
||||
static void enable_runfast()
|
||||
{
|
||||
#if HOST_CPU==CPU_ARM && !defined(ARMCC)
|
||||
static const unsigned int x = 0x04086060;
|
||||
static const unsigned int y = 0x03000000;
|
||||
#if HOST_CPU == CPU_ARM && !defined(ARMCC)
|
||||
static const unsigned int x = 0x04086060; // reset and disable FP exceptions, flush-to-zero, default NaN mode
|
||||
static const unsigned int y = 0x03000000; // round to zero
|
||||
int r;
|
||||
asm volatile (
|
||||
"fmrx %0, fpscr \n\t" //r0 = FPSCR
|
||||
|
@ -150,45 +147,58 @@ void enable_runfast()
|
|||
);
|
||||
|
||||
DEBUG_LOG(BOOT, "ARM VFP-Run Fast (NFP) enabled !");
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
void linux_fix_personality() {
|
||||
#if defined(__linux__) && !defined(__ANDROID__)
|
||||
// Some old CPUs lack the NX (no exec) flag so READ_IMPLIES_EXEC is set by default on these platforms.
|
||||
// However resetting the flag isn't going to magically change the way the CPU works. So I wonder how useful this is.
|
||||
// It's not needed on modern 64-bit architectures anyway.
|
||||
static void linux_fix_personality()
|
||||
{
|
||||
#if defined(__linux__) && !defined(__ANDROID__) && (HOST_CPU == CPU_X86 || HOST_CPU == CPU_ARM)
|
||||
DEBUG_LOG(BOOT, "Personality: %08X", personality(0xFFFFFFFF));
|
||||
personality(~READ_IMPLIES_EXEC & personality(0xFFFFFFFF));
|
||||
DEBUG_LOG(BOOT, "Updated personality: %08X", personality(0xFFFFFFFF));
|
||||
#endif
|
||||
}
|
||||
|
||||
void linux_rpi2_init() {
|
||||
#if !defined(TARGET_BSD) && !defined(__ANDROID__) && defined(TARGET_VIDEOCORE)
|
||||
void* handle;
|
||||
void (*rpi_bcm_init)(void);
|
||||
|
||||
handle = dlopen("libbcm_host.so", RTLD_LAZY);
|
||||
|
||||
if (handle) {
|
||||
DEBUG_LOG(BOOT, "found libbcm_host");
|
||||
*(void**) (&rpi_bcm_init) = dlsym(handle, "bcm_host_init");
|
||||
if (rpi_bcm_init) {
|
||||
DEBUG_LOG(BOOT, "rpi2: bcm_init");
|
||||
rpi_bcm_init();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#if defined(__unix__) && !defined(LIBRETRO) && !defined(__ANDROID__)
|
||||
static void sigintHandler(int)
|
||||
{
|
||||
dc_exit();
|
||||
}
|
||||
#endif
|
||||
|
||||
void common_linux_setup()
|
||||
{
|
||||
linux_fix_personality();
|
||||
linux_rpi2_init();
|
||||
|
||||
enable_runfast();
|
||||
os_InstallFaultHandler();
|
||||
signal(SIGINT, exit);
|
||||
#if defined(__unix__) && !defined(LIBRETRO) && !defined(__ANDROID__)
|
||||
// exit cleanly on ^C
|
||||
signal(SIGINT, sigintHandler);
|
||||
#endif
|
||||
|
||||
DEBUG_LOG(BOOT, "Linux paging: %ld %08X %08X", sysconf(_SC_PAGESIZE), PAGE_SIZE, PAGE_MASK);
|
||||
verify(PAGE_MASK==(sysconf(_SC_PAGESIZE)-1));
|
||||
}
|
||||
|
||||
#ifndef __APPLE__
|
||||
|
||||
void os_SetThreadName(const char *name)
|
||||
{
|
||||
#ifdef __linux__
|
||||
if (strlen(name) > 16)
|
||||
{
|
||||
static char tmp[17];
|
||||
strncpy(tmp, name, 16);
|
||||
name = tmp;
|
||||
}
|
||||
pthread_setname_np(pthread_self(), name);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif // __unix__ or __APPLE__ or __SWITCH__
|
||||
|
|
|
@ -175,10 +175,12 @@ LogManager::~LogManager()
|
|||
// in the form 00:00:000.
|
||||
static std::string GetTimeFormatted()
|
||||
{
|
||||
double now = os_GetSeconds();
|
||||
u32 minutes = (u32)now / 60;
|
||||
u32 seconds = (u32)now % 60;
|
||||
u32 ms = (now - (u32)now) * 1000;
|
||||
u64 now = getTimeMs();
|
||||
u32 ms = (u32)(now % 1000);
|
||||
now /= 1000;
|
||||
u32 seconds = (u32)(now % 60);
|
||||
now /= 60;
|
||||
u32 minutes = (u32)now;
|
||||
return StringFromFormat("%02d:%02d:%03d", minutes, seconds, ms);
|
||||
}
|
||||
|
||||
|
|
|
@ -21,7 +21,8 @@
|
|||
#ifdef USE_LUA
|
||||
#include <lua.hpp>
|
||||
#include <LuaBridge/LuaBridge.h>
|
||||
#include "rend/gui.h"
|
||||
#include "ui/gui.h"
|
||||
#include "ui/gui_util.h"
|
||||
#include "hw/mem/addrspace.h"
|
||||
#include "cfg/option.h"
|
||||
#include "emulator.h"
|
||||
|
@ -43,7 +44,7 @@ using lock_guard = std::lock_guard<std::recursive_mutex>;
|
|||
|
||||
static void emuEventCallback(Event event, void *)
|
||||
{
|
||||
if (L == nullptr)
|
||||
if (L == nullptr || settings.raHardcoreMode)
|
||||
return;
|
||||
lock_guard lock(mutex);
|
||||
try {
|
||||
|
@ -71,6 +72,12 @@ static void emuEventCallback(Event event, void *)
|
|||
case Event::VBlank:
|
||||
key = "vblank";
|
||||
break;
|
||||
case Event::Network:
|
||||
key = "network";
|
||||
break;
|
||||
case Event::DiskChange:
|
||||
key = "diskChange";
|
||||
break;
|
||||
}
|
||||
if (v[key].isFunction())
|
||||
v[key]();
|
||||
|
@ -363,7 +370,7 @@ static void beginWindow(const char *title, int x, int y, int w, int h)
|
|||
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0);
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0);
|
||||
ImGui::SetNextWindowPos(ImVec2(x, y));
|
||||
ImGui::SetNextWindowSize(ImVec2(w * settings.display.uiScale, h * settings.display.uiScale));
|
||||
ImGui::SetNextWindowSize(ScaledVec2(w, h));
|
||||
ImGui::SetNextWindowBgAlpha(0.7f);
|
||||
ImGui::Begin(title, NULL, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoNavInputs | ImGuiWindowFlags_NoNavFocus);
|
||||
ImGui::PushStyleColor(ImGuiCol_PlotHistogram, ImVec4(0.557f, 0.268f, 0.965f, 1.f));
|
||||
|
@ -389,7 +396,7 @@ static void uiTextRightAligned(const std::string& text)
|
|||
|
||||
static void uiBargraph(float v)
|
||||
{
|
||||
ImGui::ProgressBar(v, ImVec2(-1, 10.f * settings.display.uiScale), "");
|
||||
ImGui::ProgressBar(v, ImVec2(-1, uiScaled(10.f)), "");
|
||||
}
|
||||
|
||||
static int uiButton(lua_State *L)
|
||||
|
@ -440,7 +447,7 @@ static void luaRegister(lua_State *L)
|
|||
gui_open_settings();
|
||||
}))
|
||||
.addFunction("exit", dc_exit)
|
||||
.addFunction("displayNotification", gui_display_notification)
|
||||
.addFunction("displayNotification", os_notify)
|
||||
.endNamespace()
|
||||
|
||||
.beginNamespace("config")
|
||||
|
@ -619,6 +626,7 @@ void init()
|
|||
EventManager::listen(Event::Terminate, emuEventCallback);
|
||||
EventManager::listen(Event::LoadState, emuEventCallback);
|
||||
EventManager::listen(Event::VBlank, emuEventCallback);
|
||||
EventManager::listen(Event::Network, emuEventCallback);
|
||||
|
||||
doExec(initFile);
|
||||
}
|
||||
|
@ -633,6 +641,7 @@ void term()
|
|||
EventManager::unlisten(Event::Terminate, emuEventCallback);
|
||||
EventManager::unlisten(Event::LoadState, emuEventCallback);
|
||||
EventManager::unlisten(Event::VBlank, emuEventCallback);
|
||||
EventManager::unlisten(Event::Network, emuEventCallback);
|
||||
lua_close(L);
|
||||
L = nullptr;
|
||||
}
|
||||
|
|
|
@ -23,10 +23,9 @@
|
|||
#include "input/keyboard_device.h"
|
||||
#include "input/mouse.h"
|
||||
#include "cfg/option.h"
|
||||
#include "oslib/oslib.h"
|
||||
#include <algorithm>
|
||||
|
||||
void UpdateInputState();
|
||||
|
||||
namespace ggpo
|
||||
{
|
||||
|
||||
|
@ -35,7 +34,7 @@ bool inRollback;
|
|||
static void getLocalInput(MapleInputState inputState[4])
|
||||
{
|
||||
if (!config::ThreadedRendering)
|
||||
UpdateInputState();
|
||||
os_UpdateInputState();
|
||||
std::lock_guard<std::mutex> lock(relPosMutex);
|
||||
for (int player = 0; player < 4; player++)
|
||||
{
|
||||
|
@ -73,7 +72,8 @@ static void getLocalInput(MapleInputState inputState[4])
|
|||
#ifdef USE_GGPO
|
||||
#include "ggponet.h"
|
||||
#include "emulator.h"
|
||||
#include "rend/gui.h"
|
||||
#include "ui/gui.h"
|
||||
#include "ui/gui_util.h"
|
||||
#include "hw/mem/mem_watch.h"
|
||||
#include <string.h>
|
||||
#include <chrono>
|
||||
|
@ -216,19 +216,19 @@ static bool on_event(GGPOEvent *info)
|
|||
switch (info->code) {
|
||||
case GGPO_EVENTCODE_CONNECTED_TO_PEER:
|
||||
INFO_LOG(NETWORK, "Connected to peer %d", info->u.connected.player);
|
||||
gui_display_notification("Connected to peer", 2000);
|
||||
os_notify("Connected to peer", 2000);
|
||||
break;
|
||||
case GGPO_EVENTCODE_SYNCHRONIZING_WITH_PEER:
|
||||
INFO_LOG(NETWORK, "Synchronizing with peer %d", info->u.synchronizing.player);
|
||||
gui_display_notification("Synchronizing with peer", 2000);
|
||||
os_notify("Synchronizing with peer", 2000);
|
||||
break;
|
||||
case GGPO_EVENTCODE_SYNCHRONIZED_WITH_PEER:
|
||||
INFO_LOG(NETWORK, "Synchronized with peer %d", info->u.synchronized.player);
|
||||
gui_display_notification("Synchronized with peer", 2000);
|
||||
os_notify("Synchronized with peer", 2000);
|
||||
break;
|
||||
case GGPO_EVENTCODE_RUNNING:
|
||||
INFO_LOG(NETWORK, "Running");
|
||||
gui_display_notification("Running", 2000);
|
||||
os_notify("Running", 2000);
|
||||
synchronized = true;
|
||||
break;
|
||||
case GGPO_EVENTCODE_DISCONNECTED_FROM_PEER:
|
||||
|
@ -242,11 +242,11 @@ static bool on_event(GGPOEvent *info)
|
|||
break;
|
||||
case GGPO_EVENTCODE_CONNECTION_INTERRUPTED:
|
||||
INFO_LOG(NETWORK, "Connection interrupted with player %d", info->u.connection_interrupted.player);
|
||||
gui_display_notification("Connection interrupted", 2000);
|
||||
os_notify("Connection interrupted", 2000);
|
||||
break;
|
||||
case GGPO_EVENTCODE_CONNECTION_RESUMED:
|
||||
INFO_LOG(NETWORK, "Connection resumed with player %d", info->u.connection_resumed.player);
|
||||
gui_display_notification("Connection resumed", 2000);
|
||||
os_notify("Connection resumed", 2000);
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
|
@ -706,7 +706,7 @@ bool nextFrame()
|
|||
// may call save_game_state
|
||||
do {
|
||||
if (!config::ThreadedRendering)
|
||||
UpdateInputState();
|
||||
os_UpdateInputState();
|
||||
Inputs inputs;
|
||||
inputs.kcode = ~kcode[0];
|
||||
if (rt[0] >= 0x4000)
|
||||
|
@ -783,6 +783,7 @@ std::future<bool> startNetwork()
|
|||
synchronized = false;
|
||||
return std::async(std::launch::async, []{
|
||||
{
|
||||
ThreadName _("GGPO-start");
|
||||
std::lock_guard<std::recursive_mutex> lock(ggpoMutex);
|
||||
#ifdef SYNC_TEST
|
||||
startSession(0, 0);
|
||||
|
@ -857,17 +858,17 @@ void displayStats()
|
|||
GGPONetworkStats stats;
|
||||
ggpo_get_network_stats(ggpoSession, remotePlayer, &stats);
|
||||
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0);
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0);
|
||||
ImguiStyleVar _(ImGuiStyleVar_WindowRounding, 0);
|
||||
ImguiStyleVar _1(ImGuiStyleVar_WindowBorderSize, 0);
|
||||
ImGui::SetNextWindowPos(ImVec2(10, 10));
|
||||
ImGui::SetNextWindowSize(ImVec2(95 * settings.display.uiScale, 0));
|
||||
ImGui::SetNextWindowSize(ScaledVec2(95, 0));
|
||||
ImGui::SetNextWindowBgAlpha(0.7f);
|
||||
ImGui::Begin("##ggpostats", NULL, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoInputs);
|
||||
ImGui::PushStyleColor(ImGuiCol_PlotHistogram, ImVec4(0.557f, 0.268f, 0.965f, 1.f));
|
||||
ImguiStyleColor _2(ImGuiCol_PlotHistogram, ImVec4(0.557f, 0.268f, 0.965f, 1.f));
|
||||
|
||||
// Send Queue
|
||||
ImGui::Text("Send Q");
|
||||
ImGui::ProgressBar(stats.network.send_queue_len / 10.f, ImVec2(-1, 10.f * settings.display.uiScale), "");
|
||||
ImGui::ProgressBar(stats.network.send_queue_len / 10.f, ImVec2(-1, uiScaled(10.f)), "");
|
||||
|
||||
// Frame Delay
|
||||
ImGui::Text("Delay");
|
||||
|
@ -889,7 +890,7 @@ void displayStats()
|
|||
// yellow
|
||||
ImGui::PushStyleColor(ImGuiCol_PlotHistogram, ImVec4(.9f, .9f, .1f, 1));
|
||||
ImGui::Text("Predicted");
|
||||
ImGui::ProgressBar(stats.sync.predicted_frames / 7.f, ImVec2(-1, 10.f * settings.display.uiScale), "");
|
||||
ImGui::ProgressBar(stats.sync.predicted_frames / 7.f, ImVec2(-1, uiScaled(10.f)), "");
|
||||
if (stats.sync.predicted_frames >= 5)
|
||||
ImGui::PopStyleColor();
|
||||
|
||||
|
@ -898,16 +899,14 @@ void displayStats()
|
|||
if (timesync > 0)
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1, 0, 0, 1));
|
||||
ImGui::Text("Behind");
|
||||
ImGui::ProgressBar(0.5f + stats.timesync.local_frames_behind / 16.f, ImVec2(-1, 10.f * settings.display.uiScale), "");
|
||||
ImGui::ProgressBar(0.5f + stats.timesync.local_frames_behind / 16.f, ImVec2(-1, uiScaled(10.f)), "");
|
||||
if (timesync > 0)
|
||||
{
|
||||
ImGui::PopStyleColor();
|
||||
timesyncOccurred--;
|
||||
}
|
||||
|
||||
ImGui::PopStyleColor();
|
||||
ImGui::End();
|
||||
ImGui::PopStyleVar(2);
|
||||
}
|
||||
|
||||
void endOfFrame()
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
#include "naomi_network.h"
|
||||
#include "hw/naomi/naomi_flashrom.h"
|
||||
#include "cfg/option.h"
|
||||
#include "rend/gui.h"
|
||||
#include "oslib/oslib.h"
|
||||
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
|
@ -104,7 +104,7 @@ bool NaomiNetwork::startNetwork()
|
|||
|
||||
std::string notif = slaves.empty() ? "Waiting for players..."
|
||||
: std::to_string(slaves.size()) + " player(s) connected. Waiting...";
|
||||
gui_display_notification(notif.c_str(), timeout.count() * 2000);
|
||||
os_notify(notif.c_str(), timeout.count() * 2000);
|
||||
|
||||
poll();
|
||||
|
||||
|
@ -125,12 +125,12 @@ bool NaomiNetwork::startNetwork()
|
|||
|
||||
nextPeer = slaves[0].addr;
|
||||
|
||||
gui_display_notification("Starting game", 2000);
|
||||
os_notify("Starting game", 2000);
|
||||
SetNaomiNetworkConfig(0);
|
||||
|
||||
return true;
|
||||
}
|
||||
gui_display_notification("No player connected", 8000);
|
||||
os_notify("No player connected", 8000);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -164,7 +164,7 @@ bool NaomiNetwork::startNetwork()
|
|||
}
|
||||
|
||||
NOTICE_LOG(NETWORK, "Connecting to server");
|
||||
gui_display_notification("Connecting to server", 10000);
|
||||
os_notify("Connecting to server", 10000);
|
||||
steady_clock::time_point start_time = steady_clock::now();
|
||||
|
||||
while (!networkStopping && !_startNow && steady_clock::now() - start_time < timeout)
|
||||
|
@ -249,7 +249,7 @@ bool NaomiNetwork::receive(const sockaddr_in *addr, const Packet *packet, u32 si
|
|||
nextPeer.sin_port = packet->sync.nextNodePort;
|
||||
nextPeer.sin_addr.s_addr = packet->sync.nextNodeIp == 0 ? addr->sin_addr.s_addr : packet->sync.nextNodeIp;
|
||||
std::string notif = "Connected as slot " + std::to_string(slotId);
|
||||
gui_display_notification(notif.c_str(), 2000);
|
||||
os_notify(notif.c_str(), 2000);
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "miniupnp.h"
|
||||
#include "cfg/option.h"
|
||||
#include "emulator.h"
|
||||
#include "oslib/oslib.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <atomic>
|
||||
|
@ -44,6 +45,7 @@ public:
|
|||
networkStopping = false;
|
||||
_startNow = false;
|
||||
return std::async(std::launch::async, [this] {
|
||||
ThreadName _("NaomiNetwork-start");
|
||||
bool res = startNetwork();
|
||||
emu.setNetworkState(res);
|
||||
return res;
|
||||
|
|
|
@ -26,9 +26,6 @@
|
|||
#include "stdclass.h"
|
||||
|
||||
//#define BBA_PCAPNG_DUMP
|
||||
#ifdef BBA_PCAPNG_DUMP
|
||||
#include "oslib/oslib.h"
|
||||
#endif
|
||||
|
||||
#ifdef __MINGW32__
|
||||
#define _POSIX_SOURCE
|
||||
|
@ -51,6 +48,7 @@ extern "C" {
|
|||
#include "miniupnp.h"
|
||||
#include "cfg/option.h"
|
||||
#include "emulator.h"
|
||||
#include "oslib/oslib.h"
|
||||
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
|
@ -765,38 +763,34 @@ static void check_dns_entries()
|
|||
|
||||
if (public_ip.addr == 0)
|
||||
{
|
||||
if (!dns_query_start)
|
||||
u32 ip;
|
||||
pico_string_to_ipv4(RESOLVER1_OPENDNS_COM, &ip);
|
||||
pico_ip4 tmpdns { ip };
|
||||
if (dns_query_start == 0)
|
||||
{
|
||||
dns_query_start = PICO_TIME_MS();
|
||||
struct pico_ip4 tmpdns;
|
||||
pico_string_to_ipv4(RESOLVER1_OPENDNS_COM, &tmpdns.addr);
|
||||
get_host_by_name("myip.opendns.com", tmpdns);
|
||||
}
|
||||
else if (get_dns_answer(&public_ip, tmpdns) == 0)
|
||||
{
|
||||
dns_query_attempts = 0;
|
||||
dns_query_start = 0;
|
||||
char myip[16];
|
||||
pico_ipv4_to_string(myip, public_ip.addr);
|
||||
INFO_LOG(MODEM, "My IP is %s", myip);
|
||||
}
|
||||
else
|
||||
{
|
||||
struct pico_ip4 tmpdns;
|
||||
pico_string_to_ipv4(RESOLVER1_OPENDNS_COM, &tmpdns.addr);
|
||||
if (get_dns_answer(&public_ip, tmpdns) == 0)
|
||||
if (PICO_TIME_MS() - dns_query_start > 1000)
|
||||
{
|
||||
dns_query_attempts = 0;
|
||||
dns_query_start = 0;
|
||||
char myip[16];
|
||||
pico_ipv4_to_string(myip, public_ip.addr);
|
||||
INFO_LOG(MODEM, "My IP is %s", myip);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (PICO_TIME_MS() - dns_query_start > 1000)
|
||||
if (++dns_query_attempts >= 5)
|
||||
{
|
||||
if (++dns_query_attempts >= 5)
|
||||
{
|
||||
public_ip.addr = 0xffffffff; // Bogus but not null
|
||||
dns_query_attempts = 0;
|
||||
}
|
||||
else
|
||||
// Retry
|
||||
dns_query_start = 0;
|
||||
public_ip.addr = 0xffffffff; // Bogus but not null
|
||||
dns_query_attempts = 0;
|
||||
}
|
||||
else
|
||||
// Retry
|
||||
dns_query_start = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -900,7 +894,7 @@ static void dumpFrame(const u8 *frame, u32 size)
|
|||
fwrite(&roundedSize, sizeof(roundedSize), 1, pcapngDump);
|
||||
u32 ifId = 0;
|
||||
fwrite(&ifId, sizeof(ifId), 1, pcapngDump);
|
||||
u64 now = (u64)(os_GetSeconds() * 1000000.0);
|
||||
u64 now = getTimeMs() * 1000;
|
||||
fwrite((u32 *)&now + 1, 4, 1, pcapngDump);
|
||||
fwrite(&now, 4, 1, pcapngDump);
|
||||
fwrite(&size, sizeof(size), 1, pcapngDump);
|
||||
|
@ -969,6 +963,7 @@ static void *pico_thread_func(void *)
|
|||
std::future<MiniUPnP> upnp =
|
||||
std::async(std::launch::async, [ports]() {
|
||||
// Initialize miniupnpc and map network ports
|
||||
ThreadName _("UPNP-init");
|
||||
MiniUPnP upnp;
|
||||
if (ports != nullptr && config::EnableUPnP)
|
||||
{
|
||||
|
@ -1163,7 +1158,7 @@ static void *pico_thread_func(void *)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static cThread pico_thread(pico_thread_func, NULL);
|
||||
static cThread pico_thread(pico_thread_func, nullptr, "PicoTCP");
|
||||
|
||||
bool start_pico()
|
||||
{
|
||||
|
|
192
core/nullDC.cpp
192
core/nullDC.cpp
|
@ -5,15 +5,40 @@
|
|||
#include "cfg/cfg.h"
|
||||
#include "cfg/option.h"
|
||||
#include "log/LogManager.h"
|
||||
#include "rend/gui.h"
|
||||
#include "ui/gui.h"
|
||||
#include "oslib/oslib.h"
|
||||
#include "oslib/directory.h"
|
||||
#include "debug/gdb_server.h"
|
||||
#include "archive/rzip.h"
|
||||
#include "rend/mainui.h"
|
||||
#include "ui/mainui.h"
|
||||
#include "input/gamepad_device.h"
|
||||
#include "lua/lua.h"
|
||||
#include "stdclass.h"
|
||||
#include "serialize.h"
|
||||
#include <time.h>
|
||||
|
||||
struct SavestateHeader
|
||||
{
|
||||
void init()
|
||||
{
|
||||
memcpy(magic, MAGIC, sizeof(magic));
|
||||
creationDate = time(nullptr);
|
||||
version = Deserializer::Current;
|
||||
pngSize = 0;
|
||||
}
|
||||
|
||||
bool isValid() const {
|
||||
return !memcmp(magic, MAGIC, sizeof(magic));
|
||||
}
|
||||
|
||||
char magic[8];
|
||||
u64 creationDate;
|
||||
u32 version;
|
||||
u32 pngSize;
|
||||
// png data
|
||||
|
||||
static constexpr const char *MAGIC = "FLYSAVE1";
|
||||
};
|
||||
|
||||
int flycast_init(int argc, char* argv[])
|
||||
{
|
||||
|
@ -65,7 +90,7 @@ int flycast_init(int argc, char* argv[])
|
|||
void dc_exit()
|
||||
{
|
||||
try {
|
||||
emu.stop();
|
||||
emu.unloadGame();
|
||||
} catch (...) { }
|
||||
mainui_stop();
|
||||
}
|
||||
|
@ -86,11 +111,12 @@ void flycast_term()
|
|||
gui_cancel_load();
|
||||
lua::term();
|
||||
emu.term();
|
||||
os_DestroyWindow();
|
||||
gui_term();
|
||||
os_TermInput();
|
||||
}
|
||||
|
||||
void dc_savestate(int index)
|
||||
void dc_savestate(int index, const u8 *pngData, u32 pngSize)
|
||||
{
|
||||
if (settings.network.online)
|
||||
return;
|
||||
|
@ -102,7 +128,7 @@ void dc_savestate(int index)
|
|||
if (data == nullptr)
|
||||
{
|
||||
WARN_LOG(SAVESTATE, "Failed to save state - could not malloc %d bytes", (int)ser.size());
|
||||
gui_display_notification("Save state failed - memory full", 2000);
|
||||
os_notify("Save state failed - memory full", 5000);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -110,87 +136,105 @@ void dc_savestate(int index)
|
|||
dc_serialize(ser);
|
||||
|
||||
std::string filename = hostfs::getSavestatePath(index, true);
|
||||
#if 0
|
||||
FILE *f = nowide::fopen(filename.c_str(), "wb");
|
||||
|
||||
if ( f == NULL )
|
||||
if (f == nullptr)
|
||||
{
|
||||
WARN_LOG(SAVESTATE, "Failed to save state - could not open %s for writing", filename.c_str());
|
||||
gui_display_notification("Cannot open save file", 2000);
|
||||
os_notify("Cannot open save file", 5000);
|
||||
free(data);
|
||||
return;
|
||||
}
|
||||
|
||||
RZipFile zipFile;
|
||||
SavestateHeader header;
|
||||
header.init();
|
||||
header.pngSize = pngSize;
|
||||
if (std::fwrite(&header, sizeof(header), 1, f) != 1)
|
||||
goto fail;
|
||||
if (pngSize > 0 && std::fwrite(pngData, 1, pngSize, f) != pngSize)
|
||||
goto fail;
|
||||
|
||||
#if 0
|
||||
// Uncompressed savestate
|
||||
std::fwrite(data, 1, ser.size(), f);
|
||||
std::fclose(f);
|
||||
#else
|
||||
RZipFile zipFile;
|
||||
if (!zipFile.Open(filename, true))
|
||||
{
|
||||
WARN_LOG(SAVESTATE, "Failed to save state - could not open %s for writing", filename.c_str());
|
||||
gui_display_notification("Cannot open save file", 2000);
|
||||
free(data);
|
||||
return;
|
||||
}
|
||||
if (!zipFile.Open(f, true))
|
||||
goto fail;
|
||||
if (zipFile.Write(data, ser.size()) != ser.size())
|
||||
{
|
||||
WARN_LOG(SAVESTATE, "Failed to save state - error writing %s", filename.c_str());
|
||||
gui_display_notification("Error saving state", 2000);
|
||||
zipFile.Close();
|
||||
free(data);
|
||||
return;
|
||||
}
|
||||
goto fail;
|
||||
zipFile.Close();
|
||||
#endif
|
||||
|
||||
free(data);
|
||||
NOTICE_LOG(SAVESTATE, "Saved state to %s size %d", filename.c_str(), (int)ser.size());
|
||||
gui_display_notification("State saved", 1000);
|
||||
os_notify("State saved", 2000);
|
||||
return;
|
||||
|
||||
fail:
|
||||
WARN_LOG(SAVESTATE, "Failed to save state - error writing %s", filename.c_str());
|
||||
os_notify("Error saving state", 5000);
|
||||
if (zipFile.rawFile() != nullptr)
|
||||
zipFile.Close();
|
||||
else
|
||||
std::fclose(f);
|
||||
free(data);
|
||||
// delete failed savestate?
|
||||
}
|
||||
|
||||
void dc_loadstate(int index)
|
||||
{
|
||||
if (settings.raHardcoreMode)
|
||||
return;
|
||||
u32 total_size = 0;
|
||||
FILE *f = nullptr;
|
||||
|
||||
std::string filename = hostfs::getSavestatePath(index, false);
|
||||
RZipFile zipFile;
|
||||
if (zipFile.Open(filename, false))
|
||||
FILE *f = nowide::fopen(filename.c_str(), "rb");
|
||||
if (f == nullptr)
|
||||
{
|
||||
WARN_LOG(SAVESTATE, "Failed to load state - could not open %s for reading", filename.c_str());
|
||||
os_notify("Save state not found", 2000);
|
||||
return;
|
||||
}
|
||||
SavestateHeader header;
|
||||
if (std::fread(&header, sizeof(header), 1, f) == 1)
|
||||
{
|
||||
if (!header.isValid())
|
||||
// seek to beginning of file if this isn't a valid header (legacy savestate)
|
||||
std::fseek(f, 0, SEEK_SET);
|
||||
else
|
||||
// skip png data
|
||||
std::fseek(f, header.pngSize, SEEK_CUR);
|
||||
}
|
||||
else {
|
||||
// probably not a valid savestate but we'll fail later
|
||||
std::fseek(f, 0, SEEK_SET);
|
||||
}
|
||||
|
||||
if (index == -1 && config::GGPOEnable)
|
||||
{
|
||||
long pos = std::ftell(f);
|
||||
MD5Sum().add(f)
|
||||
.getDigest(settings.network.md5.savestate);
|
||||
std::fseek(f, pos, SEEK_SET);
|
||||
}
|
||||
RZipFile zipFile;
|
||||
if (zipFile.Open(f, false)) {
|
||||
total_size = (u32)zipFile.Size();
|
||||
if (index == -1 && config::GGPOEnable)
|
||||
{
|
||||
f = zipFile.rawFile();
|
||||
long pos = std::ftell(f);
|
||||
MD5Sum().add(f)
|
||||
.getDigest(settings.network.md5.savestate);
|
||||
std::fseek(f, pos, SEEK_SET);
|
||||
f = nullptr;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
f = nowide::fopen(filename.c_str(), "rb");
|
||||
|
||||
if ( f == NULL )
|
||||
{
|
||||
WARN_LOG(SAVESTATE, "Failed to load state - could not open %s for reading", filename.c_str());
|
||||
gui_display_notification("Save state not found", 2000);
|
||||
return;
|
||||
}
|
||||
if (index == -1 && config::GGPOEnable)
|
||||
MD5Sum().add(f)
|
||||
.getDigest(settings.network.md5.savestate);
|
||||
long pos = std::ftell(f);
|
||||
std::fseek(f, 0, SEEK_END);
|
||||
total_size = (u32)std::ftell(f);
|
||||
std::fseek(f, 0, SEEK_SET);
|
||||
total_size = (u32)std::ftell(f) - pos;
|
||||
std::fseek(f, pos, SEEK_SET);
|
||||
}
|
||||
void *data = malloc(total_size);
|
||||
if (data == nullptr)
|
||||
{
|
||||
WARN_LOG(SAVESTATE, "Failed to load state - could not malloc %d bytes", total_size);
|
||||
gui_display_notification("Failed to load state - memory full", 2000);
|
||||
if (f != nullptr)
|
||||
os_notify("Failed to load state - memory full", 5000);
|
||||
if (zipFile.rawFile() == nullptr)
|
||||
std::fclose(f);
|
||||
else
|
||||
zipFile.Close();
|
||||
|
@ -198,20 +242,20 @@ void dc_loadstate(int index)
|
|||
}
|
||||
|
||||
size_t read_size;
|
||||
if (f == nullptr)
|
||||
if (zipFile.rawFile() != nullptr)
|
||||
{
|
||||
read_size = zipFile.Read(data, total_size);
|
||||
zipFile.Close();
|
||||
}
|
||||
else
|
||||
{
|
||||
read_size = fread(data, 1, total_size, f);
|
||||
read_size = std::fread(data, 1, total_size, f);
|
||||
std::fclose(f);
|
||||
}
|
||||
if (read_size != total_size)
|
||||
{
|
||||
WARN_LOG(SAVESTATE, "Failed to load state - I/O error");
|
||||
gui_display_notification("Failed to load state - I/O error", 2000);
|
||||
os_notify("Failed to load state - I/O error", 5000);
|
||||
free(data);
|
||||
return;
|
||||
}
|
||||
|
@ -221,6 +265,7 @@ void dc_loadstate(int index)
|
|||
dc_loadstate(deser);
|
||||
NOTICE_LOG(SAVESTATE, "Loaded state ver %d from %s size %d", deser.version(), filename.c_str(), total_size);
|
||||
if (deser.size() != total_size)
|
||||
// Note: this isn't true for RA savestates
|
||||
WARN_LOG(SAVESTATE, "Savestate size %d but only %d bytes used", total_size, (int)deser.size());
|
||||
} catch (const Deserializer::Exception& e) {
|
||||
ERROR_LOG(SAVESTATE, "%s", e.what());
|
||||
|
@ -230,4 +275,41 @@ void dc_loadstate(int index)
|
|||
EventManager::event(Event::LoadState);
|
||||
}
|
||||
|
||||
time_t dc_getStateCreationDate(int index)
|
||||
{
|
||||
std::string filename = hostfs::getSavestatePath(index, false);
|
||||
FILE *f = nowide::fopen(filename.c_str(), "rb");
|
||||
if (f == nullptr)
|
||||
return 0;
|
||||
SavestateHeader header;
|
||||
if (std::fread(&header, sizeof(header), 1, f) != 1 || !header.isValid())
|
||||
{
|
||||
std::fclose(f);
|
||||
struct stat st;
|
||||
if (flycast::stat(filename.c_str(), &st) == 0)
|
||||
return st.st_mtime;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
std::fclose(f);
|
||||
return (time_t)header.creationDate;
|
||||
}
|
||||
|
||||
void dc_getStateScreenshot(int index, std::vector<u8>& pngData)
|
||||
{
|
||||
pngData.clear();
|
||||
std::string filename = hostfs::getSavestatePath(index, false);
|
||||
FILE *f = nowide::fopen(filename.c_str(), "rb");
|
||||
if (f == nullptr)
|
||||
return;
|
||||
SavestateHeader header;
|
||||
if (std::fread(&header, sizeof(header), 1, f) == 1 && header.isValid() && header.pngSize != 0)
|
||||
{
|
||||
pngData.resize(header.pngSize);
|
||||
if (std::fread(pngData.data(), 1, pngData.size(), f) != pngData.size())
|
||||
pngData.clear();
|
||||
}
|
||||
std::fclose(f);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -68,6 +68,86 @@ int get(const std::string& url, std::vector<u8>& content, std::string& contentTy
|
|||
return 200;
|
||||
}
|
||||
|
||||
static int post(const std::string& url, const char *headers, const u8 *payload, u32 payloadSize, std::vector<u8>& reply)
|
||||
{
|
||||
char scheme[16], host[256], path[256];
|
||||
URL_COMPONENTS components{};
|
||||
components.dwStructSize = sizeof(components);
|
||||
components.lpszScheme = scheme;
|
||||
components.dwSchemeLength = sizeof(scheme) / sizeof(scheme[0]);
|
||||
components.lpszHostName = host;
|
||||
components.dwHostNameLength = sizeof(host) / sizeof(host[0]);
|
||||
components.lpszUrlPath = path;
|
||||
components.dwUrlPathLength = sizeof(path) / sizeof(path[0]);
|
||||
|
||||
if (!InternetCrackUrlA(url.c_str(), url.length(), 0, &components))
|
||||
return 500;
|
||||
|
||||
bool https = !strcmp(scheme, "https");
|
||||
|
||||
int rc = 500;
|
||||
HINTERNET ic = InternetConnect(hInet, host, components.nPort, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0);
|
||||
if (ic == NULL)
|
||||
return rc;
|
||||
|
||||
HINTERNET hreq = HttpOpenRequest(ic, "POST", path, NULL, NULL, NULL, https ? INTERNET_FLAG_SECURE : 0, 0);
|
||||
if (hreq == NULL) {
|
||||
InternetCloseHandle(ic);
|
||||
return rc;
|
||||
}
|
||||
if (payloadSize > 0)
|
||||
{
|
||||
char clen[128];
|
||||
snprintf(clen, sizeof(clen), "Content-Length: %d\r\n", payloadSize);
|
||||
HttpAddRequestHeaders(hreq, clen, -1L, HTTP_ADDREQ_FLAG_ADD_IF_NEW);
|
||||
}
|
||||
if (!HttpSendRequest(hreq, headers, -1, (void *)payload, payloadSize))
|
||||
WARN_LOG(NETWORK, "HttpSendRequest Error %d", GetLastError());
|
||||
else
|
||||
{
|
||||
DWORD status;
|
||||
DWORD size = sizeof(status);
|
||||
DWORD index = 0;
|
||||
if (!HttpQueryInfo(hreq, HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER, &status, &size, &index))
|
||||
WARN_LOG(NETWORK, "HttpQueryInfo Error %d", GetLastError());
|
||||
else
|
||||
{
|
||||
rc = status;
|
||||
reply.clear();
|
||||
u8 buffer[4096];
|
||||
DWORD bytesRead = sizeof(buffer);
|
||||
while (true)
|
||||
{
|
||||
if (!InternetReadFile(hreq, buffer, sizeof(buffer), &bytesRead))
|
||||
{
|
||||
WARN_LOG(NETWORK, "InternetReadFile failed: %lx", GetLastError());
|
||||
InternetCloseHandle(hreq);
|
||||
rc = 500;
|
||||
break;
|
||||
}
|
||||
if (bytesRead == 0)
|
||||
break;
|
||||
reply.insert(reply.end(), buffer, buffer + bytesRead);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
InternetCloseHandle(hreq);
|
||||
InternetCloseHandle(ic);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int post(const std::string& url, const char *payload, const char *contentType, std::vector<u8>& reply)
|
||||
{
|
||||
char buf[512];
|
||||
if (contentType != nullptr) {
|
||||
sprintf(buf, "Content-Type: %s", contentType);
|
||||
contentType = buf;
|
||||
}
|
||||
return post(url, contentType, (const u8 *)payload, strlen(payload), reply);
|
||||
}
|
||||
|
||||
int post(const std::string& url, const std::vector<PostField>& fields)
|
||||
{
|
||||
static const std::string boundary("----flycast-boundary-8304529454");
|
||||
|
@ -122,49 +202,9 @@ int post(const std::string& url, const std::vector<PostField>& fields)
|
|||
}
|
||||
content += "--" + boundary + "--\r\n";
|
||||
|
||||
char scheme[16], host[256], path[256];
|
||||
URL_COMPONENTS components{};
|
||||
components.dwStructSize = sizeof(components);
|
||||
components.lpszScheme = scheme;
|
||||
components.dwSchemeLength = sizeof(scheme) / sizeof(scheme[0]);
|
||||
components.lpszHostName = host;
|
||||
components.dwHostNameLength = sizeof(host) / sizeof(host[0]);
|
||||
components.lpszUrlPath = path;
|
||||
components.dwUrlPathLength = sizeof(path) / sizeof(path[0]);
|
||||
|
||||
if (!InternetCrackUrlA(url.c_str(), url.length(), 0, &components))
|
||||
return 500;
|
||||
|
||||
bool https = !strcmp(scheme, "https");
|
||||
|
||||
int rc = 500;
|
||||
HINTERNET ic = InternetConnect(hInet, host, components.nPort, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0);
|
||||
if (ic == NULL)
|
||||
return rc;
|
||||
|
||||
HINTERNET hreq = HttpOpenRequest(ic, "POST", path, NULL, NULL, NULL, https ? INTERNET_FLAG_SECURE : 0, 0);
|
||||
if (hreq == NULL) {
|
||||
InternetCloseHandle(ic);
|
||||
return rc;
|
||||
}
|
||||
std::vector<u8> reply;
|
||||
std::string header("Content-Type: multipart/form-data; boundary=" + boundary);
|
||||
if (!HttpSendRequest(hreq, header.c_str(), -1, &content[0], content.length()))
|
||||
WARN_LOG(NETWORK, "HttpSendRequest Error %d", GetLastError());
|
||||
else
|
||||
{
|
||||
DWORD status;
|
||||
DWORD size = sizeof(status);
|
||||
DWORD index = 0;
|
||||
if (!HttpQueryInfo(hreq, HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER, &status, &size, &index))
|
||||
WARN_LOG(NETWORK, "HttpQueryInfo Error %d", GetLastError());
|
||||
else
|
||||
rc = status;
|
||||
}
|
||||
|
||||
InternetCloseHandle(hreq);
|
||||
InternetCloseHandle(ic);
|
||||
|
||||
return rc;
|
||||
return post(url, header.c_str(), (const u8 *)&content[0], content.length(), reply);
|
||||
}
|
||||
|
||||
void term()
|
||||
|
@ -195,7 +235,7 @@ static size_t receiveData(void *buffer, size_t size, size_t nmemb, std::vector<u
|
|||
return nmemb * size;
|
||||
}
|
||||
|
||||
int get(const std::string& url, std::vector<u8>& content, std::string& contentType)
|
||||
static CURL *makeCurlEasy(const std::string& url)
|
||||
{
|
||||
CURL *curl = curl_easy_init();
|
||||
curl_easy_setopt(curl, CURLOPT_USERAGENT, "Flycast/1.0");
|
||||
|
@ -206,6 +246,13 @@ int get(const std::string& url, std::vector<u8>& content, std::string& contentTy
|
|||
|
||||
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
|
||||
|
||||
return curl;
|
||||
}
|
||||
|
||||
int get(const std::string& url, std::vector<u8>& content, std::string& contentType)
|
||||
{
|
||||
CURL *curl = makeCurlEasy(url);
|
||||
|
||||
std::vector<u8> recvBuffer;
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, receiveData);
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &recvBuffer);
|
||||
|
@ -227,17 +274,41 @@ int get(const std::string& url, std::vector<u8>& content, std::string& contentTy
|
|||
return (int)httpCode;
|
||||
}
|
||||
|
||||
int post(const std::string& url, const std::vector<PostField>& fields)
|
||||
int post(const std::string& url, const char *payload, const char *contentType, std::vector<u8>& reply)
|
||||
{
|
||||
CURL *curl = curl_easy_init();
|
||||
curl_easy_setopt(curl, CURLOPT_USERAGENT, "Flycast/1.0");
|
||||
curl_easy_setopt(curl, CURLOPT_AUTOREFERER, 1);
|
||||
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
|
||||
CURL *curl = makeCurlEasy(url);
|
||||
curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
|
||||
|
||||
curl_easy_setopt(curl, CURLOPT_COOKIEFILE, "");
|
||||
curl_easy_setopt(curl, CURLOPT_POST, 1);
|
||||
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, payload);
|
||||
curl_slist *headers = nullptr;
|
||||
if (contentType != nullptr)
|
||||
{
|
||||
headers = curl_slist_append(headers, ("Content-Type: " + std::string(contentType)).c_str());
|
||||
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
|
||||
}
|
||||
|
||||
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
|
||||
std::vector<u8> recvBuffer;
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, receiveData);
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &recvBuffer);
|
||||
CURLcode res = curl_easy_perform(curl);
|
||||
|
||||
long httpCode = 500;
|
||||
if (res == CURLE_OK)
|
||||
{
|
||||
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &httpCode);
|
||||
reply = recvBuffer;
|
||||
}
|
||||
curl_slist_free_all(headers);
|
||||
curl_easy_cleanup(curl);
|
||||
|
||||
return (int)httpCode;
|
||||
}
|
||||
|
||||
int post(const std::string& url, const std::vector<PostField>& fields)
|
||||
{
|
||||
CURL *curl = makeCurlEasy(url);
|
||||
curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
|
||||
|
||||
curl_mime *mime = curl_mime_init(curl);
|
||||
for (const auto& field : fields)
|
||||
|
@ -263,7 +334,6 @@ int post(const std::string& url, const std::vector<PostField>& fields)
|
|||
curl_easy_cleanup(curl);
|
||||
|
||||
return (int)httpCode;
|
||||
|
||||
}
|
||||
|
||||
void term()
|
|
@ -50,6 +50,7 @@ struct PostField
|
|||
};
|
||||
|
||||
int post(const std::string& url, const std::vector<PostField>& fields);
|
||||
int post(const std::string& url, const char *payload, const char *contentType, std::vector<u8>& reply);
|
||||
|
||||
static inline bool success(int status) {
|
||||
return status >= 200 && status < 300;
|
|
@ -25,6 +25,21 @@
|
|||
#ifndef _WIN32
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#if defined(USE_SDL)
|
||||
#include "sdl/sdl.h"
|
||||
#else
|
||||
#if defined(SUPPORT_X11)
|
||||
#include "linux-dist/x11.h"
|
||||
#endif
|
||||
#if defined(USE_EVDEV)
|
||||
#include "linux-dist/evdev.h"
|
||||
#endif
|
||||
#endif
|
||||
#if defined(_WIN32) && !defined(TARGET_UWP)
|
||||
#include "windows/rawinput.h"
|
||||
#include <shlobj.h>
|
||||
#endif
|
||||
#include "profiler/fc_profiler.h"
|
||||
|
||||
namespace hostfs
|
||||
{
|
||||
|
@ -137,11 +152,190 @@ std::string getTextureDumpPath()
|
|||
return get_writable_data_path("texdump/");
|
||||
}
|
||||
|
||||
#if defined(__unix__) && !defined(__ANDROID__)
|
||||
|
||||
static std::string runCommand(const std::string& cmd)
|
||||
{
|
||||
char buf[1024] {};
|
||||
FILE *fp = popen(cmd.c_str(), "r");
|
||||
if (fp == nullptr) {
|
||||
INFO_LOG(COMMON, "popen failed: %d", errno);
|
||||
return "";
|
||||
}
|
||||
std::string result;
|
||||
while (fgets(buf, sizeof(buf), fp) != nullptr)
|
||||
result += trim_trailing_ws(buf, "\n");
|
||||
|
||||
int rc;
|
||||
if ((rc = pclose(fp)) != 0) {
|
||||
INFO_LOG(COMMON, "Command error: %d", rc);
|
||||
return "";
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static std::string getScreenshotsPath()
|
||||
{
|
||||
std::string picturesPath = runCommand("xdg-user-dir PICTURES");
|
||||
if (!picturesPath.empty())
|
||||
return picturesPath;
|
||||
const char *home = nowide::getenv("HOME");
|
||||
if (home != nullptr)
|
||||
return home;
|
||||
else
|
||||
return ".";
|
||||
}
|
||||
|
||||
#elif defined(TARGET_UWP)
|
||||
//TODO move to shell/uwp?
|
||||
using namespace Platform;
|
||||
using namespace Windows::Foundation;
|
||||
using namespace Windows::Storage;
|
||||
|
||||
void saveScreenshot(const std::string& name, const std::vector<u8>& data)
|
||||
{
|
||||
try {
|
||||
StorageFolder^ folder = KnownFolders::PicturesLibrary; // or SavedPictures?
|
||||
if (folder == nullptr) {
|
||||
INFO_LOG(COMMON, "KnownFolders::PicturesLibrary is null");
|
||||
throw FlycastException("Can't find Pictures library");
|
||||
}
|
||||
nowide::wstackstring wstr;
|
||||
wchar_t *wname = wstr.convert(name.c_str());
|
||||
String^ msname = ref new String(wname);
|
||||
ArrayReference<u8> arrayRef(const_cast<u8*>(&data[0]), data.size());
|
||||
|
||||
IAsyncOperation<StorageFile^>^ op = folder->CreateFileAsync(msname, CreationCollisionOption::FailIfExists);
|
||||
cResetEvent asyncEvent;
|
||||
op->Completed = ref new AsyncOperationCompletedHandler<StorageFile^>(
|
||||
[&asyncEvent, &arrayRef](IAsyncOperation<StorageFile^>^ op, AsyncStatus) {
|
||||
IAsyncAction^ action = FileIO::WriteBytesAsync(op->GetResults(), arrayRef);
|
||||
action->Completed = ref new AsyncActionCompletedHandler(
|
||||
[&asyncEvent](IAsyncAction^, AsyncStatus){
|
||||
asyncEvent.Set();
|
||||
});
|
||||
});
|
||||
asyncEvent.Wait();
|
||||
}
|
||||
catch (COMException^ e) {
|
||||
WARN_LOG(COMMON, "Save screenshot failed: %S", e->Message->Data());
|
||||
throw FlycastException("");
|
||||
}
|
||||
}
|
||||
|
||||
#elif defined(_WIN32) && !defined(TARGET_UWP)
|
||||
|
||||
static std::string getScreenshotsPath()
|
||||
{
|
||||
wchar_t *screenshotPath;
|
||||
if (FAILED(SHGetKnownFolderPath(FOLDERID_Screenshots, KF_FLAG_DEFAULT, NULL, &screenshotPath)))
|
||||
return get_writable_config_path("");
|
||||
nowide::stackstring path;
|
||||
std::string ret;
|
||||
if (path.convert(screenshotPath) == nullptr)
|
||||
ret = get_writable_config_path("");
|
||||
else
|
||||
ret = path.get();
|
||||
CoTaskMemFree(screenshotPath);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
std::string getScreenshotsPath();
|
||||
|
||||
#endif
|
||||
|
||||
#if !defined(__ANDROID__) && !defined(TARGET_UWP) && !defined(TARGET_IPHONE) && !defined(__SWITCH__)
|
||||
|
||||
void saveScreenshot(const std::string& name, const std::vector<u8>& data)
|
||||
{
|
||||
std::string path = getScreenshotsPath();
|
||||
path += "/" + name;
|
||||
FILE *f = nowide::fopen(path.c_str(), "wb");
|
||||
if (f == nullptr)
|
||||
throw FlycastException(path);
|
||||
if (std::fwrite(&data[0], data.size(), 1, f) != 1) {
|
||||
std::fclose(f);
|
||||
unlink(path.c_str());
|
||||
throw FlycastException(path);
|
||||
}
|
||||
std::fclose(f);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace hostfs
|
||||
|
||||
void os_CreateWindow()
|
||||
{
|
||||
#if defined(USE_SDL)
|
||||
sdl_window_create();
|
||||
#elif defined(SUPPORT_X11)
|
||||
x11_window_create();
|
||||
#endif
|
||||
}
|
||||
|
||||
void os_DestroyWindow()
|
||||
{
|
||||
#if defined(USE_SDL)
|
||||
sdl_window_destroy();
|
||||
#elif defined(SUPPORT_X11)
|
||||
x11_window_destroy();
|
||||
#endif
|
||||
}
|
||||
|
||||
void os_SetupInput()
|
||||
{
|
||||
#if defined(USE_SDL)
|
||||
input_sdl_init();
|
||||
#else
|
||||
#if defined(SUPPORT_X11)
|
||||
input_x11_init();
|
||||
#endif
|
||||
#if defined(USE_EVDEV)
|
||||
input_evdev_init();
|
||||
#endif
|
||||
#endif
|
||||
#if defined(_WIN32) && !defined(TARGET_UWP)
|
||||
if (config::UseRawInput)
|
||||
rawinput::init();
|
||||
#endif
|
||||
}
|
||||
|
||||
void os_TermInput()
|
||||
{
|
||||
#if defined(USE_SDL)
|
||||
input_sdl_quit();
|
||||
#else
|
||||
#if defined(USE_EVDEV)
|
||||
input_evdev_close();
|
||||
#endif
|
||||
#endif
|
||||
#if defined(_WIN32) && !defined(TARGET_UWP)
|
||||
if (config::UseRawInput)
|
||||
rawinput::term();
|
||||
#endif
|
||||
}
|
||||
|
||||
void os_UpdateInputState()
|
||||
{
|
||||
FC_PROFILE_SCOPE;
|
||||
|
||||
#if defined(USE_SDL)
|
||||
input_sdl_handle();
|
||||
#else
|
||||
#if defined(USE_EVDEV)
|
||||
input_evdev_handle();
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef USE_BREAKPAD
|
||||
|
||||
#include "rend/boxart/http_client.h"
|
||||
#include "http_client.h"
|
||||
#include "version.h"
|
||||
#include "log/InMemoryListener.h"
|
||||
#include "wsi/context.h"
|
||||
|
|
|
@ -1,19 +1,34 @@
|
|||
#pragma once
|
||||
#include "types.h"
|
||||
#include <vector>
|
||||
#if defined(__SWITCH__)
|
||||
#include <malloc.h>
|
||||
#endif
|
||||
|
||||
void os_SetWindowText(const char* text);
|
||||
double os_GetSeconds();
|
||||
|
||||
void os_DoEvents();
|
||||
void os_CreateWindow();
|
||||
void os_DestroyWindow();
|
||||
void os_SetupInput();
|
||||
void os_TermInput();
|
||||
void os_UpdateInputState();
|
||||
void os_InstallFaultHandler();
|
||||
void os_UninstallFaultHandler();
|
||||
void os_RunInstance(int argc, const char *argv[]);
|
||||
void os_SetThreadName(const char *name);
|
||||
void os_notify(const char *msg, int durationMs = 2000, const char *details = nullptr);
|
||||
|
||||
// raii thread name setter
|
||||
class ThreadName
|
||||
{
|
||||
public:
|
||||
ThreadName(const char *name) {
|
||||
os_SetThreadName(name);
|
||||
}
|
||||
~ThreadName() {
|
||||
// default name
|
||||
os_SetThreadName("flycast");
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <intrin.h>
|
||||
|
@ -46,6 +61,7 @@ namespace hostfs
|
|||
std::string getTextureDumpPath();
|
||||
|
||||
std::string getShaderCachePath(const std::string& filename);
|
||||
void saveScreenshot(const std::string& name, const std::vector<u8>& data);
|
||||
}
|
||||
|
||||
static inline void *allocAligned(size_t alignment, size_t size)
|
||||
|
|
|
@ -184,7 +184,8 @@ public:
|
|||
#ifndef _WIN32
|
||||
struct stat st;
|
||||
if (flycast::stat(path.c_str(), &st) != 0) {
|
||||
INFO_LOG(COMMON, "Cannot stat file '%s' errno %d", path.c_str(), errno);
|
||||
if (errno != ENOENT)
|
||||
INFO_LOG(COMMON, "Cannot stat file '%s' errno %d", path.c_str(), errno);
|
||||
throw StorageException("Cannot stat " + path);
|
||||
}
|
||||
info.isDirectory = S_ISDIR(st.st_mode);
|
||||
|
|
|
@ -284,7 +284,7 @@ void CustomTexture::DumpTexture(u32 hash, int w, int h, TextureType textype, voi
|
|||
FILE *f = nowide::fopen((const char *)context, "wb");
|
||||
if (f == nullptr)
|
||||
{
|
||||
WARN_LOG(RENDERER, "Dump texture: can't save to file %s: error %d", context, errno);
|
||||
WARN_LOG(RENDERER, "Dump texture: can't save to file %s: error %d", (const char *)context, errno);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
|
||||
class CustomTexture {
|
||||
public:
|
||||
CustomTexture() : loader_thread(loader_thread_func, this) {}
|
||||
CustomTexture() : loader_thread(loader_thread_func, this, "CustomTexLoader") {}
|
||||
~CustomTexture() { Terminate(); }
|
||||
u8* LoadCustomTexture(u32 hash, int& width, int& height);
|
||||
void LoadCustomTextureAsync(BaseTextureCacheData *texture_data);
|
||||
|
|
|
@ -17,10 +17,10 @@
|
|||
along with Flycast. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include "rend/imgui_driver.h"
|
||||
#include "ui/imgui_driver.h"
|
||||
#include "imgui_impl_dx11.h"
|
||||
#include "dx11context.h"
|
||||
#include "rend/gui.h"
|
||||
#include "ui/gui.h"
|
||||
#include <unordered_map>
|
||||
|
||||
class DX11Driver final : public ImGuiDriver
|
||||
|
@ -57,12 +57,12 @@ public:
|
|||
ImTextureID getTexture(const std::string& name) override {
|
||||
auto it = textures.find(name);
|
||||
if (it != textures.end())
|
||||
return (ImTextureID)it->second.textureView.get();
|
||||
return (ImTextureID)&it->second.imTexture;
|
||||
else
|
||||
return ImTextureID{};
|
||||
}
|
||||
|
||||
ImTextureID updateTexture(const std::string& name, const u8 *data, int width, int height) override
|
||||
ImTextureID updateTexture(const std::string& name, const u8 *data, int width, int height, bool nearestSampling) override
|
||||
{
|
||||
Texture& texture = textures[name];
|
||||
texture.texture.reset();
|
||||
|
@ -86,8 +86,14 @@ public:
|
|||
theDX11Context.getDevice()->CreateShaderResourceView(texture.texture, &viewDesc, &texture.textureView.get());
|
||||
|
||||
theDX11Context.getDeviceContext()->UpdateSubresource(texture.texture, 0, nullptr, data, width * 4, width * 4 * height);
|
||||
texture.imTexture.shaderResourceView = texture.textureView.get();
|
||||
texture.imTexture.pointSampling = nearestSampling;
|
||||
|
||||
return (ImTextureID)texture.textureView.get();
|
||||
return (ImTextureID)&texture.imTexture;
|
||||
}
|
||||
|
||||
void deleteTexture(const std::string& name) override {
|
||||
textures.erase(name);
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -95,6 +101,7 @@ private:
|
|||
{
|
||||
ComPtr<ID3D11Texture2D> texture;
|
||||
ComPtr<ID3D11ShaderResourceView> textureView;
|
||||
ImTextureDX11 imTexture;
|
||||
};
|
||||
|
||||
bool frameRendered = false;
|
||||
|
|
|
@ -56,7 +56,7 @@ void DX11Overlay::draw(u32 width, u32 height, bool vmu, bool crosshair)
|
|||
vmuTextures[i].reset();
|
||||
continue;
|
||||
}
|
||||
if (vmuTextures[i] == nullptr || vmu_lcd_changed[i])
|
||||
if (vmuTextures[i] == nullptr || this->vmuLastChanged[i] != ::vmuLastChanged[i])
|
||||
{
|
||||
vmuTextureViews[i].reset();
|
||||
vmuTextures[i].reset();
|
||||
|
@ -82,8 +82,8 @@ void DX11Overlay::draw(u32 width, u32 height, bool vmu, bool crosshair)
|
|||
for (int y = 0; y < 32; y++)
|
||||
memcpy(&data[y * 48], &vmu_lcd_data[i][(31 - y) * 48], sizeof(u32) * 48);
|
||||
deviceContext->UpdateSubresource(vmuTextures[i], 0, nullptr, data, 48 * 4, 48 * 4 * 32);
|
||||
this->vmuLastChanged[i] = ::vmuLastChanged[i];
|
||||
}
|
||||
vmu_lcd_changed[i] = false;
|
||||
}
|
||||
float x, y;
|
||||
float w = vmu_width;
|
||||
|
|
|
@ -35,6 +35,7 @@ public:
|
|||
this->deviceContext = deviceContext;
|
||||
this->samplers = samplers;
|
||||
quad.init(device, deviceContext, shaders);
|
||||
vmuLastChanged.fill({});
|
||||
}
|
||||
|
||||
void term()
|
||||
|
@ -60,6 +61,7 @@ private:
|
|||
ComPtr<ID3D11ShaderResourceView> xhairTextureView;
|
||||
std::array<ComPtr<ID3D11Texture2D>, 8> vmuTextures;
|
||||
std::array<ComPtr<ID3D11ShaderResourceView>, 8> vmuTextureViews;
|
||||
std::array<u64, 8> vmuLastChanged {};
|
||||
Quad quad;
|
||||
Samplers *samplers;
|
||||
BlendStates blendStates;
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
#include "dx11context.h"
|
||||
#include "hw/pvr/ta.h"
|
||||
#include "hw/pvr/pvr_mem.h"
|
||||
#include "rend/gui.h"
|
||||
#include "ui/gui.h"
|
||||
#include "rend/tileclip.h"
|
||||
#include "rend/sorter.h"
|
||||
|
||||
|
@ -1345,6 +1345,99 @@ void DX11Renderer::writeFramebufferToVRAM()
|
|||
WriteFramebuffer<2, 1, 0, 3>(width, height, (u8 *)tmp_buf.data(), texAddress, pvrrc.fb_W_CTRL, linestride, xClip, yClip);
|
||||
}
|
||||
|
||||
bool DX11Renderer::GetLastFrame(std::vector<u8>& data, int& width, int& height)
|
||||
{
|
||||
if (!frameRenderedOnce)
|
||||
return false;
|
||||
|
||||
if (width != 0) {
|
||||
height = width / aspectRatio;
|
||||
}
|
||||
else if (height != 0) {
|
||||
width = aspectRatio * height;
|
||||
}
|
||||
else
|
||||
{
|
||||
width = this->width;
|
||||
height = this->height;
|
||||
if (config::Rotate90)
|
||||
std::swap(width, height);
|
||||
// We need square pixels for PNG
|
||||
int w = aspectRatio * height;
|
||||
if (width > w)
|
||||
height = width / aspectRatio;
|
||||
else
|
||||
width = w;
|
||||
}
|
||||
|
||||
ComPtr<ID3D11Texture2D> dstTex;
|
||||
ComPtr<ID3D11RenderTargetView> dstRenderTarget;
|
||||
createTexAndRenderTarget(dstTex, dstRenderTarget, width, height);
|
||||
|
||||
ID3D11ShaderResourceView *nullResView = nullptr;
|
||||
deviceContext->PSSetShaderResources(0, 1, &nullResView);
|
||||
deviceContext->OMSetRenderTargets(1, &dstRenderTarget.get(), nullptr);
|
||||
D3D11_VIEWPORT vp{};
|
||||
vp.Width = (FLOAT)width;
|
||||
vp.Height = (FLOAT)height;
|
||||
vp.MinDepth = 0.f;
|
||||
vp.MaxDepth = 1.f;
|
||||
deviceContext->RSSetViewports(1, &vp);
|
||||
const D3D11_RECT r = { 0, 0, (LONG)width, (LONG)height };
|
||||
deviceContext->RSSetScissorRects(1, &r);
|
||||
deviceContext->OMSetBlendState(blendStates.getState(false), nullptr, 0xffffffff);
|
||||
deviceContext->GSSetShader(nullptr, nullptr, 0);
|
||||
deviceContext->HSSetShader(nullptr, nullptr, 0);
|
||||
deviceContext->DSSetShader(nullptr, nullptr, 0);
|
||||
deviceContext->CSSetShader(nullptr, nullptr, 0);
|
||||
|
||||
quad->draw(fbTextureView, samplers->getSampler(true), nullptr, -1.f, -1.f, 2.f, 2.f, config::Rotate90);
|
||||
|
||||
#ifndef LIBRETRO
|
||||
deviceContext->OMSetRenderTargets(1, &theDX11Context.getRenderTarget().get(), nullptr);
|
||||
#else
|
||||
ID3D11RenderTargetView *nullView = nullptr;
|
||||
deviceContext->OMSetRenderTargets(1, &nullView, nullptr);
|
||||
#endif
|
||||
D3D11_TEXTURE2D_DESC desc;
|
||||
dstTex->GetDesc(&desc);
|
||||
desc.Usage = D3D11_USAGE_STAGING;
|
||||
desc.BindFlags = 0;
|
||||
desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
|
||||
desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
|
||||
|
||||
ComPtr<ID3D11Texture2D> stagingTex;
|
||||
HRESULT hr = device->CreateTexture2D(&desc, nullptr, &stagingTex.get());
|
||||
if (FAILED(hr))
|
||||
{
|
||||
WARN_LOG(RENDERER, "Staging screenshot texture creation failed");
|
||||
return false;
|
||||
}
|
||||
deviceContext->CopyResource(stagingTex, dstTex);
|
||||
|
||||
D3D11_MAPPED_SUBRESOURCE mappedSubres;
|
||||
hr = deviceContext->Map(stagingTex, 0, D3D11_MAP_READ, 0, &mappedSubres);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
WARN_LOG(RENDERER, "Failed to map staging screenshot texture");
|
||||
return false;
|
||||
}
|
||||
const u8* const src = (const u8 *)mappedSubres.pData;
|
||||
for (int y = 0; y < height; y++)
|
||||
{
|
||||
const u8 *p = src + y * mappedSubres.RowPitch;
|
||||
for (int x = 0; x < width; x++, p += 4)
|
||||
{
|
||||
data.push_back(p[2]);
|
||||
data.push_back(p[1]);
|
||||
data.push_back(p[0]);
|
||||
}
|
||||
}
|
||||
deviceContext->Unmap(stagingTex, 0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void DX11Renderer::renderVideoRouting()
|
||||
{
|
||||
#ifdef VIDEO_ROUTING
|
||||
|
|
|
@ -53,6 +53,7 @@ struct DX11Renderer : public Renderer
|
|||
bool RenderLastFrame() override;
|
||||
void DrawOSD(bool clear_screen) override;
|
||||
BaseTextureCacheData *GetTexture(TSP tsp, TCW tcw) override;
|
||||
bool GetLastFrame(std::vector<u8>& data, int& width, int& height) override;
|
||||
|
||||
protected:
|
||||
struct VertexConstants
|
||||
|
|
|
@ -64,6 +64,7 @@ bool DX11Context::init(bool keepCurrentWindow)
|
|||
ComPtr<IDXGIFactory6> dxgiFactory6;
|
||||
ComPtr<IDXGIAdapter> dxgiAdapter;
|
||||
HRESULT hr;
|
||||
allowTearing = false;
|
||||
hr = CreateDXGIFactory1(__uuidof(IDXGIFactory1), (void **)&dxgiFactory.get());
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
|
@ -71,6 +72,10 @@ bool DX11Context::init(bool keepCurrentWindow)
|
|||
if (dxgiFactory6)
|
||||
{
|
||||
dxgiFactory6->EnumAdapterByGpuPreference(0, DXGI_GPU_PREFERENCE_HIGH_PERFORMANCE, __uuidof(IDXGIAdapter), (void **)&dxgiAdapter.get());
|
||||
UINT tearing;
|
||||
if (SUCCEEDED(dxgiFactory6->CheckFeatureSupport(DXGI_FEATURE_PRESENT_ALLOW_TEARING, &tearing,
|
||||
sizeof(tearing))) && tearing != 0)
|
||||
allowTearing = true;
|
||||
dxgiFactory6.reset();
|
||||
}
|
||||
}
|
||||
|
@ -127,6 +132,8 @@ bool DX11Context::init(bool keepCurrentWindow)
|
|||
desc.BufferCount = 2;
|
||||
desc.SampleDesc.Count = 1;
|
||||
desc.AlphaMode = DXGI_ALPHA_MODE_IGNORE;
|
||||
if (allowTearing)
|
||||
desc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING;
|
||||
|
||||
#ifdef TARGET_UWP
|
||||
desc.Width = settings.display.width;
|
||||
|
@ -157,6 +164,8 @@ bool DX11Context::init(bool keepCurrentWindow)
|
|||
desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
|
||||
desc.SampleDesc.Count = 1;
|
||||
desc.SampleDesc.Quality = 0;
|
||||
if (allowTearing)
|
||||
desc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING;
|
||||
|
||||
hr = dxgiFactory->CreateSwapChain(pDevice, &desc, &swapchain.get());
|
||||
}
|
||||
|
@ -221,26 +230,23 @@ void DX11Context::Present()
|
|||
frameRendered = false;
|
||||
bool swapOnVSync = !settings.input.fastForwardMode && config::VSync;
|
||||
HRESULT hr;
|
||||
if (!swapchain)
|
||||
{
|
||||
if (!swapchain) {
|
||||
hr = DXGI_ERROR_DEVICE_RESET;
|
||||
}
|
||||
else if (swapOnVSync)
|
||||
{
|
||||
else if (swapOnVSync) {
|
||||
int swapInterval = std::min(4, std::max(1, (int)(settings.display.refreshRate / 60)));
|
||||
hr = swapchain->Present(swapInterval, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
hr = swapchain->Present(0, DXGI_PRESENT_DO_NOT_WAIT);
|
||||
else {
|
||||
hr = swapchain->Present(0, allowTearing ? DXGI_PRESENT_ALLOW_TEARING : DXGI_PRESENT_DO_NOT_WAIT);
|
||||
}
|
||||
if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET)
|
||||
{
|
||||
if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET) {
|
||||
WARN_LOG(RENDERER, "Present failed: device removed/reset");
|
||||
handleDeviceLost();
|
||||
}
|
||||
else if (hr != DXGI_ERROR_WAS_STILL_DRAWING && FAILED(hr))
|
||||
else if (hr != DXGI_ERROR_WAS_STILL_DRAWING && FAILED(hr)) {
|
||||
WARN_LOG(RENDERER, "Present failed %x", hr);
|
||||
}
|
||||
}
|
||||
|
||||
void DX11Context::EndImGuiFrame()
|
||||
|
@ -260,10 +266,6 @@ void DX11Context::EndImGuiFrame()
|
|||
if (crosshairsNeeded() || config::FloatVMUs)
|
||||
overlay.draw(settings.display.width, settings.display.height, config::FloatVMUs, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
overlay.draw(settings.display.width, settings.display.height, true, false);
|
||||
}
|
||||
ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData());
|
||||
}
|
||||
frameRendered = true;
|
||||
|
@ -279,9 +281,9 @@ void DX11Context::resize()
|
|||
pDeviceContext->OMSetRenderTargets(1, &nullRTV, nullptr);
|
||||
renderTargetView.reset();
|
||||
#ifdef TARGET_UWP
|
||||
HRESULT hr = swapchain->ResizeBuffers(2, settings.display.width, settings.display.height, DXGI_FORMAT_R8G8B8A8_UNORM, 0);
|
||||
HRESULT hr = swapchain->ResizeBuffers(2, settings.display.width, settings.display.height, DXGI_FORMAT_R8G8B8A8_UNORM, allowTearing ? DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING : 0);
|
||||
#else
|
||||
HRESULT hr = swapchain->ResizeBuffers(0, 0, 0, DXGI_FORMAT_UNKNOWN, DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH);
|
||||
HRESULT hr = swapchain->ResizeBuffers(0, 0, 0, DXGI_FORMAT_UNKNOWN, DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH | (allowTearing ? DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING : 0));
|
||||
if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET)
|
||||
{
|
||||
handleDeviceLost();
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue