Merge remote-tracking branch 'origin/dev'

This commit is contained in:
Flyinghead 2024-05-23 10:40:57 +02:00
commit 4747252187
219 changed files with 12484 additions and 6568 deletions

View File

@ -15,7 +15,7 @@ jobs:
- uses: actions/checkout@v4
with:
fetch-depth: 0
submodules: true
submodules: recursive
- uses: actions/setup-java@v4
with:

View File

@ -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 }}

View File

@ -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

9
.gitmodules vendored
View File

@ -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

View File

@ -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

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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;
};

View File

@ -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

View File

@ -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);

View 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;
};

View File

@ -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)
{

View File

@ -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

View File

@ -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

View File

@ -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())
{

View File

@ -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

1
core/deps/discord-rpc Submodule

@ -0,0 +1 @@
Subproject commit c1197e1a1e2ff09c077e84541bd88cf90581648c

View File

@ -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();

View File

@ -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

View File

@ -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();
}

View File

@ -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

View File

@ -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();
}

View File

@ -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();

View File

@ -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

View File

@ -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();
}

View File

@ -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)

View File

@ -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();
}

View File

@ -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;

View File

@ -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; }

View File

@ -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

View File

@ -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);
}

View File

@ -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;
}
}

View File

@ -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

1
core/deps/rcheevos Submodule

@ -0,0 +1 @@
Subproject commit e88f74992527b9ade48ae1591378ec2cf363bef9

View File

@ -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 {

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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);
}
}

View File

@ -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
}
}

View File

@ -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;
}
}

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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:

View File

@ -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();

View File

@ -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;
}

View File

@ -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();

View File

@ -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)

View File

@ -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[];

View File

@ -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[])

View File

@ -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

View File

@ -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;

View File

@ -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; }

View File

@ -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);

View File

@ -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()

View File

@ -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;
}

View File

@ -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;

View File

@ -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

View File

@ -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
}

View File

@ -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;
}

View File

@ -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;

View File

@ -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,

View File

@ -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

View File

@ -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];

View File

@ -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;
}

View File

@ -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

View File

@ -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];

View File

@ -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

View File

@ -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

View File

@ -1,3 +0,0 @@
#pragma once
extern void dispmanx_window_create();

View File

@ -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;

View File

@ -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__

View File

@ -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)
{

View File

@ -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;

View File

@ -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__

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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()

View File

@ -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;

View File

@ -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;

View File

@ -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()
{

View File

@ -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

View File

@ -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()

View File

@ -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;

View File

@ -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"

View File

@ -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)

View File

@ -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);

View File

@ -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
{

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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