Update Nemirtingas overlay to latest.
parent
df94c38b0f
commit
c17fb0c931
|
@ -643,6 +643,12 @@ inline bool file_exists (const std::string& name) {
|
||||||
return (stat (name.c_str(), &buffer) == 0);
|
return (stat (name.c_str(), &buffer) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef DETOURS_64BIT
|
||||||
|
#define DLL_NAME "steam_api64.dll"
|
||||||
|
#else
|
||||||
|
#define DLL_NAME "steam_api.dll"
|
||||||
|
#endif
|
||||||
|
|
||||||
HMODULE (WINAPI *Real_GetModuleHandleA)(LPCSTR lpModuleName) = GetModuleHandleA;
|
HMODULE (WINAPI *Real_GetModuleHandleA)(LPCSTR lpModuleName) = GetModuleHandleA;
|
||||||
HMODULE WINAPI Mine_GetModuleHandleA(LPCSTR lpModuleName)
|
HMODULE WINAPI Mine_GetModuleHandleA(LPCSTR lpModuleName)
|
||||||
{
|
{
|
||||||
|
|
|
@ -76,12 +76,6 @@
|
||||||
#include <winhttp.h>
|
#include <winhttp.h>
|
||||||
|
|
||||||
#include "../detours/detours.h"
|
#include "../detours/detours.h"
|
||||||
|
|
||||||
#ifdef DETOURS_64BIT
|
|
||||||
#define DLL_NAME "steam_api64.dll"
|
|
||||||
#else
|
|
||||||
#define DLL_NAME "steam_api.dll"
|
|
||||||
#endif
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
28581
glew/glew.c
28581
glew/glew.c
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
23686
glew/include/GL/glew.h
23686
glew/include/GL/glew.h
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1,5 +1,4 @@
|
||||||
#include "Base_Hook.h"
|
#include "Base_Hook.h"
|
||||||
#include "Hook_Manager.h"
|
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
|
|
|
@ -1,36 +0,0 @@
|
||||||
#include "../dll/dll.h"
|
|
||||||
#include "Hook_Manager.h"
|
|
||||||
|
|
||||||
#ifdef EMU_OVERLAY
|
|
||||||
|
|
||||||
Hook_Manager::Hook_Manager()
|
|
||||||
{}
|
|
||||||
|
|
||||||
Hook_Manager::~Hook_Manager()
|
|
||||||
{
|
|
||||||
for (auto& i : _hooks)
|
|
||||||
delete i;
|
|
||||||
}
|
|
||||||
|
|
||||||
Hook_Manager& Hook_Manager::Inst()
|
|
||||||
{
|
|
||||||
static Hook_Manager hook;
|
|
||||||
return hook;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Hook_Manager::AddHook(Base_Hook* hook)
|
|
||||||
{
|
|
||||||
_hooks.insert(hook);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Hook_Manager::RemoveHook(Base_Hook* hook)
|
|
||||||
{
|
|
||||||
auto it = _hooks.find(hook);
|
|
||||||
if (it != _hooks.end())
|
|
||||||
{
|
|
||||||
delete hook;
|
|
||||||
_hooks.erase(it);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif//EMU_OVERLAY
|
|
|
@ -1,27 +0,0 @@
|
||||||
#ifndef __INCLUDED_HOOK_BASE_H__
|
|
||||||
#define __INCLUDED_HOOK_BASE_H__
|
|
||||||
|
|
||||||
#include "Base_Hook.h"
|
|
||||||
|
|
||||||
#ifdef EMU_OVERLAY
|
|
||||||
|
|
||||||
class Hook_Manager
|
|
||||||
{
|
|
||||||
friend class Base_Hook;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
std::set<Base_Hook*> _hooks;
|
|
||||||
|
|
||||||
Hook_Manager();
|
|
||||||
virtual ~Hook_Manager();
|
|
||||||
|
|
||||||
public:
|
|
||||||
static Hook_Manager& Inst();
|
|
||||||
|
|
||||||
void AddHook(Base_Hook* hook);
|
|
||||||
void RemoveHook(Base_Hook* hook);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif//EMU_OVERLAY
|
|
||||||
|
|
||||||
#endif//__INCLUDED_HOOK_BASE_H__
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,104 +1,30 @@
|
||||||
#ifndef __INCLUDED_RENDERER_DETECTOR_H__
|
/*
|
||||||
#define __INCLUDED_RENDERER_DETECTOR_H__
|
* Copyright (C) Nemirtingas
|
||||||
|
* This file is part of the ingame overlay project
|
||||||
|
*
|
||||||
|
* The ingame overlay project is free software; you can redistribute it
|
||||||
|
* and/or modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* The ingame overlay project 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
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with the ingame overlay project; if not, see
|
||||||
|
* <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
#include "Base_Hook.h"
|
#pragma once
|
||||||
|
|
||||||
#ifdef EMU_OVERLAY
|
#include "../dll/base.h"
|
||||||
#ifdef __WINDOWS__
|
|
||||||
|
|
||||||
struct IDXGISwapChain;
|
#include <future>
|
||||||
struct IDirect3DDevice9;
|
#include <chrono>
|
||||||
struct IDirect3DDevice9Ex;
|
#include <memory>
|
||||||
|
|
||||||
class Renderer_Detector
|
#include "Renderer_Hook.h"
|
||||||
{
|
|
||||||
private:
|
|
||||||
// Variables
|
|
||||||
std::thread* _hook_thread;
|
|
||||||
std::mutex _found_mutex;
|
|
||||||
unsigned int _hook_retries;
|
|
||||||
bool _renderer_found; // Is the renderer hooked ?
|
|
||||||
bool _dx9_hooked;
|
|
||||||
bool _dx10_hooked;
|
|
||||||
bool _dx11_hooked;
|
|
||||||
bool _dx12_hooked;
|
|
||||||
bool _dxgi_hooked;
|
|
||||||
bool _ogl_hooked; // wglMakeCurrent is hooked ? (opengl)
|
|
||||||
Base_Hook* rendererdetect_hook;
|
|
||||||
Base_Hook* game_renderer;
|
|
||||||
|
|
||||||
ATOM atom;
|
std::future<Renderer_Hook*> detect_renderer(std::chrono::milliseconds timeout = std::chrono::milliseconds{-1});
|
||||||
HWND dummy_hWnd;
|
|
||||||
|
|
||||||
// Functions
|
|
||||||
Renderer_Detector();
|
|
||||||
~Renderer_Detector();
|
|
||||||
|
|
||||||
static HRESULT STDMETHODCALLTYPE MyIDXGISwapChain_Present(IDXGISwapChain* _this, UINT SyncInterval, UINT Flags);
|
|
||||||
static HRESULT STDMETHODCALLTYPE MyPresent(IDirect3DDevice9* _this, CONST RECT* pSourceRect, CONST RECT* pDestRect, HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion);
|
|
||||||
static HRESULT STDMETHODCALLTYPE MyPresentEx(IDirect3DDevice9Ex* _this, CONST RECT* pSourceRect, CONST RECT* pDestRect, HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion, DWORD dwFlags);
|
|
||||||
static BOOL WINAPI MywglMakeCurrent(HDC hDC, HGLRC hGLRC);
|
|
||||||
|
|
||||||
void HookDXGIPresent(IDXGISwapChain* pSwapChain);
|
|
||||||
void HookDX9Present(IDirect3DDevice9* pDevice, bool ex);
|
|
||||||
void HookwglMakeCurrent(decltype(wglMakeCurrent)* wglMakeCurrent);
|
|
||||||
|
|
||||||
void hook_dx9();
|
|
||||||
void hook_dx10();
|
|
||||||
void hook_dx11();
|
|
||||||
void hook_dx12();
|
|
||||||
void hook_opengl();
|
|
||||||
|
|
||||||
void create_hwnd();
|
|
||||||
void destroy_hwnd();
|
|
||||||
void create_hook(const char* libname);
|
|
||||||
bool stop_retry();
|
|
||||||
|
|
||||||
static void find_renderer_proc(Renderer_Detector* _this);
|
|
||||||
|
|
||||||
public:
|
|
||||||
void find_renderer();
|
|
||||||
void renderer_found(Base_Hook* hook);
|
|
||||||
Base_Hook* get_renderer() const;
|
|
||||||
static Renderer_Detector& Inst();
|
|
||||||
};
|
|
||||||
|
|
||||||
#elif defined __LINUX__
|
|
||||||
#include "linux/OpenGLX_Hook.h"
|
|
||||||
|
|
||||||
class Renderer_Detector
|
|
||||||
{
|
|
||||||
// Variables
|
|
||||||
std::thread* _hook_thread;
|
|
||||||
std::mutex _found_mutex;
|
|
||||||
unsigned int _hook_retries;
|
|
||||||
bool _oglx_hooked;
|
|
||||||
bool _renderer_found; // Is the renderer hooked ?
|
|
||||||
Base_Hook* rendererdetect_hook;
|
|
||||||
Base_Hook* game_renderer;
|
|
||||||
|
|
||||||
// Functions
|
|
||||||
Renderer_Detector();
|
|
||||||
~Renderer_Detector();
|
|
||||||
|
|
||||||
static void MyglXSwapBuffers(Display *dpy, GLXDrawable drawable);
|
|
||||||
|
|
||||||
void HookglXSwapBuffers(decltype(glXSwapBuffers)* glXSwapBuffers);
|
|
||||||
|
|
||||||
void hook_openglx(const char* libname);
|
|
||||||
|
|
||||||
void create_hook(const char* libname);
|
|
||||||
bool stop_retry();
|
|
||||||
|
|
||||||
static void find_renderer_proc(Renderer_Detector* _this);
|
|
||||||
|
|
||||||
public:
|
|
||||||
void find_renderer();
|
|
||||||
void renderer_found(Base_Hook* hook);
|
|
||||||
Base_Hook* get_renderer() const;
|
|
||||||
static Renderer_Detector& Inst();
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif//__WINDOWS__
|
|
||||||
#endif//EMU_OVERLAY
|
|
||||||
#endif//__INCLUDED_RENDERER_DETECTOR_H__
|
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) Nemirtingas
|
||||||
|
* This file is part of the ingame overlay project
|
||||||
|
*
|
||||||
|
* The ingame overlay project is free software; you can redistribute it
|
||||||
|
* and/or modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* The ingame overlay project 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
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with the ingame overlay project; if not, see
|
||||||
|
* <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <string>
|
||||||
|
#include <memory>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
class Renderer_Hook
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Renderer_Hook():
|
||||||
|
OverlayProc(&DefaultOverlayProc),
|
||||||
|
OverlayHookReady(&DefaultOverlayHookReady)
|
||||||
|
{}
|
||||||
|
|
||||||
|
static void DefaultOverlayProc() {}
|
||||||
|
static void DefaultOverlayHookReady(bool) {}
|
||||||
|
std::function<void()> OverlayProc;
|
||||||
|
std::function<void(bool)> OverlayHookReady;
|
||||||
|
|
||||||
|
virtual bool StartHook(std::function<bool(bool)> key_combination_callback) = 0;
|
||||||
|
virtual bool IsStarted() = 0;
|
||||||
|
// Returns a Handle to the renderer image ressource or nullptr if it failed to create the resource, the handle can be used in ImGui's Image calls, image_buffer must be RGBA ordered
|
||||||
|
virtual std::weak_ptr<uint64_t> CreateImageResource(const void* image_data, uint32_t width, uint32_t height) = 0;
|
||||||
|
virtual void ReleaseImageResource(std::weak_ptr<uint64_t> resource) = 0;
|
||||||
|
|
||||||
|
virtual std::string GetLibraryName() const = 0;
|
||||||
|
};
|
|
@ -0,0 +1,116 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) Nemirtingas
|
||||||
|
* This file is part of System.
|
||||||
|
*
|
||||||
|
* System is free software; you can redistribute it
|
||||||
|
* and/or modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* System 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
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with System; if not, see
|
||||||
|
* <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
namespace System {
|
||||||
|
template<typename Enum>
|
||||||
|
struct EnableBitMaskOperators
|
||||||
|
{
|
||||||
|
static constexpr bool enable = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
constexpr typename std::underlying_type<T>::type GetEnumValue(T enum_value)
|
||||||
|
{
|
||||||
|
return static_cast<typename std::underlying_type<T>::type>(enum_value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Enum>
|
||||||
|
constexpr typename std::enable_if<System::EnableBitMaskOperators<Enum>::enable, Enum>::type
|
||||||
|
operator |(Enum lhs, Enum rhs)
|
||||||
|
{
|
||||||
|
using underlying = typename std::underlying_type<Enum>::type;
|
||||||
|
return static_cast<Enum> (
|
||||||
|
static_cast<underlying>(lhs) |
|
||||||
|
static_cast<underlying>(rhs)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Enum>
|
||||||
|
constexpr typename std::enable_if<System::EnableBitMaskOperators<Enum>::enable, Enum>::type
|
||||||
|
operator &(Enum lhs, Enum rhs)
|
||||||
|
{
|
||||||
|
using underlying = typename std::underlying_type<Enum>::type;
|
||||||
|
return static_cast<Enum> (
|
||||||
|
static_cast<underlying>(lhs) &
|
||||||
|
static_cast<underlying>(rhs)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Enum>
|
||||||
|
constexpr typename std::enable_if<System::EnableBitMaskOperators<Enum>::enable, Enum>::type
|
||||||
|
operator ^(Enum lhs, Enum rhs)
|
||||||
|
{
|
||||||
|
using underlying = typename std::underlying_type<Enum>::type;
|
||||||
|
return static_cast<Enum> (
|
||||||
|
static_cast<underlying>(lhs) ^
|
||||||
|
static_cast<underlying>(rhs)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Enum>
|
||||||
|
constexpr typename std::enable_if<System::EnableBitMaskOperators<Enum>::enable, Enum>::type
|
||||||
|
operator ~(Enum lhs)
|
||||||
|
{
|
||||||
|
using underlying = typename std::underlying_type<Enum>::type;
|
||||||
|
return static_cast<Enum> (~static_cast<underlying>(lhs));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Enum>
|
||||||
|
constexpr typename std::enable_if<System::EnableBitMaskOperators<Enum>::enable, Enum>::type&
|
||||||
|
operator |=(Enum& lhs, Enum rhs)
|
||||||
|
{
|
||||||
|
lhs = lhs | rhs;
|
||||||
|
return lhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Enum>
|
||||||
|
constexpr typename std::enable_if<System::EnableBitMaskOperators<Enum>::enable, Enum>::type&
|
||||||
|
operator &=(Enum& lhs, Enum rhs)
|
||||||
|
{
|
||||||
|
lhs = lhs & rhs;
|
||||||
|
return lhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Enum>
|
||||||
|
constexpr typename std::enable_if<System::EnableBitMaskOperators<Enum>::enable, Enum>::type&
|
||||||
|
operator ^=(Enum& lhs, Enum rhs)
|
||||||
|
{
|
||||||
|
lhs = lhs ^ rhs;
|
||||||
|
return lhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Enum>
|
||||||
|
constexpr typename std::enable_if<System::EnableBitMaskOperators<Enum>::enable, bool>::type
|
||||||
|
operator !(Enum lhs)
|
||||||
|
{
|
||||||
|
using underlying = typename std::underlying_type<Enum>::type;
|
||||||
|
return !static_cast<underlying>(lhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define UTILS_ENABLE_BITMASK_OPERATORS(T) \
|
||||||
|
template<> \
|
||||||
|
struct System::EnableBitMaskOperators<T> \
|
||||||
|
{ \
|
||||||
|
static constexpr bool enable = true; \
|
||||||
|
}
|
|
@ -0,0 +1,45 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) Nemirtingas
|
||||||
|
* This file is part of System.
|
||||||
|
*
|
||||||
|
* System is free software; you can redistribute it
|
||||||
|
* and/or modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* System 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
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with System; if not, see
|
||||||
|
* <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstddef> // size_t
|
||||||
|
|
||||||
|
namespace System {
|
||||||
|
namespace ConstExpr {
|
||||||
|
template<typename T, size_t N>
|
||||||
|
constexpr size_t CountOf(T(&)[N])
|
||||||
|
{
|
||||||
|
return N;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T, size_t N>
|
||||||
|
constexpr size_t StrLen(T(&)[N])
|
||||||
|
{
|
||||||
|
return N-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sum of all parameter pack sizeof
|
||||||
|
template <typename... Ts>
|
||||||
|
constexpr size_t size_of = 0;
|
||||||
|
|
||||||
|
template <typename T, typename... Ts>
|
||||||
|
constexpr size_t size_of<T, Ts...> = sizeof(T) + size_of<Ts...>;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,127 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) Nemirtingas
|
||||||
|
* This file is part of System.
|
||||||
|
*
|
||||||
|
* System is free software; you can redistribute it
|
||||||
|
* and/or modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* System 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
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with System; if not, see
|
||||||
|
* <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "System_internals.h"
|
||||||
|
|
||||||
|
#include "Encoding.hpp"
|
||||||
|
#include "utfcpp/utf8.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
namespace System {
|
||||||
|
namespace Encoding {
|
||||||
|
|
||||||
|
namespace details {
|
||||||
|
template<typename T, size_t s = sizeof(typename T::value_type)>
|
||||||
|
struct string_deducer
|
||||||
|
{
|
||||||
|
static std::string convert_string(T const& str) = delete;
|
||||||
|
static std::wstring convert_wstring(T const& str) = delete;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct string_deducer<T, 1>
|
||||||
|
{
|
||||||
|
static std::string convert_string(T const& str)
|
||||||
|
{
|
||||||
|
return std::string(std::begin(str), std::end(str));
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::wstring convert_wstring(std::string const& str)
|
||||||
|
{
|
||||||
|
std::wstring r(std::begin(str), std::end(str));
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct string_deducer<T, 2>
|
||||||
|
{
|
||||||
|
static std::string convert_string(T const& str)
|
||||||
|
{
|
||||||
|
std::string r;
|
||||||
|
utf8::utf16to8(std::begin(str), std::end(str), std::back_inserter(r));
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::wstring convert_wstring(std::string const& str)
|
||||||
|
{
|
||||||
|
std::wstring r;
|
||||||
|
utf8::utf8to16(std::begin(str), std::end(str), std::back_inserter(r));
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct string_deducer<T, 4>
|
||||||
|
{
|
||||||
|
static std::string convert_string(T const& str)
|
||||||
|
{
|
||||||
|
std::string r;
|
||||||
|
utf8::utf32to8(std::begin(str), std::end(str), std::back_inserter(r));
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::wstring convert_wstring(std::string const& str)
|
||||||
|
{
|
||||||
|
std::wstring r;
|
||||||
|
utf8::utf8to32(std::begin(str), std::end(str), std::back_inserter(r));
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::wstring Utf8ToWChar(std::string const& str)
|
||||||
|
{
|
||||||
|
return details::string_deducer<std::wstring>::convert_wstring(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::u16string Utf8ToUtf16(std::string const& str)
|
||||||
|
{
|
||||||
|
return utf8::utf8to16(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::u32string Utf8ToUtf32(std::string const& str)
|
||||||
|
{
|
||||||
|
return utf8::utf8to32(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string WCharToUtf8(std::wstring const& str)
|
||||||
|
{
|
||||||
|
return details::string_deducer<std::wstring>::convert_string(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Utf16ToUtf8(std::u16string const& str)
|
||||||
|
{
|
||||||
|
return utf8::utf16to8(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Utf32ToUtf8(std::u32string const& str)
|
||||||
|
{
|
||||||
|
return utf8::utf32to8(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t EncodedLength(std::string const& str)
|
||||||
|
{
|
||||||
|
return utf8::distance(str.begin(), str.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
}// namespace Encoding
|
||||||
|
}// namespace System
|
|
@ -0,0 +1,43 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) Nemirtingas
|
||||||
|
* This file is part of System.
|
||||||
|
*
|
||||||
|
* System is free software; you can redistribute it
|
||||||
|
* and/or modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* System 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
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with the System; if not, see
|
||||||
|
* <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace System {
|
||||||
|
namespace Encoding {
|
||||||
|
|
||||||
|
std::wstring Utf8ToWChar(std::string const& str);
|
||||||
|
|
||||||
|
std::u16string Utf8ToUtf16(std::string const& str);
|
||||||
|
|
||||||
|
std::u32string Utf8ToUtf32(std::string const& str);
|
||||||
|
|
||||||
|
std::string WCharToUtf8(std::wstring const& str);
|
||||||
|
|
||||||
|
std::string Utf16ToUtf8(std::u16string const& str);
|
||||||
|
|
||||||
|
std::string Utf32ToUtf8(std::u32string const& str);
|
||||||
|
|
||||||
|
// Size of UTF8 chars (not the size of the byte buffer).
|
||||||
|
size_t EncodedLength(std::string const& str);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,128 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) Nemirtingas
|
||||||
|
* This file is part of System.
|
||||||
|
*
|
||||||
|
* System is free software; you can redistribute it
|
||||||
|
* and/or modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* System 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
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with System; if not, see
|
||||||
|
* <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstddef> // size_t
|
||||||
|
#include <cstdint> // uint*_t
|
||||||
|
|
||||||
|
namespace System {
|
||||||
|
class Endian
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
template<typename T, size_t byte_count>
|
||||||
|
struct ByteSwapImpl
|
||||||
|
{
|
||||||
|
constexpr static inline T swap(T v)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < (byte_count/2); ++i)
|
||||||
|
{
|
||||||
|
uint8_t tmp = reinterpret_cast<uint8_t*>(&v)[i];
|
||||||
|
reinterpret_cast<uint8_t*>(&v)[i] = reinterpret_cast<uint8_t*>(&v)[byte_count - i - 1];
|
||||||
|
reinterpret_cast<uint8_t*>(&v)[byte_count - i - 1] = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct ByteSwapImpl<T, 1>
|
||||||
|
{
|
||||||
|
constexpr static inline T swap(T v) { return v; }
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct ByteSwapImpl<T, 2>
|
||||||
|
{
|
||||||
|
constexpr static inline T swap(T v)
|
||||||
|
{
|
||||||
|
uint16_t& tmp = *reinterpret_cast<uint16_t*>(&v);
|
||||||
|
tmp = ((tmp & 0x00ffu) << 8)
|
||||||
|
| ((tmp & 0xff00u) >> 8);
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct ByteSwapImpl<T, 4>
|
||||||
|
{
|
||||||
|
constexpr static inline T swap(T v)
|
||||||
|
{
|
||||||
|
uint32_t& tmp = *reinterpret_cast<uint32_t*>(&v);
|
||||||
|
tmp = ((tmp & 0x000000fful) << 24)
|
||||||
|
| ((tmp & 0x0000ff00ul) << 8)
|
||||||
|
| ((tmp & 0x00ff0000ul) >> 8)
|
||||||
|
| ((tmp & 0xff000000ul) >> 24);
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct ByteSwapImpl<T, 8>
|
||||||
|
{
|
||||||
|
constexpr static inline T swap(T v)
|
||||||
|
{
|
||||||
|
uint64_t& tmp = *reinterpret_cast<uint64_t*>(&v);
|
||||||
|
tmp = ((tmp & 0x00000000000000ffull) << 56)
|
||||||
|
| ((tmp & 0x000000000000ff00ull) << 40)
|
||||||
|
| ((tmp & 0x0000000000ff0000ull) << 24)
|
||||||
|
| ((tmp & 0x00000000ff000000ull) << 8)
|
||||||
|
| ((tmp & 0x000000ff00000000ull) >> 8)
|
||||||
|
| ((tmp & 0x0000ff0000000000ull) >> 24)
|
||||||
|
| ((tmp & 0x00ff000000000000ull) >> 40)
|
||||||
|
| ((tmp & 0xff00000000000000ull) >> 56);
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
static inline bool little()
|
||||||
|
{
|
||||||
|
const uint32_t endian_magic = 0x01020304;
|
||||||
|
return reinterpret_cast<const uint8_t*>(&endian_magic)[0] == 0x04;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool big()
|
||||||
|
{
|
||||||
|
const uint32_t endian_magic = 0x01020304;
|
||||||
|
return reinterpret_cast<const uint8_t*>(&endian_magic)[0] == 0x01;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T, size_t Size = sizeof(T)>
|
||||||
|
constexpr static inline T net_swap(T v)
|
||||||
|
{
|
||||||
|
if(Endian::little())
|
||||||
|
{
|
||||||
|
return ByteSwapImpl<T, Size>::swap(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T, size_t Size = sizeof(T)>
|
||||||
|
constexpr static inline T swap(T v)
|
||||||
|
{
|
||||||
|
return ByteSwapImpl<T, Size>::swap(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Endian() = delete;
|
||||||
|
};
|
||||||
|
}
|
|
@ -0,0 +1,562 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) Nemirtingas
|
||||||
|
* This file is part of System.
|
||||||
|
*
|
||||||
|
* System is free software; you can redistribute it
|
||||||
|
* and/or modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* System 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
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with System; if not, see
|
||||||
|
* <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "Filesystem.h"
|
||||||
|
#include "Encoding.hpp"
|
||||||
|
#include "System_internals.h"
|
||||||
|
|
||||||
|
#if defined(SYSTEM_OS_WINDOWS)
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#define VC_EXTRALEAN
|
||||||
|
#define NOMINMAX
|
||||||
|
#include <Windows.h>
|
||||||
|
|
||||||
|
#ifdef CreateDirectory
|
||||||
|
#undef CreateDirectory
|
||||||
|
#endif
|
||||||
|
#ifdef DeleteFile
|
||||||
|
#undef DeleteFile
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#elif defined(SYSTEM_OS_LINUX) || defined(SYSTEM_OS_APPLE)
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/ioctl.h> // get iface broadcast
|
||||||
|
#include <sys/stat.h> // stats on a file (is directory, size, mtime)
|
||||||
|
|
||||||
|
#include <dirent.h> // to open directories
|
||||||
|
#include <dlfcn.h> // dlopen (like dll for linux)
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <limits.h> // PATH_MAX
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#else
|
||||||
|
#error "unknown arch"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <fstream>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <iterator>
|
||||||
|
|
||||||
|
#include <ctime>
|
||||||
|
|
||||||
|
namespace System {
|
||||||
|
namespace Filesystem {
|
||||||
|
|
||||||
|
static void _CleanSlashes(std::string& str);
|
||||||
|
|
||||||
|
std::string Filename(std::string const& path)
|
||||||
|
{
|
||||||
|
size_t pos = path.find_last_of("/\\");
|
||||||
|
if (pos != std::string::npos)
|
||||||
|
return path.substr(pos+1);
|
||||||
|
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Dirname(std::string const& path)
|
||||||
|
{
|
||||||
|
std::string r(path);
|
||||||
|
_CleanSlashes(r);
|
||||||
|
size_t pos = r.find_last_of("/\\");
|
||||||
|
|
||||||
|
if (pos == std::string::npos || (pos == 0 && r.length() == 1))
|
||||||
|
return std::string();
|
||||||
|
|
||||||
|
if (pos == 0)
|
||||||
|
++pos;
|
||||||
|
|
||||||
|
return r.substr(0, pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Join(StringView r, StringView l)
|
||||||
|
{
|
||||||
|
std::string result(r.to_string());
|
||||||
|
|
||||||
|
result += Separator;
|
||||||
|
result += l.to_string();
|
||||||
|
|
||||||
|
_CleanSlashes(result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string CanonicalPath(std::string const& path)
|
||||||
|
{
|
||||||
|
if (IsAbsolute(path))
|
||||||
|
return CleanPath(path);
|
||||||
|
|
||||||
|
return CleanPath(Join(GetCwd(),path));
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t FileSize(std::string const& path)
|
||||||
|
{
|
||||||
|
std::ifstream in_file(path, std::ios::in | std::ios::binary | std::ios::ate);
|
||||||
|
if (in_file)
|
||||||
|
{
|
||||||
|
return in_file.tellg();
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::chrono::system_clock::time_point FileATime(std::string const& path)
|
||||||
|
{
|
||||||
|
struct stat file_stat = {};
|
||||||
|
if (stat(path.c_str(), &file_stat) != 0)
|
||||||
|
return std::chrono::system_clock::time_point{};
|
||||||
|
|
||||||
|
return std::chrono::system_clock::from_time_t(file_stat.st_atime);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::chrono::system_clock::time_point FileMTime(std::string const& path)
|
||||||
|
{
|
||||||
|
struct stat file_stat = {};
|
||||||
|
if (stat(path.c_str(), &file_stat) != 0)
|
||||||
|
return std::chrono::system_clock::time_point{};
|
||||||
|
|
||||||
|
return std::chrono::system_clock::from_time_t(file_stat.st_mtime);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::chrono::system_clock::time_point FileCTime(std::string const& path)
|
||||||
|
{
|
||||||
|
struct stat file_stat = {};
|
||||||
|
if (stat(path.c_str(), &file_stat) != 0)
|
||||||
|
return std::chrono::system_clock::time_point{};
|
||||||
|
|
||||||
|
return std::chrono::system_clock::from_time_t(file_stat.st_ctime);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef SYSTEM_OS_WINDOWS
|
||||||
|
|
||||||
|
static void _CleanSlashes(std::string& str)
|
||||||
|
{
|
||||||
|
size_t pos;
|
||||||
|
std::replace(str.begin(), str.end(), '/', '\\');
|
||||||
|
|
||||||
|
while ((pos = str.find("\\\\")) != std::string::npos)
|
||||||
|
str.replace(pos, 2, "\\");
|
||||||
|
|
||||||
|
pos = 0;
|
||||||
|
while ((pos = str.find("\\.", pos)) != std::string::npos)
|
||||||
|
{
|
||||||
|
if (str[pos + 2] == '\\' || (pos + 2) >= str.length())
|
||||||
|
{
|
||||||
|
str.replace(pos, 3, "\\");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
++pos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string GetCwd()
|
||||||
|
{
|
||||||
|
DWORD size = GetCurrentDirectoryW(0, nullptr);
|
||||||
|
if (size == 0)
|
||||||
|
return ".";
|
||||||
|
|
||||||
|
std::wstring wdirectory;
|
||||||
|
++size;
|
||||||
|
wdirectory.resize(size);
|
||||||
|
wdirectory.resize(GetCurrentDirectoryW(size, &wdirectory[0]));
|
||||||
|
wdirectory += L'\\';
|
||||||
|
|
||||||
|
return System::Encoding::WCharToUtf8(wdirectory);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsAbsolute(std::string const& path)
|
||||||
|
{
|
||||||
|
return path.length() >= 2 && (((path[0] >= 'a' && path[0] <= 'z') || (path[0] >= 'A' && path[0] <= 'Z')) && path[1] == ':');
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string CleanPath(std::string const& path)
|
||||||
|
{
|
||||||
|
std::string cleaned_path(path);
|
||||||
|
size_t pos;
|
||||||
|
size_t size;
|
||||||
|
|
||||||
|
_CleanSlashes(cleaned_path);
|
||||||
|
|
||||||
|
pos = 0;
|
||||||
|
while ((pos = cleaned_path.find("\\..", pos)) != std::string::npos )
|
||||||
|
{
|
||||||
|
if (cleaned_path[pos + 3] == '\\' || (pos+3) >= cleaned_path.length())
|
||||||
|
{
|
||||||
|
if (pos == 0)
|
||||||
|
size = 3;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
size_t parent_pos = cleaned_path.rfind("\\", pos - 1);
|
||||||
|
if (parent_pos == std::string::npos)
|
||||||
|
{
|
||||||
|
size = pos + 3;
|
||||||
|
pos = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
size = 3 + pos - parent_pos;
|
||||||
|
pos = parent_pos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cleaned_path.replace(pos, size, "");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
++pos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return cleaned_path;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsDir(std::string const& path)
|
||||||
|
{
|
||||||
|
std::wstring wpath(System::Encoding::Utf8ToWChar(path));
|
||||||
|
|
||||||
|
DWORD attrs = GetFileAttributesW(wpath.c_str());
|
||||||
|
return attrs != INVALID_FILE_ATTRIBUTES && attrs & FILE_ATTRIBUTE_DIRECTORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsFile(std::string const& path)
|
||||||
|
{
|
||||||
|
std::wstring wpath(System::Encoding::Utf8ToWChar(path));
|
||||||
|
|
||||||
|
DWORD attrs = GetFileAttributesW(wpath.c_str());
|
||||||
|
return attrs != INVALID_FILE_ATTRIBUTES && ((attrs & FILE_ATTRIBUTE_DIRECTORY) != FILE_ATTRIBUTE_DIRECTORY);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Exists(std::string const& path)
|
||||||
|
{
|
||||||
|
std::wstring wpath(System::Encoding::Utf8ToWChar(path));
|
||||||
|
|
||||||
|
DWORD attrs = GetFileAttributesW(wpath.c_str());
|
||||||
|
return attrs != INVALID_FILE_ATTRIBUTES;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CreateDirectory(std::string const& directory, bool recursive)
|
||||||
|
{
|
||||||
|
size_t pos = 0;
|
||||||
|
struct _stat sb;
|
||||||
|
|
||||||
|
std::wstring sub_dir;
|
||||||
|
std::wstring wdirectory(System::Encoding::Utf8ToWChar(directory));
|
||||||
|
|
||||||
|
if (wdirectory.empty())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (recursive)
|
||||||
|
{
|
||||||
|
pos = 3;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
pos = wdirectory.find_first_of(L"\\/", pos + 1);
|
||||||
|
sub_dir = std::move(wdirectory.substr(0, pos));
|
||||||
|
if (_wstat(sub_dir.c_str(), &sb) == 0)
|
||||||
|
{
|
||||||
|
if (!(sb.st_mode & _S_IFDIR))
|
||||||
|
{// A subpath in the target is not a directory
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Folder Exists
|
||||||
|
}
|
||||||
|
else if (CreateDirectoryW(wdirectory.substr(0, pos).c_str(), NULL) == FALSE && GetLastError() != ERROR_ALREADY_EXISTS)
|
||||||
|
{// Failed to create directory
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (pos != std::string::npos);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (CreateDirectoryW(wdirectory.c_str(), NULL) != FALSE || GetLastError() == ERROR_ALREADY_EXISTS);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DeleteFile(std::string const& path)
|
||||||
|
{
|
||||||
|
std::wstring wpath(System::Encoding::Utf8ToWChar(path));
|
||||||
|
return DeleteFileW(wpath.c_str()) == TRUE || GetLastError() == ERROR_FILE_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::vector<std::wstring> ListFiles(std::wstring const& path, bool files_only, bool recursive)
|
||||||
|
{
|
||||||
|
std::vector<std::wstring> files;
|
||||||
|
WIN32_FIND_DATAW hfind_data;
|
||||||
|
HANDLE hfind = INVALID_HANDLE_VALUE;
|
||||||
|
|
||||||
|
std::wstring search_path = path;
|
||||||
|
|
||||||
|
if (*path.rbegin() != L'\\')
|
||||||
|
search_path += L'\\';
|
||||||
|
|
||||||
|
search_path += L'*';
|
||||||
|
|
||||||
|
// Start iterating over the files in the path directory.
|
||||||
|
hfind = FindFirstFileW(search_path.c_str(), &hfind_data);
|
||||||
|
if (hfind != INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
search_path.pop_back();
|
||||||
|
do // Managed to locate and create an handle to that folder.
|
||||||
|
{
|
||||||
|
if (wcscmp(L".", hfind_data.cFileName) == 0
|
||||||
|
|| wcscmp(L"..", hfind_data.cFileName) == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (hfind_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
||||||
|
{
|
||||||
|
if (recursive)
|
||||||
|
{
|
||||||
|
std::wstring dir_name = hfind_data.cFileName;
|
||||||
|
|
||||||
|
std::vector<std::wstring> sub_files = std::move(ListFiles(search_path + dir_name, files_only, true));
|
||||||
|
std::transform(sub_files.begin(), sub_files.end(), std::back_inserter(files), [&dir_name](std::wstring& Filename)
|
||||||
|
{
|
||||||
|
return dir_name + L'\\' + Filename;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (!files_only)
|
||||||
|
{
|
||||||
|
files.emplace_back(hfind_data.cFileName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
files.emplace_back(hfind_data.cFileName);
|
||||||
|
}
|
||||||
|
} while (FindNextFileW(hfind, &hfind_data) == TRUE);
|
||||||
|
FindClose(hfind);
|
||||||
|
}
|
||||||
|
|
||||||
|
return files;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> ListFiles(std::string const& path, bool files_only, bool recursive)
|
||||||
|
{
|
||||||
|
std::vector<std::string> files;
|
||||||
|
std::wstring wpath(System::Encoding::Utf8ToWChar(path));
|
||||||
|
|
||||||
|
std::vector<std::wstring> wfiles(std::move(ListFiles(wpath, files_only, recursive)));
|
||||||
|
|
||||||
|
files.reserve(wfiles.size());
|
||||||
|
std::transform(wfiles.begin(), wfiles.end(), std::back_inserter(files), [](std::wstring const& wFilename)
|
||||||
|
{
|
||||||
|
return System::Encoding::WCharToUtf8(wFilename);
|
||||||
|
});
|
||||||
|
|
||||||
|
return files;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
static void _CleanSlashes(std::string& str)
|
||||||
|
{
|
||||||
|
size_t pos;
|
||||||
|
std::replace(str.begin(), str.end(), '\\', '/');
|
||||||
|
|
||||||
|
while ((pos = str.find("//")) != std::string::npos)
|
||||||
|
str.replace(pos, 2, "/");
|
||||||
|
|
||||||
|
pos = 0;
|
||||||
|
while ((pos = str.find("/.", pos)) != std::string::npos)
|
||||||
|
{
|
||||||
|
if (str[pos + 2] == '/' || (pos + 2) >= str.length())
|
||||||
|
{
|
||||||
|
str.replace(pos, 3, "/");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
++pos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string GetCwd()
|
||||||
|
{
|
||||||
|
char buff[4096];
|
||||||
|
std::string tmp(getcwd(buff, 4096) == nullptr ? "." : buff);
|
||||||
|
|
||||||
|
tmp += '/';
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsAbsolute(std::string const& path)
|
||||||
|
{
|
||||||
|
return path[0] == '/';
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string CleanPath(std::string const& path)
|
||||||
|
{
|
||||||
|
std::string cleaned_path(path);
|
||||||
|
size_t pos;
|
||||||
|
size_t size;
|
||||||
|
|
||||||
|
std::replace(cleaned_path.begin(), cleaned_path.end(), '\\', '/');
|
||||||
|
|
||||||
|
_CleanSlashes(cleaned_path);
|
||||||
|
|
||||||
|
pos = 0;
|
||||||
|
while ((pos = cleaned_path.find("/..", pos)) != std::string::npos)
|
||||||
|
{
|
||||||
|
if (cleaned_path[pos + 3] == '/' || (pos + 3) >= cleaned_path.length())
|
||||||
|
{
|
||||||
|
if (pos == 0)
|
||||||
|
size = 3;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
size_t parent_pos = cleaned_path.rfind("/", pos - 1);
|
||||||
|
if (parent_pos == std::string::npos)
|
||||||
|
{
|
||||||
|
size = pos + 3;
|
||||||
|
pos = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
size = 3 + pos - parent_pos;
|
||||||
|
pos = parent_pos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cleaned_path.replace(pos, size, "");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
++pos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return cleaned_path;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsDir(std::string const& path)
|
||||||
|
{
|
||||||
|
struct stat sb;
|
||||||
|
if (stat(path.c_str(), &sb) == 0)
|
||||||
|
{
|
||||||
|
return S_ISDIR(sb.st_mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsFile(std::string const& path)
|
||||||
|
{
|
||||||
|
struct stat sb;
|
||||||
|
if (stat(path.c_str(), &sb) == 0)
|
||||||
|
{
|
||||||
|
return S_ISREG(sb.st_mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Exists(std::string const& path)
|
||||||
|
{
|
||||||
|
struct stat sb;
|
||||||
|
return stat(path.c_str(), &sb) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CreateDirectory(std::string const& directory, bool recursive)
|
||||||
|
{
|
||||||
|
size_t pos = 0;
|
||||||
|
struct stat sb;
|
||||||
|
|
||||||
|
std::string sub_dir;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
pos = directory.find("/", pos + 1);
|
||||||
|
sub_dir = std::move(directory.substr(0, pos));
|
||||||
|
if (stat(sub_dir.c_str(), &sb) == 0)
|
||||||
|
{
|
||||||
|
if (!S_ISDIR(sb.st_mode))
|
||||||
|
{// A subpath in the target is not a directory
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Folder Exists
|
||||||
|
}
|
||||||
|
else if (mkdir(sub_dir.c_str(), 0755) < 0 && errno != EEXIST)
|
||||||
|
{// Failed to create directory (no permission?)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (pos != std::string::npos);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DeleteFile(std::string const& path)
|
||||||
|
{
|
||||||
|
return unlink(path.c_str()) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> ListFiles(std::string const& path, bool files_only, bool recursive)
|
||||||
|
{
|
||||||
|
std::vector<std::string> files;
|
||||||
|
|
||||||
|
std::string search_path = path;
|
||||||
|
|
||||||
|
if (*path.rbegin() != Separator)
|
||||||
|
search_path += Separator;
|
||||||
|
|
||||||
|
DIR* dir = opendir(search_path.c_str());
|
||||||
|
struct dirent* entry;
|
||||||
|
|
||||||
|
if (dir == nullptr)
|
||||||
|
return files;
|
||||||
|
|
||||||
|
while ((entry = readdir(dir)) != nullptr)
|
||||||
|
{
|
||||||
|
if (strcmp(entry->d_name, ".") == 0
|
||||||
|
|| strcmp(entry->d_name, "..") == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (entry->d_type == DT_DIR)
|
||||||
|
{
|
||||||
|
if (recursive)
|
||||||
|
{
|
||||||
|
std::string dir_name = entry->d_name;
|
||||||
|
std::vector<std::string> sub_files = std::move(ListFiles(search_path + dir_name, true));
|
||||||
|
std::transform(sub_files.begin(), sub_files.end(), std::back_inserter(files), [&dir_name](std::string& Filename)
|
||||||
|
{
|
||||||
|
return dir_name + Separator + Filename;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (!files_only)
|
||||||
|
{
|
||||||
|
files.emplace_back(entry->d_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (entry->d_type == DT_REG)
|
||||||
|
{
|
||||||
|
files.emplace_back(entry->d_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
closedir(dir);
|
||||||
|
|
||||||
|
return files;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,77 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) Nemirtingas
|
||||||
|
* This file is part of System.
|
||||||
|
*
|
||||||
|
* System is free software; you can redistribute it
|
||||||
|
* and/or modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* System 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
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with System; if not, see
|
||||||
|
* <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
|
#include "StringView.hpp"
|
||||||
|
|
||||||
|
#ifdef CreateDirectory
|
||||||
|
#undef CreateDirectory
|
||||||
|
#endif
|
||||||
|
#ifdef DeleteFile
|
||||||
|
#undef DeleteFile
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace System {
|
||||||
|
namespace Filesystem {
|
||||||
|
|
||||||
|
constexpr static char WindowsSeparator = '\\';
|
||||||
|
constexpr static char UnixSeparator = '/';
|
||||||
|
|
||||||
|
#if defined(WIN64) || defined(_WIN64) || defined(__MINGW64__) || defined(WIN32) || defined(_WIN32) || defined(__MINGW32__)
|
||||||
|
constexpr static char Separator = WindowsSeparator;
|
||||||
|
#else
|
||||||
|
constexpr static char Separator = UnixSeparator;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
std::string CleanPath(std::string const& path);
|
||||||
|
std::string Filename(std::string const& path);
|
||||||
|
std::string Dirname(std::string const& path);
|
||||||
|
bool IsAbsolute(std::string const& path);
|
||||||
|
|
||||||
|
inline std::string Join(StringView s) { return s.to_string(); }
|
||||||
|
std::string Join(StringView r, StringView l);
|
||||||
|
|
||||||
|
template<typename ...Args>
|
||||||
|
std::string Join(StringView path, Args&& ...args)
|
||||||
|
{
|
||||||
|
return Join(path, StringView(Join(args...)));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string GetCwd();
|
||||||
|
std::string CanonicalPath(std::string const& path);
|
||||||
|
|
||||||
|
bool IsDir(std::string const& path);
|
||||||
|
bool IsFile(std::string const& path);
|
||||||
|
bool Exists(std::string const& path);
|
||||||
|
size_t FileSize(std::string const& path);
|
||||||
|
std::chrono::system_clock::time_point FileATime(std::string const& path);
|
||||||
|
std::chrono::system_clock::time_point FileMTime(std::string const& path);
|
||||||
|
std::chrono::system_clock::time_point FileCTime(std::string const& path);
|
||||||
|
|
||||||
|
bool CreateDirectory(std::string const& folder, bool recursive = true);
|
||||||
|
bool DeleteFile(std::string const& path);
|
||||||
|
std::vector<std::string> ListFiles(std::string const& path, bool files_only, bool recursive = false);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,418 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) Nemirtingas
|
||||||
|
* This file is part of System.
|
||||||
|
*
|
||||||
|
* System is free software; you can redistribute it
|
||||||
|
* and/or modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* System 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
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with System; if not, see
|
||||||
|
* <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "Library.h"
|
||||||
|
#include "Encoding.hpp"
|
||||||
|
#include "System_internals.h"
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#if defined(SYSTEM_OS_WINDOWS)
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#define VC_EXTRALEAN
|
||||||
|
#define NOMINMAX
|
||||||
|
#include <Windows.h>
|
||||||
|
|
||||||
|
constexpr char library_suffix[] = ".dll";
|
||||||
|
|
||||||
|
#elif defined(SYSTEM_OS_LINUX) || defined(SYSTEM_OS_APPLE)
|
||||||
|
#include <dlfcn.h>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
#if defined(SYSTEM_OS_LINUX)
|
||||||
|
#include <dirent.h> // to open directories
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
constexpr char library_suffix[] = ".so";
|
||||||
|
#else
|
||||||
|
#include <mach-o/dyld_images.h>
|
||||||
|
|
||||||
|
constexpr char library_suffix[] = ".dylib";
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace System {
|
||||||
|
|
||||||
|
namespace Library {
|
||||||
|
|
||||||
|
#if defined(SYSTEM_OS_WINDOWS)
|
||||||
|
|
||||||
|
void* OpenLibrary(const char* library_name)
|
||||||
|
{
|
||||||
|
if (library_name == nullptr)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
std::wstring wide(System::Encoding::Utf8ToWChar(library_name));
|
||||||
|
return LoadLibraryW(wide.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void CloseLibrary(void* handle)
|
||||||
|
{
|
||||||
|
if(handle != nullptr)
|
||||||
|
FreeLibrary((HMODULE)handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
void* GetSymbol(void* handle, const char* symbol_name)
|
||||||
|
{
|
||||||
|
if (symbol_name == nullptr)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
return GetProcAddress((HMODULE)handle, symbol_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void* GetLibraryHandle(const char* library_name)
|
||||||
|
{
|
||||||
|
if (library_name == nullptr)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
std::wstring wide(System::Encoding::Utf8ToWChar(library_name));
|
||||||
|
return GetModuleHandleW(wide.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string GetLibraryPath(void* handle)
|
||||||
|
{
|
||||||
|
if (handle == nullptr)
|
||||||
|
return std::string();
|
||||||
|
|
||||||
|
std::wstring wpath(1024, L'\0');
|
||||||
|
|
||||||
|
DWORD size;
|
||||||
|
while ((size = GetModuleFileNameW((HMODULE)handle, &wpath[0], wpath.length())) == wpath.length())
|
||||||
|
{
|
||||||
|
wpath.resize(wpath.length() * 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
wpath.resize(size);
|
||||||
|
return System::Encoding::WCharToUtf8(wpath);
|
||||||
|
}
|
||||||
|
|
||||||
|
#elif defined(SYSTEM_OS_LINUX) || defined(SYSTEM_OS_APPLE)
|
||||||
|
|
||||||
|
void* OpenLibrary(const char* library_name)
|
||||||
|
{
|
||||||
|
if (library_name == nullptr)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
return dlopen(library_name, RTLD_NOW);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CloseLibrary(void* handle)
|
||||||
|
{
|
||||||
|
if(handle != nullptr)
|
||||||
|
dlclose(handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
void* GetSymbol(void* handle, const char* symbol_name)
|
||||||
|
{
|
||||||
|
if (handle == nullptr)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
return dlsym(handle, symbol_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(SYSTEM_OS_LINUX)
|
||||||
|
std::string GetLibraryPath(void* handle)
|
||||||
|
{
|
||||||
|
if (handle == nullptr)
|
||||||
|
return std::string();
|
||||||
|
|
||||||
|
std::string const self("/proc/self/map_files/");
|
||||||
|
DIR* dir;
|
||||||
|
struct dirent* dir_entry;
|
||||||
|
std::string file_path;
|
||||||
|
std::string res;
|
||||||
|
|
||||||
|
dir = opendir(self.c_str());
|
||||||
|
if (dir != nullptr)
|
||||||
|
{
|
||||||
|
while ((dir_entry = readdir(dir)) != nullptr)
|
||||||
|
{
|
||||||
|
file_path = (self + dir_entry->d_name);
|
||||||
|
if (dir_entry->d_type != DT_LNK)
|
||||||
|
{// Not a link
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
file_path = System::ExpandSymlink(file_path);
|
||||||
|
|
||||||
|
void* lib_handle = dlopen(file_path.c_str(), RTLD_NOW);
|
||||||
|
if (lib_handle != nullptr)
|
||||||
|
{// Don't increment ref_counter.
|
||||||
|
dlclose(lib_handle);
|
||||||
|
if (handle == lib_handle)
|
||||||
|
{
|
||||||
|
res = std::move(file_path);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
closedir(dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* GetLibraryHandle(const char* library_name)
|
||||||
|
{
|
||||||
|
if (library_name == nullptr)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
std::string const self("/proc/self/map_files/");
|
||||||
|
DIR* dir;
|
||||||
|
struct dirent* dir_entry;
|
||||||
|
void* res = nullptr;
|
||||||
|
size_t library_name_len = strlen(library_name);
|
||||||
|
|
||||||
|
dir = opendir(self.c_str());
|
||||||
|
if (dir != nullptr)
|
||||||
|
{
|
||||||
|
std::string file_path;
|
||||||
|
while ((dir_entry = readdir(dir)) != nullptr)
|
||||||
|
{
|
||||||
|
file_path = (self + dir_entry->d_name);
|
||||||
|
if (dir_entry->d_type != DT_LNK)
|
||||||
|
{// Not a link
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
file_path = System::ExpandSymlink(file_path);
|
||||||
|
|
||||||
|
auto pos = file_path.rfind('/');
|
||||||
|
if (pos != std::string::npos)
|
||||||
|
{
|
||||||
|
++pos;
|
||||||
|
if (strncmp(file_path.c_str() + pos, library_name, library_name_len) == 0)
|
||||||
|
{
|
||||||
|
res = dlopen(file_path.c_str(), RTLD_NOW);
|
||||||
|
if (res != nullptr)
|
||||||
|
{// Like Windows' GetModuleHandle, we don't want to increment the ref counter
|
||||||
|
dlclose(res);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
closedir(dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
|
||||||
|
std::string GetLibraryPath(void* handle)
|
||||||
|
{
|
||||||
|
if (handle == nullptr)
|
||||||
|
return std::string();
|
||||||
|
|
||||||
|
task_dyld_info dyld_info;
|
||||||
|
task_t t;
|
||||||
|
pid_t pid = getpid();
|
||||||
|
task_for_pid(mach_task_self(), pid, &t);
|
||||||
|
mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT;
|
||||||
|
|
||||||
|
if (task_info(t, TASK_DYLD_INFO, reinterpret_cast<task_info_t>(&dyld_info), &count) == KERN_SUCCESS)
|
||||||
|
{
|
||||||
|
dyld_all_image_infos* dyld_img_infos = reinterpret_cast<dyld_all_image_infos*>(dyld_info.all_image_info_addr);
|
||||||
|
for (int i = 0; i < dyld_img_infos->infoArrayCount; ++i)
|
||||||
|
{
|
||||||
|
void* res = dlopen(dyld_img_infos->infoArray[i].imageFilePath, RTLD_NOW);
|
||||||
|
if (res != nullptr)
|
||||||
|
{
|
||||||
|
dlclose(res);
|
||||||
|
if(res == handle)
|
||||||
|
return std::string(dyld_img_infos->infoArray[i].imageFilePath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::string();
|
||||||
|
}
|
||||||
|
|
||||||
|
void* GetLibraryHandle(const char* library_name)
|
||||||
|
{
|
||||||
|
if (library_name == nullptr)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
void* res = nullptr;
|
||||||
|
|
||||||
|
size_t library_name_len = strlen(library_name);
|
||||||
|
|
||||||
|
task_dyld_info dyld_info;
|
||||||
|
task_t t;
|
||||||
|
pid_t pid = getpid();
|
||||||
|
task_for_pid(mach_task_self(), pid, &t);
|
||||||
|
mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT;
|
||||||
|
|
||||||
|
if (task_info(t, TASK_DYLD_INFO, reinterpret_cast<task_info_t>(&dyld_info), &count) == KERN_SUCCESS)
|
||||||
|
{
|
||||||
|
const char* pos;
|
||||||
|
dyld_all_image_infos* dyld_img_infos = reinterpret_cast<dyld_all_image_infos*>(dyld_info.all_image_info_addr);
|
||||||
|
for (int i = 0; i < dyld_img_infos->infoArrayCount; ++i)
|
||||||
|
{
|
||||||
|
pos = strrchr(dyld_img_infos->infoArray[i].imageFilePath, '/');
|
||||||
|
if (pos != nullptr)
|
||||||
|
{
|
||||||
|
++pos;
|
||||||
|
if (strncmp(pos, library_name, library_name_len) == 0)
|
||||||
|
{
|
||||||
|
res = dlopen(dyld_img_infos->infoArray[i].imageFilePath, RTLD_NOW);
|
||||||
|
if (res != nullptr)
|
||||||
|
{// Like Windows' GetModuleHandle, we don't want to increment the ref counter
|
||||||
|
dlclose(res);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
std::string GetLibraryExtension()
|
||||||
|
{
|
||||||
|
return std::string{ library_suffix };
|
||||||
|
}
|
||||||
|
|
||||||
|
class LibraryImpl
|
||||||
|
{
|
||||||
|
std::shared_ptr<void> _Handle;
|
||||||
|
|
||||||
|
struct LibraryHandleDestructor
|
||||||
|
{
|
||||||
|
void operator()(void* h)
|
||||||
|
{
|
||||||
|
System::Library::CloseLibrary(h);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
inline bool OpenLibrary(std::string const& library_name, bool append_extension)
|
||||||
|
{
|
||||||
|
std::string lib_name = (append_extension ? library_name + library_suffix : library_name);
|
||||||
|
|
||||||
|
void* lib = System::Library::OpenLibrary(lib_name.c_str());
|
||||||
|
|
||||||
|
if (lib == nullptr)
|
||||||
|
{
|
||||||
|
lib_name = "lib" + lib_name;
|
||||||
|
lib = System::Library::OpenLibrary(lib_name.c_str());
|
||||||
|
|
||||||
|
if (lib == nullptr)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
_Handle = std::shared_ptr<void>(lib, LibraryHandleDestructor());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void CloseLibrary()
|
||||||
|
{
|
||||||
|
_Handle.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void* GetVSymbol(std::string const& symbol_name) const
|
||||||
|
{
|
||||||
|
return System::Library::GetSymbol(_Handle.get(), symbol_name.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::string GetLibraryPath() const
|
||||||
|
{
|
||||||
|
return System::Library::GetLibraryPath(_Handle.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void* GetLibraryNativeHandle() const
|
||||||
|
{
|
||||||
|
return _Handle.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool IsLoaded() const
|
||||||
|
{
|
||||||
|
return _Handle != nullptr;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Library::Library():
|
||||||
|
_Impl(new LibraryImpl)
|
||||||
|
{}
|
||||||
|
|
||||||
|
Library::Library(Library const& other):
|
||||||
|
_Impl(new LibraryImpl(*other._Impl))
|
||||||
|
{}
|
||||||
|
|
||||||
|
Library::Library(Library&& other) noexcept:
|
||||||
|
_Impl(other._Impl)
|
||||||
|
{
|
||||||
|
other._Impl = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Library& Library::operator=(Library const& other)
|
||||||
|
{
|
||||||
|
*_Impl = *other._Impl;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Library& Library::operator=(Library&& other) noexcept
|
||||||
|
{
|
||||||
|
std::swap(_Impl, other._Impl);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Library::~Library()
|
||||||
|
{
|
||||||
|
delete _Impl; _Impl = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Library::OpenLibrary(std::string const& library_name, bool append_extension)
|
||||||
|
{
|
||||||
|
return _Impl->OpenLibrary(library_name, append_extension);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Library::CloseLibrary()
|
||||||
|
{
|
||||||
|
_Impl->CloseLibrary();
|
||||||
|
}
|
||||||
|
|
||||||
|
void* Library::GetVSymbol(std::string const& symbol_name) const
|
||||||
|
{
|
||||||
|
return _Impl->GetVSymbol(symbol_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Library::GetLibraryPath() const
|
||||||
|
{
|
||||||
|
return _Impl->GetLibraryPath();
|
||||||
|
}
|
||||||
|
|
||||||
|
void* Library::GetLibraryNativeHandle() const
|
||||||
|
{
|
||||||
|
return _Impl->GetLibraryNativeHandle();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Library::IsLoaded() const
|
||||||
|
{
|
||||||
|
return _Impl->IsLoaded();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,80 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) Nemirtingas
|
||||||
|
* This file is part of System.
|
||||||
|
*
|
||||||
|
* System is free software; you can redistribute it
|
||||||
|
* and/or modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* System 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
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with System; if not, see
|
||||||
|
* <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace System {
|
||||||
|
|
||||||
|
namespace Library {
|
||||||
|
|
||||||
|
class Library
|
||||||
|
{
|
||||||
|
class LibraryImpl* _Impl;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Library();
|
||||||
|
|
||||||
|
Library(Library const& other);
|
||||||
|
|
||||||
|
Library(Library&& other) noexcept;
|
||||||
|
|
||||||
|
Library& operator=(Library const& other);
|
||||||
|
|
||||||
|
Library& operator=(Library&& other) noexcept;
|
||||||
|
|
||||||
|
~Library();
|
||||||
|
|
||||||
|
bool OpenLibrary(std::string const& library_name, bool append_extension);
|
||||||
|
|
||||||
|
void CloseLibrary();
|
||||||
|
|
||||||
|
void* GetVSymbol(std::string const& symbol_name) const;
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
inline T* GetSymbol(std::string const& symbol_name) const
|
||||||
|
{
|
||||||
|
return reinterpret_cast<T*>(GetVSymbol(symbol_name));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string GetLibraryPath() const;
|
||||||
|
|
||||||
|
void* GetLibraryNativeHandle() const;
|
||||||
|
|
||||||
|
bool IsLoaded() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Triies to load the library, I suggest that you use a Library instance instead
|
||||||
|
void* OpenLibrary(const char* library_name);
|
||||||
|
// Will decrease the OS' ref counter on the library, use it to close a handle opened by open_library.
|
||||||
|
// A Library instance will automatically call this in the destructor
|
||||||
|
void CloseLibrary(void* handle);
|
||||||
|
// Will try to retrieve a symbol address from the library handle
|
||||||
|
void* GetSymbol(void* handle, const char* symbol_name);
|
||||||
|
// Get a pointer to the library, if it is not loaded, will return nullptr. This doesn't increment the OS' internal ref counter
|
||||||
|
void* GetLibraryHandle(const char* library_name);
|
||||||
|
// Get the library path of a module handle
|
||||||
|
std::string GetLibraryPath(void* handle);
|
||||||
|
// Get the native extension representing a shared library.
|
||||||
|
std::string GetLibraryExtension();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,96 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) Nemirtingas
|
||||||
|
* This file is part of System.
|
||||||
|
*
|
||||||
|
* System is free software; you can redistribute it
|
||||||
|
* and/or modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* System 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
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with System; if not, see
|
||||||
|
* <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <tuple>
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
|
namespace System {
|
||||||
|
|
||||||
|
class scoped_lock {
|
||||||
|
struct value_holder
|
||||||
|
{
|
||||||
|
virtual ~value_holder() noexcept {}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename... Args>
|
||||||
|
struct templated_value_holder : value_holder
|
||||||
|
{
|
||||||
|
template<std::size_t I = 0, typename... Tp>
|
||||||
|
inline typename std::enable_if<I == sizeof...(Tp), void>::type unlock(std::tuple<Tp...>& t) { }
|
||||||
|
|
||||||
|
template<std::size_t I = 0, typename... Tp>
|
||||||
|
inline typename std::enable_if<I < sizeof...(Tp), void>::type unlock(std::tuple<Tp...>& t)
|
||||||
|
{
|
||||||
|
std::get<I>(t).unlock();
|
||||||
|
unlock<I + 1, Tp...>(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
explicit templated_value_holder(Args&... mutexes) : _mutexes(mutexes...) { std::lock(mutexes...); }
|
||||||
|
explicit templated_value_holder(std::adopt_lock_t, Args&... mutexes) : _mutexes(mutexes...) {} // construct but don't lock
|
||||||
|
|
||||||
|
virtual ~templated_value_holder() noexcept { unlock(_mutexes); }
|
||||||
|
|
||||||
|
std::tuple<Args&...> _mutexes;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename Arg>
|
||||||
|
struct templated_value_holder<Arg> : value_holder
|
||||||
|
{
|
||||||
|
explicit templated_value_holder(Arg& mutex) : _mutex(mutex) { _mutex.lock(); }
|
||||||
|
explicit templated_value_holder(std::adopt_lock_t, Arg& mutex) : _mutex(mutex) {} // construct but don't lock
|
||||||
|
|
||||||
|
virtual ~templated_value_holder() noexcept { _mutex.unlock(); }
|
||||||
|
|
||||||
|
Arg& _mutex;
|
||||||
|
};
|
||||||
|
|
||||||
|
value_holder* _val;
|
||||||
|
|
||||||
|
public:
|
||||||
|
template<typename... Args>
|
||||||
|
explicit scoped_lock(Args&... mutexes) : _val(new templated_value_holder<Args&...>(mutexes...)) { }
|
||||||
|
|
||||||
|
template<typename... Args>
|
||||||
|
explicit scoped_lock(std::adopt_lock_t, Args&... mutexes) : _val(new templated_value_holder<Args&...>(std::adopt_lock, mutexes...)) { }
|
||||||
|
|
||||||
|
explicit scoped_lock(scoped_lock && other):
|
||||||
|
_val(other._val)
|
||||||
|
{
|
||||||
|
other._val = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
scoped_lock() noexcept:
|
||||||
|
_val(nullptr)
|
||||||
|
{}
|
||||||
|
~scoped_lock() noexcept { delete _val; }
|
||||||
|
|
||||||
|
scoped_lock& operator=(scoped_lock && other)
|
||||||
|
{
|
||||||
|
_val = other._val;
|
||||||
|
other._val = nullptr;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
scoped_lock(const scoped_lock&) = delete;
|
||||||
|
scoped_lock& operator=(const scoped_lock&) = delete;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,89 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) Nemirtingas
|
||||||
|
* This file is part of System.
|
||||||
|
*
|
||||||
|
* System is free software; you can redistribute it
|
||||||
|
* and/or modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* System 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
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with System; if not, see
|
||||||
|
* <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "System_internals.h"
|
||||||
|
|
||||||
|
#include "String.hpp"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cctype>
|
||||||
|
|
||||||
|
namespace System {
|
||||||
|
namespace String {
|
||||||
|
namespace details {
|
||||||
|
|
||||||
|
void LeftTrim(std::string& str)
|
||||||
|
{
|
||||||
|
str.erase(str.begin(), std::find_if(str.begin(), str.end(), [](const char c)
|
||||||
|
{
|
||||||
|
return !std::isspace((unsigned char)c);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
void RightTrim(std::string& str)
|
||||||
|
{
|
||||||
|
str.erase(std::find_if(str.rbegin(), str.rend(), [](const char c)
|
||||||
|
{
|
||||||
|
return !std::isspace((unsigned char)c);
|
||||||
|
}).base(), str.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
void ToUpper(char* str, size_t len)
|
||||||
|
{
|
||||||
|
while(len--)
|
||||||
|
{
|
||||||
|
unsigned char c = (unsigned char)*str;
|
||||||
|
*str++ = std::toupper(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ToLower(char* str, size_t len)
|
||||||
|
{
|
||||||
|
while (len--)
|
||||||
|
{
|
||||||
|
unsigned char c = (unsigned char)*str;
|
||||||
|
*str++ = std::tolower(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
char* CloneString(System::StringView src)
|
||||||
|
{
|
||||||
|
size_t len = src.length() + 1;
|
||||||
|
char* res = new char[len];
|
||||||
|
memcpy(res, src.data(), len);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t CopyString(System::StringView src, char* dst, size_t dst_size)
|
||||||
|
{
|
||||||
|
size_t written = 0;
|
||||||
|
if (dst != nullptr && dst_size > 0)
|
||||||
|
{
|
||||||
|
written = src.length() > dst_size ? dst_size - 1 : src.length();
|
||||||
|
memcpy(dst, src.data(), written);
|
||||||
|
dst[written] = '\0';
|
||||||
|
}
|
||||||
|
return written;
|
||||||
|
}
|
||||||
|
|
||||||
|
}// namespace details
|
||||||
|
|
||||||
|
}// namespace String
|
||||||
|
}// namespace System
|
|
@ -0,0 +1,290 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) Nemirtingas
|
||||||
|
* This file is part of System.
|
||||||
|
*
|
||||||
|
* System is free software; you can redistribute it
|
||||||
|
* and/or modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* System 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
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with the System; if not, see
|
||||||
|
* <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <cstring>
|
||||||
|
#include <iterator>
|
||||||
|
|
||||||
|
#include "StringView.hpp"
|
||||||
|
#include "StringSwitch.hpp"
|
||||||
|
|
||||||
|
namespace System {
|
||||||
|
namespace String {
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////
|
||||||
|
// Implementations
|
||||||
|
|
||||||
|
namespace details {
|
||||||
|
void LeftTrim(std::string& str);
|
||||||
|
|
||||||
|
void RightTrim(std::string& str);
|
||||||
|
|
||||||
|
void ToUpper(char* str, size_t len);
|
||||||
|
|
||||||
|
void ToLower(char* str, size_t len);
|
||||||
|
|
||||||
|
char* CloneString(System::StringView src);
|
||||||
|
|
||||||
|
size_t CopyString(System::StringView src, char *dst, size_t dst_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline void LeftTrim(std::string& str)
|
||||||
|
{
|
||||||
|
details::LeftTrim(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void RightTrim(std::string& str)
|
||||||
|
{
|
||||||
|
details::RightTrim(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void Trim(std::string& str)
|
||||||
|
{
|
||||||
|
LeftTrim(str);
|
||||||
|
RightTrim(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::string CopyLeftTrim(const char* str)
|
||||||
|
{
|
||||||
|
if (str == nullptr)
|
||||||
|
return std::string();
|
||||||
|
|
||||||
|
std::string r(str);
|
||||||
|
LeftTrim(r);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::string CopyLeftTrim(System::StringView str)
|
||||||
|
{
|
||||||
|
std::string r(str.to_string());
|
||||||
|
LeftTrim(r);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::string CopyLeftTrim(std::string const& str)
|
||||||
|
{
|
||||||
|
std::string r(str);
|
||||||
|
LeftTrim(r);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::string CopyRightTrim(const char* str)
|
||||||
|
{
|
||||||
|
if (str == nullptr)
|
||||||
|
return std::string();
|
||||||
|
|
||||||
|
std::string r(str);
|
||||||
|
RightTrim(r);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::string CopyRightTrim(System::StringView str)
|
||||||
|
{
|
||||||
|
std::string r(str.to_string());
|
||||||
|
RightTrim(r);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::string CopyRightTrim(std::string const& str)
|
||||||
|
{
|
||||||
|
std::string r(str);
|
||||||
|
RightTrim(r);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::string CopyTrim(const char* str)
|
||||||
|
{
|
||||||
|
if (str == nullptr)
|
||||||
|
return std::string();
|
||||||
|
|
||||||
|
std::string r(str);
|
||||||
|
Trim(r);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::string CopyTrim(System::StringView str)
|
||||||
|
{
|
||||||
|
std::string r(str.to_string());
|
||||||
|
Trim(r);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::string CopyTrim(std::string const& str)
|
||||||
|
{
|
||||||
|
std::string r(str);
|
||||||
|
Trim(r);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void ToLower(std::string& str)
|
||||||
|
{
|
||||||
|
details::ToLower(&str[0], str.length());
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void ToLower(char* str)
|
||||||
|
{
|
||||||
|
if (str == nullptr)
|
||||||
|
return;
|
||||||
|
|
||||||
|
details::ToLower(str, strlen(str));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::string CopyLower(std::string const& str)
|
||||||
|
{
|
||||||
|
std::string r(str);
|
||||||
|
details::ToLower(&r[0], r.length());
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::string CopyLower(const char* str)
|
||||||
|
{
|
||||||
|
std::string r(str == nullptr ? "" : str);
|
||||||
|
details::ToLower(&r[0], r.length());
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::string CopyLower(System::StringView str)
|
||||||
|
{
|
||||||
|
std::string r = str.to_string();
|
||||||
|
details::ToLower(&r[0], r.length());
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void ToUpper(std::string& str)
|
||||||
|
{
|
||||||
|
details::ToUpper(&str[0], str.length());
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void ToUpper(char* str)
|
||||||
|
{
|
||||||
|
if (str == nullptr)
|
||||||
|
return;
|
||||||
|
|
||||||
|
details::ToUpper(str, strlen(str));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::string CopyUpper(std::string const& str)
|
||||||
|
{
|
||||||
|
std::string r(str);
|
||||||
|
details::ToUpper(&r[0], r.length());
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::string CopyUpper(const char* str)
|
||||||
|
{
|
||||||
|
std::string r(str == nullptr ? "" : str);
|
||||||
|
details::ToUpper(&r[0], r.length());
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::string CopyUpper(System::StringView str)
|
||||||
|
{
|
||||||
|
std::string r = str.to_string();
|
||||||
|
details::ToUpper(&r[0], r.length());
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename IteratorType>
|
||||||
|
inline std::string Join(IteratorType begin, IteratorType end, const std::string& sep)
|
||||||
|
{
|
||||||
|
std::string res;
|
||||||
|
|
||||||
|
if (begin != end)
|
||||||
|
res = *begin++;
|
||||||
|
|
||||||
|
while (begin != end)
|
||||||
|
{
|
||||||
|
res += sep;
|
||||||
|
res += *begin++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
inline std::string Join(T const& container, const std::string& sep)
|
||||||
|
{
|
||||||
|
return Join(std::begin(container), std::end(container), sep);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clone a string allocated with the "new" operator, if str is nullptr, an empty string ("") will be returned, NOT nullptr !
|
||||||
|
inline char* CloneString(const char* str)
|
||||||
|
{
|
||||||
|
if (str == nullptr)
|
||||||
|
return details::CloneString(System::StringView(""));
|
||||||
|
|
||||||
|
return details::CloneString(System::StringView(str, strlen(str)));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline char* CloneString(std::string const& str)
|
||||||
|
{
|
||||||
|
return details::CloneString(System::StringView(str));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline char* CloneString(System::StringView str)
|
||||||
|
{
|
||||||
|
return details::CloneString(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Will always end the C-String with a null char.
|
||||||
|
inline size_t CopyString(const char* src, char* dst, size_t dst_size)
|
||||||
|
{
|
||||||
|
if (src == nullptr)
|
||||||
|
return details::CopyString(System::StringView(""), dst, dst_size);
|
||||||
|
|
||||||
|
return details::CopyString(System::StringView(src, strlen(src)), dst, dst_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline size_t CopyString(System::StringView src, char* dst, size_t dst_size)
|
||||||
|
{
|
||||||
|
return details::CopyString(src, dst, dst_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline size_t CopyString(std::string const& src, char* dst, size_t dst_size)
|
||||||
|
{
|
||||||
|
return details::CopyString(System::StringView(src), dst, dst_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<size_t N>
|
||||||
|
inline size_t CopyString(const char* src, char(&dst)[N])
|
||||||
|
{
|
||||||
|
if (src == nullptr)
|
||||||
|
return details::CopyString(System::StringView(""), dst, N);
|
||||||
|
|
||||||
|
return details::CopyString(System::StringView(src, strlen(src)), dst, N);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<size_t N>
|
||||||
|
inline size_t CopyString(System::StringView src, char(&dst)[N])
|
||||||
|
{
|
||||||
|
return details::CopyString(src, dst, N);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<size_t N>
|
||||||
|
inline size_t CopyString(std::string const& src, char(&dst)[N])
|
||||||
|
{
|
||||||
|
return details::CopyString(System::StringView(src), dst, N);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,64 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) Nemirtingas
|
||||||
|
* This file is part of System.
|
||||||
|
*
|
||||||
|
* System is free software; you can redistribute it
|
||||||
|
* and/or modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* System 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
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with System; if not, see
|
||||||
|
* <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "SystemDetector.h"
|
||||||
|
#include "StringView.hpp"
|
||||||
|
|
||||||
|
namespace System {
|
||||||
|
|
||||||
|
namespace StringSwitch {
|
||||||
|
|
||||||
|
#if defined(SYSTEM_ARCH_X86)
|
||||||
|
using hash_type = uint32_t;
|
||||||
|
#else
|
||||||
|
using hash_type = uint64_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace Detail {
|
||||||
|
constexpr char lower_char(char c) { return ((c >= 'A' && c <= 'Z') ? c + 32 : c); }
|
||||||
|
}
|
||||||
|
|
||||||
|
// switch case on a string
|
||||||
|
constexpr hash_type Hash(const char* input, size_t len) { return (len > 0 ? static_cast<hash_type>(*input) + 33 * Hash(input + 1, len - 1) : 5381); }
|
||||||
|
|
||||||
|
template<size_t N>
|
||||||
|
constexpr hash_type Hash(const char(&input)[N]) { return Hash(input, N-1); }
|
||||||
|
|
||||||
|
constexpr hash_type Hash(System::StringView sv) { return Hash(sv.data(), sv.length()); }
|
||||||
|
|
||||||
|
inline hash_type Hash(const std::string& input) { return Hash(input.c_str(), input.length()); }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
constexpr hash_type IHash(const char* input, size_t len) { return (len > 0 ? static_cast<hash_type>(Detail::lower_char(*input)) + 33 * IHash(input + 1, len - 1) : 5381); }
|
||||||
|
|
||||||
|
template<size_t N>
|
||||||
|
constexpr inline hash_type IHash(const char(&input)[N]) { return IHash(input, N - 1); }
|
||||||
|
|
||||||
|
constexpr hash_type IHash(System::StringView sv) { return IHash(sv.data(), sv.length()); }
|
||||||
|
|
||||||
|
inline hash_type IHash(const std::string& input) { return IHash(input.c_str(), input.length()); }
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,256 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) Nemirtingas
|
||||||
|
* This file is part of System.
|
||||||
|
*
|
||||||
|
* System is free software; you can redistribute it
|
||||||
|
* and/or modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* System 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
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with System; if not, see
|
||||||
|
* <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <iterator>
|
||||||
|
#include <string>
|
||||||
|
#include <iostream>
|
||||||
|
#include <array>
|
||||||
|
|
||||||
|
namespace System {
|
||||||
|
|
||||||
|
template<typename char_type>
|
||||||
|
class BasicStringView {
|
||||||
|
const char_type* _string;
|
||||||
|
size_t _length;
|
||||||
|
|
||||||
|
using type = BasicStringView<char_type>;
|
||||||
|
|
||||||
|
public:
|
||||||
|
class iterator {
|
||||||
|
const char_type* _value;
|
||||||
|
|
||||||
|
public:
|
||||||
|
constexpr iterator(const iterator& o) : _value(o._value) {}
|
||||||
|
constexpr iterator(const char_type* value) : _value(value) {}
|
||||||
|
|
||||||
|
constexpr iterator& operator++() { ++_value; return *this; }
|
||||||
|
constexpr iterator operator++(int) { iterator retval = *this; ++(*this); return retval; }
|
||||||
|
constexpr iterator& operator--() { --_value; return *this; }
|
||||||
|
constexpr iterator operator--(int) { iterator retval = *this; --(*this); return retval; }
|
||||||
|
constexpr bool operator==(iterator other) const { return _value == other._value; }
|
||||||
|
constexpr bool operator!=(iterator other) const { return !(*this == other); }
|
||||||
|
constexpr const char_type& operator*() const { return *_value; }
|
||||||
|
|
||||||
|
// iterator traits
|
||||||
|
using difference_type = long;
|
||||||
|
using value_type = char_type;
|
||||||
|
using pointer = const char_type*;
|
||||||
|
using reference = const char_type&;
|
||||||
|
using iterator_category = std::random_access_iterator_tag;
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr BasicStringView() : _string(nullptr), _length(0)
|
||||||
|
{}
|
||||||
|
|
||||||
|
constexpr BasicStringView(const char_type* str, size_t length) : _string(str), _length(length)
|
||||||
|
{}
|
||||||
|
|
||||||
|
constexpr BasicStringView(std::basic_string<char_type, std::char_traits<char_type>, std::allocator<char_type>> const& str) : _string(str.data()), _length(str.length())
|
||||||
|
{}
|
||||||
|
|
||||||
|
template<size_t N>
|
||||||
|
constexpr BasicStringView(const char_type(&str)[N]) : _string(str), _length(N - 1)
|
||||||
|
{}
|
||||||
|
|
||||||
|
template<size_t N>
|
||||||
|
constexpr BasicStringView(std::array<char_type, N> const& str) : _string(&str.at[0]), _length(N)
|
||||||
|
{}
|
||||||
|
|
||||||
|
constexpr BasicStringView(type const& other) : _string(other._string), _length(other._length)
|
||||||
|
{}
|
||||||
|
|
||||||
|
constexpr BasicStringView(type&& other) : _string(other._string), _length(other._length)
|
||||||
|
{}
|
||||||
|
|
||||||
|
constexpr type& operator=(type const& other)
|
||||||
|
{
|
||||||
|
_string = other._string;
|
||||||
|
_length = other._length;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr type& operator=(type&& other)
|
||||||
|
{
|
||||||
|
_string = other._string;
|
||||||
|
_length = other._length;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr const char_type* data() const { return _string; }
|
||||||
|
|
||||||
|
constexpr bool empty() const { return _length == 0; }
|
||||||
|
|
||||||
|
constexpr size_t size() const { return _length; }
|
||||||
|
|
||||||
|
constexpr size_t length() const { return _length; }
|
||||||
|
|
||||||
|
constexpr const char_type& operator[](size_t index) const { return _string[index]; }
|
||||||
|
|
||||||
|
constexpr size_t find_first_of(type const& string, const size_t offset = 0) const
|
||||||
|
{
|
||||||
|
if(_length == 0)
|
||||||
|
return std::string::npos;
|
||||||
|
|
||||||
|
for (size_t i = offset; i < _length; ++i)
|
||||||
|
{
|
||||||
|
for (size_t j = 0; j < string._length; ++j)
|
||||||
|
{
|
||||||
|
if (_string[i] == string[j])
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::string::npos;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr size_t find_first_not_of(type const& string, const size_t offset = 0) const
|
||||||
|
{
|
||||||
|
if(_length == 0)
|
||||||
|
return std::string::npos;
|
||||||
|
|
||||||
|
for (size_t i = offset; i < _length; ++i)
|
||||||
|
{
|
||||||
|
for (size_t j = 0; j < string._length; ++j)
|
||||||
|
{
|
||||||
|
if (_string[i] == string[j])
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (j == (string._length - 1))
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::string::npos;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr size_t find(type const& string, const size_t offset = 0) const
|
||||||
|
{
|
||||||
|
if (_length < string._length)
|
||||||
|
return std::string::npos;
|
||||||
|
|
||||||
|
for (size_t i = offset; i < (_length - string._length + 1); ++i)
|
||||||
|
{
|
||||||
|
for (size_t j = 0; j < string._length; ++j)
|
||||||
|
{
|
||||||
|
if (_string[i + j] != string[j])
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (j == (string._length - 1))
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::string::npos;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr size_t find_not(type const& string, const size_t offset = 0) const
|
||||||
|
{
|
||||||
|
if (_length < string._length)
|
||||||
|
return std::string::npos;
|
||||||
|
|
||||||
|
for (size_t i = offset; i < (_length - string._length + 1); ++i)
|
||||||
|
{
|
||||||
|
for (size_t j = 0; j < string._length; ++j)
|
||||||
|
{
|
||||||
|
if (_string[i + j] == string[j])
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (j == (string._length - 1))
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::string::npos;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr size_t count(char_type const c) const
|
||||||
|
{
|
||||||
|
size_t n = 0;
|
||||||
|
for (size_t i = 0; i < _length; ++i)
|
||||||
|
if (_string[i] == c)
|
||||||
|
++n;
|
||||||
|
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr type substr(size_t offset, size_t length = std::string::npos) const
|
||||||
|
{
|
||||||
|
if (offset >= _length)
|
||||||
|
return type();
|
||||||
|
|
||||||
|
return type(_string + offset, (_length - offset) > length ? length : _length - offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr iterator begin() const
|
||||||
|
{
|
||||||
|
return iterator(_string);
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr iterator end() const
|
||||||
|
{
|
||||||
|
return iterator(_string + _length);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string to_string() const
|
||||||
|
{
|
||||||
|
return std::string(_string, _string + _length);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t copy(char_type* p, size_t p_size) const
|
||||||
|
{
|
||||||
|
size_t written = 0;
|
||||||
|
if (p != nullptr)
|
||||||
|
{
|
||||||
|
size_t to_write = (_length > p_size ? p_size : _length);
|
||||||
|
char_type* b = _string;
|
||||||
|
while (to_write--)
|
||||||
|
{
|
||||||
|
*p++ = *b++;
|
||||||
|
++written;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return written;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
using StringView = BasicStringView<char>;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename char_type>
|
||||||
|
std::basic_ostream<char_type>& operator<<(std::basic_ostream<char_type>& os, System::BasicStringView<char_type> const& sv)
|
||||||
|
{
|
||||||
|
return os.write(sv.data(), sv.length());
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename char_type>
|
||||||
|
std::basic_string<char_type> operator+(std::basic_string<char_type> const& str, System::BasicStringView<char_type> const& sv)
|
||||||
|
{
|
||||||
|
std::string r(str);
|
||||||
|
return r.append(sv.data(), sv.data() + sv.length());
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename char_type>
|
||||||
|
std::basic_string<char_type>& operator+=(std::basic_string<char_type>& str, System::BasicStringView<char_type> const& sv)
|
||||||
|
{
|
||||||
|
return str.append(sv.data(), sv.data() + sv.length());
|
||||||
|
}
|
|
@ -0,0 +1,593 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) Nemirtingas
|
||||||
|
* This file is part of System.
|
||||||
|
*
|
||||||
|
* System is free software; you can redistribute it
|
||||||
|
* and/or modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* System 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
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with System; if not, see
|
||||||
|
* <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "System.h"
|
||||||
|
#include "Filesystem.h"
|
||||||
|
#include "Encoding.hpp"
|
||||||
|
#include "System_internals.h"
|
||||||
|
|
||||||
|
#if defined(SYSTEM_OS_WINDOWS)
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#define VC_EXTRALEAN
|
||||||
|
#define NOMINMAX
|
||||||
|
#include <Windows.h>
|
||||||
|
#include <TlHelp32.h>
|
||||||
|
#include <shellapi.h>
|
||||||
|
#include <shlobj.h> // (shell32.lib) Infos about current user folders
|
||||||
|
|
||||||
|
inline bool handle_is_valid(HANDLE h)
|
||||||
|
{
|
||||||
|
return (h != (HANDLE)0 && h != (HANDLE)-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#elif defined(SYSTEM_OS_LINUX) || defined(SYSTEM_OS_APPLE)
|
||||||
|
#if defined(SYSTEM_OS_LINUX)
|
||||||
|
#include <sys/sysinfo.h> // Get uptime (second resolution)
|
||||||
|
#include <dirent.h>
|
||||||
|
#else
|
||||||
|
#include <sys/sysctl.h>
|
||||||
|
#include <mach-o/dyld_images.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <pwd.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <dlfcn.h>
|
||||||
|
|
||||||
|
#else
|
||||||
|
#error "unknown arch"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
|
namespace System {
|
||||||
|
|
||||||
|
std::chrono::microseconds GetUpTime()
|
||||||
|
{
|
||||||
|
return std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::system_clock::now() - GetBootTime());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace System {
|
||||||
|
|
||||||
|
#if defined(SYSTEM_OS_WINDOWS)
|
||||||
|
|
||||||
|
std::chrono::system_clock::time_point GetBootTime()
|
||||||
|
{
|
||||||
|
static std::chrono::system_clock::time_point boottime(std::chrono::system_clock::now() - std::chrono::milliseconds(GetTickCount64()));
|
||||||
|
return boottime;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> GetProcArgs()
|
||||||
|
{
|
||||||
|
std::vector<std::string> res;
|
||||||
|
|
||||||
|
LPWSTR* szArglist;
|
||||||
|
int nArgs;
|
||||||
|
|
||||||
|
szArglist = CommandLineToArgvW(GetCommandLineW(), &nArgs);
|
||||||
|
|
||||||
|
res.reserve(nArgs);
|
||||||
|
for (int i = 0; i < nArgs; ++i)
|
||||||
|
{
|
||||||
|
res.emplace_back(System::Encoding::WCharToUtf8(szArglist[i]));
|
||||||
|
}
|
||||||
|
|
||||||
|
LocalFree(szArglist);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string GetEnvVar(std::string const& var)
|
||||||
|
{
|
||||||
|
std::wstring wide(System::Encoding::Utf8ToWChar(var));
|
||||||
|
std::wstring wVar;
|
||||||
|
|
||||||
|
DWORD size = GetEnvironmentVariableW(wide.c_str(), nullptr, 0);
|
||||||
|
// Size can be 0, and the size includes the null char, so resize to size - 1
|
||||||
|
if (size < 2)
|
||||||
|
return std::string();
|
||||||
|
|
||||||
|
wVar.resize(size - 1);
|
||||||
|
GetEnvironmentVariableW(wide.c_str(), &wVar[0], size);
|
||||||
|
|
||||||
|
return System::Encoding::WCharToUtf8(wVar);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string GetUserdataPath()
|
||||||
|
{
|
||||||
|
WCHAR szPath[4096] = {};
|
||||||
|
HRESULT hr = SHGetFolderPathW(NULL, CSIDL_APPDATA, NULL, 0, szPath);
|
||||||
|
|
||||||
|
if (FAILED(hr))
|
||||||
|
return std::string();
|
||||||
|
|
||||||
|
return System::Encoding::WCharToUtf8(std::wstring(szPath));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string GetExecutablePath()
|
||||||
|
{
|
||||||
|
std::string path;
|
||||||
|
std::wstring wpath(4096, L'\0');
|
||||||
|
|
||||||
|
wpath.resize(GetModuleFileNameW(nullptr, &wpath[0], wpath.length()));
|
||||||
|
return System::Encoding::WCharToUtf8(wpath);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string GetModulePath()
|
||||||
|
{
|
||||||
|
std::string path;
|
||||||
|
std::wstring wpath(4096, L'\0');
|
||||||
|
HMODULE hModule;
|
||||||
|
|
||||||
|
if (GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT | GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (LPCWSTR)&GetModulePath, &hModule) != FALSE)
|
||||||
|
{
|
||||||
|
DWORD size = GetModuleFileNameW((HINSTANCE)hModule, &wpath[0], wpath.length());
|
||||||
|
wpath.resize(size);
|
||||||
|
}
|
||||||
|
return System::Encoding::WCharToUtf8(wpath);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> GetModules()
|
||||||
|
{
|
||||||
|
std::vector<std::string> paths;
|
||||||
|
std::wstring wpath;
|
||||||
|
DWORD size;
|
||||||
|
HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, GetProcessId(GetCurrentProcess()));
|
||||||
|
if (handle_is_valid(hSnap))
|
||||||
|
{
|
||||||
|
MODULEENTRY32W entry{};
|
||||||
|
entry.dwSize = sizeof(entry);
|
||||||
|
if (Module32FirstW(hSnap, &entry) != FALSE)
|
||||||
|
{
|
||||||
|
wpath.resize(4096);
|
||||||
|
size = GetModuleFileNameW((HINSTANCE)entry.hModule, &wpath[0], wpath.length());
|
||||||
|
wpath.resize(size);
|
||||||
|
paths.emplace_back(System::Encoding::WCharToUtf8(wpath));
|
||||||
|
|
||||||
|
while (Module32NextW(hSnap, &entry) != FALSE)
|
||||||
|
{
|
||||||
|
wpath.resize(4096);
|
||||||
|
size = GetModuleFileNameW((HINSTANCE)entry.hModule, &wpath[0], wpath.length());
|
||||||
|
wpath.resize(size);
|
||||||
|
paths.emplace_back(System::Encoding::WCharToUtf8(wpath));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CloseHandle(hSnap);
|
||||||
|
}
|
||||||
|
|
||||||
|
return paths;
|
||||||
|
}
|
||||||
|
|
||||||
|
#elif defined(SYSTEM_OS_LINUX) || defined(SYSTEM_OS_APPLE)
|
||||||
|
#ifdef SYSTEM_OS_LINUX
|
||||||
|
|
||||||
|
std::chrono::system_clock::time_point GetBootTime()
|
||||||
|
{
|
||||||
|
static std::chrono::system_clock::time_point boottime(std::chrono::seconds(0));
|
||||||
|
if (boottime == std::chrono::system_clock::time_point{})
|
||||||
|
{
|
||||||
|
std::ifstream uptime_file("/proc/uptime");
|
||||||
|
|
||||||
|
double uptime;
|
||||||
|
if (uptime_file)
|
||||||
|
{// Get uptime (millisecond resolution)
|
||||||
|
uptime_file >> uptime;
|
||||||
|
uptime_file.close();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{// If we can't open /proc/uptime, fallback to sysinfo (second resolution)
|
||||||
|
struct sysinfo infos;
|
||||||
|
if (sysinfo(&infos) != 0)
|
||||||
|
return boottime;
|
||||||
|
|
||||||
|
uptime = infos.uptime;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::chrono::system_clock::time_point now_tp = std::chrono::system_clock::now();
|
||||||
|
std::chrono::system_clock::time_point uptime_tp(std::chrono::milliseconds(static_cast<uint64_t>(uptime * 1000)));
|
||||||
|
|
||||||
|
boottime = std::chrono::system_clock::time_point(now_tp - uptime_tp);
|
||||||
|
}
|
||||||
|
|
||||||
|
return boottime;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string GetExecutablePath()
|
||||||
|
{
|
||||||
|
std::string exec_path("./");
|
||||||
|
|
||||||
|
char link[2048] = {};
|
||||||
|
if (readlink("/proc/self/exe", link, sizeof(link)) > 0)
|
||||||
|
{
|
||||||
|
exec_path = link;
|
||||||
|
}
|
||||||
|
|
||||||
|
return exec_path;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string GetModulePath()
|
||||||
|
{
|
||||||
|
std::string const self("/proc/self/map_files/");
|
||||||
|
DIR* dir;
|
||||||
|
struct dirent* dir_entry;
|
||||||
|
std::string file_path;
|
||||||
|
std::string res;
|
||||||
|
uint64_t handle = (uint64_t)&GetModulePath;
|
||||||
|
uint64_t low, high;
|
||||||
|
char* tmp;
|
||||||
|
|
||||||
|
dir = opendir(self.c_str());
|
||||||
|
if (dir != nullptr)
|
||||||
|
{
|
||||||
|
while ((dir_entry = readdir(dir)) != nullptr)
|
||||||
|
{
|
||||||
|
file_path = dir_entry->d_name;
|
||||||
|
if (dir_entry->d_type != DT_LNK)
|
||||||
|
{// Not a link
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp = &file_path[0];
|
||||||
|
low = strtoull(tmp, &tmp, 16);
|
||||||
|
if ((tmp - file_path.c_str()) < file_path.length())
|
||||||
|
{
|
||||||
|
high = strtoull(tmp+1, nullptr, 16);
|
||||||
|
if (low != 0 && high > low && low <= handle && handle <= high)
|
||||||
|
{
|
||||||
|
res = System::ExpandSymlink(self + file_path);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
closedir(dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> GetModules()
|
||||||
|
{
|
||||||
|
std::string const self("/proc/self/map_files/");
|
||||||
|
std::vector<std::string> paths;
|
||||||
|
|
||||||
|
DIR* dir;
|
||||||
|
struct dirent* dir_entry;
|
||||||
|
std::string path;
|
||||||
|
bool found;
|
||||||
|
|
||||||
|
dir = opendir(self.c_str());
|
||||||
|
if (dir != nullptr)
|
||||||
|
{
|
||||||
|
while ((dir_entry = readdir(dir)) != nullptr)
|
||||||
|
{
|
||||||
|
if (dir_entry->d_type != DT_LNK)
|
||||||
|
{// Not a link
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
found = false;
|
||||||
|
path = System::ExpandSymlink(self + dir_entry->d_name);
|
||||||
|
for (auto const& item : paths)
|
||||||
|
{
|
||||||
|
if (item == path)
|
||||||
|
{
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found)
|
||||||
|
paths.emplace_back(std::move(path));
|
||||||
|
}
|
||||||
|
|
||||||
|
closedir(dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
return paths;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> GetProcArgs()
|
||||||
|
{
|
||||||
|
std::vector<std::string> res;
|
||||||
|
std::ifstream fcmdline("/proc/self/cmdline", std::ios::in | std::ios::binary);
|
||||||
|
|
||||||
|
if (fcmdline)
|
||||||
|
{
|
||||||
|
for (std::string line; std::getline(fcmdline, line, '\0');)
|
||||||
|
{
|
||||||
|
res.emplace_back(std::move(line));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
static int IsProcessTranslated()
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
size_t size = sizeof(ret);
|
||||||
|
|
||||||
|
// Call the sysctl and if successful return the result
|
||||||
|
if (sysctlbyname("sysctl.proc_translated", &ret, &size, NULL, 0) != -1)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
// If "sysctl.proc_translated" is not present then must be native
|
||||||
|
if (errno == ENOENT)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::chrono::system_clock::time_point GetBootTime()
|
||||||
|
{
|
||||||
|
static std::chrono::system_clock::time_point boottime{};
|
||||||
|
if (boottime == std::chrono::system_clock::time_point{})
|
||||||
|
{
|
||||||
|
struct timeval boottime_tv;
|
||||||
|
size_t len = sizeof(boottime_tv);
|
||||||
|
int mib[2] = { CTL_KERN, KERN_BOOTTIME };
|
||||||
|
if (sysctl(mib, sizeof(mib)/sizeof(*mib), &boottime_tv, &len, nullptr, 0) < 0)
|
||||||
|
return boottime;
|
||||||
|
|
||||||
|
boottime = std::chrono::system_clock::time_point(
|
||||||
|
std::chrono::seconds(boottime_tv.tv_sec) +
|
||||||
|
std::chrono::microseconds(boottime_tv.tv_usec));
|
||||||
|
}
|
||||||
|
|
||||||
|
return boottime;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string GetExecutablePath()
|
||||||
|
{
|
||||||
|
std::string exec_path("./");
|
||||||
|
|
||||||
|
task_dyld_info dyld_info;
|
||||||
|
task_t t;
|
||||||
|
pid_t pid = getpid();
|
||||||
|
task_for_pid(mach_task_self(), pid, &t);
|
||||||
|
mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT;
|
||||||
|
|
||||||
|
if (task_info(t, TASK_DYLD_INFO, reinterpret_cast<task_info_t>(&dyld_info), &count) == KERN_SUCCESS)
|
||||||
|
{
|
||||||
|
dyld_all_image_infos *dyld_img_infos = reinterpret_cast<dyld_all_image_infos*>(dyld_info.all_image_info_addr);
|
||||||
|
if (IsProcessTranslated() == 1)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < dyld_img_infos->infoArrayCount; ++i)
|
||||||
|
{
|
||||||
|
exec_path = dyld_img_infos->infoArray[i].imageFilePath;
|
||||||
|
if (strcasestr(exec_path.c_str(), "rosetta") != nullptr)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// In case of a translated process (Rosetta maybe ?), the executable path is not the first entry.
|
||||||
|
size_t pos;
|
||||||
|
while ((pos = exec_path.find("/./")) != std::string::npos)
|
||||||
|
{
|
||||||
|
exec_path.replace(pos, 3, "/");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (int i = 0; i < dyld_img_infos->infoArrayCount; ++i)
|
||||||
|
{
|
||||||
|
// For now I don't know how to be sure to get the executable path
|
||||||
|
// but looks like the 1st entry is the executable path
|
||||||
|
exec_path = dyld_img_infos->infoArray[i].imageFilePath;
|
||||||
|
size_t pos;
|
||||||
|
while ((pos = exec_path.find("/./")) != std::string::npos)
|
||||||
|
{
|
||||||
|
exec_path.replace(pos, 3, "/");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return exec_path;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Workaround for MacOS, I don't know how to get module path from address.
|
||||||
|
SYSTEM_EXPORT_API(SYSTEM_EXTERN_C, void, SYSTEM_MODE_EXPORT, SYSTEM_CALL_DEFAULT) GetModulePathPlaceholder() {}
|
||||||
|
|
||||||
|
std::string GetModulePath()
|
||||||
|
{
|
||||||
|
task_dyld_info dyld_info;
|
||||||
|
task_t t;
|
||||||
|
pid_t pid = getpid();
|
||||||
|
task_for_pid(mach_task_self(), pid, &t);
|
||||||
|
mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT;
|
||||||
|
|
||||||
|
if (task_info(t, TASK_DYLD_INFO, reinterpret_cast<task_info_t>(&dyld_info), &count) == KERN_SUCCESS)
|
||||||
|
{
|
||||||
|
dyld_all_image_infos* dyld_img_infos = reinterpret_cast<dyld_all_image_infos*>(dyld_info.all_image_info_addr);
|
||||||
|
for (int i = 0; i < dyld_img_infos->infoArrayCount; ++i)
|
||||||
|
{
|
||||||
|
void* res = dlopen(dyld_img_infos->infoArray[i].imageFilePath, RTLD_NOW);
|
||||||
|
if (res != nullptr)
|
||||||
|
{
|
||||||
|
void* placeholder = dlsym(res, "GetModulePathPlaceholder");
|
||||||
|
dlclose(res);
|
||||||
|
if(placeholder == (void*)&GetModulePathPlaceholder)
|
||||||
|
{
|
||||||
|
std::string res(dyld_img_infos->infoArray[i].imageFilePath);
|
||||||
|
size_t pos;
|
||||||
|
while((pos = res.find("/./")) != std::string::npos)
|
||||||
|
{
|
||||||
|
res.replace(pos, 3, "/");
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::string();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> GetModules()
|
||||||
|
{
|
||||||
|
std::vector<std::string> paths;
|
||||||
|
std::string path;
|
||||||
|
size_t pos;
|
||||||
|
task_dyld_info dyld_info;
|
||||||
|
task_t t;
|
||||||
|
pid_t pid = getpid();
|
||||||
|
task_for_pid(mach_task_self(), pid, &t);
|
||||||
|
mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT;
|
||||||
|
|
||||||
|
if (task_info(t, TASK_DYLD_INFO, reinterpret_cast<task_info_t>(&dyld_info), &count) == KERN_SUCCESS)
|
||||||
|
{
|
||||||
|
dyld_all_image_infos* dyld_img_infos = reinterpret_cast<dyld_all_image_infos*>(dyld_info.all_image_info_addr);
|
||||||
|
for (int i = 0; i < dyld_img_infos->infoArrayCount; ++i)
|
||||||
|
{
|
||||||
|
path = dyld_img_infos->infoArray[i].imageFilePath;
|
||||||
|
while ((pos = path.find("/./")) != std::string::npos)
|
||||||
|
{
|
||||||
|
path.replace(pos, 3, "/");
|
||||||
|
}
|
||||||
|
paths.emplace_back(std::move(path));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return paths;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> GetProcArgs()
|
||||||
|
{
|
||||||
|
std::vector<std::string> res;
|
||||||
|
int mib[3];
|
||||||
|
int argmax;
|
||||||
|
size_t size;
|
||||||
|
int nargs;
|
||||||
|
|
||||||
|
mib[0] = CTL_KERN;
|
||||||
|
mib[1] = KERN_ARGMAX;
|
||||||
|
|
||||||
|
size = sizeof(argmax);
|
||||||
|
if (sysctl(mib, 2, &argmax, &size, NULL, 0) == -1)
|
||||||
|
{
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<char[]> procargs(new char[argmax]);
|
||||||
|
if (procargs == nullptr)
|
||||||
|
{
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
mib[0] = CTL_KERN;
|
||||||
|
mib[1] = KERN_PROCARGS2;
|
||||||
|
mib[2] = getpid();
|
||||||
|
|
||||||
|
size = (size_t)argmax;
|
||||||
|
if (sysctl(mib, 3, procargs.get(), &size, NULL, 0) == -1)
|
||||||
|
{
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(&nargs, procargs.get(), sizeof(nargs));
|
||||||
|
if (nargs <= 0)
|
||||||
|
{
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* args_end = procargs.get() + size;
|
||||||
|
char* arg_iterator = procargs.get() + sizeof(nargs);
|
||||||
|
// Skip saved exec path
|
||||||
|
while (*arg_iterator != '\0' && arg_iterator < args_end)
|
||||||
|
{
|
||||||
|
++arg_iterator;
|
||||||
|
}
|
||||||
|
// Skip trailing(s) '\0'
|
||||||
|
while (*arg_iterator == '\0' && arg_iterator < args_end)
|
||||||
|
{
|
||||||
|
++arg_iterator;
|
||||||
|
}
|
||||||
|
|
||||||
|
res.reserve(nargs);
|
||||||
|
char* arg = arg_iterator;
|
||||||
|
for (int i = 0; i < nargs && arg_iterator < args_end; ++arg_iterator)
|
||||||
|
{
|
||||||
|
if (*arg_iterator == '\0')
|
||||||
|
{
|
||||||
|
++i;
|
||||||
|
res.emplace_back(arg);
|
||||||
|
arg = arg_iterator + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
std::string GetUserdataPath()
|
||||||
|
{
|
||||||
|
std::string user_appdata_path;
|
||||||
|
/*
|
||||||
|
~/Library/Application Support/<application name>
|
||||||
|
~/Library/Preferences/<application name>
|
||||||
|
~/Library/<application name>/
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct passwd* user_entry = getpwuid(getuid());
|
||||||
|
if (user_entry == nullptr || user_entry->pw_dir == nullptr)
|
||||||
|
{
|
||||||
|
char* env_var = getenv("HOME");
|
||||||
|
if (env_var != nullptr)
|
||||||
|
{
|
||||||
|
user_appdata_path = env_var;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
user_appdata_path = user_entry->pw_dir;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!user_appdata_path.empty())
|
||||||
|
{
|
||||||
|
#ifdef SYSTEM_OS_LINUX
|
||||||
|
user_appdata_path = System::Filesystem::Join(user_appdata_path, ".config");
|
||||||
|
#else
|
||||||
|
user_appdata_path = System::Filesystem::Join(user_appdata_path, "Library", "Application Support");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
return user_appdata_path;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string GetEnvVar(std::string const& var)
|
||||||
|
{
|
||||||
|
char* env = getenv(var.c_str());
|
||||||
|
if (env == nullptr)
|
||||||
|
return std::string();
|
||||||
|
|
||||||
|
return env;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,44 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) Nemirtingas
|
||||||
|
* This file is part of System.
|
||||||
|
*
|
||||||
|
* System is free software; you can redistribute it
|
||||||
|
* and/or modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* System 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
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with the System; if not, see
|
||||||
|
* <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace System {
|
||||||
|
|
||||||
|
std::chrono::system_clock::time_point GetBootTime();
|
||||||
|
std::chrono::microseconds GetUpTime();
|
||||||
|
|
||||||
|
// Get the current process argv
|
||||||
|
std::vector<std::string> GetProcArgs();
|
||||||
|
// Get User env variable
|
||||||
|
std::string GetEnvVar(std::string const& var);
|
||||||
|
// User appdata full path
|
||||||
|
std::string GetUserdataPath();
|
||||||
|
// Executable full path
|
||||||
|
std::string GetExecutablePath();
|
||||||
|
// .dll, .so or .dylib full path
|
||||||
|
std::string GetModulePath();
|
||||||
|
// List all loaded modules
|
||||||
|
std::vector<std::string> GetModules();
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,105 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) Nemirtingas
|
||||||
|
* This file is part of System.
|
||||||
|
*
|
||||||
|
* System is free software; you can redistribute it
|
||||||
|
* and/or modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* System 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
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with System; if not, see
|
||||||
|
* <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#if defined(WIN64) || defined(_WIN64) || defined(__MINGW64__) || defined(WIN32) || defined(_WIN32) || defined(__MINGW32__)
|
||||||
|
#define SYSTEM_OS_WINDOWS
|
||||||
|
|
||||||
|
#if defined(_M_IX86)
|
||||||
|
#define SYSTEM_ARCH_X86
|
||||||
|
#elif defined(_M_AMD64)
|
||||||
|
#define SYSTEM_ARCH_X64
|
||||||
|
#elif defined(_M_ARM)
|
||||||
|
#define SYSTEM_ARCH_ARM
|
||||||
|
#elif defined(_M_ARM64)
|
||||||
|
#define SYSTEM_ARCH_ARM64
|
||||||
|
#else
|
||||||
|
#error "Unhandled arch"
|
||||||
|
#endif
|
||||||
|
#elif defined(__linux__) || defined(linux)
|
||||||
|
#define SYSTEM_OS_LINUX
|
||||||
|
|
||||||
|
#if defined(__i386__) || defined(__i386) || defined(i386)
|
||||||
|
#define SYSTEM_ARCH_X86
|
||||||
|
#elif defined(__x86_64__) || defined(__x86_64) || defined(__amd64) || defined(__amd64__)
|
||||||
|
#define SYSTEM_ARCH_X64
|
||||||
|
#elif defined(__arm__)
|
||||||
|
#define SYSTEM_ARCH_ARM
|
||||||
|
#elif defined(__aarch64__)
|
||||||
|
#define SYSTEM_ARCH_ARM64
|
||||||
|
#else
|
||||||
|
#error "Unhandled arch"
|
||||||
|
#endif
|
||||||
|
#elif defined(__APPLE__)
|
||||||
|
#define SYSTEM_OS_APPLE
|
||||||
|
|
||||||
|
#if defined(__i386__) || defined(__i386) || defined(i386)
|
||||||
|
#define SYSTEM_ARCH_X86
|
||||||
|
#elif defined(__x86_64__) || defined(__x86_64) || defined(__amd64) || defined(__amd64__)
|
||||||
|
#define SYSTEM_ARCH_X64
|
||||||
|
#elif defined(__arm__)
|
||||||
|
#define SYSTEM_ARCH_ARM
|
||||||
|
#elif defined(__aarch64__)
|
||||||
|
#define SYSTEM_ARCH_ARM64
|
||||||
|
#else
|
||||||
|
#error "Unhandled arch"
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
//#error "Unknown OS"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
// Some constexpr for C++17 constexpr if.
|
||||||
|
namespace System {
|
||||||
|
enum class OperatingSystem {
|
||||||
|
Windows = 0,
|
||||||
|
Linux = 1,
|
||||||
|
Apple = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class Arch {
|
||||||
|
x86 = 0,
|
||||||
|
x64 = 1,
|
||||||
|
arm = 2,
|
||||||
|
aarch64 = 3,
|
||||||
|
};
|
||||||
|
|
||||||
|
static constexpr OperatingSystem os =
|
||||||
|
#if defined(SYSTEM_OS_WINDOWS)
|
||||||
|
OperatingSystem::Windows;
|
||||||
|
#elif defined(SYSTEM_OS_LINUX)
|
||||||
|
OperatingSystem::Linux;
|
||||||
|
#elif defined(SYSTEM_OS_APPLE)
|
||||||
|
OperatingSystem::Apple;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static constexpr Arch arch =
|
||||||
|
#if defined(SYSTEM_ARCH_X86)
|
||||||
|
Arch::x86;
|
||||||
|
#elif defined(SYSTEM_ARCH_X64)
|
||||||
|
Arch::x64;
|
||||||
|
#elif defined(SYSTEM_ARCH_ARM)
|
||||||
|
Arch::arm;
|
||||||
|
#elif defined(SYSTEM_ARCH_ARM64)
|
||||||
|
Arch::aarch64;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -0,0 +1,125 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) Nemirtingas
|
||||||
|
* This file is part of System.
|
||||||
|
*
|
||||||
|
* System is free software; you can redistribute it
|
||||||
|
* and/or modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* System 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
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with System; if not, see
|
||||||
|
* <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "SystemDetector.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
#define SYSTEM_EXTERN_NONE
|
||||||
|
#define SYSTEM_EXTERN_C extern "C"
|
||||||
|
#define SYSTEM_EXTERN_CXX extern
|
||||||
|
#else
|
||||||
|
#define SYSTEM_EXTERN_NONE
|
||||||
|
#define SYSTEM_EXTERN_C extern
|
||||||
|
#define SYSTEM_EXTERN_CXX #error "No C++ export in C"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(SYSTEM_OS_WINDOWS)
|
||||||
|
#if defined(__clang__)
|
||||||
|
#define SYSTEM_CALL_DEFAULT
|
||||||
|
#define SYSTEM_CALL_STDL __stdcall
|
||||||
|
#define SYSTEM_CALL_CDECL __cdecl
|
||||||
|
#define SYSTEM_CALL_FAST __fastcall
|
||||||
|
#define SYSTEM_CALL_THIS __thiscall
|
||||||
|
|
||||||
|
#define SYSTEM_MODE_DEFAULT
|
||||||
|
#define SYSTEM_MODE_EXPORT __declspec(dllexport)
|
||||||
|
#define SYSTEM_MODE_IMPORT __declspec(dllimport)
|
||||||
|
#define SYSTEM_MODE_HIDDEN
|
||||||
|
|
||||||
|
#define SYSTEM_HIDE_CLASS(keyword) SYSTEM_EXTERN_NONE SYSTEM_MODE_HIDDEN keyword
|
||||||
|
#define SYSTEM_HIDE_API(return_type, call_convention) SYSTEM_EXTERN_NONE SYSTEM_MODE_HIDDEN return_type call_convention
|
||||||
|
#define SYSTEM_EXPORT_API(extern_type, return_type, mode, call_convention) extern_type mode return_type call_convention
|
||||||
|
#else
|
||||||
|
#define SYSTEM_CALL_DEFAULT
|
||||||
|
#define SYSTEM_CALL_STDL __stdcall
|
||||||
|
#define SYSTEM_CALL_CDECL __cdecl
|
||||||
|
#define SYSTEM_CALL_FAST __fastcall
|
||||||
|
#define SYSTEM_CALL_THIS __thiscall
|
||||||
|
|
||||||
|
#define SYSTEM_MODE_DEFAULT
|
||||||
|
#define SYSTEM_MODE_EXPORT __declspec(dllexport)
|
||||||
|
#define SYSTEM_MODE_IMPORT __declspec(dllimport)
|
||||||
|
#define SYSTEM_MODE_HIDDEN
|
||||||
|
|
||||||
|
#define SYSTEM_HIDE_CLASS(keyword) SYSTEM_EXTERN_NONE SYSTEM_MODE_HIDDEN keyword
|
||||||
|
#define SYSTEM_HIDE_API(return_type, call_convention) SYSTEM_EXTERN_NONE SYSTEM_MODE_HIDDEN return_type call_convention
|
||||||
|
#define SYSTEM_EXPORT_API(extern_type, return_type, mode, call_convention) extern_type mode return_type call_convention
|
||||||
|
#endif
|
||||||
|
#elif defined(SYSTEM_OS_LINUX) || defined(SYSTEM_OS_APPLE)
|
||||||
|
#define SYSTEM_CALL_DEFAULT
|
||||||
|
#define SYSTEM_CALL_STD __attribute__((stdcall))
|
||||||
|
#define SYSTEM_CALL_CDECL __attribute__((cdecl))
|
||||||
|
#define SYSTEM_CALL_FAST __attribute__((fastcall))
|
||||||
|
#define SYSTEM_CALL_THIS __attribute__((thiscall))
|
||||||
|
|
||||||
|
#define SYSTEM_MODE_DEFAULT
|
||||||
|
#define SYSTEM_MODE_EXPORT __attribute__((visibility("default")))
|
||||||
|
#define SYSTEM_MODE_IMPORT __attribute__((visibility("default")))
|
||||||
|
#define SYSTEM_MODE_HIDDEN __attribute__((visibility("hidden")))
|
||||||
|
|
||||||
|
#define SYSTEM_HIDE_CLASS(keyword) SYSTEM_EXTERN_NONE keyword SYSTEM_MODE_HIDDEN
|
||||||
|
#define SYSTEM_HIDE_API(return_type, call_convention) SYSTEM_EXTERN_NONE SYSTEM_MODE_HIDDEN return_type call_convention
|
||||||
|
#define SYSTEM_EXPORT_API(extern_type, return_type, mode, call_convention) extern_type mode return_type call_convention
|
||||||
|
|
||||||
|
//#define LOCAL_API __attribute__((visibility ("internal")))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
Copy/Paste this code in some source file if you want to call a function when the shared_library is loaded/unloaded.
|
||||||
|
|
||||||
|
#if defined(SYSTEM_OS_WINDOWS)
|
||||||
|
|
||||||
|
#define VC_EXTRALEAN
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#include <Windows.h>
|
||||||
|
|
||||||
|
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved)
|
||||||
|
{
|
||||||
|
switch (fdwReason)
|
||||||
|
{
|
||||||
|
case DLL_PROCESS_ATTACH:
|
||||||
|
shared_library_load();
|
||||||
|
break;
|
||||||
|
case DLL_THREAD_ATTACH:
|
||||||
|
break;
|
||||||
|
case DLL_THREAD_DETACH:
|
||||||
|
break;
|
||||||
|
case DLL_PROCESS_DETACH:
|
||||||
|
shared_library_unload();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
#elif defined(SYSTEM_OS_LINUX) || defined(SYSTEM_OS_APPLE)
|
||||||
|
|
||||||
|
__attribute__((constructor)) SYSTEM_HIDE_API(void, SYSTEM_CALL_DEFAULT) system_shared_library_constructor()
|
||||||
|
{
|
||||||
|
shared_library_load();
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute__((destructor)) SYSTEM_HIDE_API(void, SYSTEM_CALL_DEFAULT) system_shared_library_destructor()
|
||||||
|
{
|
||||||
|
shared_library_unload();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
*/
|
|
@ -0,0 +1,60 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) Nemirtingas
|
||||||
|
* This file is part of System.
|
||||||
|
*
|
||||||
|
* System is free software; you can redistribute it
|
||||||
|
* and/or modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* System 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
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with System; if not, see
|
||||||
|
* <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "System_internals.h"
|
||||||
|
|
||||||
|
#if defined(SYSTEM_OS_WINDOWS)
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#define VC_EXTRALEAN
|
||||||
|
#define NOMINMAX
|
||||||
|
#include <Windows.h>
|
||||||
|
|
||||||
|
namespace System {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#elif defined(SYSTEM_OS_LINUX)
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
namespace System {
|
||||||
|
SYSTEM_HIDE_API(std::string, SYSTEM_CALL_DEFAULT) ExpandSymlink(std::string file_path)
|
||||||
|
{
|
||||||
|
struct stat file_stat;
|
||||||
|
std::string link_target;
|
||||||
|
ssize_t name_len = 128;
|
||||||
|
while(lstat(file_path.c_str(), &file_stat) >= 0 && S_ISLNK(file_stat.st_mode) == 1)
|
||||||
|
{
|
||||||
|
do
|
||||||
|
{
|
||||||
|
name_len *= 2;
|
||||||
|
link_target.resize(name_len);
|
||||||
|
name_len = readlink(file_path.c_str(), &link_target[0], link_target.length());
|
||||||
|
} while (name_len == link_target.length());
|
||||||
|
link_target.resize(name_len);
|
||||||
|
file_path = std::move(link_target);
|
||||||
|
}
|
||||||
|
|
||||||
|
return file_path;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,37 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) Nemirtingas
|
||||||
|
* This file is part of System.
|
||||||
|
*
|
||||||
|
* System is free software; you can redistribute it
|
||||||
|
* and/or modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* System 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
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with System; if not, see
|
||||||
|
* <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "SystemExports.h"
|
||||||
|
|
||||||
|
#if defined(SYSTEM_OS_WINDOWS)
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace System {
|
||||||
|
}
|
||||||
|
|
||||||
|
#elif defined(SYSTEM_OS_LINUX)
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace System {
|
||||||
|
SYSTEM_HIDE_API(std::string , SYSTEM_CALL_DEFAULT) ExpandSymlink(std::string file_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,164 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) Nemirtingas
|
||||||
|
* This file is part of System.
|
||||||
|
*
|
||||||
|
* System is free software; you can redistribute it
|
||||||
|
* and/or modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* System 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
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with the System; if not, see
|
||||||
|
* <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
|
#include <condition_variable>
|
||||||
|
#include <functional>
|
||||||
|
#include <future>
|
||||||
|
#include <memory>
|
||||||
|
#include <mutex>
|
||||||
|
#include <queue>
|
||||||
|
#include <thread>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace System {
|
||||||
|
class ThreadPool
|
||||||
|
{
|
||||||
|
using task_t = std::function<void()>;
|
||||||
|
|
||||||
|
std::atomic<bool> _StopWorkers;
|
||||||
|
std::atomic<std::size_t> _ActiveCount;
|
||||||
|
|
||||||
|
std::condition_variable _WorkerNotifier;
|
||||||
|
std::mutex _Mutex;
|
||||||
|
|
||||||
|
std::vector<std::thread> _Workers;
|
||||||
|
std::queue<task_t> _Tasks;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit ThreadPool():
|
||||||
|
_ActiveCount(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
~ThreadPool()
|
||||||
|
{
|
||||||
|
Join();
|
||||||
|
}
|
||||||
|
|
||||||
|
ThreadPool(ThreadPool const &) = delete;
|
||||||
|
ThreadPool(ThreadPool&&) = default;
|
||||||
|
|
||||||
|
ThreadPool&operator=(ThreadPool const &) = delete;
|
||||||
|
ThreadPool&operator=(ThreadPool&&) = default;
|
||||||
|
|
||||||
|
template <class Func, class... Args>
|
||||||
|
auto Push(Func &&fn, Args &&...args)
|
||||||
|
{
|
||||||
|
using return_type = typename std::result_of<Func(Args...)>::type;
|
||||||
|
|
||||||
|
auto task{ std::make_shared<std::packaged_task<return_type()>>(
|
||||||
|
std::bind(std::forward<Func>(fn), std::forward<Args>(args)...)
|
||||||
|
) };
|
||||||
|
|
||||||
|
auto future{ task->get_future() };
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(_Mutex);
|
||||||
|
|
||||||
|
_Tasks.emplace([task]()
|
||||||
|
{
|
||||||
|
(*task)();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
_WorkerNotifier.notify_one();
|
||||||
|
return future;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove all pending tasks from the queue
|
||||||
|
void Clear()
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(_Mutex);
|
||||||
|
_Tasks = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stops all previous and creates new worker threads.
|
||||||
|
void Start(std::size_t worker_count = std::thread::hardware_concurrency())
|
||||||
|
{
|
||||||
|
Join();
|
||||||
|
|
||||||
|
_StopWorkers = false;
|
||||||
|
for (std::size_t i = 0; i < worker_count; ++i)
|
||||||
|
_Workers.emplace_back(std::bind(&ThreadPool::_WorkerLoop, this));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait all workers to finish
|
||||||
|
void Join()
|
||||||
|
{
|
||||||
|
_StopWorkers = true;
|
||||||
|
_WorkerNotifier.notify_all();
|
||||||
|
|
||||||
|
for (auto &thread : _Workers)
|
||||||
|
{
|
||||||
|
if (thread.joinable())
|
||||||
|
thread.join();
|
||||||
|
}
|
||||||
|
|
||||||
|
_Workers.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t WorkerCount() const
|
||||||
|
{
|
||||||
|
return _Workers.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the number of active workers
|
||||||
|
std::size_t ActiveCount() const
|
||||||
|
{
|
||||||
|
return _ActiveCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void _WorkerLoop()
|
||||||
|
{
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
auto task{ _NextTask() };
|
||||||
|
|
||||||
|
if (task)
|
||||||
|
{
|
||||||
|
++_ActiveCount;
|
||||||
|
task();
|
||||||
|
--_ActiveCount;
|
||||||
|
}
|
||||||
|
else if (_StopWorkers)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
task_t _NextTask()
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lock{ _Mutex };
|
||||||
|
|
||||||
|
_WorkerNotifier.wait(lock, [this]() { return !_Tasks.empty() || _StopWorkers; });
|
||||||
|
|
||||||
|
if (_Tasks.empty())
|
||||||
|
return {};
|
||||||
|
|
||||||
|
auto task{ _Tasks.front() };
|
||||||
|
_Tasks.pop();
|
||||||
|
return task;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
// Copyright 2006 Nemanja Trifunovic
|
||||||
|
|
||||||
|
/*
|
||||||
|
Permission is hereby granted, free of charge, to any person or organization
|
||||||
|
obtaining a copy of the software and accompanying documentation covered by
|
||||||
|
this license (the "Software") to use, reproduce, display, distribute,
|
||||||
|
execute, and transmit the Software, and to prepare derivative works of the
|
||||||
|
Software, and to permit third-parties to whom the Software is furnished to
|
||||||
|
do so, all subject to the following:
|
||||||
|
|
||||||
|
The copyright notices in the Software and this entire statement, including
|
||||||
|
the above license grant, this restriction and the following disclaimer,
|
||||||
|
must be included in all copies of the Software, in whole or in part, and
|
||||||
|
all derivative works of the Software, unless such copies or derivative
|
||||||
|
works are solely in the form of machine-executable object code generated by
|
||||||
|
a source language processor.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||||
|
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||||
|
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||||
|
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef UTF8_FOR_CPP_2675DCD0_9480_4c0c_B92A_CC14C027B731
|
||||||
|
#define UTF8_FOR_CPP_2675DCD0_9480_4c0c_B92A_CC14C027B731
|
||||||
|
|
||||||
|
#include "utf8/checked.h"
|
||||||
|
#include "utf8/unchecked.h"
|
||||||
|
|
||||||
|
#endif // header guard
|
|
@ -0,0 +1,336 @@
|
||||||
|
// Copyright 2006-2016 Nemanja Trifunovic
|
||||||
|
|
||||||
|
/*
|
||||||
|
Permission is hereby granted, free of charge, to any person or organization
|
||||||
|
obtaining a copy of the software and accompanying documentation covered by
|
||||||
|
this license (the "Software") to use, reproduce, display, distribute,
|
||||||
|
execute, and transmit the Software, and to prepare derivative works of the
|
||||||
|
Software, and to permit third-parties to whom the Software is furnished to
|
||||||
|
do so, all subject to the following:
|
||||||
|
|
||||||
|
The copyright notices in the Software and this entire statement, including
|
||||||
|
the above license grant, this restriction and the following disclaimer,
|
||||||
|
must be included in all copies of the Software, in whole or in part, and
|
||||||
|
all derivative works of the Software, unless such copies or derivative
|
||||||
|
works are solely in the form of machine-executable object code generated by
|
||||||
|
a source language processor.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||||
|
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||||
|
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||||
|
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef UTF8_FOR_CPP_CHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
|
||||||
|
#define UTF8_FOR_CPP_CHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
|
||||||
|
|
||||||
|
#include "core.h"
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
namespace utf8
|
||||||
|
{
|
||||||
|
// Base for the exceptions that may be thrown from the library
|
||||||
|
class exception : public ::std::exception {
|
||||||
|
};
|
||||||
|
|
||||||
|
// Exceptions that may be thrown from the library functions.
|
||||||
|
class invalid_code_point : public exception {
|
||||||
|
uint32_t cp;
|
||||||
|
public:
|
||||||
|
invalid_code_point(uint32_t codepoint) : cp(codepoint) {}
|
||||||
|
virtual const char* what() const UTF_CPP_NOEXCEPT UTF_CPP_OVERRIDE { return "Invalid code point"; }
|
||||||
|
uint32_t code_point() const {return cp;}
|
||||||
|
};
|
||||||
|
|
||||||
|
class invalid_utf8 : public exception {
|
||||||
|
uint8_t u8;
|
||||||
|
public:
|
||||||
|
invalid_utf8 (uint8_t u) : u8(u) {}
|
||||||
|
virtual const char* what() const UTF_CPP_NOEXCEPT UTF_CPP_OVERRIDE { return "Invalid UTF-8"; }
|
||||||
|
uint8_t utf8_octet() const {return u8;}
|
||||||
|
};
|
||||||
|
|
||||||
|
class invalid_utf16 : public exception {
|
||||||
|
uint16_t u16;
|
||||||
|
public:
|
||||||
|
invalid_utf16 (uint16_t u) : u16(u) {}
|
||||||
|
virtual const char* what() const UTF_CPP_NOEXCEPT UTF_CPP_OVERRIDE { return "Invalid UTF-16"; }
|
||||||
|
uint16_t utf16_word() const {return u16;}
|
||||||
|
};
|
||||||
|
|
||||||
|
class not_enough_room : public exception {
|
||||||
|
public:
|
||||||
|
virtual const char* what() const UTF_CPP_NOEXCEPT UTF_CPP_OVERRIDE { return "Not enough space"; }
|
||||||
|
};
|
||||||
|
|
||||||
|
/// The library API - functions intended to be called by the users
|
||||||
|
|
||||||
|
template <typename octet_iterator>
|
||||||
|
octet_iterator append(uint32_t cp, octet_iterator result)
|
||||||
|
{
|
||||||
|
if (!utf8::internal::is_code_point_valid(cp))
|
||||||
|
throw invalid_code_point(cp);
|
||||||
|
|
||||||
|
if (cp < 0x80) // one octet
|
||||||
|
*(result++) = static_cast<uint8_t>(cp);
|
||||||
|
else if (cp < 0x800) { // two octets
|
||||||
|
*(result++) = static_cast<uint8_t>((cp >> 6) | 0xc0);
|
||||||
|
*(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80);
|
||||||
|
}
|
||||||
|
else if (cp < 0x10000) { // three octets
|
||||||
|
*(result++) = static_cast<uint8_t>((cp >> 12) | 0xe0);
|
||||||
|
*(result++) = static_cast<uint8_t>(((cp >> 6) & 0x3f) | 0x80);
|
||||||
|
*(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80);
|
||||||
|
}
|
||||||
|
else { // four octets
|
||||||
|
*(result++) = static_cast<uint8_t>((cp >> 18) | 0xf0);
|
||||||
|
*(result++) = static_cast<uint8_t>(((cp >> 12) & 0x3f) | 0x80);
|
||||||
|
*(result++) = static_cast<uint8_t>(((cp >> 6) & 0x3f) | 0x80);
|
||||||
|
*(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename octet_iterator, typename output_iterator>
|
||||||
|
output_iterator replace_invalid(octet_iterator start, octet_iterator end, output_iterator out, uint32_t replacement)
|
||||||
|
{
|
||||||
|
while (start != end) {
|
||||||
|
octet_iterator sequence_start = start;
|
||||||
|
internal::utf_error err_code = utf8::internal::validate_next(start, end);
|
||||||
|
switch (err_code) {
|
||||||
|
case internal::UTF8_OK :
|
||||||
|
for (octet_iterator it = sequence_start; it != start; ++it)
|
||||||
|
*out++ = *it;
|
||||||
|
break;
|
||||||
|
case internal::NOT_ENOUGH_ROOM:
|
||||||
|
out = utf8::append (replacement, out);
|
||||||
|
start = end;
|
||||||
|
break;
|
||||||
|
case internal::INVALID_LEAD:
|
||||||
|
out = utf8::append (replacement, out);
|
||||||
|
++start;
|
||||||
|
break;
|
||||||
|
case internal::INCOMPLETE_SEQUENCE:
|
||||||
|
case internal::OVERLONG_SEQUENCE:
|
||||||
|
case internal::INVALID_CODE_POINT:
|
||||||
|
out = utf8::append (replacement, out);
|
||||||
|
++start;
|
||||||
|
// just one replacement mark for the sequence
|
||||||
|
while (start != end && utf8::internal::is_trail(*start))
|
||||||
|
++start;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename octet_iterator, typename output_iterator>
|
||||||
|
inline output_iterator replace_invalid(octet_iterator start, octet_iterator end, output_iterator out)
|
||||||
|
{
|
||||||
|
static const uint32_t replacement_marker = utf8::internal::mask16(0xfffd);
|
||||||
|
return utf8::replace_invalid(start, end, out, replacement_marker);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename octet_iterator>
|
||||||
|
uint32_t next(octet_iterator& it, octet_iterator end)
|
||||||
|
{
|
||||||
|
uint32_t cp = 0;
|
||||||
|
internal::utf_error err_code = utf8::internal::validate_next(it, end, cp);
|
||||||
|
switch (err_code) {
|
||||||
|
case internal::UTF8_OK :
|
||||||
|
break;
|
||||||
|
case internal::NOT_ENOUGH_ROOM :
|
||||||
|
throw not_enough_room();
|
||||||
|
case internal::INVALID_LEAD :
|
||||||
|
case internal::INCOMPLETE_SEQUENCE :
|
||||||
|
case internal::OVERLONG_SEQUENCE :
|
||||||
|
throw invalid_utf8(*it);
|
||||||
|
case internal::INVALID_CODE_POINT :
|
||||||
|
throw invalid_code_point(cp);
|
||||||
|
}
|
||||||
|
return cp;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename octet_iterator>
|
||||||
|
uint32_t peek_next(octet_iterator it, octet_iterator end)
|
||||||
|
{
|
||||||
|
return utf8::next(it, end);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename octet_iterator>
|
||||||
|
uint32_t prior(octet_iterator& it, octet_iterator start)
|
||||||
|
{
|
||||||
|
// can't do much if it == start
|
||||||
|
if (it == start)
|
||||||
|
throw not_enough_room();
|
||||||
|
|
||||||
|
octet_iterator end = it;
|
||||||
|
// Go back until we hit either a lead octet or start
|
||||||
|
while (utf8::internal::is_trail(*(--it)))
|
||||||
|
if (it == start)
|
||||||
|
throw invalid_utf8(*it); // error - no lead byte in the sequence
|
||||||
|
return utf8::peek_next(it, end);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename octet_iterator, typename distance_type>
|
||||||
|
void advance (octet_iterator& it, distance_type n, octet_iterator end)
|
||||||
|
{
|
||||||
|
const distance_type zero(0);
|
||||||
|
if (n < zero) {
|
||||||
|
// backward
|
||||||
|
for (distance_type i = n; i < zero; ++i)
|
||||||
|
utf8::prior(it, end);
|
||||||
|
} else {
|
||||||
|
// forward
|
||||||
|
for (distance_type i = zero; i < n; ++i)
|
||||||
|
utf8::next(it, end);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename octet_iterator>
|
||||||
|
typename std::iterator_traits<octet_iterator>::difference_type
|
||||||
|
distance (octet_iterator first, octet_iterator last)
|
||||||
|
{
|
||||||
|
typename std::iterator_traits<octet_iterator>::difference_type dist;
|
||||||
|
for (dist = 0; first < last; ++dist)
|
||||||
|
utf8::next(first, last);
|
||||||
|
return dist;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename u16bit_iterator, typename octet_iterator>
|
||||||
|
octet_iterator utf16to8 (u16bit_iterator start, u16bit_iterator end, octet_iterator result)
|
||||||
|
{
|
||||||
|
while (start != end) {
|
||||||
|
uint32_t cp = utf8::internal::mask16(*start++);
|
||||||
|
// Take care of surrogate pairs first
|
||||||
|
if (utf8::internal::is_lead_surrogate(cp)) {
|
||||||
|
if (start != end) {
|
||||||
|
uint32_t trail_surrogate = utf8::internal::mask16(*start++);
|
||||||
|
if (utf8::internal::is_trail_surrogate(trail_surrogate))
|
||||||
|
cp = (cp << 10) + trail_surrogate + internal::SURROGATE_OFFSET;
|
||||||
|
else
|
||||||
|
throw invalid_utf16(static_cast<uint16_t>(trail_surrogate));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
throw invalid_utf16(static_cast<uint16_t>(cp));
|
||||||
|
|
||||||
|
}
|
||||||
|
// Lone trail surrogate
|
||||||
|
else if (utf8::internal::is_trail_surrogate(cp))
|
||||||
|
throw invalid_utf16(static_cast<uint16_t>(cp));
|
||||||
|
|
||||||
|
result = utf8::append(cp, result);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename u16bit_iterator, typename octet_iterator>
|
||||||
|
u16bit_iterator utf8to16 (octet_iterator start, octet_iterator end, u16bit_iterator result)
|
||||||
|
{
|
||||||
|
while (start < end) {
|
||||||
|
uint32_t cp = utf8::next(start, end);
|
||||||
|
if (cp > 0xffff) { //make a surrogate pair
|
||||||
|
*result++ = static_cast<uint16_t>((cp >> 10) + internal::LEAD_OFFSET);
|
||||||
|
*result++ = static_cast<uint16_t>((cp & 0x3ff) + internal::TRAIL_SURROGATE_MIN);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
*result++ = static_cast<uint16_t>(cp);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename octet_iterator, typename u32bit_iterator>
|
||||||
|
octet_iterator utf32to8 (u32bit_iterator start, u32bit_iterator end, octet_iterator result)
|
||||||
|
{
|
||||||
|
while (start != end)
|
||||||
|
result = utf8::append(*(start++), result);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename octet_iterator, typename u32bit_iterator>
|
||||||
|
u32bit_iterator utf8to32 (octet_iterator start, octet_iterator end, u32bit_iterator result)
|
||||||
|
{
|
||||||
|
while (start < end)
|
||||||
|
(*result++) = utf8::next(start, end);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The iterator class
|
||||||
|
template <typename octet_iterator>
|
||||||
|
class iterator {
|
||||||
|
octet_iterator it;
|
||||||
|
octet_iterator range_start;
|
||||||
|
octet_iterator range_end;
|
||||||
|
public:
|
||||||
|
typedef uint32_t value_type;
|
||||||
|
typedef uint32_t* pointer;
|
||||||
|
typedef uint32_t& reference;
|
||||||
|
typedef std::ptrdiff_t difference_type;
|
||||||
|
typedef std::bidirectional_iterator_tag iterator_category;
|
||||||
|
iterator () {}
|
||||||
|
explicit iterator (const octet_iterator& octet_it,
|
||||||
|
const octet_iterator& rangestart,
|
||||||
|
const octet_iterator& rangeend) :
|
||||||
|
it(octet_it), range_start(rangestart), range_end(rangeend)
|
||||||
|
{
|
||||||
|
if (it < range_start || it > range_end)
|
||||||
|
throw std::out_of_range("Invalid utf-8 iterator position");
|
||||||
|
}
|
||||||
|
// the default "big three" are OK
|
||||||
|
octet_iterator base () const { return it; }
|
||||||
|
uint32_t operator * () const
|
||||||
|
{
|
||||||
|
octet_iterator temp = it;
|
||||||
|
return utf8::next(temp, range_end);
|
||||||
|
}
|
||||||
|
bool operator == (const iterator& rhs) const
|
||||||
|
{
|
||||||
|
if (range_start != rhs.range_start || range_end != rhs.range_end)
|
||||||
|
throw std::logic_error("Comparing utf-8 iterators defined with different ranges");
|
||||||
|
return (it == rhs.it);
|
||||||
|
}
|
||||||
|
bool operator != (const iterator& rhs) const
|
||||||
|
{
|
||||||
|
return !(operator == (rhs));
|
||||||
|
}
|
||||||
|
iterator& operator ++ ()
|
||||||
|
{
|
||||||
|
utf8::next(it, range_end);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
iterator operator ++ (int)
|
||||||
|
{
|
||||||
|
iterator temp = *this;
|
||||||
|
utf8::next(it, range_end);
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
iterator& operator -- ()
|
||||||
|
{
|
||||||
|
utf8::prior(it, range_start);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
iterator operator -- (int)
|
||||||
|
{
|
||||||
|
iterator temp = *this;
|
||||||
|
utf8::prior(it, range_start);
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
}; // class iterator
|
||||||
|
|
||||||
|
} // namespace utf8
|
||||||
|
|
||||||
|
#if UTF_CPP_CPLUSPLUS >= 201703L // C++ 17 or later
|
||||||
|
#include "cpp17.h"
|
||||||
|
//#elif UTF_CPP_CPLUSPLUS >= 201103L // C++ 11 or later
|
||||||
|
#else
|
||||||
|
#include "cpp11.h"
|
||||||
|
#endif // C++ 11 or later
|
||||||
|
|
||||||
|
#endif //header guard
|
||||||
|
|
|
@ -0,0 +1,338 @@
|
||||||
|
// Copyright 2006 Nemanja Trifunovic
|
||||||
|
|
||||||
|
/*
|
||||||
|
Permission is hereby granted, free of charge, to any person or organization
|
||||||
|
obtaining a copy of the software and accompanying documentation covered by
|
||||||
|
this license (the "Software") to use, reproduce, display, distribute,
|
||||||
|
execute, and transmit the Software, and to prepare derivative works of the
|
||||||
|
Software, and to permit third-parties to whom the Software is furnished to
|
||||||
|
do so, all subject to the following:
|
||||||
|
|
||||||
|
The copyright notices in the Software and this entire statement, including
|
||||||
|
the above license grant, this restriction and the following disclaimer,
|
||||||
|
must be included in all copies of the Software, in whole or in part, and
|
||||||
|
all derivative works of the Software, unless such copies or derivative
|
||||||
|
works are solely in the form of machine-executable object code generated by
|
||||||
|
a source language processor.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||||
|
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||||
|
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||||
|
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef UTF8_FOR_CPP_CORE_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
|
||||||
|
#define UTF8_FOR_CPP_CORE_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
|
||||||
|
|
||||||
|
#include <iterator>
|
||||||
|
|
||||||
|
// Determine the C++ standard version.
|
||||||
|
// If the user defines UTF_CPP_CPLUSPLUS, use that.
|
||||||
|
// Otherwise, trust the unreliable predefined macro __cplusplus
|
||||||
|
|
||||||
|
#if !defined UTF_CPP_CPLUSPLUS
|
||||||
|
#define UTF_CPP_CPLUSPLUS __cplusplus
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if UTF_CPP_CPLUSPLUS >= 201103L // C++ 11 or later
|
||||||
|
#define UTF_CPP_OVERRIDE override
|
||||||
|
#define UTF_CPP_NOEXCEPT noexcept
|
||||||
|
#else // C++ 98/03
|
||||||
|
#define UTF_CPP_OVERRIDE
|
||||||
|
#define UTF_CPP_NOEXCEPT throw()
|
||||||
|
#endif // C++ 11 or later
|
||||||
|
|
||||||
|
|
||||||
|
namespace utf8
|
||||||
|
{
|
||||||
|
// The typedefs for 8-bit, 16-bit and 32-bit unsigned integers
|
||||||
|
// You may need to change them to match your system.
|
||||||
|
// These typedefs have the same names as ones from cstdint, or boost/cstdint
|
||||||
|
typedef unsigned char uint8_t;
|
||||||
|
typedef unsigned short uint16_t;
|
||||||
|
typedef unsigned int uint32_t;
|
||||||
|
|
||||||
|
// Helper code - not intended to be directly called by the library users. May be changed at any time
|
||||||
|
namespace internal
|
||||||
|
{
|
||||||
|
// Unicode constants
|
||||||
|
// Leading (high) surrogates: 0xd800 - 0xdbff
|
||||||
|
// Trailing (low) surrogates: 0xdc00 - 0xdfff
|
||||||
|
const uint16_t LEAD_SURROGATE_MIN = 0xd800u;
|
||||||
|
const uint16_t LEAD_SURROGATE_MAX = 0xdbffu;
|
||||||
|
const uint16_t TRAIL_SURROGATE_MIN = 0xdc00u;
|
||||||
|
const uint16_t TRAIL_SURROGATE_MAX = 0xdfffu;
|
||||||
|
const uint16_t LEAD_OFFSET = 0xd7c0u; // LEAD_SURROGATE_MIN - (0x10000 >> 10)
|
||||||
|
const uint32_t SURROGATE_OFFSET = 0xfca02400u; // 0x10000u - (LEAD_SURROGATE_MIN << 10) - TRAIL_SURROGATE_MIN
|
||||||
|
|
||||||
|
// Maximum valid value for a Unicode code point
|
||||||
|
const uint32_t CODE_POINT_MAX = 0x0010ffffu;
|
||||||
|
|
||||||
|
template<typename octet_type>
|
||||||
|
inline uint8_t mask8(octet_type oc)
|
||||||
|
{
|
||||||
|
return static_cast<uint8_t>(0xff & oc);
|
||||||
|
}
|
||||||
|
template<typename u16_type>
|
||||||
|
inline uint16_t mask16(u16_type oc)
|
||||||
|
{
|
||||||
|
return static_cast<uint16_t>(0xffff & oc);
|
||||||
|
}
|
||||||
|
template<typename octet_type>
|
||||||
|
inline bool is_trail(octet_type oc)
|
||||||
|
{
|
||||||
|
return ((utf8::internal::mask8(oc) >> 6) == 0x2);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename u16>
|
||||||
|
inline bool is_lead_surrogate(u16 cp)
|
||||||
|
{
|
||||||
|
return (cp >= LEAD_SURROGATE_MIN && cp <= LEAD_SURROGATE_MAX);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename u16>
|
||||||
|
inline bool is_trail_surrogate(u16 cp)
|
||||||
|
{
|
||||||
|
return (cp >= TRAIL_SURROGATE_MIN && cp <= TRAIL_SURROGATE_MAX);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename u16>
|
||||||
|
inline bool is_surrogate(u16 cp)
|
||||||
|
{
|
||||||
|
return (cp >= LEAD_SURROGATE_MIN && cp <= TRAIL_SURROGATE_MAX);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename u32>
|
||||||
|
inline bool is_code_point_valid(u32 cp)
|
||||||
|
{
|
||||||
|
return (cp <= CODE_POINT_MAX && !utf8::internal::is_surrogate(cp));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename octet_iterator>
|
||||||
|
inline typename std::iterator_traits<octet_iterator>::difference_type
|
||||||
|
sequence_length(octet_iterator lead_it)
|
||||||
|
{
|
||||||
|
uint8_t lead = utf8::internal::mask8(*lead_it);
|
||||||
|
if (lead < 0x80)
|
||||||
|
return 1;
|
||||||
|
else if ((lead >> 5) == 0x6)
|
||||||
|
return 2;
|
||||||
|
else if ((lead >> 4) == 0xe)
|
||||||
|
return 3;
|
||||||
|
else if ((lead >> 3) == 0x1e)
|
||||||
|
return 4;
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename octet_difference_type>
|
||||||
|
inline bool is_overlong_sequence(uint32_t cp, octet_difference_type length)
|
||||||
|
{
|
||||||
|
if (cp < 0x80) {
|
||||||
|
if (length != 1)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (cp < 0x800) {
|
||||||
|
if (length != 2)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (cp < 0x10000) {
|
||||||
|
if (length != 3)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum utf_error {UTF8_OK, NOT_ENOUGH_ROOM, INVALID_LEAD, INCOMPLETE_SEQUENCE, OVERLONG_SEQUENCE, INVALID_CODE_POINT};
|
||||||
|
|
||||||
|
/// Helper for get_sequence_x
|
||||||
|
template <typename octet_iterator>
|
||||||
|
utf_error increase_safely(octet_iterator& it, octet_iterator end)
|
||||||
|
{
|
||||||
|
if (++it == end)
|
||||||
|
return NOT_ENOUGH_ROOM;
|
||||||
|
|
||||||
|
if (!utf8::internal::is_trail(*it))
|
||||||
|
return INCOMPLETE_SEQUENCE;
|
||||||
|
|
||||||
|
return UTF8_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(IT, END) {utf_error ret = increase_safely(IT, END); if (ret != UTF8_OK) return ret;}
|
||||||
|
|
||||||
|
/// get_sequence_x functions decode utf-8 sequences of the length x
|
||||||
|
template <typename octet_iterator>
|
||||||
|
utf_error get_sequence_1(octet_iterator& it, octet_iterator end, uint32_t& code_point)
|
||||||
|
{
|
||||||
|
if (it == end)
|
||||||
|
return NOT_ENOUGH_ROOM;
|
||||||
|
|
||||||
|
code_point = utf8::internal::mask8(*it);
|
||||||
|
|
||||||
|
return UTF8_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename octet_iterator>
|
||||||
|
utf_error get_sequence_2(octet_iterator& it, octet_iterator end, uint32_t& code_point)
|
||||||
|
{
|
||||||
|
if (it == end)
|
||||||
|
return NOT_ENOUGH_ROOM;
|
||||||
|
|
||||||
|
code_point = utf8::internal::mask8(*it);
|
||||||
|
|
||||||
|
UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
|
||||||
|
|
||||||
|
code_point = ((code_point << 6) & 0x7ff) + ((*it) & 0x3f);
|
||||||
|
|
||||||
|
return UTF8_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename octet_iterator>
|
||||||
|
utf_error get_sequence_3(octet_iterator& it, octet_iterator end, uint32_t& code_point)
|
||||||
|
{
|
||||||
|
if (it == end)
|
||||||
|
return NOT_ENOUGH_ROOM;
|
||||||
|
|
||||||
|
code_point = utf8::internal::mask8(*it);
|
||||||
|
|
||||||
|
UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
|
||||||
|
|
||||||
|
code_point = ((code_point << 12) & 0xffff) + ((utf8::internal::mask8(*it) << 6) & 0xfff);
|
||||||
|
|
||||||
|
UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
|
||||||
|
|
||||||
|
code_point += (*it) & 0x3f;
|
||||||
|
|
||||||
|
return UTF8_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename octet_iterator>
|
||||||
|
utf_error get_sequence_4(octet_iterator& it, octet_iterator end, uint32_t& code_point)
|
||||||
|
{
|
||||||
|
if (it == end)
|
||||||
|
return NOT_ENOUGH_ROOM;
|
||||||
|
|
||||||
|
code_point = utf8::internal::mask8(*it);
|
||||||
|
|
||||||
|
UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
|
||||||
|
|
||||||
|
code_point = ((code_point << 18) & 0x1fffff) + ((utf8::internal::mask8(*it) << 12) & 0x3ffff);
|
||||||
|
|
||||||
|
UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
|
||||||
|
|
||||||
|
code_point += (utf8::internal::mask8(*it) << 6) & 0xfff;
|
||||||
|
|
||||||
|
UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
|
||||||
|
|
||||||
|
code_point += (*it) & 0x3f;
|
||||||
|
|
||||||
|
return UTF8_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR
|
||||||
|
|
||||||
|
template <typename octet_iterator>
|
||||||
|
utf_error validate_next(octet_iterator& it, octet_iterator end, uint32_t& code_point)
|
||||||
|
{
|
||||||
|
if (it == end)
|
||||||
|
return NOT_ENOUGH_ROOM;
|
||||||
|
|
||||||
|
// Save the original value of it so we can go back in case of failure
|
||||||
|
// Of course, it does not make much sense with i.e. stream iterators
|
||||||
|
octet_iterator original_it = it;
|
||||||
|
|
||||||
|
uint32_t cp = 0;
|
||||||
|
// Determine the sequence length based on the lead octet
|
||||||
|
typedef typename std::iterator_traits<octet_iterator>::difference_type octet_difference_type;
|
||||||
|
const octet_difference_type length = utf8::internal::sequence_length(it);
|
||||||
|
|
||||||
|
// Get trail octets and calculate the code point
|
||||||
|
utf_error err = UTF8_OK;
|
||||||
|
switch (length) {
|
||||||
|
case 0:
|
||||||
|
return INVALID_LEAD;
|
||||||
|
case 1:
|
||||||
|
err = utf8::internal::get_sequence_1(it, end, cp);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
err = utf8::internal::get_sequence_2(it, end, cp);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
err = utf8::internal::get_sequence_3(it, end, cp);
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
err = utf8::internal::get_sequence_4(it, end, cp);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (err == UTF8_OK) {
|
||||||
|
// Decoding succeeded. Now, security checks...
|
||||||
|
if (utf8::internal::is_code_point_valid(cp)) {
|
||||||
|
if (!utf8::internal::is_overlong_sequence(cp, length)){
|
||||||
|
// Passed! Return here.
|
||||||
|
code_point = cp;
|
||||||
|
++it;
|
||||||
|
return UTF8_OK;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
err = OVERLONG_SEQUENCE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
err = INVALID_CODE_POINT;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Failure branch - restore the original value of the iterator
|
||||||
|
it = original_it;
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename octet_iterator>
|
||||||
|
inline utf_error validate_next(octet_iterator& it, octet_iterator end) {
|
||||||
|
uint32_t ignored;
|
||||||
|
return utf8::internal::validate_next(it, end, ignored);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
|
||||||
|
/// The library API - functions intended to be called by the users
|
||||||
|
|
||||||
|
// Byte order mark
|
||||||
|
constexpr uint8_t bom[] = {0xef, 0xbb, 0xbf};
|
||||||
|
|
||||||
|
template <typename octet_iterator>
|
||||||
|
octet_iterator find_invalid(octet_iterator start, octet_iterator end)
|
||||||
|
{
|
||||||
|
octet_iterator result = start;
|
||||||
|
while (result != end) {
|
||||||
|
utf8::internal::utf_error err_code = utf8::internal::validate_next(result, end);
|
||||||
|
if (err_code != internal::UTF8_OK)
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename octet_iterator>
|
||||||
|
inline bool is_valid(octet_iterator start, octet_iterator end)
|
||||||
|
{
|
||||||
|
return (utf8::find_invalid(start, end) == end);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename octet_iterator>
|
||||||
|
inline bool starts_with_bom (octet_iterator it, octet_iterator end)
|
||||||
|
{
|
||||||
|
return (
|
||||||
|
((it != end) && (utf8::internal::mask8(*it++)) == bom[0]) &&
|
||||||
|
((it != end) && (utf8::internal::mask8(*it++)) == bom[1]) &&
|
||||||
|
((it != end) && (utf8::internal::mask8(*it)) == bom[2])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} // namespace utf8
|
||||||
|
|
||||||
|
#endif // header guard
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,103 @@
|
||||||
|
// Copyright 2018 Nemanja Trifunovic
|
||||||
|
|
||||||
|
/*
|
||||||
|
Permission is hereby granted, free of charge, to any person or organization
|
||||||
|
obtaining a copy of the software and accompanying documentation covered by
|
||||||
|
this license (the "Software") to use, reproduce, display, distribute,
|
||||||
|
execute, and transmit the Software, and to prepare derivative works of the
|
||||||
|
Software, and to permit third-parties to whom the Software is furnished to
|
||||||
|
do so, all subject to the following:
|
||||||
|
|
||||||
|
The copyright notices in the Software and this entire statement, including
|
||||||
|
the above license grant, this restriction and the following disclaimer,
|
||||||
|
must be included in all copies of the Software, in whole or in part, and
|
||||||
|
all derivative works of the Software, unless such copies or derivative
|
||||||
|
works are solely in the form of machine-executable object code generated by
|
||||||
|
a source language processor.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||||
|
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||||
|
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||||
|
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef UTF8_FOR_CPP_a184c22c_d012_11e8_a8d5_f2801f1b9fd1
|
||||||
|
#define UTF8_FOR_CPP_a184c22c_d012_11e8_a8d5_f2801f1b9fd1
|
||||||
|
|
||||||
|
#include "checked.h"
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace utf8
|
||||||
|
{
|
||||||
|
|
||||||
|
inline void append(char32_t cp, std::string& s)
|
||||||
|
{
|
||||||
|
append(uint32_t(cp), std::back_inserter(s));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::string utf16to8(const std::u16string& s)
|
||||||
|
{
|
||||||
|
std::string result;
|
||||||
|
utf16to8(s.begin(), s.end(), std::back_inserter(result));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::u16string utf8to16(const std::string& s)
|
||||||
|
{
|
||||||
|
std::u16string result;
|
||||||
|
utf8to16(s.begin(), s.end(), std::back_inserter(result));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::string utf32to8(const std::u32string& s)
|
||||||
|
{
|
||||||
|
std::string result;
|
||||||
|
utf32to8(s.begin(), s.end(), std::back_inserter(result));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::u32string utf8to32(const std::string& s)
|
||||||
|
{
|
||||||
|
std::u32string result;
|
||||||
|
utf8to32(s.begin(), s.end(), std::back_inserter(result));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::size_t find_invalid(const std::string& s)
|
||||||
|
{
|
||||||
|
std::string::const_iterator invalid = find_invalid(s.begin(), s.end());
|
||||||
|
return (invalid == s.end()) ? std::string::npos : (invalid - s.begin());
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool is_valid(const std::string& s)
|
||||||
|
{
|
||||||
|
return is_valid(s.begin(), s.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::string replace_invalid(const std::string& s, char32_t replacement)
|
||||||
|
{
|
||||||
|
std::string result;
|
||||||
|
replace_invalid(s.begin(), s.end(), std::back_inserter(result), replacement);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::string replace_invalid(const std::string& s)
|
||||||
|
{
|
||||||
|
std::string result;
|
||||||
|
replace_invalid(s.begin(), s.end(), std::back_inserter(result));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool starts_with_bom(const std::string& s)
|
||||||
|
{
|
||||||
|
return starts_with_bom(s.begin(), s.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace utf8
|
||||||
|
|
||||||
|
#endif // header guard
|
||||||
|
|
|
@ -0,0 +1,103 @@
|
||||||
|
// Copyright 2018 Nemanja Trifunovic
|
||||||
|
|
||||||
|
/*
|
||||||
|
Permission is hereby granted, free of charge, to any person or organization
|
||||||
|
obtaining a copy of the software and accompanying documentation covered by
|
||||||
|
this license (the "Software") to use, reproduce, display, distribute,
|
||||||
|
execute, and transmit the Software, and to prepare derivative works of the
|
||||||
|
Software, and to permit third-parties to whom the Software is furnished to
|
||||||
|
do so, all subject to the following:
|
||||||
|
|
||||||
|
The copyright notices in the Software and this entire statement, including
|
||||||
|
the above license grant, this restriction and the following disclaimer,
|
||||||
|
must be included in all copies of the Software, in whole or in part, and
|
||||||
|
all derivative works of the Software, unless such copies or derivative
|
||||||
|
works are solely in the form of machine-executable object code generated by
|
||||||
|
a source language processor.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||||
|
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||||
|
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||||
|
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef UTF8_FOR_CPP_7e906c01_03a3_4daf_b420_ea7ea952b3c9
|
||||||
|
#define UTF8_FOR_CPP_7e906c01_03a3_4daf_b420_ea7ea952b3c9
|
||||||
|
|
||||||
|
#include "checked.h"
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace utf8
|
||||||
|
{
|
||||||
|
|
||||||
|
inline void append(char32_t cp, std::string& s)
|
||||||
|
{
|
||||||
|
append(uint32_t(cp), std::back_inserter(s));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::string utf16to8(std::u16string_view s)
|
||||||
|
{
|
||||||
|
std::string result;
|
||||||
|
utf16to8(s.begin(), s.end(), std::back_inserter(result));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::u16string utf8to16(std::string_view s)
|
||||||
|
{
|
||||||
|
std::u16string result;
|
||||||
|
utf8to16(s.begin(), s.end(), std::back_inserter(result));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::string utf32to8(std::u32string_view s)
|
||||||
|
{
|
||||||
|
std::string result;
|
||||||
|
utf32to8(s.begin(), s.end(), std::back_inserter(result));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::u32string utf8to32(std::string_view s)
|
||||||
|
{
|
||||||
|
std::u32string result;
|
||||||
|
utf8to32(s.begin(), s.end(), std::back_inserter(result));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::size_t find_invalid(std::string_view s)
|
||||||
|
{
|
||||||
|
std::string_view::const_iterator invalid = find_invalid(s.begin(), s.end());
|
||||||
|
return (invalid == s.end()) ? std::string_view::npos : (invalid - s.begin());
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool is_valid(std::string_view s)
|
||||||
|
{
|
||||||
|
return is_valid(s.begin(), s.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::string replace_invalid(std::string_view s, char32_t replacement)
|
||||||
|
{
|
||||||
|
std::string result;
|
||||||
|
replace_invalid(s.begin(), s.end(), std::back_inserter(result), replacement);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::string replace_invalid(std::string_view s)
|
||||||
|
{
|
||||||
|
std::string result;
|
||||||
|
replace_invalid(s.begin(), s.end(), std::back_inserter(result));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool starts_with_bom(std::string_view s)
|
||||||
|
{
|
||||||
|
return starts_with_bom(s.begin(), s.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace utf8
|
||||||
|
|
||||||
|
#endif // header guard
|
||||||
|
|
|
@ -0,0 +1,274 @@
|
||||||
|
// Copyright 2006 Nemanja Trifunovic
|
||||||
|
|
||||||
|
/*
|
||||||
|
Permission is hereby granted, free of charge, to any person or organization
|
||||||
|
obtaining a copy of the software and accompanying documentation covered by
|
||||||
|
this license (the "Software") to use, reproduce, display, distribute,
|
||||||
|
execute, and transmit the Software, and to prepare derivative works of the
|
||||||
|
Software, and to permit third-parties to whom the Software is furnished to
|
||||||
|
do so, all subject to the following:
|
||||||
|
|
||||||
|
The copyright notices in the Software and this entire statement, including
|
||||||
|
the above license grant, this restriction and the following disclaimer,
|
||||||
|
must be included in all copies of the Software, in whole or in part, and
|
||||||
|
all derivative works of the Software, unless such copies or derivative
|
||||||
|
works are solely in the form of machine-executable object code generated by
|
||||||
|
a source language processor.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||||
|
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||||
|
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||||
|
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef UTF8_FOR_CPP_UNCHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
|
||||||
|
#define UTF8_FOR_CPP_UNCHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
|
||||||
|
|
||||||
|
#include "core.h"
|
||||||
|
|
||||||
|
namespace utf8
|
||||||
|
{
|
||||||
|
namespace unchecked
|
||||||
|
{
|
||||||
|
template <typename octet_iterator>
|
||||||
|
octet_iterator append(uint32_t cp, octet_iterator result)
|
||||||
|
{
|
||||||
|
if (cp < 0x80) // one octet
|
||||||
|
*(result++) = static_cast<uint8_t>(cp);
|
||||||
|
else if (cp < 0x800) { // two octets
|
||||||
|
*(result++) = static_cast<uint8_t>((cp >> 6) | 0xc0);
|
||||||
|
*(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80);
|
||||||
|
}
|
||||||
|
else if (cp < 0x10000) { // three octets
|
||||||
|
*(result++) = static_cast<uint8_t>((cp >> 12) | 0xe0);
|
||||||
|
*(result++) = static_cast<uint8_t>(((cp >> 6) & 0x3f) | 0x80);
|
||||||
|
*(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80);
|
||||||
|
}
|
||||||
|
else { // four octets
|
||||||
|
*(result++) = static_cast<uint8_t>((cp >> 18) | 0xf0);
|
||||||
|
*(result++) = static_cast<uint8_t>(((cp >> 12) & 0x3f)| 0x80);
|
||||||
|
*(result++) = static_cast<uint8_t>(((cp >> 6) & 0x3f) | 0x80);
|
||||||
|
*(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename octet_iterator, typename output_iterator>
|
||||||
|
output_iterator replace_invalid(octet_iterator start, octet_iterator end, output_iterator out, uint32_t replacement)
|
||||||
|
{
|
||||||
|
while (start != end) {
|
||||||
|
octet_iterator sequence_start = start;
|
||||||
|
internal::utf_error err_code = utf8::internal::validate_next(start, end);
|
||||||
|
switch (err_code) {
|
||||||
|
case internal::UTF8_OK :
|
||||||
|
for (octet_iterator it = sequence_start; it != start; ++it)
|
||||||
|
*out++ = *it;
|
||||||
|
break;
|
||||||
|
case internal::NOT_ENOUGH_ROOM:
|
||||||
|
out = utf8::unchecked::append (replacement, out);
|
||||||
|
start = end;
|
||||||
|
break;
|
||||||
|
case internal::INVALID_LEAD:
|
||||||
|
out = utf8::unchecked::append (replacement, out);
|
||||||
|
++start;
|
||||||
|
break;
|
||||||
|
case internal::INCOMPLETE_SEQUENCE:
|
||||||
|
case internal::OVERLONG_SEQUENCE:
|
||||||
|
case internal::INVALID_CODE_POINT:
|
||||||
|
out = utf8::unchecked::append (replacement, out);
|
||||||
|
++start;
|
||||||
|
// just one replacement mark for the sequence
|
||||||
|
while (start != end && utf8::internal::is_trail(*start))
|
||||||
|
++start;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename octet_iterator, typename output_iterator>
|
||||||
|
inline output_iterator replace_invalid(octet_iterator start, octet_iterator end, output_iterator out)
|
||||||
|
{
|
||||||
|
static const uint32_t replacement_marker = utf8::internal::mask16(0xfffd);
|
||||||
|
return utf8::unchecked::replace_invalid(start, end, out, replacement_marker);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename octet_iterator>
|
||||||
|
uint32_t next(octet_iterator& it)
|
||||||
|
{
|
||||||
|
uint32_t cp = utf8::internal::mask8(*it);
|
||||||
|
typename std::iterator_traits<octet_iterator>::difference_type length = utf8::internal::sequence_length(it);
|
||||||
|
switch (length) {
|
||||||
|
case 1:
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
it++;
|
||||||
|
cp = ((cp << 6) & 0x7ff) + ((*it) & 0x3f);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
++it;
|
||||||
|
cp = ((cp << 12) & 0xffff) + ((utf8::internal::mask8(*it) << 6) & 0xfff);
|
||||||
|
++it;
|
||||||
|
cp += (*it) & 0x3f;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
++it;
|
||||||
|
cp = ((cp << 18) & 0x1fffff) + ((utf8::internal::mask8(*it) << 12) & 0x3ffff);
|
||||||
|
++it;
|
||||||
|
cp += (utf8::internal::mask8(*it) << 6) & 0xfff;
|
||||||
|
++it;
|
||||||
|
cp += (*it) & 0x3f;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
++it;
|
||||||
|
return cp;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename octet_iterator>
|
||||||
|
uint32_t peek_next(octet_iterator it)
|
||||||
|
{
|
||||||
|
return utf8::unchecked::next(it);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename octet_iterator>
|
||||||
|
uint32_t prior(octet_iterator& it)
|
||||||
|
{
|
||||||
|
while (utf8::internal::is_trail(*(--it))) ;
|
||||||
|
octet_iterator temp = it;
|
||||||
|
return utf8::unchecked::next(temp);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename octet_iterator, typename distance_type>
|
||||||
|
void advance (octet_iterator& it, distance_type n)
|
||||||
|
{
|
||||||
|
const distance_type zero(0);
|
||||||
|
if (n < zero) {
|
||||||
|
// backward
|
||||||
|
for (distance_type i = n; i < zero; ++i)
|
||||||
|
utf8::unchecked::prior(it);
|
||||||
|
} else {
|
||||||
|
// forward
|
||||||
|
for (distance_type i = zero; i < n; ++i)
|
||||||
|
utf8::unchecked::next(it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename octet_iterator>
|
||||||
|
typename std::iterator_traits<octet_iterator>::difference_type
|
||||||
|
distance (octet_iterator first, octet_iterator last)
|
||||||
|
{
|
||||||
|
typename std::iterator_traits<octet_iterator>::difference_type dist;
|
||||||
|
for (dist = 0; first < last; ++dist)
|
||||||
|
utf8::unchecked::next(first);
|
||||||
|
return dist;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename u16bit_iterator, typename octet_iterator>
|
||||||
|
octet_iterator utf16to8 (u16bit_iterator start, u16bit_iterator end, octet_iterator result)
|
||||||
|
{
|
||||||
|
while (start != end) {
|
||||||
|
uint32_t cp = utf8::internal::mask16(*start++);
|
||||||
|
// Take care of surrogate pairs first
|
||||||
|
if (utf8::internal::is_lead_surrogate(cp)) {
|
||||||
|
uint32_t trail_surrogate = utf8::internal::mask16(*start++);
|
||||||
|
cp = (cp << 10) + trail_surrogate + internal::SURROGATE_OFFSET;
|
||||||
|
}
|
||||||
|
result = utf8::unchecked::append(cp, result);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename u16bit_iterator, typename octet_iterator>
|
||||||
|
u16bit_iterator utf8to16 (octet_iterator start, octet_iterator end, u16bit_iterator result)
|
||||||
|
{
|
||||||
|
while (start < end) {
|
||||||
|
uint32_t cp = utf8::unchecked::next(start);
|
||||||
|
if (cp > 0xffff) { //make a surrogate pair
|
||||||
|
*result++ = static_cast<uint16_t>((cp >> 10) + internal::LEAD_OFFSET);
|
||||||
|
*result++ = static_cast<uint16_t>((cp & 0x3ff) + internal::TRAIL_SURROGATE_MIN);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
*result++ = static_cast<uint16_t>(cp);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename octet_iterator, typename u32bit_iterator>
|
||||||
|
octet_iterator utf32to8 (u32bit_iterator start, u32bit_iterator end, octet_iterator result)
|
||||||
|
{
|
||||||
|
while (start != end)
|
||||||
|
result = utf8::unchecked::append(*(start++), result);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename octet_iterator, typename u32bit_iterator>
|
||||||
|
u32bit_iterator utf8to32 (octet_iterator start, octet_iterator end, u32bit_iterator result)
|
||||||
|
{
|
||||||
|
while (start < end)
|
||||||
|
(*result++) = utf8::unchecked::next(start);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The iterator class
|
||||||
|
template <typename octet_iterator>
|
||||||
|
class iterator {
|
||||||
|
octet_iterator it;
|
||||||
|
public:
|
||||||
|
typedef uint32_t value_type;
|
||||||
|
typedef uint32_t* pointer;
|
||||||
|
typedef uint32_t& reference;
|
||||||
|
typedef std::ptrdiff_t difference_type;
|
||||||
|
typedef std::bidirectional_iterator_tag iterator_category;
|
||||||
|
iterator () {}
|
||||||
|
explicit iterator (const octet_iterator& octet_it): it(octet_it) {}
|
||||||
|
// the default "big three" are OK
|
||||||
|
octet_iterator base () const { return it; }
|
||||||
|
uint32_t operator * () const
|
||||||
|
{
|
||||||
|
octet_iterator temp = it;
|
||||||
|
return utf8::unchecked::next(temp);
|
||||||
|
}
|
||||||
|
bool operator == (const iterator& rhs) const
|
||||||
|
{
|
||||||
|
return (it == rhs.it);
|
||||||
|
}
|
||||||
|
bool operator != (const iterator& rhs) const
|
||||||
|
{
|
||||||
|
return !(operator == (rhs));
|
||||||
|
}
|
||||||
|
iterator& operator ++ ()
|
||||||
|
{
|
||||||
|
::std::advance(it, utf8::internal::sequence_length(it));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
iterator operator ++ (int)
|
||||||
|
{
|
||||||
|
iterator temp = *this;
|
||||||
|
::std::advance(it, utf8::internal::sequence_length(it));
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
iterator& operator -- ()
|
||||||
|
{
|
||||||
|
utf8::unchecked::prior(it);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
iterator operator -- (int)
|
||||||
|
{
|
||||||
|
iterator temp = *this;
|
||||||
|
utf8::unchecked::prior(it);
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
}; // class iterator
|
||||||
|
|
||||||
|
} // namespace utf8::unchecked
|
||||||
|
} // namespace utf8
|
||||||
|
|
||||||
|
|
||||||
|
#endif // header guard
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,55 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) Nemirtingas
|
||||||
|
* This file is part of the ingame overlay project
|
||||||
|
*
|
||||||
|
* The ingame overlay project is free software; you can redistribute it
|
||||||
|
* and/or modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* The ingame overlay project 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
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with the ingame overlay project; if not, see
|
||||||
|
* <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <set>
|
||||||
|
|
||||||
|
#include "Base_Hook.h"
|
||||||
|
#include "Renderer_Hook.h"
|
||||||
|
|
||||||
|
#if defined(_WIN32) || defined(WIN32) || defined(_WIN64) || defined(WIN64)
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
#ifdef GetModuleHandle
|
||||||
|
#undef GetModuleHandle
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_SPDLOG
|
||||||
|
#define SPDLOG_ACTIVE_LEVEL 0
|
||||||
|
#include <spdlog/spdlog.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef SPDLOG_TRACE
|
||||||
|
#define SPDLOG_TRACE(x, ...) PRINT_DEBUG(x "\n", __VA_ARGS__)
|
||||||
|
#endif
|
||||||
|
#ifndef SPDLOG_DEBUG
|
||||||
|
#define SPDLOG_DEBUG(x, ...) PRINT_DEBUG(x "\n", __VA_ARGS__)
|
||||||
|
#endif
|
||||||
|
#ifndef SPDLOG_INFO
|
||||||
|
#define SPDLOG_INFO(x, ...) PRINT_DEBUG(x "\n", __VA_ARGS__)
|
||||||
|
#endif
|
||||||
|
#ifndef SPDLOG_WARN
|
||||||
|
#define SPDLOG_WARN(x, ...) PRINT_DEBUG(x "\n", __VA_ARGS__)
|
||||||
|
#endif
|
||||||
|
#ifndef SPDLOG_ERROR
|
||||||
|
#define SPDLOG_ERROR(x, ...) PRINT_DEBUG(x "\n", __VA_ARGS__)
|
||||||
|
#endif
|
|
@ -1,151 +1,164 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2019-2020 Nemirtingas
|
||||||
|
* This file is part of the ingame overlay project
|
||||||
|
*
|
||||||
|
* The ingame overlay project is free software; you can redistribute it
|
||||||
|
* and/or modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* The ingame overlay project 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
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with the ingame overlay project; if not, see
|
||||||
|
* <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <glad/gl.h>
|
||||||
|
|
||||||
#include "OpenGLX_Hook.h"
|
#include "OpenGLX_Hook.h"
|
||||||
#include "X11_Hook.h"
|
#include "X11_Hook.h"
|
||||||
#include "../Renderer_Detector.h"
|
|
||||||
#include "../dll/dll.h"
|
|
||||||
|
|
||||||
#ifdef __LINUX__
|
|
||||||
#ifdef EMU_OVERLAY
|
|
||||||
|
|
||||||
#include <imgui.h>
|
#include <imgui.h>
|
||||||
#include <impls/imgui_impl_opengl3.h>
|
#include <backends/imgui_impl_opengl3.h>
|
||||||
|
|
||||||
#include "../steam_overlay.h"
|
|
||||||
|
|
||||||
OpenGLX_Hook* OpenGLX_Hook::_inst = nullptr;
|
OpenGLX_Hook* OpenGLX_Hook::_inst = nullptr;
|
||||||
|
|
||||||
bool OpenGLX_Hook::start_hook()
|
constexpr decltype(OpenGLX_Hook::DLL_NAME) OpenGLX_Hook::DLL_NAME;
|
||||||
|
|
||||||
|
bool OpenGLX_Hook::StartHook(std::function<bool(bool)> key_combination_callback)
|
||||||
{
|
{
|
||||||
bool res = true;
|
if (!_Hooked)
|
||||||
if (!hooked)
|
|
||||||
{
|
{
|
||||||
if (!X11_Hook::Inst()->start_hook())
|
if (glXSwapBuffers == nullptr)
|
||||||
|
{
|
||||||
|
SPDLOG_WARN("Failed to hook OpenGLX: Rendering functions missing.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!X11_Hook::Inst()->StartHook(key_combination_callback))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
GLenum err = glewInit();
|
_X11Hooked = true;
|
||||||
|
|
||||||
if (err == GLEW_OK)
|
SPDLOG_INFO("Hooked OpenGLX");
|
||||||
{
|
|
||||||
PRINT_DEBUG("Hooked OpenGLX\n");
|
|
||||||
|
|
||||||
hooked = true;
|
_Hooked = true;
|
||||||
Renderer_Detector::Inst().renderer_found(this);
|
|
||||||
|
|
||||||
/*
|
|
||||||
UnhookAll();
|
UnhookAll();
|
||||||
BeginHook();
|
BeginHook();
|
||||||
HookFuncs(
|
HookFuncs(
|
||||||
std::make_pair<void**, void*>(&(void*&)_glXSwapBuffers, (void*)&OpenGLX_Hook::MyglXSwapBuffers)
|
std::make_pair<void**, void*>((void**)&glXSwapBuffers, (void*)&OpenGLX_Hook::MyglXSwapBuffers)
|
||||||
);
|
);
|
||||||
EndHook();
|
EndHook();
|
||||||
*/
|
|
||||||
|
|
||||||
get_steam_client()->steam_overlay->HookReady();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
PRINT_DEBUG("Failed to hook OpenGLX\n");
|
|
||||||
/* Problem: glewInit failed, something is seriously wrong. */
|
|
||||||
PRINT_DEBUG("Error: %s\n", glewGetErrorString(err));
|
|
||||||
res = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGLX_Hook::resetRenderState()
|
bool OpenGLX_Hook::IsStarted()
|
||||||
{
|
{
|
||||||
if (initialized)
|
return _Hooked;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLX_Hook::_ResetRenderState()
|
||||||
{
|
{
|
||||||
|
if (_Initialized)
|
||||||
|
{
|
||||||
|
OverlayHookReady(false);
|
||||||
|
|
||||||
ImGui_ImplOpenGL3_Shutdown();
|
ImGui_ImplOpenGL3_Shutdown();
|
||||||
X11_Hook::Inst()->resetRenderState();
|
X11_Hook::Inst()->ResetRenderState();
|
||||||
ImGui::DestroyContext();
|
ImGui::DestroyContext();
|
||||||
|
|
||||||
glXDestroyContext(display, context);
|
glXDestroyContext(_Display, _Context);
|
||||||
display = nullptr;
|
_Display = nullptr;
|
||||||
initialized = false;
|
_Initialized = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to make this function and overlay's proc as short as possible or it might affect game's fps.
|
// Try to make this function and overlay's proc as short as possible or it might affect game's fps.
|
||||||
void OpenGLX_Hook::prepareForOverlay(Display* display, GLXDrawable drawable)
|
void OpenGLX_Hook::_PrepareForOverlay(Display* display, GLXDrawable drawable)
|
||||||
{
|
{
|
||||||
PRINT_DEBUG("Called SwapBuffer hook");
|
if( !_Initialized )
|
||||||
|
|
||||||
if( (Window)drawable != X11_Hook::Inst()->get_game_wnd() )
|
|
||||||
X11_Hook::Inst()->resetRenderState();
|
|
||||||
|
|
||||||
if( ! initialized )
|
|
||||||
{
|
{
|
||||||
ImGui::CreateContext();
|
ImGui::CreateContext();
|
||||||
ImGuiIO& io = ImGui::GetIO();
|
|
||||||
io.IniFilename = NULL;
|
|
||||||
|
|
||||||
ImGui_ImplOpenGL3_Init();
|
ImGui_ImplOpenGL3_Init();
|
||||||
|
|
||||||
int attributes[] = { //can't be const b/c X11 doesn't like it. Not sure if that's intentional or just stupid.
|
//int attributes[] = { //can't be const b/c X11 doesn't like it. Not sure if that's intentional or just stupid.
|
||||||
GLX_RGBA, //apparently nothing comes after this?
|
// GLX_RGBA, //apparently nothing comes after this?
|
||||||
GLX_RED_SIZE, 8,
|
// GLX_RED_SIZE, 8,
|
||||||
GLX_GREEN_SIZE, 8,
|
// GLX_GREEN_SIZE, 8,
|
||||||
GLX_BLUE_SIZE, 8,
|
// GLX_BLUE_SIZE, 8,
|
||||||
GLX_ALPHA_SIZE, 8,
|
// GLX_ALPHA_SIZE, 8,
|
||||||
//Ideally, the size would be 32 (or at least 24), but I have actually seen
|
// //Ideally, the size would be 32 (or at least 24), but I have actually seen
|
||||||
// this size (on a modern OS even).
|
// // this size (on a modern OS even).
|
||||||
GLX_DEPTH_SIZE, 16,
|
// GLX_DEPTH_SIZE, 16,
|
||||||
GLX_DOUBLEBUFFER, True,
|
// GLX_DOUBLEBUFFER, True,
|
||||||
None
|
// None
|
||||||
};
|
//};
|
||||||
|
//
|
||||||
|
//XVisualInfo* visual_info = glXChooseVisual(_Display, DefaultScreen(_Display), attributes);
|
||||||
|
//if (visual_info == nullptr)
|
||||||
|
// return;
|
||||||
|
//
|
||||||
|
//_Context = glXCreateContext(_Display, visual_info, nullptr, True);
|
||||||
|
//if (_Context == nullptr)
|
||||||
|
// return;
|
||||||
|
|
||||||
XVisualInfo* visual_info = glXChooseVisual(display, DefaultScreen(display), attributes);
|
_Display = display;
|
||||||
|
|
||||||
context = glXCreateContext(display, visual_info, nullptr, True);
|
_Initialized = true;
|
||||||
this->display = display;
|
OverlayHookReady(true);
|
||||||
|
|
||||||
get_steam_client()->steam_overlay->CreateFonts();
|
|
||||||
|
|
||||||
initialized = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto oldContext = glXGetCurrentContext();
|
//auto oldContext = glXGetCurrentContext();
|
||||||
|
|
||||||
glXMakeCurrent(display, drawable, context);
|
//glXMakeCurrent(_Display, drawable, _Context);
|
||||||
|
|
||||||
ImGui_ImplOpenGL3_NewFrame();
|
|
||||||
X11_Hook::Inst()->prepareForOverlay(display, (Window)drawable);
|
|
||||||
|
|
||||||
|
if (ImGui_ImplOpenGL3_NewFrame() && X11_Hook::Inst()->PrepareForOverlay(_Display, (Window)drawable))
|
||||||
|
{
|
||||||
ImGui::NewFrame();
|
ImGui::NewFrame();
|
||||||
|
|
||||||
get_steam_client()->steam_overlay->OverlayProc();
|
OverlayProc();
|
||||||
|
|
||||||
ImGui::Render();
|
ImGui::Render();
|
||||||
|
|
||||||
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
|
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
|
||||||
|
}
|
||||||
|
|
||||||
glXMakeCurrent(display, drawable, oldContext);
|
//glXMakeCurrent(_Display, drawable, oldContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGLX_Hook::MyglXSwapBuffers(Display* display, GLXDrawable drawable)
|
void OpenGLX_Hook::MyglXSwapBuffers(Display* display, GLXDrawable drawable)
|
||||||
{
|
{
|
||||||
OpenGLX_Hook::Inst()->prepareForOverlay(display, drawable);
|
OpenGLX_Hook::Inst()->_PrepareForOverlay(display, drawable);
|
||||||
OpenGLX_Hook::Inst()->_glXSwapBuffers(display, drawable);
|
OpenGLX_Hook::Inst()->glXSwapBuffers(display, drawable);
|
||||||
}
|
}
|
||||||
|
|
||||||
OpenGLX_Hook::OpenGLX_Hook():
|
OpenGLX_Hook::OpenGLX_Hook():
|
||||||
initialized(false),
|
_Initialized(false),
|
||||||
hooked(false),
|
_Hooked(false),
|
||||||
_glXSwapBuffers(nullptr)
|
_X11Hooked(false),
|
||||||
|
glXSwapBuffers(nullptr)
|
||||||
{
|
{
|
||||||
//_library = dlopen(DLL_NAME);
|
//_library = dlopen(DLL_NAME);
|
||||||
}
|
}
|
||||||
|
|
||||||
OpenGLX_Hook::~OpenGLX_Hook()
|
OpenGLX_Hook::~OpenGLX_Hook()
|
||||||
{
|
{
|
||||||
PRINT_DEBUG("OpenGLX Hook removed\n");
|
SPDLOG_INFO("OpenGLX Hook removed");
|
||||||
|
|
||||||
if (initialized)
|
if (_X11Hooked)
|
||||||
|
delete X11_Hook::Inst();
|
||||||
|
|
||||||
|
if (_Initialized)
|
||||||
{
|
{
|
||||||
ImGui_ImplOpenGL3_Shutdown();
|
ImGui_ImplOpenGL3_Shutdown();
|
||||||
ImGui::DestroyContext();
|
ImGui::DestroyContext();
|
||||||
glXDestroyContext(display, context);
|
glXDestroyContext(_Display, _Context);
|
||||||
}
|
}
|
||||||
|
|
||||||
//dlclose(_library);
|
//dlclose(_library);
|
||||||
|
@ -161,15 +174,62 @@ OpenGLX_Hook* OpenGLX_Hook::Inst()
|
||||||
return _inst;
|
return _inst;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* OpenGLX_Hook::get_lib_name() const
|
std::string OpenGLX_Hook::GetLibraryName() const
|
||||||
{
|
{
|
||||||
return DLL_NAME;
|
return LibraryName;
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGLX_Hook::loadFunctions(decltype(glXSwapBuffers)* pfnglXSwapBuffers)
|
void OpenGLX_Hook::LoadFunctions(decltype(::glXSwapBuffers)* pfnglXSwapBuffers)
|
||||||
{
|
{
|
||||||
_glXSwapBuffers = pfnglXSwapBuffers;
|
glXSwapBuffers = pfnglXSwapBuffers;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif//EMU_OVERLAY
|
std::weak_ptr<uint64_t> OpenGLX_Hook::CreateImageResource(const void* image_data, uint32_t width, uint32_t height)
|
||||||
#endif//__LINUX__
|
{
|
||||||
|
GLuint* texture = new GLuint(0);
|
||||||
|
glGenTextures(1, texture);
|
||||||
|
if (glGetError() != GL_NO_ERROR)
|
||||||
|
{
|
||||||
|
delete texture;
|
||||||
|
return std::shared_ptr<uint64_t>(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save old texture id
|
||||||
|
GLint oldTex;
|
||||||
|
glGetIntegerv(GL_TEXTURE_BINDING_2D, &oldTex);
|
||||||
|
|
||||||
|
glBindTexture(GL_TEXTURE_2D, *texture);
|
||||||
|
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
|
|
||||||
|
// Upload pixels into texture
|
||||||
|
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, image_data);
|
||||||
|
|
||||||
|
glBindTexture(GL_TEXTURE_2D, oldTex);
|
||||||
|
|
||||||
|
auto ptr = std::shared_ptr<uint64_t>((uint64_t*)texture, [](uint64_t* handle)
|
||||||
|
{
|
||||||
|
if (handle != nullptr)
|
||||||
|
{
|
||||||
|
GLuint* texture = (GLuint*)handle;
|
||||||
|
glDeleteTextures(1, texture);
|
||||||
|
delete texture;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
_ImageResources.emplace(ptr);
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLX_Hook::ReleaseImageResource(std::weak_ptr<uint64_t> resource)
|
||||||
|
{
|
||||||
|
auto ptr = resource.lock();
|
||||||
|
if (ptr)
|
||||||
|
{
|
||||||
|
auto it = _ImageResources.find(ptr);
|
||||||
|
if (it != _ImageResources.end())
|
||||||
|
_ImageResources.erase(it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,14 +1,33 @@
|
||||||
#ifndef __INCLUDED_OPENGLX_HOOK_H__
|
/*
|
||||||
#define __INCLUDED_OPENGLX_HOOK_H__
|
* Copyright (C) 2019-2020 Nemirtingas
|
||||||
|
* This file is part of the ingame overlay project
|
||||||
|
*
|
||||||
|
* The ingame overlay project is free software; you can redistribute it
|
||||||
|
* and/or modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* The ingame overlay project 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
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with the ingame overlay project; if not, see
|
||||||
|
* <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
#include "../Base_Hook.h"
|
#pragma once
|
||||||
|
|
||||||
|
#include <ingame_overlay/Renderer_Hook.h>
|
||||||
|
|
||||||
|
#include "../internal_includes.h"
|
||||||
|
|
||||||
#ifdef __LINUX__
|
|
||||||
#ifdef EMU_OVERLAY
|
|
||||||
#include <GL/glew.h>
|
|
||||||
#include <GL/glx.h>
|
#include <GL/glx.h>
|
||||||
|
|
||||||
class OpenGLX_Hook : public Base_Hook
|
class OpenGLX_Hook :
|
||||||
|
public Renderer_Hook,
|
||||||
|
public Base_Hook
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static constexpr const char *DLL_NAME = "libGLX.so";
|
static constexpr const char *DLL_NAME = "libGLX.so";
|
||||||
|
@ -17,33 +36,35 @@ private:
|
||||||
static OpenGLX_Hook* _inst;
|
static OpenGLX_Hook* _inst;
|
||||||
|
|
||||||
// Variables
|
// Variables
|
||||||
bool hooked;
|
bool _Hooked;
|
||||||
bool initialized;
|
bool _X11Hooked;
|
||||||
Display *display;
|
bool _Initialized;
|
||||||
GLXContext context;
|
Display *_Display;
|
||||||
|
GLXContext _Context;
|
||||||
|
std::set<std::shared_ptr<uint64_t>> _ImageResources;
|
||||||
|
|
||||||
// Functions
|
// Functions
|
||||||
OpenGLX_Hook();
|
OpenGLX_Hook();
|
||||||
|
|
||||||
void resetRenderState();
|
void _ResetRenderState();
|
||||||
void prepareForOverlay(Display* display, GLXDrawable drawable);
|
void _PrepareForOverlay(Display* display, GLXDrawable drawable);
|
||||||
|
|
||||||
// Hook to render functions
|
// Hook to render functions
|
||||||
|
decltype(::glXSwapBuffers)* glXSwapBuffers;
|
||||||
|
|
||||||
decltype(glXSwapBuffers)* _glXSwapBuffers;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
std::string LibraryName;
|
||||||
|
|
||||||
static void MyglXSwapBuffers(Display* display, GLXDrawable drawable);
|
static void MyglXSwapBuffers(Display* display, GLXDrawable drawable);
|
||||||
|
|
||||||
virtual ~OpenGLX_Hook();
|
virtual ~OpenGLX_Hook();
|
||||||
|
|
||||||
bool start_hook();
|
virtual bool StartHook(std::function<bool(bool)> key_combination_callback);
|
||||||
|
virtual bool IsStarted();
|
||||||
static OpenGLX_Hook* Inst();
|
static OpenGLX_Hook* Inst();
|
||||||
virtual const char* get_lib_name() const;
|
virtual std::string GetLibraryName() const;
|
||||||
void loadFunctions(decltype(glXSwapBuffers)* pfnglXSwapBuffers);
|
void LoadFunctions(decltype(::glXSwapBuffers)* pfnglXSwapBuffers);
|
||||||
};
|
|
||||||
|
|
||||||
#endif//EMU_OVERLAY
|
virtual std::weak_ptr<uint64_t> CreateImageResource(const void* image_data, uint32_t width, uint32_t height);
|
||||||
#endif//__LINUX__
|
virtual void ReleaseImageResource(std::weak_ptr<uint64_t> resource);
|
||||||
#endif//__INCLUDED_OPENGLX_HOOK_H__
|
};
|
||||||
|
|
|
@ -1,54 +1,107 @@
|
||||||
#include "X11_Hook.h"
|
/*
|
||||||
#include "../Renderer_Detector.h"
|
* Copyright (C) 2019-2020 Nemirtingas
|
||||||
#include "../dll/dll.h"
|
* This file is part of the ingame overlay project
|
||||||
|
*
|
||||||
|
* The ingame overlay project is free software; you can redistribute it
|
||||||
|
* and/or modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* The ingame overlay project 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
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with the ingame overlay project; if not, see
|
||||||
|
* <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
#ifdef __LINUX__
|
#include "X11_Hook.h"
|
||||||
#ifdef EMU_OVERLAY
|
|
||||||
|
|
||||||
#include <imgui.h>
|
#include <imgui.h>
|
||||||
#include <impls/linux/imgui_impl_x11.h>
|
#include <backends/imgui_impl_x11.h>
|
||||||
|
#include <System/Library.h>
|
||||||
#include <dlfcn.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <fstream>
|
|
||||||
|
|
||||||
extern int ImGui_ImplX11_EventHandler(XEvent &event);
|
extern int ImGui_ImplX11_EventHandler(XEvent &event);
|
||||||
|
|
||||||
|
constexpr decltype(X11_Hook::DLL_NAME) X11_Hook::DLL_NAME;
|
||||||
|
|
||||||
X11_Hook* X11_Hook::_inst = nullptr;
|
X11_Hook* X11_Hook::_inst = nullptr;
|
||||||
|
|
||||||
bool X11_Hook::start_hook()
|
bool X11_Hook::StartHook(std::function<bool(bool)>& _key_combination_callback)
|
||||||
{
|
{
|
||||||
bool res = true;
|
if (!_Hooked)
|
||||||
if (!hooked)
|
|
||||||
{
|
{
|
||||||
PRINT_DEBUG("Hooked X11\n");
|
void* hX11 = System::Library::GetLibraryHandle(DLL_NAME);
|
||||||
hooked = true;
|
if (hX11 == nullptr)
|
||||||
}
|
{
|
||||||
return res;
|
SPDLOG_WARN("Failed to hook X11: Cannot find {}", DLL_NAME);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void X11_Hook::resetRenderState()
|
System::Library::Library libX11;
|
||||||
|
LibraryName = System::Library::GetLibraryPath(hX11);
|
||||||
|
|
||||||
|
if (!libX11.OpenLibrary(LibraryName, false))
|
||||||
{
|
{
|
||||||
if (initialized)
|
SPDLOG_WARN("Failed to hook X11: Cannot load {}", LibraryName);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
XEventsQueued = libX11.GetSymbol<decltype(::XEventsQueued)>("XEventsQueued");
|
||||||
|
XPending = libX11.GetSymbol<decltype(::XPending)>("XPending");
|
||||||
|
|
||||||
|
if (XPending == nullptr || XEventsQueued == nullptr)
|
||||||
{
|
{
|
||||||
game_wnd = 0;
|
SPDLOG_WARN("Failed to hook X11: Cannot load functions.({}, {})", DLL_NAME, (void*)XEventsQueued, (void*)XPending);
|
||||||
initialized = false;
|
return false;
|
||||||
|
}
|
||||||
|
SPDLOG_INFO("Hooked X11");
|
||||||
|
|
||||||
|
_KeyCombinationCallback = std::move(_key_combination_callback);
|
||||||
|
_Hooked = true;
|
||||||
|
|
||||||
|
UnhookAll();
|
||||||
|
BeginHook();
|
||||||
|
HookFuncs(
|
||||||
|
std::make_pair<void**, void*>(&(void*&)XEventsQueued, (void*)&X11_Hook::MyXEventsQueued),
|
||||||
|
std::make_pair<void**, void*>(&(void*&)XPending, (void*)&X11_Hook::MyXPending)
|
||||||
|
);
|
||||||
|
EndHook();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void X11_Hook::ResetRenderState()
|
||||||
|
{
|
||||||
|
if (_Initialized)
|
||||||
|
{
|
||||||
|
_GameWnd = 0;
|
||||||
|
_Initialized = false;
|
||||||
ImGui_ImplX11_Shutdown();
|
ImGui_ImplX11_Shutdown();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void X11_Hook::prepareForOverlay(Display *display, Window wnd)
|
bool X11_Hook::PrepareForOverlay(Display *display, Window wnd)
|
||||||
{
|
{
|
||||||
if (!initialized)
|
if(!_Hooked)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (_GameWnd != wnd)
|
||||||
|
ResetRenderState();
|
||||||
|
|
||||||
|
if (!_Initialized)
|
||||||
{
|
{
|
||||||
ImGui_ImplX11_Init(display, (void*)wnd);
|
ImGui_ImplX11_Init(display, (void*)wnd);
|
||||||
|
_GameWnd = wnd;
|
||||||
|
|
||||||
game_wnd = wnd;
|
_Initialized = true;
|
||||||
|
|
||||||
initialized = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui_ImplX11_NewFrame();
|
ImGui_ImplX11_NewFrame();
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -63,66 +116,57 @@ bool IgnoreEvent(XEvent &event)
|
||||||
case ButtonPress: case ButtonRelease:
|
case ButtonPress: case ButtonRelease:
|
||||||
// Mouse move
|
// Mouse move
|
||||||
case MotionNotify:
|
case MotionNotify:
|
||||||
|
// Copy to clipboard request
|
||||||
|
case SelectionRequest:
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int X11_Hook::check_for_overlay(Display *d, int num_events)
|
int X11_Hook::_CheckForOverlay(Display *d, int num_events)
|
||||||
{
|
{
|
||||||
static Time prev_time = {};
|
static Time prev_time = {};
|
||||||
|
|
||||||
X11_Hook* inst = Inst();
|
X11_Hook* inst = Inst();
|
||||||
|
|
||||||
if( inst->initialized )
|
if( inst->_Initialized )
|
||||||
{
|
{
|
||||||
XEvent event;
|
XEvent event;
|
||||||
while(num_events)
|
while(num_events)
|
||||||
{
|
{
|
||||||
//inst->_XPeekEvent(d, &event);
|
bool skip_input = inst->_KeyCombinationCallback(false);
|
||||||
XPeekEvent(d, &event);
|
|
||||||
|
XPeekEvent(d, &event);
|
||||||
|
ImGui_ImplX11_EventHandler(event);
|
||||||
|
|
||||||
Steam_Overlay* overlay = get_steam_client()->steam_overlay;
|
|
||||||
bool show = overlay->ShowOverlay();
|
|
||||||
// Is the event is a key press
|
// Is the event is a key press
|
||||||
if (event.type == KeyPress)
|
if (event.type == KeyPress)
|
||||||
{
|
{
|
||||||
// Tab is pressed and was not pressed before
|
// Tab is pressed and was not pressed before
|
||||||
//if (event.xkey.keycode == inst->_XKeysymToKeycode(d, XK_Tab) && event.xkey.state & ShiftMask)
|
|
||||||
if (event.xkey.keycode == XKeysymToKeycode(d, XK_Tab) && event.xkey.state & ShiftMask)
|
if (event.xkey.keycode == XKeysymToKeycode(d, XK_Tab) && event.xkey.state & ShiftMask)
|
||||||
{
|
{
|
||||||
// if key TAB is held, don't make the overlay flicker :p
|
// if key TAB is held, don't make the overlay flicker :p
|
||||||
if (event.xkey.time != prev_time)
|
if (event.xkey.time != prev_time)
|
||||||
{
|
{
|
||||||
overlay->ShowOverlay(!overlay->ShowOverlay());
|
skip_input = true;
|
||||||
|
inst->_KeyCombinationCallback(true);
|
||||||
if (overlay->ShowOverlay())
|
|
||||||
show = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//else if(event.type == KeyRelease && event.xkey.keycode == inst->_XKeysymToKeycode(d, XK_Tab))
|
|
||||||
else if(event.type == KeyRelease && event.xkey.keycode == XKeysymToKeycode(d, XK_Tab))
|
else if(event.type == KeyRelease && event.xkey.keycode == XKeysymToKeycode(d, XK_Tab))
|
||||||
{
|
{
|
||||||
prev_time = event.xkey.time;
|
prev_time = event.xkey.time;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (show)
|
if (!skip_input || !IgnoreEvent(event))
|
||||||
{
|
{
|
||||||
ImGui_ImplX11_EventHandler(event);
|
if(num_events)
|
||||||
|
num_events = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (IgnoreEvent(event))
|
|
||||||
{
|
|
||||||
//inst->_XNextEvent(d, &event);
|
|
||||||
XNextEvent(d, &event);
|
XNextEvent(d, &event);
|
||||||
--num_events;
|
--num_events;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return num_events;
|
return num_events;
|
||||||
}
|
}
|
||||||
|
@ -131,33 +175,23 @@ int X11_Hook::MyXEventsQueued(Display *display, int mode)
|
||||||
{
|
{
|
||||||
X11_Hook* inst = X11_Hook::Inst();
|
X11_Hook* inst = X11_Hook::Inst();
|
||||||
|
|
||||||
int res = inst->_XEventsQueued(display, mode);
|
int res = inst->XEventsQueued(display, mode);
|
||||||
|
|
||||||
if( res )
|
if( res )
|
||||||
{
|
{
|
||||||
res = inst->check_for_overlay(display, res);
|
res = inst->_CheckForOverlay(display, res);
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
int X11_Hook::MyXNextEvent(Display* display, XEvent *event)
|
|
||||||
{
|
|
||||||
return Inst()->_XNextEvent(display, event);
|
|
||||||
}
|
|
||||||
|
|
||||||
int X11_Hook::MyXPeekEvent(Display* display, XEvent *event)
|
|
||||||
{
|
|
||||||
return Inst()->_XPeekEvent(display, event);
|
|
||||||
}
|
|
||||||
|
|
||||||
int X11_Hook::MyXPending(Display* display)
|
int X11_Hook::MyXPending(Display* display)
|
||||||
{
|
{
|
||||||
int res = Inst()->_XPending(display);
|
int res = Inst()->XPending(display);
|
||||||
|
|
||||||
if( res )
|
if( res )
|
||||||
{
|
{
|
||||||
res = Inst()->check_for_overlay(display, res);
|
res = Inst()->_CheckForOverlay(display, res);
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
|
@ -166,24 +200,19 @@ int X11_Hook::MyXPending(Display* display)
|
||||||
/////////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
X11_Hook::X11_Hook() :
|
X11_Hook::X11_Hook() :
|
||||||
initialized(false),
|
_Initialized(false),
|
||||||
hooked(false),
|
_Hooked(false),
|
||||||
game_wnd(0),
|
_GameWnd(0),
|
||||||
_XEventsQueued(nullptr),
|
XEventsQueued(nullptr),
|
||||||
_XPeekEvent(nullptr),
|
XPending(nullptr)
|
||||||
_XNextEvent(nullptr),
|
|
||||||
_XPending(nullptr)
|
|
||||||
{
|
{
|
||||||
//_library = dlopen(DLL_NAME, RTLD_NOW);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
X11_Hook::~X11_Hook()
|
X11_Hook::~X11_Hook()
|
||||||
{
|
{
|
||||||
PRINT_DEBUG("X11 Hook removed\n");
|
SPDLOG_INFO("X11 Hook removed");
|
||||||
|
|
||||||
resetRenderState();
|
ResetRenderState();
|
||||||
|
|
||||||
//dlclose(_library);
|
|
||||||
|
|
||||||
_inst = nullptr;
|
_inst = nullptr;
|
||||||
}
|
}
|
||||||
|
@ -196,10 +225,7 @@ X11_Hook* X11_Hook::Inst()
|
||||||
return _inst;
|
return _inst;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* X11_Hook::get_lib_name() const
|
std::string X11_Hook::GetLibraryName() const
|
||||||
{
|
{
|
||||||
return DLL_NAME;
|
return LibraryName;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif//EMU_OVERLAY
|
|
||||||
#endif//#__LINUX__
|
|
||||||
|
|
|
@ -1,63 +1,70 @@
|
||||||
#ifndef __INCLUDED_X11_HOOK_H__
|
/*
|
||||||
#define __INCLUDED_X11_HOOK_H__
|
* Copyright (C) 2019-2020 Nemirtingas
|
||||||
|
* This file is part of the ingame overlay project
|
||||||
|
*
|
||||||
|
* The ingame overlay project is free software; you can redistribute it
|
||||||
|
* and/or modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* The ingame overlay project 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
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with the ingame overlay project; if not, see
|
||||||
|
* <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
#include "../Base_Hook.h"
|
#pragma once
|
||||||
|
|
||||||
#ifdef __LINUX__
|
#include <ingame_overlay/Renderer_Hook.h>
|
||||||
#ifdef EMU_OVERLAY
|
|
||||||
|
#include "../internal_includes.h"
|
||||||
|
|
||||||
#include <X11/X.h> // XEvent types
|
#include <X11/X.h> // XEvent types
|
||||||
#include <X11/Xlib.h> // XEvent structure
|
#include <X11/Xlib.h> // XEvent structure
|
||||||
|
#include <X11/Xutil.h> // XEvent keysym
|
||||||
|
|
||||||
extern "C" int XEventsQueued(Display *display, int mode);
|
class X11_Hook :
|
||||||
extern "C" int XPending(Display *display);
|
public Base_Hook
|
||||||
|
|
||||||
class X11_Hook : public Base_Hook
|
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
friend int XEventsQueued(Display *display, int mode);
|
|
||||||
friend int XPending(Display *display);
|
|
||||||
static constexpr const char* DLL_NAME = "libX11.so";
|
static constexpr const char* DLL_NAME = "libX11.so";
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static X11_Hook* _inst;
|
static X11_Hook* _inst;
|
||||||
|
|
||||||
// Variables
|
// Variables
|
||||||
bool hooked;
|
bool _Hooked;
|
||||||
bool initialized;
|
bool _Initialized;
|
||||||
Window game_wnd;
|
Window _GameWnd;
|
||||||
|
|
||||||
// Functions
|
// Functions
|
||||||
X11_Hook();
|
X11_Hook();
|
||||||
int check_for_overlay(Display *d, int num_events);
|
int _CheckForOverlay(Display *d, int num_events);
|
||||||
|
|
||||||
// Hook to X11 window messages
|
// Hook to X11 window messages
|
||||||
decltype(XEventsQueued)* _XEventsQueued;
|
decltype(::XEventsQueued)* XEventsQueued;
|
||||||
decltype(XPeekEvent)* _XPeekEvent;
|
decltype(::XPending)* XPending;
|
||||||
decltype(XNextEvent)* _XNextEvent;
|
|
||||||
decltype(XPending)* _XPending;
|
|
||||||
//decltype(XKeysymToKeycode)* _XKeysymToKeycode;
|
|
||||||
//decltype(XLookupKeysym)* _XLookupKeysym;
|
|
||||||
//decltype(XGetGeometry)* _XGetGeometry;
|
|
||||||
|
|
||||||
static int MyXEventsQueued(Display * display, int mode);
|
static int MyXEventsQueued(Display * display, int mode);
|
||||||
static int MyXNextEvent(Display* display, XEvent *event);
|
|
||||||
static int MyXPeekEvent(Display* display, XEvent *event);
|
|
||||||
static int MyXPending(Display* display);
|
static int MyXPending(Display* display);
|
||||||
|
|
||||||
|
std::function<bool(bool)> _KeyCombinationCallback;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
std::string LibraryName;
|
||||||
|
|
||||||
virtual ~X11_Hook();
|
virtual ~X11_Hook();
|
||||||
|
|
||||||
void resetRenderState();
|
void ResetRenderState();
|
||||||
void prepareForOverlay(Display *display, Window wnd);
|
bool PrepareForOverlay(Display *display, Window wnd);
|
||||||
|
|
||||||
Window get_game_wnd() const{ return game_wnd; }
|
Window GetGameWnd() const{ return _GameWnd; }
|
||||||
|
|
||||||
bool start_hook();
|
bool StartHook(std::function<bool(bool)>& key_combination_callback);
|
||||||
static X11_Hook* Inst();
|
static X11_Hook* Inst();
|
||||||
virtual const char* get_lib_name() const;
|
virtual std::string GetLibraryName() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif//EMU_OVERLAY
|
|
||||||
#endif//__LINUX__
|
|
||||||
#endif//__INCLUDED_X11_HOOK_H__
|
|
||||||
|
|
|
@ -0,0 +1,236 @@
|
||||||
|
//
|
||||||
|
// File: vk_icd.h
|
||||||
|
//
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2015-2016 The Khronos Group Inc.
|
||||||
|
* Copyright (c) 2015-2016 Valve Corporation
|
||||||
|
* Copyright (c) 2015-2016 LunarG, Inc.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef VKICD_H
|
||||||
|
#define VKICD_H
|
||||||
|
|
||||||
|
#include "vulkan.h"
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
// Loader-ICD version negotiation API. Versions add the following features:
|
||||||
|
// Version 0 - Initial. Doesn't support vk_icdGetInstanceProcAddr
|
||||||
|
// or vk_icdNegotiateLoaderICDInterfaceVersion.
|
||||||
|
// Version 1 - Add support for vk_icdGetInstanceProcAddr.
|
||||||
|
// Version 2 - Add Loader/ICD Interface version negotiation
|
||||||
|
// via vk_icdNegotiateLoaderICDInterfaceVersion.
|
||||||
|
// Version 3 - Add ICD creation/destruction of KHR_surface objects.
|
||||||
|
// Version 4 - Add unknown physical device extension qyering via
|
||||||
|
// vk_icdGetPhysicalDeviceProcAddr.
|
||||||
|
// Version 5 - Tells ICDs that the loader is now paying attention to the
|
||||||
|
// application version of Vulkan passed into the ApplicationInfo
|
||||||
|
// structure during vkCreateInstance. This will tell the ICD
|
||||||
|
// that if the loader is older, it should automatically fail a
|
||||||
|
// call for any API version > 1.0. Otherwise, the loader will
|
||||||
|
// manually determine if it can support the expected version.
|
||||||
|
// Version 6 - Add support for vk_icdEnumerateAdapterPhysicalDevices.
|
||||||
|
#define CURRENT_LOADER_ICD_INTERFACE_VERSION 6
|
||||||
|
#define MIN_SUPPORTED_LOADER_ICD_INTERFACE_VERSION 0
|
||||||
|
#define MIN_PHYS_DEV_EXTENSION_ICD_INTERFACE_VERSION 4
|
||||||
|
|
||||||
|
// Old typedefs that don't follow a proper naming convention but are preserved for compatibility
|
||||||
|
typedef VkResult(VKAPI_PTR *PFN_vkNegotiateLoaderICDInterfaceVersion)(uint32_t *pVersion);
|
||||||
|
// This is defined in vk_layer.h which will be found by the loader, but if an ICD is building against this
|
||||||
|
// file directly, it won't be found.
|
||||||
|
#ifndef PFN_GetPhysicalDeviceProcAddr
|
||||||
|
typedef PFN_vkVoidFunction(VKAPI_PTR *PFN_GetPhysicalDeviceProcAddr)(VkInstance instance, const char *pName);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Typedefs for loader/ICD interface
|
||||||
|
typedef VkResult (VKAPI_PTR *PFN_vk_icdNegotiateLoaderICDInterfaceVersion)(uint32_t* pVersion);
|
||||||
|
typedef PFN_vkVoidFunction (VKAPI_PTR *PFN_vk_icdGetInstanceProcAddr)(VkInstance instance, const char* pName);
|
||||||
|
typedef PFN_vkVoidFunction (VKAPI_PTR *PFN_vk_icdGetPhysicalDeviceProcAddr)(VkInstance instance, const char* pName);
|
||||||
|
#if defined(VK_USE_PLATFORM_WIN32_KHR)
|
||||||
|
typedef VkResult (VKAPI_PTR *PFN_vk_icdEnumerateAdapterPhysicalDevices)(VkInstance instance, LUID adapterLUID,
|
||||||
|
uint32_t* pPhysicalDeviceCount, VkPhysicalDevice* pPhysicalDevices);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Prototypes for loader/ICD interface
|
||||||
|
#if !defined(VK_NO_PROTOTYPES)
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
VKAPI_ATTR VkResult VKAPI_CALL vk_icdNegotiateLoaderICDInterfaceVersion(uint32_t* pVersion);
|
||||||
|
VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vk_icdGetInstanceProcAddr(VkInstance instance, const char* pName);
|
||||||
|
VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vk_icdGetPhysicalDeviceProcAddr(VkInstance isntance, const char* pName);
|
||||||
|
#if defined(VK_USE_PLATFORM_WIN32_KHR)
|
||||||
|
VKAPI_ATTR VkResult VKAPI_CALL vk_icdEnumerateAdapterPhysicalDevices(VkInstance instance, LUID adapterLUID,
|
||||||
|
uint32_t* pPhysicalDeviceCount, VkPhysicalDevice* pPhysicalDevices);
|
||||||
|
#endif
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The ICD must reserve space for a pointer for the loader's dispatch
|
||||||
|
* table, at the start of <each object>.
|
||||||
|
* The ICD must initialize this variable using the SET_LOADER_MAGIC_VALUE macro.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define ICD_LOADER_MAGIC 0x01CDC0DE
|
||||||
|
|
||||||
|
typedef union {
|
||||||
|
uintptr_t loaderMagic;
|
||||||
|
void *loaderData;
|
||||||
|
} VK_LOADER_DATA;
|
||||||
|
|
||||||
|
static inline void set_loader_magic_value(void *pNewObject) {
|
||||||
|
VK_LOADER_DATA *loader_info = (VK_LOADER_DATA *)pNewObject;
|
||||||
|
loader_info->loaderMagic = ICD_LOADER_MAGIC;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool valid_loader_magic_value(void *pNewObject) {
|
||||||
|
const VK_LOADER_DATA *loader_info = (VK_LOADER_DATA *)pNewObject;
|
||||||
|
return (loader_info->loaderMagic & 0xffffffff) == ICD_LOADER_MAGIC;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Windows and Linux ICDs will treat VkSurfaceKHR as a pointer to a struct that
|
||||||
|
* contains the platform-specific connection and surface information.
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
VK_ICD_WSI_PLATFORM_MIR,
|
||||||
|
VK_ICD_WSI_PLATFORM_WAYLAND,
|
||||||
|
VK_ICD_WSI_PLATFORM_WIN32,
|
||||||
|
VK_ICD_WSI_PLATFORM_XCB,
|
||||||
|
VK_ICD_WSI_PLATFORM_XLIB,
|
||||||
|
VK_ICD_WSI_PLATFORM_ANDROID,
|
||||||
|
VK_ICD_WSI_PLATFORM_MACOS,
|
||||||
|
VK_ICD_WSI_PLATFORM_IOS,
|
||||||
|
VK_ICD_WSI_PLATFORM_DISPLAY,
|
||||||
|
VK_ICD_WSI_PLATFORM_HEADLESS,
|
||||||
|
VK_ICD_WSI_PLATFORM_METAL,
|
||||||
|
VK_ICD_WSI_PLATFORM_DIRECTFB,
|
||||||
|
VK_ICD_WSI_PLATFORM_VI,
|
||||||
|
VK_ICD_WSI_PLATFORM_GGP,
|
||||||
|
} VkIcdWsiPlatform;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
VkIcdWsiPlatform platform;
|
||||||
|
} VkIcdSurfaceBase;
|
||||||
|
|
||||||
|
#ifdef VK_USE_PLATFORM_MIR_KHR
|
||||||
|
typedef struct {
|
||||||
|
VkIcdSurfaceBase base;
|
||||||
|
MirConnection *connection;
|
||||||
|
MirSurface *mirSurface;
|
||||||
|
} VkIcdSurfaceMir;
|
||||||
|
#endif // VK_USE_PLATFORM_MIR_KHR
|
||||||
|
|
||||||
|
#ifdef VK_USE_PLATFORM_WAYLAND_KHR
|
||||||
|
typedef struct {
|
||||||
|
VkIcdSurfaceBase base;
|
||||||
|
struct wl_display *display;
|
||||||
|
struct wl_surface *surface;
|
||||||
|
} VkIcdSurfaceWayland;
|
||||||
|
#endif // VK_USE_PLATFORM_WAYLAND_KHR
|
||||||
|
|
||||||
|
#ifdef VK_USE_PLATFORM_WIN32_KHR
|
||||||
|
typedef struct {
|
||||||
|
VkIcdSurfaceBase base;
|
||||||
|
HINSTANCE hinstance;
|
||||||
|
HWND hwnd;
|
||||||
|
} VkIcdSurfaceWin32;
|
||||||
|
#endif // VK_USE_PLATFORM_WIN32_KHR
|
||||||
|
|
||||||
|
#ifdef VK_USE_PLATFORM_XCB_KHR
|
||||||
|
typedef struct {
|
||||||
|
VkIcdSurfaceBase base;
|
||||||
|
xcb_connection_t *connection;
|
||||||
|
xcb_window_t window;
|
||||||
|
} VkIcdSurfaceXcb;
|
||||||
|
#endif // VK_USE_PLATFORM_XCB_KHR
|
||||||
|
|
||||||
|
#ifdef VK_USE_PLATFORM_XLIB_KHR
|
||||||
|
typedef struct {
|
||||||
|
VkIcdSurfaceBase base;
|
||||||
|
Display *dpy;
|
||||||
|
Window window;
|
||||||
|
} VkIcdSurfaceXlib;
|
||||||
|
#endif // VK_USE_PLATFORM_XLIB_KHR
|
||||||
|
|
||||||
|
#ifdef VK_USE_PLATFORM_DIRECTFB_EXT
|
||||||
|
typedef struct {
|
||||||
|
VkIcdSurfaceBase base;
|
||||||
|
IDirectFB *dfb;
|
||||||
|
IDirectFBSurface *surface;
|
||||||
|
} VkIcdSurfaceDirectFB;
|
||||||
|
#endif // VK_USE_PLATFORM_DIRECTFB_EXT
|
||||||
|
|
||||||
|
#ifdef VK_USE_PLATFORM_ANDROID_KHR
|
||||||
|
typedef struct {
|
||||||
|
VkIcdSurfaceBase base;
|
||||||
|
struct ANativeWindow *window;
|
||||||
|
} VkIcdSurfaceAndroid;
|
||||||
|
#endif // VK_USE_PLATFORM_ANDROID_KHR
|
||||||
|
|
||||||
|
#ifdef VK_USE_PLATFORM_MACOS_MVK
|
||||||
|
typedef struct {
|
||||||
|
VkIcdSurfaceBase base;
|
||||||
|
const void *pView;
|
||||||
|
} VkIcdSurfaceMacOS;
|
||||||
|
#endif // VK_USE_PLATFORM_MACOS_MVK
|
||||||
|
|
||||||
|
#ifdef VK_USE_PLATFORM_IOS_MVK
|
||||||
|
typedef struct {
|
||||||
|
VkIcdSurfaceBase base;
|
||||||
|
const void *pView;
|
||||||
|
} VkIcdSurfaceIOS;
|
||||||
|
#endif // VK_USE_PLATFORM_IOS_MVK
|
||||||
|
|
||||||
|
#ifdef VK_USE_PLATFORM_GGP
|
||||||
|
typedef struct {
|
||||||
|
VkIcdSurfaceBase base;
|
||||||
|
GgpStreamDescriptor streamDescriptor;
|
||||||
|
} VkIcdSurfaceGgp;
|
||||||
|
#endif // VK_USE_PLATFORM_GGP
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
VkIcdSurfaceBase base;
|
||||||
|
VkDisplayModeKHR displayMode;
|
||||||
|
uint32_t planeIndex;
|
||||||
|
uint32_t planeStackIndex;
|
||||||
|
VkSurfaceTransformFlagBitsKHR transform;
|
||||||
|
float globalAlpha;
|
||||||
|
VkDisplayPlaneAlphaFlagBitsKHR alphaMode;
|
||||||
|
VkExtent2D imageExtent;
|
||||||
|
} VkIcdSurfaceDisplay;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
VkIcdSurfaceBase base;
|
||||||
|
} VkIcdSurfaceHeadless;
|
||||||
|
|
||||||
|
#ifdef VK_USE_PLATFORM_METAL_EXT
|
||||||
|
typedef struct {
|
||||||
|
VkIcdSurfaceBase base;
|
||||||
|
const CAMetalLayer *pLayer;
|
||||||
|
} VkIcdSurfaceMetal;
|
||||||
|
#endif // VK_USE_PLATFORM_METAL_EXT
|
||||||
|
|
||||||
|
#ifdef VK_USE_PLATFORM_VI_NN
|
||||||
|
typedef struct {
|
||||||
|
VkIcdSurfaceBase base;
|
||||||
|
void *window;
|
||||||
|
} VkIcdSurfaceVi;
|
||||||
|
#endif // VK_USE_PLATFORM_VI_NN
|
||||||
|
|
||||||
|
#endif // VKICD_H
|
|
@ -0,0 +1,210 @@
|
||||||
|
//
|
||||||
|
// File: vk_layer.h
|
||||||
|
//
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2015-2017 The Khronos Group Inc.
|
||||||
|
* Copyright (c) 2015-2017 Valve Corporation
|
||||||
|
* Copyright (c) 2015-2017 LunarG, Inc.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Need to define dispatch table
|
||||||
|
* Core struct can then have ptr to dispatch table at the top
|
||||||
|
* Along with object ptrs for current and next OBJ
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "vulkan.h"
|
||||||
|
#if defined(__GNUC__) && __GNUC__ >= 4
|
||||||
|
#define VK_LAYER_EXPORT __attribute__((visibility("default")))
|
||||||
|
#elif defined(__SUNPRO_C) && (__SUNPRO_C >= 0x590)
|
||||||
|
#define VK_LAYER_EXPORT __attribute__((visibility("default")))
|
||||||
|
#else
|
||||||
|
#define VK_LAYER_EXPORT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define MAX_NUM_UNKNOWN_EXTS 250
|
||||||
|
|
||||||
|
// Loader-Layer version negotiation API. Versions add the following features:
|
||||||
|
// Versions 0/1 - Initial. Doesn't support vk_layerGetPhysicalDeviceProcAddr
|
||||||
|
// or vk_icdNegotiateLoaderLayerInterfaceVersion.
|
||||||
|
// Version 2 - Add support for vk_layerGetPhysicalDeviceProcAddr and
|
||||||
|
// vk_icdNegotiateLoaderLayerInterfaceVersion.
|
||||||
|
#define CURRENT_LOADER_LAYER_INTERFACE_VERSION 2
|
||||||
|
#define MIN_SUPPORTED_LOADER_LAYER_INTERFACE_VERSION 1
|
||||||
|
|
||||||
|
#define VK_CURRENT_CHAIN_VERSION 1
|
||||||
|
|
||||||
|
// Typedef for use in the interfaces below
|
||||||
|
typedef PFN_vkVoidFunction (VKAPI_PTR *PFN_GetPhysicalDeviceProcAddr)(VkInstance instance, const char* pName);
|
||||||
|
|
||||||
|
// Version negotiation values
|
||||||
|
typedef enum VkNegotiateLayerStructType {
|
||||||
|
LAYER_NEGOTIATE_UNINTIALIZED = 0,
|
||||||
|
LAYER_NEGOTIATE_INTERFACE_STRUCT = 1,
|
||||||
|
} VkNegotiateLayerStructType;
|
||||||
|
|
||||||
|
// Version negotiation structures
|
||||||
|
typedef struct VkNegotiateLayerInterface {
|
||||||
|
VkNegotiateLayerStructType sType;
|
||||||
|
void *pNext;
|
||||||
|
uint32_t loaderLayerInterfaceVersion;
|
||||||
|
PFN_vkGetInstanceProcAddr pfnGetInstanceProcAddr;
|
||||||
|
PFN_vkGetDeviceProcAddr pfnGetDeviceProcAddr;
|
||||||
|
PFN_GetPhysicalDeviceProcAddr pfnGetPhysicalDeviceProcAddr;
|
||||||
|
} VkNegotiateLayerInterface;
|
||||||
|
|
||||||
|
// Version negotiation functions
|
||||||
|
typedef VkResult (VKAPI_PTR *PFN_vkNegotiateLoaderLayerInterfaceVersion)(VkNegotiateLayerInterface *pVersionStruct);
|
||||||
|
|
||||||
|
// Function prototype for unknown physical device extension command
|
||||||
|
typedef VkResult(VKAPI_PTR *PFN_PhysDevExt)(VkPhysicalDevice phys_device);
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
// CreateInstance and CreateDevice support structures
|
||||||
|
|
||||||
|
/* Sub type of structure for instance and device loader ext of CreateInfo.
|
||||||
|
* When sType == VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO
|
||||||
|
* or sType == VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO
|
||||||
|
* then VkLayerFunction indicates struct type pointed to by pNext
|
||||||
|
*/
|
||||||
|
typedef enum VkLayerFunction_ {
|
||||||
|
VK_LAYER_LINK_INFO = 0,
|
||||||
|
VK_LOADER_DATA_CALLBACK = 1,
|
||||||
|
VK_LOADER_LAYER_CREATE_DEVICE_CALLBACK = 2,
|
||||||
|
VK_LOADER_FEATURES = 3,
|
||||||
|
} VkLayerFunction;
|
||||||
|
|
||||||
|
typedef struct VkLayerInstanceLink_ {
|
||||||
|
struct VkLayerInstanceLink_ *pNext;
|
||||||
|
PFN_vkGetInstanceProcAddr pfnNextGetInstanceProcAddr;
|
||||||
|
PFN_GetPhysicalDeviceProcAddr pfnNextGetPhysicalDeviceProcAddr;
|
||||||
|
} VkLayerInstanceLink;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When creating the device chain the loader needs to pass
|
||||||
|
* down information about it's device structure needed at
|
||||||
|
* the end of the chain. Passing the data via the
|
||||||
|
* VkLayerDeviceInfo avoids issues with finding the
|
||||||
|
* exact instance being used.
|
||||||
|
*/
|
||||||
|
typedef struct VkLayerDeviceInfo_ {
|
||||||
|
void *device_info;
|
||||||
|
PFN_vkGetInstanceProcAddr pfnNextGetInstanceProcAddr;
|
||||||
|
} VkLayerDeviceInfo;
|
||||||
|
|
||||||
|
typedef VkResult (VKAPI_PTR *PFN_vkSetInstanceLoaderData)(VkInstance instance,
|
||||||
|
void *object);
|
||||||
|
typedef VkResult (VKAPI_PTR *PFN_vkSetDeviceLoaderData)(VkDevice device,
|
||||||
|
void *object);
|
||||||
|
typedef VkResult (VKAPI_PTR *PFN_vkLayerCreateDevice)(VkInstance instance, VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo *pCreateInfo,
|
||||||
|
const VkAllocationCallbacks *pAllocator, VkDevice *pDevice, PFN_vkGetInstanceProcAddr layerGIPA, PFN_vkGetDeviceProcAddr *nextGDPA);
|
||||||
|
typedef void (VKAPI_PTR *PFN_vkLayerDestroyDevice)(VkDevice physicalDevice, const VkAllocationCallbacks *pAllocator, PFN_vkDestroyDevice destroyFunction);
|
||||||
|
|
||||||
|
typedef enum VkLoaderFeastureFlagBits {
|
||||||
|
VK_LOADER_FEATURE_PHYSICAL_DEVICE_SORTING = 0x00000001,
|
||||||
|
} VkLoaderFlagBits;
|
||||||
|
typedef VkFlags VkLoaderFeatureFlags;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
VkStructureType sType; // VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO
|
||||||
|
const void *pNext;
|
||||||
|
VkLayerFunction function;
|
||||||
|
union {
|
||||||
|
VkLayerInstanceLink *pLayerInfo;
|
||||||
|
PFN_vkSetInstanceLoaderData pfnSetInstanceLoaderData;
|
||||||
|
struct {
|
||||||
|
PFN_vkLayerCreateDevice pfnLayerCreateDevice;
|
||||||
|
PFN_vkLayerDestroyDevice pfnLayerDestroyDevice;
|
||||||
|
} layerDevice;
|
||||||
|
VkLoaderFeatureFlags loaderFeatures;
|
||||||
|
} u;
|
||||||
|
} VkLayerInstanceCreateInfo;
|
||||||
|
|
||||||
|
typedef struct VkLayerDeviceLink_ {
|
||||||
|
struct VkLayerDeviceLink_ *pNext;
|
||||||
|
PFN_vkGetInstanceProcAddr pfnNextGetInstanceProcAddr;
|
||||||
|
PFN_vkGetDeviceProcAddr pfnNextGetDeviceProcAddr;
|
||||||
|
} VkLayerDeviceLink;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
VkStructureType sType; // VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO
|
||||||
|
const void *pNext;
|
||||||
|
VkLayerFunction function;
|
||||||
|
union {
|
||||||
|
VkLayerDeviceLink *pLayerInfo;
|
||||||
|
PFN_vkSetDeviceLoaderData pfnSetDeviceLoaderData;
|
||||||
|
} u;
|
||||||
|
} VkLayerDeviceCreateInfo;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
VKAPI_ATTR VkResult VKAPI_CALL vkNegotiateLoaderLayerInterfaceVersion(VkNegotiateLayerInterface *pVersionStruct);
|
||||||
|
|
||||||
|
typedef enum VkChainType {
|
||||||
|
VK_CHAIN_TYPE_UNKNOWN = 0,
|
||||||
|
VK_CHAIN_TYPE_ENUMERATE_INSTANCE_EXTENSION_PROPERTIES = 1,
|
||||||
|
VK_CHAIN_TYPE_ENUMERATE_INSTANCE_LAYER_PROPERTIES = 2,
|
||||||
|
VK_CHAIN_TYPE_ENUMERATE_INSTANCE_VERSION = 3,
|
||||||
|
} VkChainType;
|
||||||
|
|
||||||
|
typedef struct VkChainHeader {
|
||||||
|
VkChainType type;
|
||||||
|
uint32_t version;
|
||||||
|
uint32_t size;
|
||||||
|
} VkChainHeader;
|
||||||
|
|
||||||
|
typedef struct VkEnumerateInstanceExtensionPropertiesChain {
|
||||||
|
VkChainHeader header;
|
||||||
|
VkResult(VKAPI_PTR *pfnNextLayer)(const struct VkEnumerateInstanceExtensionPropertiesChain *, const char *, uint32_t *,
|
||||||
|
VkExtensionProperties *);
|
||||||
|
const struct VkEnumerateInstanceExtensionPropertiesChain *pNextLink;
|
||||||
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
inline VkResult CallDown(const char *pLayerName, uint32_t *pPropertyCount, VkExtensionProperties *pProperties) const {
|
||||||
|
return pfnNextLayer(pNextLink, pLayerName, pPropertyCount, pProperties);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
} VkEnumerateInstanceExtensionPropertiesChain;
|
||||||
|
|
||||||
|
typedef struct VkEnumerateInstanceLayerPropertiesChain {
|
||||||
|
VkChainHeader header;
|
||||||
|
VkResult(VKAPI_PTR *pfnNextLayer)(const struct VkEnumerateInstanceLayerPropertiesChain *, uint32_t *, VkLayerProperties *);
|
||||||
|
const struct VkEnumerateInstanceLayerPropertiesChain *pNextLink;
|
||||||
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
inline VkResult CallDown(uint32_t *pPropertyCount, VkLayerProperties *pProperties) const {
|
||||||
|
return pfnNextLayer(pNextLink, pPropertyCount, pProperties);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
} VkEnumerateInstanceLayerPropertiesChain;
|
||||||
|
|
||||||
|
typedef struct VkEnumerateInstanceVersionChain {
|
||||||
|
VkChainHeader header;
|
||||||
|
VkResult(VKAPI_PTR *pfnNextLayer)(const struct VkEnumerateInstanceVersionChain *, uint32_t *);
|
||||||
|
const struct VkEnumerateInstanceVersionChain *pNextLink;
|
||||||
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
inline VkResult CallDown(uint32_t *pApiVersion) const {
|
||||||
|
return pfnNextLayer(pNextLink, pApiVersion);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
} VkEnumerateInstanceVersionChain;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -0,0 +1,82 @@
|
||||||
|
//
|
||||||
|
// File: vk_platform.h
|
||||||
|
//
|
||||||
|
/*
|
||||||
|
** Copyright (c) 2014-2020 The Khronos Group Inc.
|
||||||
|
**
|
||||||
|
** SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef VK_PLATFORM_H_
|
||||||
|
#define VK_PLATFORM_H_
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#endif // __cplusplus
|
||||||
|
|
||||||
|
/*
|
||||||
|
***************************************************************************************************
|
||||||
|
* Platform-specific directives and type declarations
|
||||||
|
***************************************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Platform-specific calling convention macros.
|
||||||
|
*
|
||||||
|
* Platforms should define these so that Vulkan clients call Vulkan commands
|
||||||
|
* with the same calling conventions that the Vulkan implementation expects.
|
||||||
|
*
|
||||||
|
* VKAPI_ATTR - Placed before the return type in function declarations.
|
||||||
|
* Useful for C++11 and GCC/Clang-style function attribute syntax.
|
||||||
|
* VKAPI_CALL - Placed after the return type in function declarations.
|
||||||
|
* Useful for MSVC-style calling convention syntax.
|
||||||
|
* VKAPI_PTR - Placed between the '(' and '*' in function pointer types.
|
||||||
|
*
|
||||||
|
* Function declaration: VKAPI_ATTR void VKAPI_CALL vkCommand(void);
|
||||||
|
* Function pointer type: typedef void (VKAPI_PTR *PFN_vkCommand)(void);
|
||||||
|
*/
|
||||||
|
#if defined(_WIN32)
|
||||||
|
// On Windows, Vulkan commands use the stdcall convention
|
||||||
|
#define VKAPI_ATTR
|
||||||
|
#define VKAPI_CALL __stdcall
|
||||||
|
#define VKAPI_PTR VKAPI_CALL
|
||||||
|
#elif defined(__ANDROID__) && defined(__ARM_ARCH) && __ARM_ARCH < 7
|
||||||
|
#error "Vulkan isn't supported for the 'armeabi' NDK ABI"
|
||||||
|
#elif defined(__ANDROID__) && defined(__ARM_ARCH) && __ARM_ARCH >= 7 && defined(__ARM_32BIT_STATE)
|
||||||
|
// On Android 32-bit ARM targets, Vulkan functions use the "hardfloat"
|
||||||
|
// calling convention, i.e. float parameters are passed in registers. This
|
||||||
|
// is true even if the rest of the application passes floats on the stack,
|
||||||
|
// as it does by default when compiling for the armeabi-v7a NDK ABI.
|
||||||
|
#define VKAPI_ATTR __attribute__((pcs("aapcs-vfp")))
|
||||||
|
#define VKAPI_CALL
|
||||||
|
#define VKAPI_PTR VKAPI_ATTR
|
||||||
|
#else
|
||||||
|
// On other platforms, use the default calling convention
|
||||||
|
#define VKAPI_ATTR
|
||||||
|
#define VKAPI_CALL
|
||||||
|
#define VKAPI_PTR
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#if !defined(VK_NO_STDINT_H)
|
||||||
|
#if defined(_MSC_VER) && (_MSC_VER < 1600)
|
||||||
|
typedef signed __int8 int8_t;
|
||||||
|
typedef unsigned __int8 uint8_t;
|
||||||
|
typedef signed __int16 int16_t;
|
||||||
|
typedef unsigned __int16 uint16_t;
|
||||||
|
typedef signed __int32 int32_t;
|
||||||
|
typedef unsigned __int32 uint32_t;
|
||||||
|
typedef signed __int64 int64_t;
|
||||||
|
typedef unsigned __int64 uint64_t;
|
||||||
|
#else
|
||||||
|
#include <stdint.h>
|
||||||
|
#endif
|
||||||
|
#endif // !defined(VK_NO_STDINT_H)
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} // extern "C"
|
||||||
|
#endif // __cplusplus
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,69 @@
|
||||||
|
//
|
||||||
|
// File: vk_sdk_platform.h
|
||||||
|
//
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2015-2016 The Khronos Group Inc.
|
||||||
|
* Copyright (c) 2015-2016 Valve Corporation
|
||||||
|
* Copyright (c) 2015-2016 LunarG, Inc.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef VK_SDK_PLATFORM_H
|
||||||
|
#define VK_SDK_PLATFORM_H
|
||||||
|
|
||||||
|
#if defined(_WIN32)
|
||||||
|
#define NOMINMAX
|
||||||
|
#ifndef __cplusplus
|
||||||
|
#undef inline
|
||||||
|
#define inline __inline
|
||||||
|
#endif // __cplusplus
|
||||||
|
|
||||||
|
#if (defined(_MSC_VER) && _MSC_VER < 1900 /*vs2015*/)
|
||||||
|
// C99:
|
||||||
|
// Microsoft didn't implement C99 in Visual Studio; but started adding it with
|
||||||
|
// VS2013. However, VS2013 still didn't have snprintf(). The following is a
|
||||||
|
// work-around (Note: The _CRT_SECURE_NO_WARNINGS macro must be set in the
|
||||||
|
// "CMakeLists.txt" file).
|
||||||
|
// NOTE: This is fixed in Visual Studio 2015.
|
||||||
|
#define snprintf _snprintf
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define strdup _strdup
|
||||||
|
|
||||||
|
#endif // _WIN32
|
||||||
|
|
||||||
|
// Check for noexcept support using clang, with fallback to Windows or GCC version numbers
|
||||||
|
#ifndef NOEXCEPT
|
||||||
|
#if defined(__clang__)
|
||||||
|
#if __has_feature(cxx_noexcept)
|
||||||
|
#define HAS_NOEXCEPT
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#if defined(__GXX_EXPERIMENTAL_CXX0X__) && __GNUC__ * 10 + __GNUC_MINOR__ >= 46
|
||||||
|
#define HAS_NOEXCEPT
|
||||||
|
#else
|
||||||
|
#if defined(_MSC_FULL_VER) && _MSC_FULL_VER >= 190023026 && defined(_HAS_EXCEPTIONS) && _HAS_EXCEPTIONS
|
||||||
|
#define HAS_NOEXCEPT
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAS_NOEXCEPT
|
||||||
|
#define NOEXCEPT noexcept
|
||||||
|
#else
|
||||||
|
#define NOEXCEPT
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // VK_SDK_PLATFORM_H
|
|
@ -0,0 +1,87 @@
|
||||||
|
#ifndef VULKAN_H_
|
||||||
|
#define VULKAN_H_ 1
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Copyright (c) 2015-2020 The Khronos Group Inc.
|
||||||
|
**
|
||||||
|
** SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "vk_platform.h"
|
||||||
|
#include "vulkan_core.h"
|
||||||
|
|
||||||
|
#ifdef VK_USE_PLATFORM_ANDROID_KHR
|
||||||
|
#include "vulkan_android.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef VK_USE_PLATFORM_FUCHSIA
|
||||||
|
#include <zircon/types.h>
|
||||||
|
#include "vulkan_fuchsia.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef VK_USE_PLATFORM_IOS_MVK
|
||||||
|
#include "vulkan_ios.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef VK_USE_PLATFORM_MACOS_MVK
|
||||||
|
#include "vulkan_macos.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef VK_USE_PLATFORM_METAL_EXT
|
||||||
|
#include "vulkan_metal.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef VK_USE_PLATFORM_VI_NN
|
||||||
|
#include "vulkan_vi.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef VK_USE_PLATFORM_WAYLAND_KHR
|
||||||
|
#include <wayland-client.h>
|
||||||
|
#include "vulkan_wayland.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef VK_USE_PLATFORM_WIN32_KHR
|
||||||
|
#include <windows.h>
|
||||||
|
#include "vulkan_win32.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef VK_USE_PLATFORM_XCB_KHR
|
||||||
|
#include <xcb/xcb.h>
|
||||||
|
#include "vulkan_xcb.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef VK_USE_PLATFORM_XLIB_KHR
|
||||||
|
#include <X11/Xlib.h>
|
||||||
|
#include "vulkan_xlib.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef VK_USE_PLATFORM_DIRECTFB_EXT
|
||||||
|
#include <directfb.h>
|
||||||
|
#include "vulkan_directfb.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT
|
||||||
|
#include <X11/Xlib.h>
|
||||||
|
#include <X11/extensions/Xrandr.h>
|
||||||
|
#include "vulkan_xlib_xrandr.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef VK_USE_PLATFORM_GGP
|
||||||
|
#include <ggp_c/vulkan_types.h>
|
||||||
|
#include "vulkan_ggp.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef VK_ENABLE_BETA_EXTENSIONS
|
||||||
|
#include "vulkan_beta.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // VULKAN_H_
|
|
@ -0,0 +1,112 @@
|
||||||
|
#ifndef VULKAN_ANDROID_H_
|
||||||
|
#define VULKAN_ANDROID_H_ 1
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Copyright (c) 2015-2020 The Khronos Group Inc.
|
||||||
|
**
|
||||||
|
** SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
** This header is generated from the Khronos Vulkan XML API Registry.
|
||||||
|
**
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#define VK_KHR_android_surface 1
|
||||||
|
struct ANativeWindow;
|
||||||
|
#define VK_KHR_ANDROID_SURFACE_SPEC_VERSION 6
|
||||||
|
#define VK_KHR_ANDROID_SURFACE_EXTENSION_NAME "VK_KHR_android_surface"
|
||||||
|
typedef VkFlags VkAndroidSurfaceCreateFlagsKHR;
|
||||||
|
typedef struct VkAndroidSurfaceCreateInfoKHR {
|
||||||
|
VkStructureType sType;
|
||||||
|
const void* pNext;
|
||||||
|
VkAndroidSurfaceCreateFlagsKHR flags;
|
||||||
|
struct ANativeWindow* window;
|
||||||
|
} VkAndroidSurfaceCreateInfoKHR;
|
||||||
|
|
||||||
|
typedef VkResult (VKAPI_PTR *PFN_vkCreateAndroidSurfaceKHR)(VkInstance instance, const VkAndroidSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface);
|
||||||
|
|
||||||
|
#ifndef VK_NO_PROTOTYPES
|
||||||
|
VKAPI_ATTR VkResult VKAPI_CALL vkCreateAndroidSurfaceKHR(
|
||||||
|
VkInstance instance,
|
||||||
|
const VkAndroidSurfaceCreateInfoKHR* pCreateInfo,
|
||||||
|
const VkAllocationCallbacks* pAllocator,
|
||||||
|
VkSurfaceKHR* pSurface);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#define VK_ANDROID_external_memory_android_hardware_buffer 1
|
||||||
|
struct AHardwareBuffer;
|
||||||
|
#define VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_SPEC_VERSION 3
|
||||||
|
#define VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME "VK_ANDROID_external_memory_android_hardware_buffer"
|
||||||
|
typedef struct VkAndroidHardwareBufferUsageANDROID {
|
||||||
|
VkStructureType sType;
|
||||||
|
void* pNext;
|
||||||
|
uint64_t androidHardwareBufferUsage;
|
||||||
|
} VkAndroidHardwareBufferUsageANDROID;
|
||||||
|
|
||||||
|
typedef struct VkAndroidHardwareBufferPropertiesANDROID {
|
||||||
|
VkStructureType sType;
|
||||||
|
void* pNext;
|
||||||
|
VkDeviceSize allocationSize;
|
||||||
|
uint32_t memoryTypeBits;
|
||||||
|
} VkAndroidHardwareBufferPropertiesANDROID;
|
||||||
|
|
||||||
|
typedef struct VkAndroidHardwareBufferFormatPropertiesANDROID {
|
||||||
|
VkStructureType sType;
|
||||||
|
void* pNext;
|
||||||
|
VkFormat format;
|
||||||
|
uint64_t externalFormat;
|
||||||
|
VkFormatFeatureFlags formatFeatures;
|
||||||
|
VkComponentMapping samplerYcbcrConversionComponents;
|
||||||
|
VkSamplerYcbcrModelConversion suggestedYcbcrModel;
|
||||||
|
VkSamplerYcbcrRange suggestedYcbcrRange;
|
||||||
|
VkChromaLocation suggestedXChromaOffset;
|
||||||
|
VkChromaLocation suggestedYChromaOffset;
|
||||||
|
} VkAndroidHardwareBufferFormatPropertiesANDROID;
|
||||||
|
|
||||||
|
typedef struct VkImportAndroidHardwareBufferInfoANDROID {
|
||||||
|
VkStructureType sType;
|
||||||
|
const void* pNext;
|
||||||
|
struct AHardwareBuffer* buffer;
|
||||||
|
} VkImportAndroidHardwareBufferInfoANDROID;
|
||||||
|
|
||||||
|
typedef struct VkMemoryGetAndroidHardwareBufferInfoANDROID {
|
||||||
|
VkStructureType sType;
|
||||||
|
const void* pNext;
|
||||||
|
VkDeviceMemory memory;
|
||||||
|
} VkMemoryGetAndroidHardwareBufferInfoANDROID;
|
||||||
|
|
||||||
|
typedef struct VkExternalFormatANDROID {
|
||||||
|
VkStructureType sType;
|
||||||
|
void* pNext;
|
||||||
|
uint64_t externalFormat;
|
||||||
|
} VkExternalFormatANDROID;
|
||||||
|
|
||||||
|
typedef VkResult (VKAPI_PTR *PFN_vkGetAndroidHardwareBufferPropertiesANDROID)(VkDevice device, const struct AHardwareBuffer* buffer, VkAndroidHardwareBufferPropertiesANDROID* pProperties);
|
||||||
|
typedef VkResult (VKAPI_PTR *PFN_vkGetMemoryAndroidHardwareBufferANDROID)(VkDevice device, const VkMemoryGetAndroidHardwareBufferInfoANDROID* pInfo, struct AHardwareBuffer** pBuffer);
|
||||||
|
|
||||||
|
#ifndef VK_NO_PROTOTYPES
|
||||||
|
VKAPI_ATTR VkResult VKAPI_CALL vkGetAndroidHardwareBufferPropertiesANDROID(
|
||||||
|
VkDevice device,
|
||||||
|
const struct AHardwareBuffer* buffer,
|
||||||
|
VkAndroidHardwareBufferPropertiesANDROID* pProperties);
|
||||||
|
|
||||||
|
VKAPI_ATTR VkResult VKAPI_CALL vkGetMemoryAndroidHardwareBufferANDROID(
|
||||||
|
VkDevice device,
|
||||||
|
const VkMemoryGetAndroidHardwareBufferInfoANDROID* pInfo,
|
||||||
|
struct AHardwareBuffer** pBuffer);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,56 @@
|
||||||
|
#ifndef VULKAN_BETA_H_
|
||||||
|
#define VULKAN_BETA_H_ 1
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Copyright (c) 2015-2020 The Khronos Group Inc.
|
||||||
|
**
|
||||||
|
** SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
** This header is generated from the Khronos Vulkan XML API Registry.
|
||||||
|
**
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#define VK_KHR_portability_subset 1
|
||||||
|
#define VK_KHR_PORTABILITY_SUBSET_SPEC_VERSION 1
|
||||||
|
#define VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME "VK_KHR_portability_subset"
|
||||||
|
typedef struct VkPhysicalDevicePortabilitySubsetFeaturesKHR {
|
||||||
|
VkStructureType sType;
|
||||||
|
void* pNext;
|
||||||
|
VkBool32 constantAlphaColorBlendFactors;
|
||||||
|
VkBool32 events;
|
||||||
|
VkBool32 imageViewFormatReinterpretation;
|
||||||
|
VkBool32 imageViewFormatSwizzle;
|
||||||
|
VkBool32 imageView2DOn3DImage;
|
||||||
|
VkBool32 multisampleArrayImage;
|
||||||
|
VkBool32 mutableComparisonSamplers;
|
||||||
|
VkBool32 pointPolygons;
|
||||||
|
VkBool32 samplerMipLodBias;
|
||||||
|
VkBool32 separateStencilMaskRef;
|
||||||
|
VkBool32 shaderSampleRateInterpolationFunctions;
|
||||||
|
VkBool32 tessellationIsolines;
|
||||||
|
VkBool32 tessellationPointMode;
|
||||||
|
VkBool32 triangleFans;
|
||||||
|
VkBool32 vertexAttributeAccessBeyondStride;
|
||||||
|
} VkPhysicalDevicePortabilitySubsetFeaturesKHR;
|
||||||
|
|
||||||
|
typedef struct VkPhysicalDevicePortabilitySubsetPropertiesKHR {
|
||||||
|
VkStructureType sType;
|
||||||
|
void* pNext;
|
||||||
|
uint32_t minVertexInputBindingStrideAlignment;
|
||||||
|
} VkPhysicalDevicePortabilitySubsetPropertiesKHR;
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,54 @@
|
||||||
|
#ifndef VULKAN_DIRECTFB_H_
|
||||||
|
#define VULKAN_DIRECTFB_H_ 1
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Copyright (c) 2015-2020 The Khronos Group Inc.
|
||||||
|
**
|
||||||
|
** SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
** This header is generated from the Khronos Vulkan XML API Registry.
|
||||||
|
**
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#define VK_EXT_directfb_surface 1
|
||||||
|
#define VK_EXT_DIRECTFB_SURFACE_SPEC_VERSION 1
|
||||||
|
#define VK_EXT_DIRECTFB_SURFACE_EXTENSION_NAME "VK_EXT_directfb_surface"
|
||||||
|
typedef VkFlags VkDirectFBSurfaceCreateFlagsEXT;
|
||||||
|
typedef struct VkDirectFBSurfaceCreateInfoEXT {
|
||||||
|
VkStructureType sType;
|
||||||
|
const void* pNext;
|
||||||
|
VkDirectFBSurfaceCreateFlagsEXT flags;
|
||||||
|
IDirectFB* dfb;
|
||||||
|
IDirectFBSurface* surface;
|
||||||
|
} VkDirectFBSurfaceCreateInfoEXT;
|
||||||
|
|
||||||
|
typedef VkResult (VKAPI_PTR *PFN_vkCreateDirectFBSurfaceEXT)(VkInstance instance, const VkDirectFBSurfaceCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface);
|
||||||
|
typedef VkBool32 (VKAPI_PTR *PFN_vkGetPhysicalDeviceDirectFBPresentationSupportEXT)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, IDirectFB* dfb);
|
||||||
|
|
||||||
|
#ifndef VK_NO_PROTOTYPES
|
||||||
|
VKAPI_ATTR VkResult VKAPI_CALL vkCreateDirectFBSurfaceEXT(
|
||||||
|
VkInstance instance,
|
||||||
|
const VkDirectFBSurfaceCreateInfoEXT* pCreateInfo,
|
||||||
|
const VkAllocationCallbacks* pAllocator,
|
||||||
|
VkSurfaceKHR* pSurface);
|
||||||
|
|
||||||
|
VKAPI_ATTR VkBool32 VKAPI_CALL vkGetPhysicalDeviceDirectFBPresentationSupportEXT(
|
||||||
|
VkPhysicalDevice physicalDevice,
|
||||||
|
uint32_t queueFamilyIndex,
|
||||||
|
IDirectFB* dfb);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,47 @@
|
||||||
|
#ifndef VULKAN_FUCHSIA_H_
|
||||||
|
#define VULKAN_FUCHSIA_H_ 1
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Copyright (c) 2015-2020 The Khronos Group Inc.
|
||||||
|
**
|
||||||
|
** SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
** This header is generated from the Khronos Vulkan XML API Registry.
|
||||||
|
**
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#define VK_FUCHSIA_imagepipe_surface 1
|
||||||
|
#define VK_FUCHSIA_IMAGEPIPE_SURFACE_SPEC_VERSION 1
|
||||||
|
#define VK_FUCHSIA_IMAGEPIPE_SURFACE_EXTENSION_NAME "VK_FUCHSIA_imagepipe_surface"
|
||||||
|
typedef VkFlags VkImagePipeSurfaceCreateFlagsFUCHSIA;
|
||||||
|
typedef struct VkImagePipeSurfaceCreateInfoFUCHSIA {
|
||||||
|
VkStructureType sType;
|
||||||
|
const void* pNext;
|
||||||
|
VkImagePipeSurfaceCreateFlagsFUCHSIA flags;
|
||||||
|
zx_handle_t imagePipeHandle;
|
||||||
|
} VkImagePipeSurfaceCreateInfoFUCHSIA;
|
||||||
|
|
||||||
|
typedef VkResult (VKAPI_PTR *PFN_vkCreateImagePipeSurfaceFUCHSIA)(VkInstance instance, const VkImagePipeSurfaceCreateInfoFUCHSIA* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface);
|
||||||
|
|
||||||
|
#ifndef VK_NO_PROTOTYPES
|
||||||
|
VKAPI_ATTR VkResult VKAPI_CALL vkCreateImagePipeSurfaceFUCHSIA(
|
||||||
|
VkInstance instance,
|
||||||
|
const VkImagePipeSurfaceCreateInfoFUCHSIA* pCreateInfo,
|
||||||
|
const VkAllocationCallbacks* pAllocator,
|
||||||
|
VkSurfaceKHR* pSurface);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,58 @@
|
||||||
|
#ifndef VULKAN_GGP_H_
|
||||||
|
#define VULKAN_GGP_H_ 1
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Copyright (c) 2015-2020 The Khronos Group Inc.
|
||||||
|
**
|
||||||
|
** SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
** This header is generated from the Khronos Vulkan XML API Registry.
|
||||||
|
**
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#define VK_GGP_stream_descriptor_surface 1
|
||||||
|
#define VK_GGP_STREAM_DESCRIPTOR_SURFACE_SPEC_VERSION 1
|
||||||
|
#define VK_GGP_STREAM_DESCRIPTOR_SURFACE_EXTENSION_NAME "VK_GGP_stream_descriptor_surface"
|
||||||
|
typedef VkFlags VkStreamDescriptorSurfaceCreateFlagsGGP;
|
||||||
|
typedef struct VkStreamDescriptorSurfaceCreateInfoGGP {
|
||||||
|
VkStructureType sType;
|
||||||
|
const void* pNext;
|
||||||
|
VkStreamDescriptorSurfaceCreateFlagsGGP flags;
|
||||||
|
GgpStreamDescriptor streamDescriptor;
|
||||||
|
} VkStreamDescriptorSurfaceCreateInfoGGP;
|
||||||
|
|
||||||
|
typedef VkResult (VKAPI_PTR *PFN_vkCreateStreamDescriptorSurfaceGGP)(VkInstance instance, const VkStreamDescriptorSurfaceCreateInfoGGP* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface);
|
||||||
|
|
||||||
|
#ifndef VK_NO_PROTOTYPES
|
||||||
|
VKAPI_ATTR VkResult VKAPI_CALL vkCreateStreamDescriptorSurfaceGGP(
|
||||||
|
VkInstance instance,
|
||||||
|
const VkStreamDescriptorSurfaceCreateInfoGGP* pCreateInfo,
|
||||||
|
const VkAllocationCallbacks* pAllocator,
|
||||||
|
VkSurfaceKHR* pSurface);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#define VK_GGP_frame_token 1
|
||||||
|
#define VK_GGP_FRAME_TOKEN_SPEC_VERSION 1
|
||||||
|
#define VK_GGP_FRAME_TOKEN_EXTENSION_NAME "VK_GGP_frame_token"
|
||||||
|
typedef struct VkPresentFrameTokenGGP {
|
||||||
|
VkStructureType sType;
|
||||||
|
const void* pNext;
|
||||||
|
GgpFrameToken frameToken;
|
||||||
|
} VkPresentFrameTokenGGP;
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,47 @@
|
||||||
|
#ifndef VULKAN_IOS_H_
|
||||||
|
#define VULKAN_IOS_H_ 1
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Copyright (c) 2015-2020 The Khronos Group Inc.
|
||||||
|
**
|
||||||
|
** SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
** This header is generated from the Khronos Vulkan XML API Registry.
|
||||||
|
**
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#define VK_MVK_ios_surface 1
|
||||||
|
#define VK_MVK_IOS_SURFACE_SPEC_VERSION 3
|
||||||
|
#define VK_MVK_IOS_SURFACE_EXTENSION_NAME "VK_MVK_ios_surface"
|
||||||
|
typedef VkFlags VkIOSSurfaceCreateFlagsMVK;
|
||||||
|
typedef struct VkIOSSurfaceCreateInfoMVK {
|
||||||
|
VkStructureType sType;
|
||||||
|
const void* pNext;
|
||||||
|
VkIOSSurfaceCreateFlagsMVK flags;
|
||||||
|
const void* pView;
|
||||||
|
} VkIOSSurfaceCreateInfoMVK;
|
||||||
|
|
||||||
|
typedef VkResult (VKAPI_PTR *PFN_vkCreateIOSSurfaceMVK)(VkInstance instance, const VkIOSSurfaceCreateInfoMVK* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface);
|
||||||
|
|
||||||
|
#ifndef VK_NO_PROTOTYPES
|
||||||
|
VKAPI_ATTR VkResult VKAPI_CALL vkCreateIOSSurfaceMVK(
|
||||||
|
VkInstance instance,
|
||||||
|
const VkIOSSurfaceCreateInfoMVK* pCreateInfo,
|
||||||
|
const VkAllocationCallbacks* pAllocator,
|
||||||
|
VkSurfaceKHR* pSurface);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,47 @@
|
||||||
|
#ifndef VULKAN_MACOS_H_
|
||||||
|
#define VULKAN_MACOS_H_ 1
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Copyright (c) 2015-2020 The Khronos Group Inc.
|
||||||
|
**
|
||||||
|
** SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
** This header is generated from the Khronos Vulkan XML API Registry.
|
||||||
|
**
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#define VK_MVK_macos_surface 1
|
||||||
|
#define VK_MVK_MACOS_SURFACE_SPEC_VERSION 3
|
||||||
|
#define VK_MVK_MACOS_SURFACE_EXTENSION_NAME "VK_MVK_macos_surface"
|
||||||
|
typedef VkFlags VkMacOSSurfaceCreateFlagsMVK;
|
||||||
|
typedef struct VkMacOSSurfaceCreateInfoMVK {
|
||||||
|
VkStructureType sType;
|
||||||
|
const void* pNext;
|
||||||
|
VkMacOSSurfaceCreateFlagsMVK flags;
|
||||||
|
const void* pView;
|
||||||
|
} VkMacOSSurfaceCreateInfoMVK;
|
||||||
|
|
||||||
|
typedef VkResult (VKAPI_PTR *PFN_vkCreateMacOSSurfaceMVK)(VkInstance instance, const VkMacOSSurfaceCreateInfoMVK* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface);
|
||||||
|
|
||||||
|
#ifndef VK_NO_PROTOTYPES
|
||||||
|
VKAPI_ATTR VkResult VKAPI_CALL vkCreateMacOSSurfaceMVK(
|
||||||
|
VkInstance instance,
|
||||||
|
const VkMacOSSurfaceCreateInfoMVK* pCreateInfo,
|
||||||
|
const VkAllocationCallbacks* pAllocator,
|
||||||
|
VkSurfaceKHR* pSurface);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,54 @@
|
||||||
|
#ifndef VULKAN_METAL_H_
|
||||||
|
#define VULKAN_METAL_H_ 1
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Copyright (c) 2015-2020 The Khronos Group Inc.
|
||||||
|
**
|
||||||
|
** SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
** This header is generated from the Khronos Vulkan XML API Registry.
|
||||||
|
**
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#define VK_EXT_metal_surface 1
|
||||||
|
|
||||||
|
#ifdef __OBJC__
|
||||||
|
@class CAMetalLayer;
|
||||||
|
#else
|
||||||
|
typedef void CAMetalLayer;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define VK_EXT_METAL_SURFACE_SPEC_VERSION 1
|
||||||
|
#define VK_EXT_METAL_SURFACE_EXTENSION_NAME "VK_EXT_metal_surface"
|
||||||
|
typedef VkFlags VkMetalSurfaceCreateFlagsEXT;
|
||||||
|
typedef struct VkMetalSurfaceCreateInfoEXT {
|
||||||
|
VkStructureType sType;
|
||||||
|
const void* pNext;
|
||||||
|
VkMetalSurfaceCreateFlagsEXT flags;
|
||||||
|
const CAMetalLayer* pLayer;
|
||||||
|
} VkMetalSurfaceCreateInfoEXT;
|
||||||
|
|
||||||
|
typedef VkResult (VKAPI_PTR *PFN_vkCreateMetalSurfaceEXT)(VkInstance instance, const VkMetalSurfaceCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface);
|
||||||
|
|
||||||
|
#ifndef VK_NO_PROTOTYPES
|
||||||
|
VKAPI_ATTR VkResult VKAPI_CALL vkCreateMetalSurfaceEXT(
|
||||||
|
VkInstance instance,
|
||||||
|
const VkMetalSurfaceCreateInfoEXT* pCreateInfo,
|
||||||
|
const VkAllocationCallbacks* pAllocator,
|
||||||
|
VkSurfaceKHR* pSurface);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,47 @@
|
||||||
|
#ifndef VULKAN_VI_H_
|
||||||
|
#define VULKAN_VI_H_ 1
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Copyright (c) 2015-2020 The Khronos Group Inc.
|
||||||
|
**
|
||||||
|
** SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
** This header is generated from the Khronos Vulkan XML API Registry.
|
||||||
|
**
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#define VK_NN_vi_surface 1
|
||||||
|
#define VK_NN_VI_SURFACE_SPEC_VERSION 1
|
||||||
|
#define VK_NN_VI_SURFACE_EXTENSION_NAME "VK_NN_vi_surface"
|
||||||
|
typedef VkFlags VkViSurfaceCreateFlagsNN;
|
||||||
|
typedef struct VkViSurfaceCreateInfoNN {
|
||||||
|
VkStructureType sType;
|
||||||
|
const void* pNext;
|
||||||
|
VkViSurfaceCreateFlagsNN flags;
|
||||||
|
void* window;
|
||||||
|
} VkViSurfaceCreateInfoNN;
|
||||||
|
|
||||||
|
typedef VkResult (VKAPI_PTR *PFN_vkCreateViSurfaceNN)(VkInstance instance, const VkViSurfaceCreateInfoNN* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface);
|
||||||
|
|
||||||
|
#ifndef VK_NO_PROTOTYPES
|
||||||
|
VKAPI_ATTR VkResult VKAPI_CALL vkCreateViSurfaceNN(
|
||||||
|
VkInstance instance,
|
||||||
|
const VkViSurfaceCreateInfoNN* pCreateInfo,
|
||||||
|
const VkAllocationCallbacks* pAllocator,
|
||||||
|
VkSurfaceKHR* pSurface);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,54 @@
|
||||||
|
#ifndef VULKAN_WAYLAND_H_
|
||||||
|
#define VULKAN_WAYLAND_H_ 1
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Copyright (c) 2015-2020 The Khronos Group Inc.
|
||||||
|
**
|
||||||
|
** SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
** This header is generated from the Khronos Vulkan XML API Registry.
|
||||||
|
**
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#define VK_KHR_wayland_surface 1
|
||||||
|
#define VK_KHR_WAYLAND_SURFACE_SPEC_VERSION 6
|
||||||
|
#define VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME "VK_KHR_wayland_surface"
|
||||||
|
typedef VkFlags VkWaylandSurfaceCreateFlagsKHR;
|
||||||
|
typedef struct VkWaylandSurfaceCreateInfoKHR {
|
||||||
|
VkStructureType sType;
|
||||||
|
const void* pNext;
|
||||||
|
VkWaylandSurfaceCreateFlagsKHR flags;
|
||||||
|
struct wl_display* display;
|
||||||
|
struct wl_surface* surface;
|
||||||
|
} VkWaylandSurfaceCreateInfoKHR;
|
||||||
|
|
||||||
|
typedef VkResult (VKAPI_PTR *PFN_vkCreateWaylandSurfaceKHR)(VkInstance instance, const VkWaylandSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface);
|
||||||
|
typedef VkBool32 (VKAPI_PTR *PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, struct wl_display* display);
|
||||||
|
|
||||||
|
#ifndef VK_NO_PROTOTYPES
|
||||||
|
VKAPI_ATTR VkResult VKAPI_CALL vkCreateWaylandSurfaceKHR(
|
||||||
|
VkInstance instance,
|
||||||
|
const VkWaylandSurfaceCreateInfoKHR* pCreateInfo,
|
||||||
|
const VkAllocationCallbacks* pAllocator,
|
||||||
|
VkSurfaceKHR* pSurface);
|
||||||
|
|
||||||
|
VKAPI_ATTR VkBool32 VKAPI_CALL vkGetPhysicalDeviceWaylandPresentationSupportKHR(
|
||||||
|
VkPhysicalDevice physicalDevice,
|
||||||
|
uint32_t queueFamilyIndex,
|
||||||
|
struct wl_display* display);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,315 @@
|
||||||
|
#ifndef VULKAN_WIN32_H_
|
||||||
|
#define VULKAN_WIN32_H_ 1
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Copyright (c) 2015-2020 The Khronos Group Inc.
|
||||||
|
**
|
||||||
|
** SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
** This header is generated from the Khronos Vulkan XML API Registry.
|
||||||
|
**
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#define VK_KHR_win32_surface 1
|
||||||
|
#define VK_KHR_WIN32_SURFACE_SPEC_VERSION 6
|
||||||
|
#define VK_KHR_WIN32_SURFACE_EXTENSION_NAME "VK_KHR_win32_surface"
|
||||||
|
typedef VkFlags VkWin32SurfaceCreateFlagsKHR;
|
||||||
|
typedef struct VkWin32SurfaceCreateInfoKHR {
|
||||||
|
VkStructureType sType;
|
||||||
|
const void* pNext;
|
||||||
|
VkWin32SurfaceCreateFlagsKHR flags;
|
||||||
|
HINSTANCE hinstance;
|
||||||
|
HWND hwnd;
|
||||||
|
} VkWin32SurfaceCreateInfoKHR;
|
||||||
|
|
||||||
|
typedef VkResult (VKAPI_PTR *PFN_vkCreateWin32SurfaceKHR)(VkInstance instance, const VkWin32SurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface);
|
||||||
|
typedef VkBool32 (VKAPI_PTR *PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex);
|
||||||
|
|
||||||
|
#ifndef VK_NO_PROTOTYPES
|
||||||
|
VKAPI_ATTR VkResult VKAPI_CALL vkCreateWin32SurfaceKHR(
|
||||||
|
VkInstance instance,
|
||||||
|
const VkWin32SurfaceCreateInfoKHR* pCreateInfo,
|
||||||
|
const VkAllocationCallbacks* pAllocator,
|
||||||
|
VkSurfaceKHR* pSurface);
|
||||||
|
|
||||||
|
VKAPI_ATTR VkBool32 VKAPI_CALL vkGetPhysicalDeviceWin32PresentationSupportKHR(
|
||||||
|
VkPhysicalDevice physicalDevice,
|
||||||
|
uint32_t queueFamilyIndex);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#define VK_KHR_external_memory_win32 1
|
||||||
|
#define VK_KHR_EXTERNAL_MEMORY_WIN32_SPEC_VERSION 1
|
||||||
|
#define VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME "VK_KHR_external_memory_win32"
|
||||||
|
typedef struct VkImportMemoryWin32HandleInfoKHR {
|
||||||
|
VkStructureType sType;
|
||||||
|
const void* pNext;
|
||||||
|
VkExternalMemoryHandleTypeFlagBits handleType;
|
||||||
|
HANDLE handle;
|
||||||
|
LPCWSTR name;
|
||||||
|
} VkImportMemoryWin32HandleInfoKHR;
|
||||||
|
|
||||||
|
typedef struct VkExportMemoryWin32HandleInfoKHR {
|
||||||
|
VkStructureType sType;
|
||||||
|
const void* pNext;
|
||||||
|
const SECURITY_ATTRIBUTES* pAttributes;
|
||||||
|
DWORD dwAccess;
|
||||||
|
LPCWSTR name;
|
||||||
|
} VkExportMemoryWin32HandleInfoKHR;
|
||||||
|
|
||||||
|
typedef struct VkMemoryWin32HandlePropertiesKHR {
|
||||||
|
VkStructureType sType;
|
||||||
|
void* pNext;
|
||||||
|
uint32_t memoryTypeBits;
|
||||||
|
} VkMemoryWin32HandlePropertiesKHR;
|
||||||
|
|
||||||
|
typedef struct VkMemoryGetWin32HandleInfoKHR {
|
||||||
|
VkStructureType sType;
|
||||||
|
const void* pNext;
|
||||||
|
VkDeviceMemory memory;
|
||||||
|
VkExternalMemoryHandleTypeFlagBits handleType;
|
||||||
|
} VkMemoryGetWin32HandleInfoKHR;
|
||||||
|
|
||||||
|
typedef VkResult (VKAPI_PTR *PFN_vkGetMemoryWin32HandleKHR)(VkDevice device, const VkMemoryGetWin32HandleInfoKHR* pGetWin32HandleInfo, HANDLE* pHandle);
|
||||||
|
typedef VkResult (VKAPI_PTR *PFN_vkGetMemoryWin32HandlePropertiesKHR)(VkDevice device, VkExternalMemoryHandleTypeFlagBits handleType, HANDLE handle, VkMemoryWin32HandlePropertiesKHR* pMemoryWin32HandleProperties);
|
||||||
|
|
||||||
|
#ifndef VK_NO_PROTOTYPES
|
||||||
|
VKAPI_ATTR VkResult VKAPI_CALL vkGetMemoryWin32HandleKHR(
|
||||||
|
VkDevice device,
|
||||||
|
const VkMemoryGetWin32HandleInfoKHR* pGetWin32HandleInfo,
|
||||||
|
HANDLE* pHandle);
|
||||||
|
|
||||||
|
VKAPI_ATTR VkResult VKAPI_CALL vkGetMemoryWin32HandlePropertiesKHR(
|
||||||
|
VkDevice device,
|
||||||
|
VkExternalMemoryHandleTypeFlagBits handleType,
|
||||||
|
HANDLE handle,
|
||||||
|
VkMemoryWin32HandlePropertiesKHR* pMemoryWin32HandleProperties);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#define VK_KHR_win32_keyed_mutex 1
|
||||||
|
#define VK_KHR_WIN32_KEYED_MUTEX_SPEC_VERSION 1
|
||||||
|
#define VK_KHR_WIN32_KEYED_MUTEX_EXTENSION_NAME "VK_KHR_win32_keyed_mutex"
|
||||||
|
typedef struct VkWin32KeyedMutexAcquireReleaseInfoKHR {
|
||||||
|
VkStructureType sType;
|
||||||
|
const void* pNext;
|
||||||
|
uint32_t acquireCount;
|
||||||
|
const VkDeviceMemory* pAcquireSyncs;
|
||||||
|
const uint64_t* pAcquireKeys;
|
||||||
|
const uint32_t* pAcquireTimeouts;
|
||||||
|
uint32_t releaseCount;
|
||||||
|
const VkDeviceMemory* pReleaseSyncs;
|
||||||
|
const uint64_t* pReleaseKeys;
|
||||||
|
} VkWin32KeyedMutexAcquireReleaseInfoKHR;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#define VK_KHR_external_semaphore_win32 1
|
||||||
|
#define VK_KHR_EXTERNAL_SEMAPHORE_WIN32_SPEC_VERSION 1
|
||||||
|
#define VK_KHR_EXTERNAL_SEMAPHORE_WIN32_EXTENSION_NAME "VK_KHR_external_semaphore_win32"
|
||||||
|
typedef struct VkImportSemaphoreWin32HandleInfoKHR {
|
||||||
|
VkStructureType sType;
|
||||||
|
const void* pNext;
|
||||||
|
VkSemaphore semaphore;
|
||||||
|
VkSemaphoreImportFlags flags;
|
||||||
|
VkExternalSemaphoreHandleTypeFlagBits handleType;
|
||||||
|
HANDLE handle;
|
||||||
|
LPCWSTR name;
|
||||||
|
} VkImportSemaphoreWin32HandleInfoKHR;
|
||||||
|
|
||||||
|
typedef struct VkExportSemaphoreWin32HandleInfoKHR {
|
||||||
|
VkStructureType sType;
|
||||||
|
const void* pNext;
|
||||||
|
const SECURITY_ATTRIBUTES* pAttributes;
|
||||||
|
DWORD dwAccess;
|
||||||
|
LPCWSTR name;
|
||||||
|
} VkExportSemaphoreWin32HandleInfoKHR;
|
||||||
|
|
||||||
|
typedef struct VkD3D12FenceSubmitInfoKHR {
|
||||||
|
VkStructureType sType;
|
||||||
|
const void* pNext;
|
||||||
|
uint32_t waitSemaphoreValuesCount;
|
||||||
|
const uint64_t* pWaitSemaphoreValues;
|
||||||
|
uint32_t signalSemaphoreValuesCount;
|
||||||
|
const uint64_t* pSignalSemaphoreValues;
|
||||||
|
} VkD3D12FenceSubmitInfoKHR;
|
||||||
|
|
||||||
|
typedef struct VkSemaphoreGetWin32HandleInfoKHR {
|
||||||
|
VkStructureType sType;
|
||||||
|
const void* pNext;
|
||||||
|
VkSemaphore semaphore;
|
||||||
|
VkExternalSemaphoreHandleTypeFlagBits handleType;
|
||||||
|
} VkSemaphoreGetWin32HandleInfoKHR;
|
||||||
|
|
||||||
|
typedef VkResult (VKAPI_PTR *PFN_vkImportSemaphoreWin32HandleKHR)(VkDevice device, const VkImportSemaphoreWin32HandleInfoKHR* pImportSemaphoreWin32HandleInfo);
|
||||||
|
typedef VkResult (VKAPI_PTR *PFN_vkGetSemaphoreWin32HandleKHR)(VkDevice device, const VkSemaphoreGetWin32HandleInfoKHR* pGetWin32HandleInfo, HANDLE* pHandle);
|
||||||
|
|
||||||
|
#ifndef VK_NO_PROTOTYPES
|
||||||
|
VKAPI_ATTR VkResult VKAPI_CALL vkImportSemaphoreWin32HandleKHR(
|
||||||
|
VkDevice device,
|
||||||
|
const VkImportSemaphoreWin32HandleInfoKHR* pImportSemaphoreWin32HandleInfo);
|
||||||
|
|
||||||
|
VKAPI_ATTR VkResult VKAPI_CALL vkGetSemaphoreWin32HandleKHR(
|
||||||
|
VkDevice device,
|
||||||
|
const VkSemaphoreGetWin32HandleInfoKHR* pGetWin32HandleInfo,
|
||||||
|
HANDLE* pHandle);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#define VK_KHR_external_fence_win32 1
|
||||||
|
#define VK_KHR_EXTERNAL_FENCE_WIN32_SPEC_VERSION 1
|
||||||
|
#define VK_KHR_EXTERNAL_FENCE_WIN32_EXTENSION_NAME "VK_KHR_external_fence_win32"
|
||||||
|
typedef struct VkImportFenceWin32HandleInfoKHR {
|
||||||
|
VkStructureType sType;
|
||||||
|
const void* pNext;
|
||||||
|
VkFence fence;
|
||||||
|
VkFenceImportFlags flags;
|
||||||
|
VkExternalFenceHandleTypeFlagBits handleType;
|
||||||
|
HANDLE handle;
|
||||||
|
LPCWSTR name;
|
||||||
|
} VkImportFenceWin32HandleInfoKHR;
|
||||||
|
|
||||||
|
typedef struct VkExportFenceWin32HandleInfoKHR {
|
||||||
|
VkStructureType sType;
|
||||||
|
const void* pNext;
|
||||||
|
const SECURITY_ATTRIBUTES* pAttributes;
|
||||||
|
DWORD dwAccess;
|
||||||
|
LPCWSTR name;
|
||||||
|
} VkExportFenceWin32HandleInfoKHR;
|
||||||
|
|
||||||
|
typedef struct VkFenceGetWin32HandleInfoKHR {
|
||||||
|
VkStructureType sType;
|
||||||
|
const void* pNext;
|
||||||
|
VkFence fence;
|
||||||
|
VkExternalFenceHandleTypeFlagBits handleType;
|
||||||
|
} VkFenceGetWin32HandleInfoKHR;
|
||||||
|
|
||||||
|
typedef VkResult (VKAPI_PTR *PFN_vkImportFenceWin32HandleKHR)(VkDevice device, const VkImportFenceWin32HandleInfoKHR* pImportFenceWin32HandleInfo);
|
||||||
|
typedef VkResult (VKAPI_PTR *PFN_vkGetFenceWin32HandleKHR)(VkDevice device, const VkFenceGetWin32HandleInfoKHR* pGetWin32HandleInfo, HANDLE* pHandle);
|
||||||
|
|
||||||
|
#ifndef VK_NO_PROTOTYPES
|
||||||
|
VKAPI_ATTR VkResult VKAPI_CALL vkImportFenceWin32HandleKHR(
|
||||||
|
VkDevice device,
|
||||||
|
const VkImportFenceWin32HandleInfoKHR* pImportFenceWin32HandleInfo);
|
||||||
|
|
||||||
|
VKAPI_ATTR VkResult VKAPI_CALL vkGetFenceWin32HandleKHR(
|
||||||
|
VkDevice device,
|
||||||
|
const VkFenceGetWin32HandleInfoKHR* pGetWin32HandleInfo,
|
||||||
|
HANDLE* pHandle);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#define VK_NV_external_memory_win32 1
|
||||||
|
#define VK_NV_EXTERNAL_MEMORY_WIN32_SPEC_VERSION 1
|
||||||
|
#define VK_NV_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME "VK_NV_external_memory_win32"
|
||||||
|
typedef struct VkImportMemoryWin32HandleInfoNV {
|
||||||
|
VkStructureType sType;
|
||||||
|
const void* pNext;
|
||||||
|
VkExternalMemoryHandleTypeFlagsNV handleType;
|
||||||
|
HANDLE handle;
|
||||||
|
} VkImportMemoryWin32HandleInfoNV;
|
||||||
|
|
||||||
|
typedef struct VkExportMemoryWin32HandleInfoNV {
|
||||||
|
VkStructureType sType;
|
||||||
|
const void* pNext;
|
||||||
|
const SECURITY_ATTRIBUTES* pAttributes;
|
||||||
|
DWORD dwAccess;
|
||||||
|
} VkExportMemoryWin32HandleInfoNV;
|
||||||
|
|
||||||
|
typedef VkResult (VKAPI_PTR *PFN_vkGetMemoryWin32HandleNV)(VkDevice device, VkDeviceMemory memory, VkExternalMemoryHandleTypeFlagsNV handleType, HANDLE* pHandle);
|
||||||
|
|
||||||
|
#ifndef VK_NO_PROTOTYPES
|
||||||
|
VKAPI_ATTR VkResult VKAPI_CALL vkGetMemoryWin32HandleNV(
|
||||||
|
VkDevice device,
|
||||||
|
VkDeviceMemory memory,
|
||||||
|
VkExternalMemoryHandleTypeFlagsNV handleType,
|
||||||
|
HANDLE* pHandle);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#define VK_NV_win32_keyed_mutex 1
|
||||||
|
#define VK_NV_WIN32_KEYED_MUTEX_SPEC_VERSION 2
|
||||||
|
#define VK_NV_WIN32_KEYED_MUTEX_EXTENSION_NAME "VK_NV_win32_keyed_mutex"
|
||||||
|
typedef struct VkWin32KeyedMutexAcquireReleaseInfoNV {
|
||||||
|
VkStructureType sType;
|
||||||
|
const void* pNext;
|
||||||
|
uint32_t acquireCount;
|
||||||
|
const VkDeviceMemory* pAcquireSyncs;
|
||||||
|
const uint64_t* pAcquireKeys;
|
||||||
|
const uint32_t* pAcquireTimeoutMilliseconds;
|
||||||
|
uint32_t releaseCount;
|
||||||
|
const VkDeviceMemory* pReleaseSyncs;
|
||||||
|
const uint64_t* pReleaseKeys;
|
||||||
|
} VkWin32KeyedMutexAcquireReleaseInfoNV;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#define VK_EXT_full_screen_exclusive 1
|
||||||
|
#define VK_EXT_FULL_SCREEN_EXCLUSIVE_SPEC_VERSION 4
|
||||||
|
#define VK_EXT_FULL_SCREEN_EXCLUSIVE_EXTENSION_NAME "VK_EXT_full_screen_exclusive"
|
||||||
|
|
||||||
|
typedef enum VkFullScreenExclusiveEXT {
|
||||||
|
VK_FULL_SCREEN_EXCLUSIVE_DEFAULT_EXT = 0,
|
||||||
|
VK_FULL_SCREEN_EXCLUSIVE_ALLOWED_EXT = 1,
|
||||||
|
VK_FULL_SCREEN_EXCLUSIVE_DISALLOWED_EXT = 2,
|
||||||
|
VK_FULL_SCREEN_EXCLUSIVE_APPLICATION_CONTROLLED_EXT = 3,
|
||||||
|
VK_FULL_SCREEN_EXCLUSIVE_MAX_ENUM_EXT = 0x7FFFFFFF
|
||||||
|
} VkFullScreenExclusiveEXT;
|
||||||
|
typedef struct VkSurfaceFullScreenExclusiveInfoEXT {
|
||||||
|
VkStructureType sType;
|
||||||
|
void* pNext;
|
||||||
|
VkFullScreenExclusiveEXT fullScreenExclusive;
|
||||||
|
} VkSurfaceFullScreenExclusiveInfoEXT;
|
||||||
|
|
||||||
|
typedef struct VkSurfaceCapabilitiesFullScreenExclusiveEXT {
|
||||||
|
VkStructureType sType;
|
||||||
|
void* pNext;
|
||||||
|
VkBool32 fullScreenExclusiveSupported;
|
||||||
|
} VkSurfaceCapabilitiesFullScreenExclusiveEXT;
|
||||||
|
|
||||||
|
typedef struct VkSurfaceFullScreenExclusiveWin32InfoEXT {
|
||||||
|
VkStructureType sType;
|
||||||
|
const void* pNext;
|
||||||
|
HMONITOR hmonitor;
|
||||||
|
} VkSurfaceFullScreenExclusiveWin32InfoEXT;
|
||||||
|
|
||||||
|
typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSurfacePresentModes2EXT)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo, uint32_t* pPresentModeCount, VkPresentModeKHR* pPresentModes);
|
||||||
|
typedef VkResult (VKAPI_PTR *PFN_vkAcquireFullScreenExclusiveModeEXT)(VkDevice device, VkSwapchainKHR swapchain);
|
||||||
|
typedef VkResult (VKAPI_PTR *PFN_vkReleaseFullScreenExclusiveModeEXT)(VkDevice device, VkSwapchainKHR swapchain);
|
||||||
|
typedef VkResult (VKAPI_PTR *PFN_vkGetDeviceGroupSurfacePresentModes2EXT)(VkDevice device, const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo, VkDeviceGroupPresentModeFlagsKHR* pModes);
|
||||||
|
|
||||||
|
#ifndef VK_NO_PROTOTYPES
|
||||||
|
VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfacePresentModes2EXT(
|
||||||
|
VkPhysicalDevice physicalDevice,
|
||||||
|
const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo,
|
||||||
|
uint32_t* pPresentModeCount,
|
||||||
|
VkPresentModeKHR* pPresentModes);
|
||||||
|
|
||||||
|
VKAPI_ATTR VkResult VKAPI_CALL vkAcquireFullScreenExclusiveModeEXT(
|
||||||
|
VkDevice device,
|
||||||
|
VkSwapchainKHR swapchain);
|
||||||
|
|
||||||
|
VKAPI_ATTR VkResult VKAPI_CALL vkReleaseFullScreenExclusiveModeEXT(
|
||||||
|
VkDevice device,
|
||||||
|
VkSwapchainKHR swapchain);
|
||||||
|
|
||||||
|
VKAPI_ATTR VkResult VKAPI_CALL vkGetDeviceGroupSurfacePresentModes2EXT(
|
||||||
|
VkDevice device,
|
||||||
|
const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo,
|
||||||
|
VkDeviceGroupPresentModeFlagsKHR* pModes);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,55 @@
|
||||||
|
#ifndef VULKAN_XCB_H_
|
||||||
|
#define VULKAN_XCB_H_ 1
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Copyright (c) 2015-2020 The Khronos Group Inc.
|
||||||
|
**
|
||||||
|
** SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
** This header is generated from the Khronos Vulkan XML API Registry.
|
||||||
|
**
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#define VK_KHR_xcb_surface 1
|
||||||
|
#define VK_KHR_XCB_SURFACE_SPEC_VERSION 6
|
||||||
|
#define VK_KHR_XCB_SURFACE_EXTENSION_NAME "VK_KHR_xcb_surface"
|
||||||
|
typedef VkFlags VkXcbSurfaceCreateFlagsKHR;
|
||||||
|
typedef struct VkXcbSurfaceCreateInfoKHR {
|
||||||
|
VkStructureType sType;
|
||||||
|
const void* pNext;
|
||||||
|
VkXcbSurfaceCreateFlagsKHR flags;
|
||||||
|
xcb_connection_t* connection;
|
||||||
|
xcb_window_t window;
|
||||||
|
} VkXcbSurfaceCreateInfoKHR;
|
||||||
|
|
||||||
|
typedef VkResult (VKAPI_PTR *PFN_vkCreateXcbSurfaceKHR)(VkInstance instance, const VkXcbSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface);
|
||||||
|
typedef VkBool32 (VKAPI_PTR *PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, xcb_connection_t* connection, xcb_visualid_t visual_id);
|
||||||
|
|
||||||
|
#ifndef VK_NO_PROTOTYPES
|
||||||
|
VKAPI_ATTR VkResult VKAPI_CALL vkCreateXcbSurfaceKHR(
|
||||||
|
VkInstance instance,
|
||||||
|
const VkXcbSurfaceCreateInfoKHR* pCreateInfo,
|
||||||
|
const VkAllocationCallbacks* pAllocator,
|
||||||
|
VkSurfaceKHR* pSurface);
|
||||||
|
|
||||||
|
VKAPI_ATTR VkBool32 VKAPI_CALL vkGetPhysicalDeviceXcbPresentationSupportKHR(
|
||||||
|
VkPhysicalDevice physicalDevice,
|
||||||
|
uint32_t queueFamilyIndex,
|
||||||
|
xcb_connection_t* connection,
|
||||||
|
xcb_visualid_t visual_id);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,55 @@
|
||||||
|
#ifndef VULKAN_XLIB_H_
|
||||||
|
#define VULKAN_XLIB_H_ 1
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Copyright (c) 2015-2020 The Khronos Group Inc.
|
||||||
|
**
|
||||||
|
** SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
** This header is generated from the Khronos Vulkan XML API Registry.
|
||||||
|
**
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#define VK_KHR_xlib_surface 1
|
||||||
|
#define VK_KHR_XLIB_SURFACE_SPEC_VERSION 6
|
||||||
|
#define VK_KHR_XLIB_SURFACE_EXTENSION_NAME "VK_KHR_xlib_surface"
|
||||||
|
typedef VkFlags VkXlibSurfaceCreateFlagsKHR;
|
||||||
|
typedef struct VkXlibSurfaceCreateInfoKHR {
|
||||||
|
VkStructureType sType;
|
||||||
|
const void* pNext;
|
||||||
|
VkXlibSurfaceCreateFlagsKHR flags;
|
||||||
|
Display* dpy;
|
||||||
|
Window window;
|
||||||
|
} VkXlibSurfaceCreateInfoKHR;
|
||||||
|
|
||||||
|
typedef VkResult (VKAPI_PTR *PFN_vkCreateXlibSurfaceKHR)(VkInstance instance, const VkXlibSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface);
|
||||||
|
typedef VkBool32 (VKAPI_PTR *PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, Display* dpy, VisualID visualID);
|
||||||
|
|
||||||
|
#ifndef VK_NO_PROTOTYPES
|
||||||
|
VKAPI_ATTR VkResult VKAPI_CALL vkCreateXlibSurfaceKHR(
|
||||||
|
VkInstance instance,
|
||||||
|
const VkXlibSurfaceCreateInfoKHR* pCreateInfo,
|
||||||
|
const VkAllocationCallbacks* pAllocator,
|
||||||
|
VkSurfaceKHR* pSurface);
|
||||||
|
|
||||||
|
VKAPI_ATTR VkBool32 VKAPI_CALL vkGetPhysicalDeviceXlibPresentationSupportKHR(
|
||||||
|
VkPhysicalDevice physicalDevice,
|
||||||
|
uint32_t queueFamilyIndex,
|
||||||
|
Display* dpy,
|
||||||
|
VisualID visualID);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,45 @@
|
||||||
|
#ifndef VULKAN_XLIB_XRANDR_H_
|
||||||
|
#define VULKAN_XLIB_XRANDR_H_ 1
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Copyright (c) 2015-2020 The Khronos Group Inc.
|
||||||
|
**
|
||||||
|
** SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
** This header is generated from the Khronos Vulkan XML API Registry.
|
||||||
|
**
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#define VK_EXT_acquire_xlib_display 1
|
||||||
|
#define VK_EXT_ACQUIRE_XLIB_DISPLAY_SPEC_VERSION 1
|
||||||
|
#define VK_EXT_ACQUIRE_XLIB_DISPLAY_EXTENSION_NAME "VK_EXT_acquire_xlib_display"
|
||||||
|
typedef VkResult (VKAPI_PTR *PFN_vkAcquireXlibDisplayEXT)(VkPhysicalDevice physicalDevice, Display* dpy, VkDisplayKHR display);
|
||||||
|
typedef VkResult (VKAPI_PTR *PFN_vkGetRandROutputDisplayEXT)(VkPhysicalDevice physicalDevice, Display* dpy, RROutput rrOutput, VkDisplayKHR* pDisplay);
|
||||||
|
|
||||||
|
#ifndef VK_NO_PROTOTYPES
|
||||||
|
VKAPI_ATTR VkResult VKAPI_CALL vkAcquireXlibDisplayEXT(
|
||||||
|
VkPhysicalDevice physicalDevice,
|
||||||
|
Display* dpy,
|
||||||
|
VkDisplayKHR display);
|
||||||
|
|
||||||
|
VKAPI_ATTR VkResult VKAPI_CALL vkGetRandROutputDisplayEXT(
|
||||||
|
VkPhysicalDevice physicalDevice,
|
||||||
|
Display* dpy,
|
||||||
|
RROutput rrOutput,
|
||||||
|
VkDisplayKHR* pDisplay);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
|
@ -1,146 +1,198 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) Nemirtingas
|
||||||
|
* This file is part of the ingame overlay project
|
||||||
|
*
|
||||||
|
* The ingame overlay project is free software; you can redistribute it
|
||||||
|
* and/or modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* The ingame overlay project 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
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with the ingame overlay project; if not, see
|
||||||
|
* <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
#include "DX10_Hook.h"
|
#include "DX10_Hook.h"
|
||||||
#include "Windows_Hook.h"
|
#include "Windows_Hook.h"
|
||||||
#include "../Renderer_Detector.h"
|
|
||||||
#include "../../dll/dll.h"
|
|
||||||
|
|
||||||
#ifdef EMU_OVERLAY
|
|
||||||
|
|
||||||
#include <imgui.h>
|
#include <imgui.h>
|
||||||
#include <impls/windows/imgui_impl_dx10.h>
|
#include <backends/imgui_impl_dx10.h>
|
||||||
|
|
||||||
DX10_Hook* DX10_Hook::_inst = nullptr;
|
DX10_Hook* DX10_Hook::_inst = nullptr;
|
||||||
|
|
||||||
bool DX10_Hook::start_hook()
|
template<typename T>
|
||||||
|
inline void SafeRelease(T*& pUnk)
|
||||||
{
|
{
|
||||||
bool res = true;
|
if (pUnk != nullptr)
|
||||||
if (!hooked)
|
|
||||||
{
|
{
|
||||||
if (!Windows_Hook::Inst()->start_hook())
|
pUnk->Release();
|
||||||
|
pUnk = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DX10_Hook::StartHook(std::function<bool(bool)> key_combination_callback)
|
||||||
|
{
|
||||||
|
if (!_Hooked)
|
||||||
|
{
|
||||||
|
if (Present == nullptr || ResizeTarget == nullptr || ResizeBuffers == nullptr)
|
||||||
|
{
|
||||||
|
SPDLOG_WARN("Failed to hook DirectX 11: Rendering functions missing.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Windows_Hook::Inst()->StartHook(key_combination_callback))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
PRINT_DEBUG("Hooked DirectX 10\n");
|
_WindowsHooked = true;
|
||||||
hooked = true;
|
|
||||||
|
|
||||||
Renderer_Detector::Inst().renderer_found(this);
|
SPDLOG_INFO("Hooked DirectX 10");
|
||||||
|
_Hooked = true;
|
||||||
|
|
||||||
BeginHook();
|
BeginHook();
|
||||||
HookFuncs(
|
HookFuncs(
|
||||||
std::make_pair<void**, void*>(&(PVOID&)DX10_Hook::Present, &DX10_Hook::MyPresent),
|
std::make_pair<void**, void*>(&(PVOID&)Present , &DX10_Hook::MyPresent),
|
||||||
std::make_pair<void**, void*>(&(PVOID&)DX10_Hook::ResizeTarget, &DX10_Hook::MyResizeTarget),
|
std::make_pair<void**, void*>(&(PVOID&)ResizeTarget , &DX10_Hook::MyResizeTarget),
|
||||||
std::make_pair<void**, void*>(&(PVOID&)DX10_Hook::ResizeBuffers, &DX10_Hook::MyResizeBuffers)
|
std::make_pair<void**, void*>(&(PVOID&)ResizeBuffers, &DX10_Hook::MyResizeBuffers)
|
||||||
);
|
);
|
||||||
|
if (Present1 != nullptr)
|
||||||
|
{
|
||||||
|
HookFuncs(
|
||||||
|
std::make_pair<void**, void*>(&(PVOID&)Present1, &DX10_Hook::MyPresent1)
|
||||||
|
);
|
||||||
|
}
|
||||||
EndHook();
|
EndHook();
|
||||||
|
|
||||||
get_steam_client()->steam_overlay->HookReady();
|
|
||||||
}
|
}
|
||||||
return res;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DX10_Hook::resetRenderState()
|
bool DX10_Hook::IsStarted()
|
||||||
{
|
{
|
||||||
if (initialized)
|
return _Hooked;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DX10_Hook::_ResetRenderState()
|
||||||
{
|
{
|
||||||
mainRenderTargetView->Release();
|
if (_Initialized)
|
||||||
|
{
|
||||||
|
OverlayHookReady(false);
|
||||||
|
|
||||||
ImGui_ImplDX10_Shutdown();
|
ImGui_ImplDX10_Shutdown();
|
||||||
Windows_Hook::Inst()->resetRenderState();
|
Windows_Hook::Inst()->_ResetRenderState();
|
||||||
ImGui::DestroyContext();
|
ImGui::DestroyContext();
|
||||||
|
|
||||||
initialized = false;
|
SafeRelease(mainRenderTargetView);
|
||||||
|
SafeRelease(pDevice);
|
||||||
|
|
||||||
|
_Initialized = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to make this function and overlay's proc as short as possible or it might affect game's fps.
|
// Try to make this function and overlay's proc as short as possible or it might affect game's fps.
|
||||||
void DX10_Hook::prepareForOverlay(IDXGISwapChain* pSwapChain)
|
void DX10_Hook::_PrepareForOverlay(IDXGISwapChain* pSwapChain)
|
||||||
{
|
{
|
||||||
DXGI_SWAP_CHAIN_DESC desc;
|
DXGI_SWAP_CHAIN_DESC desc;
|
||||||
pSwapChain->GetDesc(&desc);
|
pSwapChain->GetDesc(&desc);
|
||||||
|
|
||||||
if (!initialized)
|
if (!_Initialized)
|
||||||
{
|
{
|
||||||
if (FAILED(pSwapChain->GetDevice(IID_PPV_ARGS(&pDevice))))
|
if (FAILED(pSwapChain->GetDevice(IID_PPV_ARGS(&pDevice))))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ImGui::CreateContext();
|
ID3D10Texture2D* pBackBuffer = nullptr;
|
||||||
ImGuiIO& io = ImGui::GetIO();
|
|
||||||
io.IniFilename = NULL;
|
|
||||||
|
|
||||||
ID3D10Texture2D* pBackBuffer;
|
|
||||||
|
|
||||||
pSwapChain->GetBuffer(0, IID_PPV_ARGS(&pBackBuffer));
|
pSwapChain->GetBuffer(0, IID_PPV_ARGS(&pBackBuffer));
|
||||||
pDevice->CreateRenderTargetView(pBackBuffer, NULL, &mainRenderTargetView);
|
if (pBackBuffer == nullptr)
|
||||||
pBackBuffer->Release();
|
{
|
||||||
|
|
||||||
ImGui_ImplDX10_Init(pDevice);
|
|
||||||
|
|
||||||
pDevice->Release();
|
pDevice->Release();
|
||||||
|
return;
|
||||||
get_steam_client()->steam_overlay->CreateFonts();
|
|
||||||
|
|
||||||
initialized = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ImGui_ImplDX10_NewFrame())
|
pDevice->CreateRenderTargetView(pBackBuffer, nullptr, &mainRenderTargetView);
|
||||||
{
|
pBackBuffer->Release();
|
||||||
Windows_Hook::Inst()->prepareForOverlay(desc.OutputWindow);
|
|
||||||
|
|
||||||
|
ImGui::CreateContext();
|
||||||
|
ImGui_ImplDX10_Init(pDevice);
|
||||||
|
|
||||||
|
_Initialized = true;
|
||||||
|
OverlayHookReady(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui_ImplDX10_NewFrame() && Windows_Hook::Inst()->_PrepareForOverlay(desc.OutputWindow))
|
||||||
|
{
|
||||||
ImGui::NewFrame();
|
ImGui::NewFrame();
|
||||||
|
|
||||||
get_steam_client()->steam_overlay->OverlayProc();
|
OverlayProc();
|
||||||
|
|
||||||
ImGui::Render();
|
ImGui::Render();
|
||||||
|
|
||||||
pDevice->OMSetRenderTargets(1, &mainRenderTargetView, NULL);
|
pDevice->OMSetRenderTargets(1, &mainRenderTargetView, nullptr);
|
||||||
ImGui_ImplDX10_RenderDrawData(ImGui::GetDrawData());
|
ImGui_ImplDX10_RenderDrawData(ImGui::GetDrawData());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
HRESULT STDMETHODCALLTYPE DX10_Hook::MyPresent(IDXGISwapChain *_this, UINT SyncInterval, UINT Flags)
|
HRESULT STDMETHODCALLTYPE DX10_Hook::MyPresent(IDXGISwapChain *_this, UINT SyncInterval, UINT Flags)
|
||||||
{
|
{
|
||||||
DX10_Hook::Inst()->prepareForOverlay(_this);
|
auto inst= DX10_Hook::Inst();
|
||||||
return (_this->*DX10_Hook::Inst()->Present)(SyncInterval, Flags);
|
inst->_PrepareForOverlay(_this);
|
||||||
|
return (_this->*inst->Present)(SyncInterval, Flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
HRESULT STDMETHODCALLTYPE DX10_Hook::MyResizeTarget(IDXGISwapChain* _this, const DXGI_MODE_DESC* pNewTargetParameters)
|
HRESULT STDMETHODCALLTYPE DX10_Hook::MyResizeTarget(IDXGISwapChain* _this, const DXGI_MODE_DESC* pNewTargetParameters)
|
||||||
{
|
{
|
||||||
DX10_Hook::Inst()->resetRenderState();
|
auto inst= DX10_Hook::Inst();
|
||||||
return (_this->*DX10_Hook::Inst()->ResizeTarget)(pNewTargetParameters);
|
inst->_ResetRenderState();
|
||||||
|
return (_this->*inst->ResizeTarget)(pNewTargetParameters);
|
||||||
}
|
}
|
||||||
|
|
||||||
HRESULT STDMETHODCALLTYPE DX10_Hook::MyResizeBuffers(IDXGISwapChain* _this, UINT BufferCount, UINT Width, UINT Height, DXGI_FORMAT NewFormat, UINT SwapChainFlags)
|
HRESULT STDMETHODCALLTYPE DX10_Hook::MyResizeBuffers(IDXGISwapChain* _this, UINT BufferCount, UINT Width, UINT Height, DXGI_FORMAT NewFormat, UINT SwapChainFlags)
|
||||||
{
|
{
|
||||||
DX10_Hook::Inst()->resetRenderState();
|
auto inst= DX10_Hook::Inst();
|
||||||
return (_this->*DX10_Hook::Inst()->ResizeBuffers)(BufferCount, Width, Height, NewFormat, SwapChainFlags);
|
inst->_ResetRenderState();
|
||||||
|
return (_this->*inst->ResizeBuffers)(BufferCount, Width, Height, NewFormat, SwapChainFlags);
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT STDMETHODCALLTYPE DX10_Hook::MyPresent1(IDXGISwapChain1* _this, UINT SyncInterval, UINT Flags, const DXGI_PRESENT_PARAMETERS* pPresentParameters)
|
||||||
|
{
|
||||||
|
auto inst = DX10_Hook::Inst();
|
||||||
|
inst->_PrepareForOverlay(_this);
|
||||||
|
return (_this->*inst->Present1)(SyncInterval, Flags, pPresentParameters);
|
||||||
}
|
}
|
||||||
|
|
||||||
DX10_Hook::DX10_Hook():
|
DX10_Hook::DX10_Hook():
|
||||||
initialized(false),
|
_Initialized(false),
|
||||||
hooked(false),
|
_Hooked(false),
|
||||||
|
_WindowsHooked(false),
|
||||||
pDevice(nullptr),
|
pDevice(nullptr),
|
||||||
mainRenderTargetView(nullptr),
|
mainRenderTargetView(nullptr),
|
||||||
Present(nullptr),
|
Present(nullptr),
|
||||||
ResizeBuffers(nullptr),
|
ResizeBuffers(nullptr),
|
||||||
ResizeTarget(nullptr)
|
ResizeTarget(nullptr),
|
||||||
|
Present1(nullptr)
|
||||||
{
|
{
|
||||||
_library = LoadLibrary(DX10_DLL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DX10_Hook::~DX10_Hook()
|
DX10_Hook::~DX10_Hook()
|
||||||
{
|
{
|
||||||
PRINT_DEBUG("DX10 Hook removed\n");
|
//SPDLOG_INFO("DX10 Hook removed");
|
||||||
|
|
||||||
if (initialized)
|
if (_WindowsHooked)
|
||||||
|
delete Windows_Hook::Inst();
|
||||||
|
|
||||||
|
if (_Initialized)
|
||||||
{
|
{
|
||||||
mainRenderTargetView->Release();
|
mainRenderTargetView->Release();
|
||||||
|
|
||||||
ImGui_ImplDX10_InvalidateDeviceObjects();
|
ImGui_ImplDX10_InvalidateDeviceObjects();
|
||||||
ImGui::DestroyContext();
|
ImGui::DestroyContext();
|
||||||
|
|
||||||
initialized = false;
|
_Initialized = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
FreeLibrary(reinterpret_cast<HMODULE>(_library));
|
|
||||||
|
|
||||||
_inst = nullptr;
|
_inst = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -152,21 +204,85 @@ DX10_Hook* DX10_Hook::Inst()
|
||||||
return _inst;
|
return _inst;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* DX10_Hook::get_lib_name() const
|
std::string DX10_Hook::GetLibraryName() const
|
||||||
{
|
{
|
||||||
return DX10_DLL;
|
return LibraryName;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DX10_Hook::loadFunctions(IDXGISwapChain *pSwapChain)
|
void DX10_Hook::LoadFunctions(
|
||||||
|
decltype(Present) PresentFcn,
|
||||||
|
decltype(ResizeBuffers) ResizeBuffersFcn,
|
||||||
|
decltype(ResizeTarget) ResizeTargetFcn,
|
||||||
|
decltype(Present1) Present1Fcn)
|
||||||
{
|
{
|
||||||
void** vTable;
|
Present = PresentFcn;
|
||||||
|
ResizeBuffers = ResizeBuffersFcn;
|
||||||
vTable = *reinterpret_cast<void***>(pSwapChain);
|
ResizeTarget = ResizeTargetFcn;
|
||||||
#define LOAD_FUNC(X) (void*&)X = vTable[(int)IDXGISwapChainVTable::X]
|
Present1 = Present1Fcn;
|
||||||
LOAD_FUNC(Present);
|
|
||||||
LOAD_FUNC(ResizeBuffers);
|
|
||||||
LOAD_FUNC(ResizeTarget);
|
|
||||||
#undef LOAD_FUNC
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif//EMU_OVERLAY
|
std::weak_ptr<uint64_t> DX10_Hook::CreateImageResource(const void* image_data, uint32_t width, uint32_t height)
|
||||||
|
{
|
||||||
|
ID3D10ShaderResourceView** resource = new ID3D10ShaderResourceView*(nullptr);
|
||||||
|
|
||||||
|
// Create texture
|
||||||
|
D3D10_TEXTURE2D_DESC desc = {};
|
||||||
|
desc.Width = static_cast<UINT>(width);
|
||||||
|
desc.Height = static_cast<UINT>(height);
|
||||||
|
desc.MipLevels = 1;
|
||||||
|
desc.ArraySize = 1;
|
||||||
|
desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||||
|
desc.SampleDesc.Count = 1;
|
||||||
|
desc.Usage = D3D10_USAGE_DEFAULT;
|
||||||
|
desc.BindFlags = D3D10_BIND_SHADER_RESOURCE;
|
||||||
|
desc.CPUAccessFlags = 0;
|
||||||
|
|
||||||
|
ID3D10Texture2D* pTexture = nullptr;
|
||||||
|
D3D10_SUBRESOURCE_DATA subResource;
|
||||||
|
subResource.pSysMem = image_data;
|
||||||
|
subResource.SysMemPitch = desc.Width * 4;
|
||||||
|
subResource.SysMemSlicePitch = 0;
|
||||||
|
pDevice->CreateTexture2D(&desc, &subResource, &pTexture);
|
||||||
|
|
||||||
|
if (pTexture != nullptr)
|
||||||
|
{
|
||||||
|
// Create texture view
|
||||||
|
D3D10_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
|
||||||
|
srvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||||
|
srvDesc.ViewDimension = D3D10_SRV_DIMENSION_TEXTURE2D;
|
||||||
|
srvDesc.Texture2D.MipLevels = desc.MipLevels;
|
||||||
|
srvDesc.Texture2D.MostDetailedMip = 0;
|
||||||
|
|
||||||
|
pDevice->CreateShaderResourceView(pTexture, &srvDesc, resource);
|
||||||
|
// Release Texure, the shader resource increases the reference count.
|
||||||
|
pTexture->Release();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*resource == nullptr)
|
||||||
|
return std::shared_ptr<uint64_t>();
|
||||||
|
|
||||||
|
auto ptr = std::shared_ptr<uint64_t>((uint64_t*)resource, [](uint64_t* handle)
|
||||||
|
{
|
||||||
|
if (handle != nullptr)
|
||||||
|
{
|
||||||
|
ID3D10ShaderResourceView** resource = reinterpret_cast<ID3D10ShaderResourceView**>(handle);
|
||||||
|
(*resource)->Release();
|
||||||
|
delete resource;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
_ImageResources.emplace(ptr);
|
||||||
|
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DX10_Hook::ReleaseImageResource(std::weak_ptr<uint64_t> resource)
|
||||||
|
{
|
||||||
|
auto ptr = resource.lock();
|
||||||
|
if (ptr)
|
||||||
|
{
|
||||||
|
auto it = _ImageResources.find(ptr);
|
||||||
|
if (it != _ImageResources.end())
|
||||||
|
_ImageResources.erase(it);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,51 +1,80 @@
|
||||||
#ifndef __INCLUDED_DX10_HOOK_H__
|
/*
|
||||||
#define __INCLUDED_DX10_HOOK_H__
|
* Copyright (C) Nemirtingas
|
||||||
|
* This file is part of the ingame overlay project
|
||||||
|
*
|
||||||
|
* The ingame overlay project is free software; you can redistribute it
|
||||||
|
* and/or modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* The ingame overlay project 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
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with the ingame overlay project; if not, see
|
||||||
|
* <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
#include "../Base_Hook.h"
|
#pragma once
|
||||||
#ifdef EMU_OVERLAY
|
|
||||||
|
#include "../internal_includes.h"
|
||||||
|
|
||||||
#include <d3d10.h>
|
#include <d3d10.h>
|
||||||
#include "DirectX_VTables.h"
|
#include <dxgi1_2.h>
|
||||||
|
|
||||||
class DX10_Hook : public Base_Hook
|
class DX10_Hook :
|
||||||
|
public Renderer_Hook,
|
||||||
|
public Base_Hook
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
#define DX10_DLL "d3d10.dll"
|
static constexpr const char *DLL_NAME = "d3d10.dll";
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static DX10_Hook* _inst;
|
static DX10_Hook* _inst;
|
||||||
|
|
||||||
// Variables
|
// Variables
|
||||||
bool hooked;
|
bool _Hooked;
|
||||||
bool initialized;
|
bool _WindowsHooked;
|
||||||
|
bool _Initialized;
|
||||||
ID3D10Device* pDevice;
|
ID3D10Device* pDevice;
|
||||||
ID3D10RenderTargetView* mainRenderTargetView;
|
ID3D10RenderTargetView* mainRenderTargetView;
|
||||||
|
std::set<std::shared_ptr<uint64_t>> _ImageResources;
|
||||||
|
|
||||||
// Functions
|
// Functions
|
||||||
DX10_Hook();
|
DX10_Hook();
|
||||||
|
|
||||||
void resetRenderState();
|
void _ResetRenderState();
|
||||||
void prepareForOverlay(IDXGISwapChain *pSwapChain);
|
void _PrepareForOverlay(IDXGISwapChain *pSwapChain);
|
||||||
|
|
||||||
// Hook to render functions
|
// Hook to render functions
|
||||||
static HRESULT STDMETHODCALLTYPE MyPresent(IDXGISwapChain* _this, UINT SyncInterval, UINT Flags);
|
static HRESULT STDMETHODCALLTYPE MyPresent(IDXGISwapChain* _this, UINT SyncInterval, UINT Flags);
|
||||||
static HRESULT STDMETHODCALLTYPE MyResizeTarget(IDXGISwapChain* _this, const DXGI_MODE_DESC* pNewTargetParameters);
|
static HRESULT STDMETHODCALLTYPE MyResizeTarget(IDXGISwapChain* _this, const DXGI_MODE_DESC* pNewTargetParameters);
|
||||||
static HRESULT STDMETHODCALLTYPE MyResizeBuffers(IDXGISwapChain* _this, UINT BufferCount, UINT Width, UINT Height, DXGI_FORMAT NewFormat, UINT SwapChainFlags);
|
static HRESULT STDMETHODCALLTYPE MyResizeBuffers(IDXGISwapChain* _this, UINT BufferCount, UINT Width, UINT Height, DXGI_FORMAT NewFormat, UINT SwapChainFlags);
|
||||||
|
static HRESULT STDMETHODCALLTYPE MyPresent1(IDXGISwapChain1* _this, UINT SyncInterval, UINT Flags, const DXGI_PRESENT_PARAMETERS* pPresentParameters);
|
||||||
|
|
||||||
decltype(&IDXGISwapChain::Present) Present;
|
decltype(&IDXGISwapChain::Present) Present;
|
||||||
decltype(&IDXGISwapChain::ResizeBuffers) ResizeBuffers;
|
decltype(&IDXGISwapChain::ResizeBuffers) ResizeBuffers;
|
||||||
decltype(&IDXGISwapChain::ResizeTarget) ResizeTarget;
|
decltype(&IDXGISwapChain::ResizeTarget) ResizeTarget;
|
||||||
|
decltype(&IDXGISwapChain1::Present1) Present1;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
std::string LibraryName;
|
||||||
|
|
||||||
virtual ~DX10_Hook();
|
virtual ~DX10_Hook();
|
||||||
|
|
||||||
bool start_hook();
|
virtual bool StartHook(std::function<bool(bool)> key_combination_callback);
|
||||||
|
virtual bool IsStarted();
|
||||||
static DX10_Hook* Inst();
|
static DX10_Hook* Inst();
|
||||||
virtual const char* get_lib_name() const;
|
virtual std::string GetLibraryName() const;
|
||||||
|
|
||||||
void loadFunctions(IDXGISwapChain *pSwapChain);
|
void LoadFunctions(
|
||||||
|
decltype(Present) PresentFcn,
|
||||||
|
decltype(ResizeBuffers) ResizeBuffersFcn,
|
||||||
|
decltype(ResizeTarget) ResizeTargetFcn,
|
||||||
|
decltype(Present1) Present1Fcn);
|
||||||
|
|
||||||
|
virtual std::weak_ptr<uint64_t> CreateImageResource(const void* image_data, uint32_t width, uint32_t height);
|
||||||
|
virtual void ReleaseImageResource(std::weak_ptr<uint64_t> resource);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif//EMU_OVERLAY
|
|
||||||
|
|
||||||
#endif//__INCLUDED_DX10_HOOK_H__
|
|
||||||
|
|
|
@ -1,16 +1,41 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) Nemirtingas
|
||||||
|
* This file is part of the ingame overlay project
|
||||||
|
*
|
||||||
|
* The ingame overlay project is free software; you can redistribute it
|
||||||
|
* and/or modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* The ingame overlay project 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
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with the ingame overlay project; if not, see
|
||||||
|
* <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
#include "DX11_Hook.h"
|
#include "DX11_Hook.h"
|
||||||
#include "Windows_Hook.h"
|
#include "Windows_Hook.h"
|
||||||
#include "../Renderer_Detector.h"
|
|
||||||
#include "../../dll/dll.h"
|
|
||||||
|
|
||||||
#ifdef EMU_OVERLAY
|
|
||||||
|
|
||||||
#include <imgui.h>
|
#include <imgui.h>
|
||||||
#include <impls/windows/imgui_impl_dx11.h>
|
#include <backends/imgui_impl_dx11.h>
|
||||||
|
|
||||||
DX11_Hook* DX11_Hook::_inst = nullptr;
|
DX11_Hook* DX11_Hook::_inst = nullptr;
|
||||||
|
|
||||||
HRESULT GetDeviceAndCtxFromSwapchain(IDXGISwapChain* pSwapChain, ID3D11Device** ppDevice, ID3D11DeviceContext** ppContext)
|
template<typename T>
|
||||||
|
inline void SafeRelease(T*& pUnk)
|
||||||
|
{
|
||||||
|
if (pUnk != nullptr)
|
||||||
|
{
|
||||||
|
pUnk->Release();
|
||||||
|
pUnk = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static HRESULT GetDeviceAndCtxFromSwapchain(IDXGISwapChain* pSwapChain, ID3D11Device** ppDevice, ID3D11DeviceContext** ppContext)
|
||||||
{
|
{
|
||||||
HRESULT ret = pSwapChain->GetDevice(IID_PPV_ARGS(ppDevice));
|
HRESULT ret = pSwapChain->GetDevice(IID_PPV_ARGS(ppDevice));
|
||||||
|
|
||||||
|
@ -20,118 +45,126 @@ HRESULT GetDeviceAndCtxFromSwapchain(IDXGISwapChain* pSwapChain, ID3D11Device**
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DX11_Hook::start_hook()
|
bool DX11_Hook::StartHook(std::function<bool(bool)> key_combination_callback)
|
||||||
{
|
{
|
||||||
bool res = true;
|
if (!_Hooked)
|
||||||
if (!hooked)
|
|
||||||
{
|
{
|
||||||
if (!Windows_Hook::Inst()->start_hook())
|
if (Present == nullptr || ResizeTarget == nullptr || ResizeBuffers == nullptr)
|
||||||
|
{
|
||||||
|
SPDLOG_WARN("Failed to hook DirectX 11: Rendering functions missing.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Windows_Hook::Inst()->StartHook(key_combination_callback))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
PRINT_DEBUG("Hooked DirectX 11\n");
|
_WindowsHooked = true;
|
||||||
hooked = true;
|
|
||||||
|
|
||||||
Renderer_Detector::Inst().renderer_found(this);
|
SPDLOG_INFO("Hooked DirectX 11");
|
||||||
|
_Hooked = true;
|
||||||
|
|
||||||
BeginHook();
|
BeginHook();
|
||||||
HookFuncs(
|
HookFuncs(
|
||||||
std::make_pair<void**, void*>(&(PVOID&)DX11_Hook::Present, &DX11_Hook::MyPresent),
|
std::make_pair<void**, void*>(&(PVOID&)Present , &DX11_Hook::MyPresent),
|
||||||
std::make_pair<void**, void*>(&(PVOID&)DX11_Hook::ResizeTarget, &DX11_Hook::MyResizeTarget),
|
std::make_pair<void**, void*>(&(PVOID&)ResizeTarget , &DX11_Hook::MyResizeTarget),
|
||||||
std::make_pair<void**, void*>(&(PVOID&)DX11_Hook::ResizeBuffers, &DX11_Hook::MyResizeBuffers)
|
std::make_pair<void**, void*>(&(PVOID&)ResizeBuffers, &DX11_Hook::MyResizeBuffers)
|
||||||
);
|
);
|
||||||
|
if (Present1 != nullptr)
|
||||||
|
{
|
||||||
|
HookFuncs(
|
||||||
|
std::make_pair<void**, void*>(&(PVOID&)Present1, &DX11_Hook::MyPresent1)
|
||||||
|
);
|
||||||
|
}
|
||||||
EndHook();
|
EndHook();
|
||||||
|
|
||||||
get_steam_client()->steam_overlay->HookReady();
|
|
||||||
}
|
}
|
||||||
return res;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DX11_Hook::resetRenderState()
|
bool DX11_Hook::IsStarted()
|
||||||
{
|
{
|
||||||
if (initialized)
|
return _Hooked;
|
||||||
{
|
|
||||||
if (mainRenderTargetView) {
|
|
||||||
mainRenderTargetView->Release();
|
|
||||||
mainRenderTargetView = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pContext->Release();
|
void DX11_Hook::_ResetRenderState()
|
||||||
|
{
|
||||||
|
if (_Initialized)
|
||||||
|
{
|
||||||
|
OverlayHookReady(false);
|
||||||
|
|
||||||
ImGui_ImplDX11_Shutdown();
|
ImGui_ImplDX11_Shutdown();
|
||||||
Windows_Hook::Inst()->resetRenderState();
|
Windows_Hook::Inst()->_ResetRenderState();
|
||||||
ImGui::DestroyContext();
|
//ImGui::DestroyContext();
|
||||||
|
|
||||||
initialized = false;
|
SafeRelease(mainRenderTargetView);
|
||||||
|
SafeRelease(pContext);
|
||||||
|
SafeRelease(pDevice);
|
||||||
|
|
||||||
|
_Initialized = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to make this function and overlay's proc as short as possible or it might affect game's fps.
|
// Try to make this function and overlay's proc as short as possible or it might affect game's fps.
|
||||||
void DX11_Hook::prepareForOverlay(IDXGISwapChain* pSwapChain)
|
void DX11_Hook::_PrepareForOverlay(IDXGISwapChain* pSwapChain)
|
||||||
{
|
{
|
||||||
DXGI_SWAP_CHAIN_DESC desc;
|
DXGI_SWAP_CHAIN_DESC desc;
|
||||||
pSwapChain->GetDesc(&desc);
|
pSwapChain->GetDesc(&desc);
|
||||||
|
|
||||||
if (!initialized)
|
if (!_Initialized)
|
||||||
{
|
{
|
||||||
ID3D11Device* pDevice = nullptr;
|
pDevice = nullptr;
|
||||||
if (FAILED(GetDeviceAndCtxFromSwapchain(pSwapChain, &pDevice, &pContext)))
|
if (FAILED(GetDeviceAndCtxFromSwapchain(pSwapChain, &pDevice, &pContext)))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ImGui::CreateContext();
|
|
||||||
ImGuiIO& io = ImGui::GetIO();
|
|
||||||
io.IniFilename = NULL;
|
|
||||||
|
|
||||||
ID3D11Texture2D* pBackBuffer;
|
ID3D11Texture2D* pBackBuffer;
|
||||||
pSwapChain->GetBuffer(0, IID_PPV_ARGS(&pBackBuffer));
|
pSwapChain->GetBuffer(0, IID_PPV_ARGS(&pBackBuffer));
|
||||||
|
|
||||||
ID3D11RenderTargetView *get_targets[D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT] = {};
|
|
||||||
pContext->OMGetRenderTargets(D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT, get_targets, NULL);
|
|
||||||
bool bind_target = true;
|
|
||||||
|
|
||||||
for (unsigned i = 0; i < D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT; ++i) {
|
|
||||||
if (get_targets[i]) {
|
|
||||||
ID3D11Resource *res = NULL;
|
|
||||||
get_targets[i]->GetResource(&res);
|
|
||||||
if (res) {
|
|
||||||
if (res == (ID3D11Resource*)pBackBuffer) {
|
|
||||||
bind_target = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
res->Release();
|
|
||||||
}
|
|
||||||
|
|
||||||
get_targets[i]->Release();
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bind_target) {
|
|
||||||
pDevice->CreateRenderTargetView(pBackBuffer, NULL, &mainRenderTargetView);
|
pDevice->CreateRenderTargetView(pBackBuffer, NULL, &mainRenderTargetView);
|
||||||
}
|
|
||||||
|
|
||||||
pBackBuffer->Release();
|
//ID3D11RenderTargetView* targets[D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT] = {};
|
||||||
|
//pContext->OMGetRenderTargets(D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT, targets, NULL);
|
||||||
|
//bool bind_target = true;
|
||||||
|
//
|
||||||
|
//for (unsigned i = 0; i < D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT && targets[i] != nullptr; ++i)
|
||||||
|
//{
|
||||||
|
// ID3D11Resource* res = NULL;
|
||||||
|
// targets[i]->GetResource(&res);
|
||||||
|
// if (res)
|
||||||
|
// {
|
||||||
|
// if (res == (ID3D11Resource*)pBackBuffer)
|
||||||
|
// {
|
||||||
|
// pDevice->CreateRenderTargetView(pBackBuffer, NULL, &mainRenderTargetView);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// res->Release();
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// targets[i]->Release();
|
||||||
|
//}
|
||||||
|
|
||||||
|
SafeRelease(pBackBuffer);
|
||||||
|
|
||||||
|
if (mainRenderTargetView == nullptr)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if(ImGui::GetCurrentContext() == nullptr)
|
||||||
|
ImGui::CreateContext();
|
||||||
|
|
||||||
ImGui_ImplDX11_Init(pDevice, pContext);
|
ImGui_ImplDX11_Init(pDevice, pContext);
|
||||||
|
|
||||||
pDevice->Release();
|
_Initialized = true;
|
||||||
|
OverlayHookReady(true);
|
||||||
get_steam_client()->steam_overlay->CreateFonts();
|
|
||||||
|
|
||||||
initialized = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ImGui_ImplDX11_NewFrame())
|
if (ImGui_ImplDX11_NewFrame() && Windows_Hook::Inst()->_PrepareForOverlay(desc.OutputWindow))
|
||||||
{
|
{
|
||||||
Windows_Hook::Inst()->prepareForOverlay(desc.OutputWindow);
|
|
||||||
|
|
||||||
ImGui::NewFrame();
|
ImGui::NewFrame();
|
||||||
|
|
||||||
get_steam_client()->steam_overlay->OverlayProc();
|
OverlayProc();
|
||||||
|
|
||||||
ImGui::Render();
|
ImGui::Render();
|
||||||
|
|
||||||
if (mainRenderTargetView) {
|
if (mainRenderTargetView)
|
||||||
|
{
|
||||||
pContext->OMSetRenderTargets(1, &mainRenderTargetView, NULL);
|
pContext->OMSetRenderTargets(1, &mainRenderTargetView, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -141,56 +174,63 @@ void DX11_Hook::prepareForOverlay(IDXGISwapChain* pSwapChain)
|
||||||
|
|
||||||
HRESULT STDMETHODCALLTYPE DX11_Hook::MyPresent(IDXGISwapChain *_this, UINT SyncInterval, UINT Flags)
|
HRESULT STDMETHODCALLTYPE DX11_Hook::MyPresent(IDXGISwapChain *_this, UINT SyncInterval, UINT Flags)
|
||||||
{
|
{
|
||||||
DX11_Hook::Inst()->prepareForOverlay(_this);
|
auto inst = DX11_Hook::Inst();
|
||||||
|
inst->_PrepareForOverlay(_this);
|
||||||
return (_this->*DX11_Hook::Inst()->Present)(SyncInterval, Flags);
|
return (_this->*inst->Present)(SyncInterval, Flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
HRESULT STDMETHODCALLTYPE DX11_Hook::MyResizeTarget(IDXGISwapChain* _this, const DXGI_MODE_DESC* pNewTargetParameters)
|
HRESULT STDMETHODCALLTYPE DX11_Hook::MyResizeTarget(IDXGISwapChain* _this, const DXGI_MODE_DESC* pNewTargetParameters)
|
||||||
{
|
{
|
||||||
DX11_Hook::Inst()->resetRenderState();
|
auto inst = DX11_Hook::Inst();
|
||||||
return (_this->*DX11_Hook::Inst()->ResizeTarget)(pNewTargetParameters);
|
inst->_ResetRenderState();
|
||||||
|
return (_this->*inst->ResizeTarget)(pNewTargetParameters);
|
||||||
}
|
}
|
||||||
|
|
||||||
HRESULT STDMETHODCALLTYPE DX11_Hook::MyResizeBuffers(IDXGISwapChain* _this, UINT BufferCount, UINT Width, UINT Height, DXGI_FORMAT NewFormat, UINT SwapChainFlags)
|
HRESULT STDMETHODCALLTYPE DX11_Hook::MyResizeBuffers(IDXGISwapChain* _this, UINT BufferCount, UINT Width, UINT Height, DXGI_FORMAT NewFormat, UINT SwapChainFlags)
|
||||||
{
|
{
|
||||||
DX11_Hook::Inst()->resetRenderState();
|
auto inst = DX11_Hook::Inst();
|
||||||
return (_this->*DX11_Hook::Inst()->ResizeBuffers)(BufferCount, Width, Height, NewFormat, SwapChainFlags);
|
inst->_ResetRenderState();
|
||||||
|
return (_this->*inst->ResizeBuffers)(BufferCount, Width, Height, NewFormat, SwapChainFlags);
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT STDMETHODCALLTYPE DX11_Hook::MyPresent1(IDXGISwapChain1* _this, UINT SyncInterval, UINT Flags, const DXGI_PRESENT_PARAMETERS* pPresentParameters)
|
||||||
|
{
|
||||||
|
auto inst = DX11_Hook::Inst();
|
||||||
|
inst->_PrepareForOverlay(_this);
|
||||||
|
return (_this->*inst->Present1)(SyncInterval, Flags, pPresentParameters);
|
||||||
}
|
}
|
||||||
|
|
||||||
DX11_Hook::DX11_Hook():
|
DX11_Hook::DX11_Hook():
|
||||||
initialized(false),
|
_Initialized(false),
|
||||||
hooked(false),
|
_Hooked(false),
|
||||||
|
_WindowsHooked(false),
|
||||||
pContext(nullptr),
|
pContext(nullptr),
|
||||||
mainRenderTargetView(nullptr),
|
mainRenderTargetView(nullptr),
|
||||||
Present(nullptr),
|
Present(nullptr),
|
||||||
ResizeBuffers(nullptr),
|
ResizeBuffers(nullptr),
|
||||||
ResizeTarget(nullptr)
|
ResizeTarget(nullptr),
|
||||||
|
Present1(nullptr)
|
||||||
{
|
{
|
||||||
_library = LoadLibrary(DX11_DLL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DX11_Hook::~DX11_Hook()
|
DX11_Hook::~DX11_Hook()
|
||||||
{
|
{
|
||||||
PRINT_DEBUG("DX11 Hook removed\n");
|
SPDLOG_INFO("DX11 Hook removed");
|
||||||
|
|
||||||
if (initialized)
|
if (_WindowsHooked)
|
||||||
|
delete Windows_Hook::Inst();
|
||||||
|
|
||||||
|
if (_Initialized)
|
||||||
{
|
{
|
||||||
if (mainRenderTargetView) {
|
SafeRelease(mainRenderTargetView);
|
||||||
mainRenderTargetView->Release();
|
SafeRelease(pContext);
|
||||||
mainRenderTargetView = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
pContext->Release();
|
|
||||||
|
|
||||||
ImGui_ImplDX11_InvalidateDeviceObjects();
|
ImGui_ImplDX11_InvalidateDeviceObjects();
|
||||||
ImGui::DestroyContext();
|
ImGui::DestroyContext();
|
||||||
|
|
||||||
initialized = false;
|
_Initialized = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
FreeLibrary(reinterpret_cast<HMODULE>(_library));
|
|
||||||
|
|
||||||
_inst = nullptr;
|
_inst = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -202,21 +242,85 @@ DX11_Hook* DX11_Hook::Inst()
|
||||||
return _inst;
|
return _inst;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* DX11_Hook::get_lib_name() const
|
std::string DX11_Hook::GetLibraryName() const
|
||||||
{
|
{
|
||||||
return DX11_DLL;
|
return LibraryName;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DX11_Hook::loadFunctions(IDXGISwapChain *pSwapChain)
|
void DX11_Hook::LoadFunctions(
|
||||||
|
decltype(Present) PresentFcn,
|
||||||
|
decltype(ResizeBuffers) ResizeBuffersFcn,
|
||||||
|
decltype(ResizeTarget) ResizeTargetFcn,
|
||||||
|
decltype(Present1) Present1Fcn)
|
||||||
{
|
{
|
||||||
void** vTable;
|
Present = PresentFcn;
|
||||||
|
ResizeBuffers = ResizeBuffersFcn;
|
||||||
vTable = *reinterpret_cast<void***>(pSwapChain);
|
ResizeTarget = ResizeTargetFcn;
|
||||||
#define LOAD_FUNC(X) (void*&)X = vTable[(int)IDXGISwapChainVTable::X]
|
Present1 = Present1Fcn;
|
||||||
LOAD_FUNC(Present);
|
|
||||||
LOAD_FUNC(ResizeBuffers);
|
|
||||||
LOAD_FUNC(ResizeTarget);
|
|
||||||
#undef LOAD_FUNC
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif//EMU_OVERLAY
|
std::weak_ptr<uint64_t> DX11_Hook::CreateImageResource(const void* image_data, uint32_t width, uint32_t height)
|
||||||
|
{
|
||||||
|
ID3D11ShaderResourceView** resource = new ID3D11ShaderResourceView*(nullptr);
|
||||||
|
|
||||||
|
// Create texture
|
||||||
|
D3D11_TEXTURE2D_DESC desc = {};
|
||||||
|
desc.Width = static_cast<UINT>(width);
|
||||||
|
desc.Height = static_cast<UINT>(height);
|
||||||
|
desc.MipLevels = 1;
|
||||||
|
desc.ArraySize = 1;
|
||||||
|
desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||||
|
desc.SampleDesc.Count = 1;
|
||||||
|
desc.Usage = D3D11_USAGE_DEFAULT;
|
||||||
|
desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
|
||||||
|
desc.CPUAccessFlags = 0;
|
||||||
|
|
||||||
|
ID3D11Texture2D* pTexture = nullptr;
|
||||||
|
D3D11_SUBRESOURCE_DATA subResource;
|
||||||
|
subResource.pSysMem = image_data;
|
||||||
|
subResource.SysMemPitch = desc.Width * 4;
|
||||||
|
subResource.SysMemSlicePitch = 0;
|
||||||
|
pDevice->CreateTexture2D(&desc, &subResource, &pTexture);
|
||||||
|
|
||||||
|
if (pTexture != nullptr)
|
||||||
|
{
|
||||||
|
// Create texture view
|
||||||
|
D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc{};
|
||||||
|
srvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||||
|
srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
|
||||||
|
srvDesc.Texture2D.MipLevels = desc.MipLevels;
|
||||||
|
srvDesc.Texture2D.MostDetailedMip = 0;
|
||||||
|
|
||||||
|
pDevice->CreateShaderResourceView(pTexture, &srvDesc, resource);
|
||||||
|
// Release Texture, the shader resource increases the reference count.
|
||||||
|
pTexture->Release();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*resource == nullptr)
|
||||||
|
return std::shared_ptr<uint64_t>();
|
||||||
|
|
||||||
|
auto ptr = std::shared_ptr<uint64_t>((uint64_t*)resource, [](uint64_t* handle)
|
||||||
|
{
|
||||||
|
if(handle != nullptr)
|
||||||
|
{
|
||||||
|
ID3D11ShaderResourceView** resource = reinterpret_cast<ID3D11ShaderResourceView**>(handle);
|
||||||
|
(*resource)->Release();
|
||||||
|
delete resource;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
_ImageResources.emplace(ptr);
|
||||||
|
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DX11_Hook::ReleaseImageResource(std::weak_ptr<uint64_t> resource)
|
||||||
|
{
|
||||||
|
auto ptr = resource.lock();
|
||||||
|
if (ptr)
|
||||||
|
{
|
||||||
|
auto it = _ImageResources.find(ptr);
|
||||||
|
if (it != _ImageResources.end())
|
||||||
|
_ImageResources.erase(it);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,51 +1,81 @@
|
||||||
#ifndef __INCLUDED_DX11_HOOK_H__
|
/*
|
||||||
#define __INCLUDED_DX11_HOOK_H__
|
* Copyright (C) Nemirtingas
|
||||||
|
* This file is part of the ingame overlay project
|
||||||
|
*
|
||||||
|
* The ingame overlay project is free software; you can redistribute it
|
||||||
|
* and/or modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* The ingame overlay project 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
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with the ingame overlay project; if not, see
|
||||||
|
* <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
#include "../Base_Hook.h"
|
#pragma once
|
||||||
#ifdef EMU_OVERLAY
|
|
||||||
|
#include "../internal_includes.h"
|
||||||
|
|
||||||
#include <d3d11.h>
|
#include <d3d11.h>
|
||||||
#include "DirectX_VTables.h"
|
#include <dxgi1_2.h>
|
||||||
|
|
||||||
class DX11_Hook : public Base_Hook
|
class DX11_Hook :
|
||||||
|
public Renderer_Hook,
|
||||||
|
public Base_Hook
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
#define DX11_DLL "d3d11.dll"
|
static constexpr const char *DLL_NAME = "d3d11.dll";
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static DX11_Hook* _inst;
|
static DX11_Hook* _inst;
|
||||||
|
|
||||||
// Variables
|
// Variables
|
||||||
bool hooked;
|
bool _Hooked;
|
||||||
bool initialized;
|
bool _WindowsHooked;
|
||||||
|
bool _Initialized;
|
||||||
|
ID3D11Device* pDevice;
|
||||||
ID3D11DeviceContext* pContext;
|
ID3D11DeviceContext* pContext;
|
||||||
ID3D11RenderTargetView* mainRenderTargetView;
|
ID3D11RenderTargetView* mainRenderTargetView;
|
||||||
|
std::set<std::shared_ptr<uint64_t>> _ImageResources;
|
||||||
|
|
||||||
// Functions
|
// Functions
|
||||||
DX11_Hook();
|
DX11_Hook();
|
||||||
|
|
||||||
void resetRenderState();
|
void _ResetRenderState();
|
||||||
void prepareForOverlay(IDXGISwapChain* pSwapChain);
|
void _PrepareForOverlay(IDXGISwapChain* pSwapChain);
|
||||||
|
|
||||||
// Hook to render functions
|
// Hook to render functions
|
||||||
static HRESULT STDMETHODCALLTYPE MyPresent(IDXGISwapChain* _this, UINT SyncInterval, UINT Flags);
|
static HRESULT STDMETHODCALLTYPE MyPresent(IDXGISwapChain* _this, UINT SyncInterval, UINT Flags);
|
||||||
static HRESULT STDMETHODCALLTYPE MyResizeTarget(IDXGISwapChain* _this, const DXGI_MODE_DESC* pNewTargetParameters);
|
static HRESULT STDMETHODCALLTYPE MyResizeTarget(IDXGISwapChain* _this, const DXGI_MODE_DESC* pNewTargetParameters);
|
||||||
static HRESULT STDMETHODCALLTYPE MyResizeBuffers(IDXGISwapChain* _this, UINT BufferCount, UINT Width, UINT Height, DXGI_FORMAT NewFormat, UINT SwapChainFlags);
|
static HRESULT STDMETHODCALLTYPE MyResizeBuffers(IDXGISwapChain* _this, UINT BufferCount, UINT Width, UINT Height, DXGI_FORMAT NewFormat, UINT SwapChainFlags);
|
||||||
|
static HRESULT STDMETHODCALLTYPE MyPresent1(IDXGISwapChain1* _this, UINT SyncInterval, UINT Flags, const DXGI_PRESENT_PARAMETERS* pPresentParameters);
|
||||||
|
|
||||||
decltype(&IDXGISwapChain::Present) Present;
|
decltype(&IDXGISwapChain::Present) Present;
|
||||||
decltype(&IDXGISwapChain::ResizeBuffers) ResizeBuffers;
|
decltype(&IDXGISwapChain::ResizeBuffers) ResizeBuffers;
|
||||||
decltype(&IDXGISwapChain::ResizeTarget) ResizeTarget;
|
decltype(&IDXGISwapChain::ResizeTarget) ResizeTarget;
|
||||||
|
decltype(&IDXGISwapChain1::Present1) Present1;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
std::string LibraryName;
|
||||||
|
|
||||||
virtual ~DX11_Hook();
|
virtual ~DX11_Hook();
|
||||||
|
|
||||||
bool start_hook();
|
virtual bool StartHook(std::function<bool(bool)> key_combination_callback);
|
||||||
|
virtual bool IsStarted();
|
||||||
static DX11_Hook* Inst();
|
static DX11_Hook* Inst();
|
||||||
virtual const char* get_lib_name() const;
|
virtual std::string GetLibraryName() const;
|
||||||
|
|
||||||
void loadFunctions(IDXGISwapChain *pSwapChain);
|
void LoadFunctions(
|
||||||
|
decltype(Present) PresentFcn,
|
||||||
|
decltype(ResizeBuffers) ResizeBuffersFcn,
|
||||||
|
decltype(ResizeTarget) ResizeTargetFcn,
|
||||||
|
decltype(Present1) Present1Fcn);
|
||||||
|
|
||||||
|
virtual std::weak_ptr<uint64_t> CreateImageResource(const void* image_data, uint32_t width, uint32_t height);
|
||||||
|
virtual void ReleaseImageResource(std::weak_ptr<uint64_t> resource);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif//EMU_OVERLAY
|
|
||||||
|
|
||||||
#endif//__INCLUDED_DX11_HOOK_H__
|
|
||||||
|
|
|
@ -1,74 +1,161 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) Nemirtingas
|
||||||
|
* This file is part of the ingame overlay project
|
||||||
|
*
|
||||||
|
* The ingame overlay project is free software; you can redistribute it
|
||||||
|
* and/or modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* The ingame overlay project 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
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with the ingame overlay project; if not, see
|
||||||
|
* <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
#include "DX12_Hook.h"
|
#include "DX12_Hook.h"
|
||||||
#include "Windows_Hook.h"
|
#include "Windows_Hook.h"
|
||||||
#include "../Renderer_Detector.h"
|
|
||||||
#include "../../dll/dll.h"
|
|
||||||
|
|
||||||
#ifdef EMU_OVERLAY
|
|
||||||
|
|
||||||
#include <imgui.h>
|
#include <imgui.h>
|
||||||
#include <impls/windows/imgui_impl_dx12.h>
|
#include <backends/imgui_impl_dx12.h>
|
||||||
|
|
||||||
#include <dxgi1_4.h>
|
|
||||||
|
|
||||||
DX12_Hook* DX12_Hook::_inst = nullptr;
|
DX12_Hook* DX12_Hook::_inst = nullptr;
|
||||||
|
|
||||||
bool DX12_Hook::start_hook()
|
template<typename T>
|
||||||
|
inline void SafeRelease(T*& pUnk)
|
||||||
{
|
{
|
||||||
bool res = true;
|
if (pUnk != nullptr)
|
||||||
if (!hooked)
|
|
||||||
{
|
{
|
||||||
if (!Windows_Hook::Inst()->start_hook())
|
pUnk->Release();
|
||||||
|
pUnk = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DX12_Hook::StartHook(std::function<bool(bool)> key_combination_callback)
|
||||||
|
{
|
||||||
|
if (!_Hooked)
|
||||||
|
{
|
||||||
|
if (Present == nullptr || ResizeTarget == nullptr || ResizeBuffers == nullptr || ExecuteCommandLists == nullptr)
|
||||||
|
{
|
||||||
|
SPDLOG_WARN("Failed to hook DirectX 12: Rendering functions missing.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Windows_Hook::Inst()->StartHook(key_combination_callback))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
PRINT_DEBUG("Hooked DirectX 12\n");
|
_WindowsHooked = true;
|
||||||
hooked = true;
|
|
||||||
|
|
||||||
Renderer_Detector::Inst().renderer_found(this);
|
SPDLOG_INFO("Hooked DirectX 12");
|
||||||
|
_Hooked = true;
|
||||||
|
|
||||||
BeginHook();
|
BeginHook();
|
||||||
HookFuncs(
|
HookFuncs(
|
||||||
std::make_pair<void**, void*>(&(PVOID&)DX12_Hook::Present, &DX12_Hook::MyPresent),
|
std::make_pair<void**, void*>(&(PVOID&)Present , &DX12_Hook::MyPresent),
|
||||||
std::make_pair<void**, void*>(&(PVOID&)DX12_Hook::ResizeTarget, &DX12_Hook::MyResizeTarget),
|
std::make_pair<void**, void*>(&(PVOID&)ResizeTarget , &DX12_Hook::MyResizeTarget),
|
||||||
std::make_pair<void**, void*>(&(PVOID&)DX12_Hook::ResizeBuffers, &DX12_Hook::MyResizeBuffers),
|
std::make_pair<void**, void*>(&(PVOID&)ResizeBuffers , &DX12_Hook::MyResizeBuffers),
|
||||||
std::make_pair<void**, void*>(&(PVOID&)DX12_Hook::ExecuteCommandLists, &DX12_Hook::MyExecuteCommandLists)
|
std::make_pair<void**, void*>(&(PVOID&)ExecuteCommandLists, &DX12_Hook::MyExecuteCommandLists)
|
||||||
);
|
);
|
||||||
|
if (Present1 != nullptr)
|
||||||
|
{
|
||||||
|
HookFuncs(
|
||||||
|
std::make_pair<void**, void*>(&(PVOID&)Present1, &DX12_Hook::MyPresent1)
|
||||||
|
);
|
||||||
|
}
|
||||||
EndHook();
|
EndHook();
|
||||||
|
|
||||||
get_steam_client()->steam_overlay->HookReady();
|
|
||||||
}
|
}
|
||||||
return res;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DX12_Hook::resetRenderState()
|
bool DX12_Hook::IsStarted()
|
||||||
{
|
{
|
||||||
if (initialized)
|
return _Hooked;
|
||||||
{
|
|
||||||
pSrvDescHeap->Release();
|
|
||||||
for (UINT i = 0; i < bufferCount; ++i)
|
|
||||||
{
|
|
||||||
pCmdAlloc[i]->Release();
|
|
||||||
pBackBuffer[i]->Release();
|
|
||||||
}
|
}
|
||||||
pRtvDescHeap->Release();
|
|
||||||
delete[]pCmdAlloc;
|
//DX12_Hook::heap_t DX12_Hook::get_free_texture_heap()
|
||||||
delete[]pBackBuffer;
|
//{
|
||||||
|
// int64_t i;
|
||||||
|
// std::vector<bool>::reference* free_heap;
|
||||||
|
// for (i = 0; i < srvDescHeapBitmap.size(); ++i)
|
||||||
|
// {
|
||||||
|
// if (!srvDescHeapBitmap[i])
|
||||||
|
// {
|
||||||
|
// srvDescHeapBitmap[i] = true;
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// if (i == srvDescHeapBitmap.size())
|
||||||
|
// return heap_t{ {}, {}, -1 };
|
||||||
|
//
|
||||||
|
// UINT inc = pDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
|
||||||
|
//
|
||||||
|
// return heap_t{
|
||||||
|
// pSrvDescHeap->GetGPUDescriptorHandleForHeapStart().ptr + inc * i,
|
||||||
|
// pSrvDescHeap->GetCPUDescriptorHandleForHeapStart().ptr + inc * i,
|
||||||
|
// i
|
||||||
|
// };
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//bool DX12_Hook::release_texture_heap(int64_t heap_id)
|
||||||
|
//{
|
||||||
|
// srvDescHeapBitmap[heap_id] = false;
|
||||||
|
// return true;
|
||||||
|
//}
|
||||||
|
|
||||||
|
ID3D12CommandQueue* DX12_Hook::_FindCommandQueueFromSwapChain(IDXGISwapChain* pSwapChain)
|
||||||
|
{
|
||||||
|
ID3D12CommandQueue* pCommandQueue = nullptr;
|
||||||
|
|
||||||
|
if (CommandQueueOffset == 0 && pCmdQueue != nullptr)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < 1024; ++i)
|
||||||
|
{
|
||||||
|
if (*reinterpret_cast<ID3D12CommandQueue**>(reinterpret_cast<uintptr_t>(pSwapChain) + i) == pCmdQueue)
|
||||||
|
{
|
||||||
|
SPDLOG_INFO("Found IDXGISwapChain::ppCommandQueue at offset {}.", i);
|
||||||
|
CommandQueueOffset = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CommandQueueOffset != 0)
|
||||||
|
pCommandQueue = *reinterpret_cast<ID3D12CommandQueue**>(reinterpret_cast<uintptr_t>(pSwapChain) + CommandQueueOffset);
|
||||||
|
|
||||||
|
return pCommandQueue;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DX12_Hook::_ResetRenderState()
|
||||||
|
{
|
||||||
|
if (_Initialized)
|
||||||
|
{
|
||||||
|
OverlayHookReady(false);
|
||||||
|
|
||||||
ImGui_ImplDX12_Shutdown();
|
ImGui_ImplDX12_Shutdown();
|
||||||
Windows_Hook::Inst()->resetRenderState();
|
Windows_Hook::Inst()->_ResetRenderState();
|
||||||
ImGui::DestroyContext();
|
ImGui::DestroyContext();
|
||||||
|
|
||||||
initialized = false;
|
OverlayFrames.clear();
|
||||||
|
|
||||||
|
SafeRelease(pSrvDescHeap);
|
||||||
|
SafeRelease(pRtvDescHeap);
|
||||||
|
SafeRelease(pDevice);
|
||||||
|
|
||||||
|
_Initialized = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to make this function and overlay's proc as short as possible or it might affect game's fps.
|
// Try to make this function and overlay's proc as short as possible or it might affect game's fps.
|
||||||
void DX12_Hook::prepareForOverlay(IDXGISwapChain* pSwapChain)
|
void DX12_Hook::_PrepareForOverlay(IDXGISwapChain* pSwapChain, ID3D12CommandQueue* pCommandQueue)
|
||||||
{
|
{
|
||||||
if (pCmdQueue == nullptr)
|
if (pCommandQueue == nullptr)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ID3D12CommandQueue* pCmdQueue = this->pCmdQueue;
|
|
||||||
|
|
||||||
IDXGISwapChain3* pSwapChain3 = nullptr;
|
IDXGISwapChain3* pSwapChain3 = nullptr;
|
||||||
DXGI_SWAP_CHAIN_DESC sc_desc;
|
DXGI_SWAP_CHAIN_DESC sc_desc;
|
||||||
pSwapChain->QueryInterface(IID_PPV_ARGS(&pSwapChain3));
|
pSwapChain->QueryInterface(IID_PPV_ARGS(&pSwapChain3));
|
||||||
|
@ -77,21 +164,24 @@ void DX12_Hook::prepareForOverlay(IDXGISwapChain* pSwapChain)
|
||||||
|
|
||||||
pSwapChain3->GetDesc(&sc_desc);
|
pSwapChain3->GetDesc(&sc_desc);
|
||||||
|
|
||||||
if (!initialized)
|
if (!_Initialized)
|
||||||
{
|
{
|
||||||
UINT bufferIndex = pSwapChain3->GetCurrentBackBufferIndex();
|
UINT bufferIndex = pSwapChain3->GetCurrentBackBufferIndex();
|
||||||
ID3D12Device* pDevice;
|
pDevice = nullptr;
|
||||||
if (pSwapChain3->GetDevice(IID_PPV_ARGS(&pDevice)) != S_OK)
|
if (pSwapChain3->GetDevice(IID_PPV_ARGS(&pDevice)) != S_OK)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
bufferCount = sc_desc.BufferCount;
|
UINT bufferCount = sc_desc.BufferCount;
|
||||||
|
|
||||||
mainRenderTargets.clear();
|
//srvDescHeapBitmap.clear();
|
||||||
|
|
||||||
|
//constexpr UINT descriptor_count = 1024;
|
||||||
|
|
||||||
{
|
{
|
||||||
D3D12_DESCRIPTOR_HEAP_DESC desc = {};
|
D3D12_DESCRIPTOR_HEAP_DESC desc = {};
|
||||||
desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
|
desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
|
||||||
desc.NumDescriptors = 1;
|
desc.NumDescriptors = 1;
|
||||||
|
//desc.NumDescriptors = descriptor_count;
|
||||||
desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
|
desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
|
||||||
if (pDevice->CreateDescriptorHeap(&desc, IID_PPV_ARGS(&pSrvDescHeap)) != S_OK)
|
if (pDevice->CreateDescriptorHeap(&desc, IID_PPV_ARGS(&pSrvDescHeap)) != S_OK)
|
||||||
{
|
{
|
||||||
|
@ -100,6 +190,9 @@ void DX12_Hook::prepareForOverlay(IDXGISwapChain* pSwapChain)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//srvDescHeapBitmap.resize(descriptor_count, false);
|
||||||
|
|
||||||
{
|
{
|
||||||
D3D12_DESCRIPTOR_HEAP_DESC desc = {};
|
D3D12_DESCRIPTOR_HEAP_DESC desc = {};
|
||||||
desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV;
|
desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV;
|
||||||
|
@ -116,88 +209,92 @@ void DX12_Hook::prepareForOverlay(IDXGISwapChain* pSwapChain)
|
||||||
|
|
||||||
SIZE_T rtvDescriptorSize = pDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
|
SIZE_T rtvDescriptorSize = pDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
|
||||||
D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = pRtvDescHeap->GetCPUDescriptorHandleForHeapStart();
|
D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = pRtvDescHeap->GetCPUDescriptorHandleForHeapStart();
|
||||||
pCmdAlloc = new ID3D12CommandAllocator * [bufferCount];
|
ID3D12CommandAllocator* pCmdAlloc;
|
||||||
for (int i = 0; i < bufferCount; ++i)
|
ID3D12Resource* pBackBuffer;
|
||||||
|
|
||||||
|
for (UINT i = 0; i < bufferCount; ++i)
|
||||||
{
|
{
|
||||||
mainRenderTargets.push_back(rtvHandle);
|
pCmdAlloc = nullptr;
|
||||||
|
pBackBuffer = nullptr;
|
||||||
|
|
||||||
|
if (pDevice->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&pCmdAlloc)) != S_OK || pCmdAlloc == nullptr)
|
||||||
|
{
|
||||||
|
OverlayFrames.clear();
|
||||||
|
pSrvDescHeap->Release();
|
||||||
|
pRtvDescHeap->Release();
|
||||||
|
pDevice->Release();
|
||||||
|
pSwapChain3->Release();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i == 0)
|
||||||
|
{
|
||||||
|
if (pDevice->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, pCmdAlloc, NULL, IID_PPV_ARGS(&pCmdList)) != S_OK ||
|
||||||
|
pCmdList == nullptr || pCmdList->Close() != S_OK)
|
||||||
|
{
|
||||||
|
OverlayFrames.clear();
|
||||||
|
SafeRelease(pCmdList);
|
||||||
|
pCmdAlloc->Release();
|
||||||
|
pSrvDescHeap->Release();
|
||||||
|
pRtvDescHeap->Release();
|
||||||
|
pDevice->Release();
|
||||||
|
pSwapChain3->Release();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pSwapChain3->GetBuffer(i, IID_PPV_ARGS(&pBackBuffer)) != S_OK || pBackBuffer == nullptr)
|
||||||
|
{
|
||||||
|
OverlayFrames.clear();
|
||||||
|
pCmdList->Release();
|
||||||
|
pCmdAlloc->Release();
|
||||||
|
pSrvDescHeap->Release();
|
||||||
|
pRtvDescHeap->Release();
|
||||||
|
pDevice->Release();
|
||||||
|
pSwapChain3->Release();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pDevice->CreateRenderTargetView(pBackBuffer, NULL, rtvHandle);
|
||||||
|
|
||||||
|
OverlayFrames.emplace_back(rtvHandle, pCmdAlloc, pBackBuffer);
|
||||||
rtvHandle.ptr += rtvDescriptorSize;
|
rtvHandle.ptr += rtvDescriptorSize;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (UINT i = 0; i < sc_desc.BufferCount; ++i)
|
//auto heaps = std::move(get_free_texture_heap());
|
||||||
{
|
|
||||||
if (pDevice->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&pCmdAlloc[i])) != S_OK)
|
|
||||||
{
|
|
||||||
pDevice->Release();
|
|
||||||
pSwapChain3->Release();
|
|
||||||
pSrvDescHeap->Release();
|
|
||||||
for (UINT j = 0; j < i; ++j)
|
|
||||||
{
|
|
||||||
pCmdAlloc[j]->Release();
|
|
||||||
}
|
|
||||||
pRtvDescHeap->Release();
|
|
||||||
delete[]pCmdAlloc;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pDevice->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, pCmdAlloc[0], NULL, IID_PPV_ARGS(&pCmdList)) != S_OK ||
|
|
||||||
pCmdList->Close() != S_OK)
|
|
||||||
{
|
|
||||||
pDevice->Release();
|
|
||||||
pSwapChain3->Release();
|
|
||||||
pSrvDescHeap->Release();
|
|
||||||
for (UINT i = 0; i < bufferCount; ++i)
|
|
||||||
pCmdAlloc[i]->Release();
|
|
||||||
pRtvDescHeap->Release();
|
|
||||||
delete[]pCmdAlloc;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
pBackBuffer = new ID3D12Resource * [bufferCount];
|
|
||||||
for (UINT i = 0; i < bufferCount; i++)
|
|
||||||
{
|
|
||||||
pSwapChain3->GetBuffer(i, IID_PPV_ARGS(&pBackBuffer[i]));
|
|
||||||
pDevice->CreateRenderTargetView(pBackBuffer[i], NULL, mainRenderTargets[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::CreateContext();
|
ImGui::CreateContext();
|
||||||
ImGuiIO& io = ImGui::GetIO();
|
ImGui_ImplDX12_Init(pDevice, bufferCount, DXGI_FORMAT_R8G8B8A8_UNORM, pSrvDescHeap,
|
||||||
io.IniFilename = NULL;
|
|
||||||
|
|
||||||
ImGui_ImplDX12_Init(pDevice, bufferCount, DXGI_FORMAT_R8G8B8A8_UNORM, NULL,
|
|
||||||
pSrvDescHeap->GetCPUDescriptorHandleForHeapStart(),
|
pSrvDescHeap->GetCPUDescriptorHandleForHeapStart(),
|
||||||
pSrvDescHeap->GetGPUDescriptorHandleForHeapStart());
|
pSrvDescHeap->GetGPUDescriptorHandleForHeapStart());
|
||||||
|
//heaps.cpu_handle,
|
||||||
|
//heaps.gpu_handle);
|
||||||
|
|
||||||
get_steam_client()->steam_overlay->CreateFonts();
|
_Initialized = true;
|
||||||
|
OverlayHookReady(true);
|
||||||
initialized = true;
|
|
||||||
|
|
||||||
pDevice->Release();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ImGui_ImplDX12_NewFrame())
|
if (ImGui_ImplDX12_NewFrame() && Windows_Hook::Inst()->_PrepareForOverlay(sc_desc.OutputWindow))
|
||||||
{
|
{
|
||||||
Windows_Hook::Inst()->prepareForOverlay(sc_desc.OutputWindow);
|
|
||||||
|
|
||||||
ImGui::NewFrame();
|
ImGui::NewFrame();
|
||||||
|
|
||||||
get_steam_client()->steam_overlay->OverlayProc();
|
OverlayProc();
|
||||||
|
|
||||||
UINT bufferIndex = pSwapChain3->GetCurrentBackBufferIndex();
|
UINT bufferIndex = pSwapChain3->GetCurrentBackBufferIndex();
|
||||||
|
|
||||||
D3D12_RESOURCE_BARRIER barrier = {};
|
D3D12_RESOURCE_BARRIER barrier = {};
|
||||||
barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
||||||
barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
||||||
barrier.Transition.pResource = pBackBuffer[bufferIndex];
|
barrier.Transition.pResource = OverlayFrames[bufferIndex].pBackBuffer;
|
||||||
barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
|
barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
|
||||||
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_PRESENT;
|
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_PRESENT;
|
||||||
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET;
|
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET;
|
||||||
|
|
||||||
pCmdAlloc[bufferIndex]->Reset();
|
OverlayFrames[bufferIndex].pCmdAlloc->Reset();
|
||||||
pCmdList->Reset(pCmdAlloc[bufferIndex], NULL);
|
pCmdList->Reset(OverlayFrames[bufferIndex].pCmdAlloc, NULL);
|
||||||
pCmdList->ResourceBarrier(1, &barrier);
|
pCmdList->ResourceBarrier(1, &barrier);
|
||||||
pCmdList->OMSetRenderTargets(1, &mainRenderTargets[bufferIndex], FALSE, NULL);
|
pCmdList->OMSetRenderTargets(1, &OverlayFrames[bufferIndex].RenderTarget, FALSE, NULL);
|
||||||
pCmdList->SetDescriptorHeaps(1, &pSrvDescHeap);
|
pCmdList->SetDescriptorHeaps(1, &pSrvDescHeap);
|
||||||
|
|
||||||
ImGui::Render();
|
ImGui::Render();
|
||||||
|
@ -208,81 +305,98 @@ void DX12_Hook::prepareForOverlay(IDXGISwapChain* pSwapChain)
|
||||||
pCmdList->ResourceBarrier(1, &barrier);
|
pCmdList->ResourceBarrier(1, &barrier);
|
||||||
pCmdList->Close();
|
pCmdList->Close();
|
||||||
|
|
||||||
pCmdQueue->ExecuteCommandLists(1, (ID3D12CommandList**)&pCmdList);
|
pCommandQueue->ExecuteCommandLists(1, (ID3D12CommandList* const*)&pCmdList);
|
||||||
}
|
}
|
||||||
|
|
||||||
pSwapChain3->Release();
|
pSwapChain3->Release();
|
||||||
}
|
}
|
||||||
|
|
||||||
HRESULT STDMETHODCALLTYPE DX12_Hook::MyPresent(IDXGISwapChain *_this, UINT SyncInterval, UINT Flags)
|
HRESULT STDMETHODCALLTYPE DX12_Hook::MyPresent(IDXGISwapChain *_this, UINT SyncInterval, UINT Flags)
|
||||||
{
|
{
|
||||||
DX12_Hook::Inst()->prepareForOverlay(_this);
|
auto inst = DX12_Hook::Inst();
|
||||||
|
|
||||||
return (_this->*DX12_Hook::Inst()->Present)(SyncInterval, Flags);
|
ID3D12CommandQueue* pCommandQueue = inst->_FindCommandQueueFromSwapChain(_this);
|
||||||
|
if (pCommandQueue != nullptr)
|
||||||
|
{
|
||||||
|
inst->_PrepareForOverlay(_this, pCommandQueue);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (_this->*inst->Present)(SyncInterval, Flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
HRESULT STDMETHODCALLTYPE DX12_Hook::MyResizeTarget(IDXGISwapChain* _this, const DXGI_MODE_DESC* pNewTargetParameters)
|
HRESULT STDMETHODCALLTYPE DX12_Hook::MyResizeTarget(IDXGISwapChain* _this, const DXGI_MODE_DESC* pNewTargetParameters)
|
||||||
{
|
{
|
||||||
DX12_Hook::Inst()->resetRenderState();
|
auto inst = DX12_Hook::Inst();
|
||||||
return (_this->*DX12_Hook::Inst()->ResizeTarget)(pNewTargetParameters);
|
inst->_ResetRenderState();
|
||||||
|
return (_this->*inst->ResizeTarget)(pNewTargetParameters);
|
||||||
}
|
}
|
||||||
|
|
||||||
HRESULT STDMETHODCALLTYPE DX12_Hook::MyResizeBuffers(IDXGISwapChain* _this, UINT BufferCount, UINT Width, UINT Height, DXGI_FORMAT NewFormat, UINT SwapChainFlags)
|
HRESULT STDMETHODCALLTYPE DX12_Hook::MyResizeBuffers(IDXGISwapChain* _this, UINT BufferCount, UINT Width, UINT Height, DXGI_FORMAT NewFormat, UINT SwapChainFlags)
|
||||||
{
|
{
|
||||||
DX12_Hook::Inst()->resetRenderState();
|
auto inst = DX12_Hook::Inst();
|
||||||
return (_this->*DX12_Hook::Inst()->ResizeBuffers)(BufferCount, Width, Height, NewFormat, SwapChainFlags);
|
inst->_ResetRenderState();
|
||||||
|
return (_this->*inst->ResizeBuffers)(BufferCount, Width, Height, NewFormat, SwapChainFlags);
|
||||||
}
|
}
|
||||||
|
|
||||||
void STDMETHODCALLTYPE DX12_Hook::MyExecuteCommandLists(ID3D12CommandQueue *_this, UINT NumCommandLists, ID3D12CommandList* const* ppCommandLists)
|
void STDMETHODCALLTYPE DX12_Hook::MyExecuteCommandLists(ID3D12CommandQueue *_this, UINT NumCommandLists, ID3D12CommandList* const* ppCommandLists)
|
||||||
{
|
{
|
||||||
DX12_Hook* me = DX12_Hook::Inst();
|
auto inst = DX12_Hook::Inst();
|
||||||
me->pCmdQueue = _this;
|
inst->pCmdQueue = _this;
|
||||||
|
(_this->*inst->ExecuteCommandLists)(NumCommandLists, ppCommandLists);
|
||||||
|
}
|
||||||
|
|
||||||
(_this->*DX12_Hook::Inst()->ExecuteCommandLists)(NumCommandLists, ppCommandLists);
|
HRESULT STDMETHODCALLTYPE DX12_Hook::MyPresent1(IDXGISwapChain1* _this, UINT SyncInterval, UINT Flags, const DXGI_PRESENT_PARAMETERS* pPresentParameters)
|
||||||
|
{
|
||||||
|
auto inst = DX12_Hook::Inst();
|
||||||
|
|
||||||
|
ID3D12CommandQueue* pCommandQueue = inst->_FindCommandQueueFromSwapChain(_this);
|
||||||
|
if (pCommandQueue != nullptr)
|
||||||
|
{
|
||||||
|
inst->_PrepareForOverlay(_this, pCommandQueue);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (_this->*inst->Present1)(SyncInterval, Flags, pPresentParameters);
|
||||||
}
|
}
|
||||||
|
|
||||||
DX12_Hook::DX12_Hook():
|
DX12_Hook::DX12_Hook():
|
||||||
initialized(false),
|
_Initialized(false),
|
||||||
|
CommandQueueOffset(0),
|
||||||
|
pDevice(nullptr),
|
||||||
pCmdQueue(nullptr),
|
pCmdQueue(nullptr),
|
||||||
bufferCount(0),
|
|
||||||
pCmdAlloc(nullptr),
|
|
||||||
pSrvDescHeap(nullptr),
|
pSrvDescHeap(nullptr),
|
||||||
pCmdList(nullptr),
|
pCmdList(nullptr),
|
||||||
pRtvDescHeap(nullptr),
|
pRtvDescHeap(nullptr),
|
||||||
hooked(false),
|
_Hooked(false),
|
||||||
|
_WindowsHooked(false),
|
||||||
Present(nullptr),
|
Present(nullptr),
|
||||||
ResizeBuffers(nullptr),
|
ResizeBuffers(nullptr),
|
||||||
ResizeTarget(nullptr),
|
ResizeTarget(nullptr),
|
||||||
ExecuteCommandLists(nullptr)
|
ExecuteCommandLists(nullptr),
|
||||||
|
Present1(nullptr)
|
||||||
{
|
{
|
||||||
_library = LoadLibrary(DX12_DLL);
|
SPDLOG_WARN("DX12 support is experimental, don't complain if it doesn't work as expected.");
|
||||||
|
|
||||||
PRINT_DEBUG("DX12 support is experimental, don't complain if it doesn't work as expected.\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DX12_Hook::~DX12_Hook()
|
DX12_Hook::~DX12_Hook()
|
||||||
{
|
{
|
||||||
PRINT_DEBUG("DX12 Hook removed\n");
|
SPDLOG_INFO("DX12 Hook removed");
|
||||||
|
|
||||||
if (initialized)
|
if (_WindowsHooked)
|
||||||
|
delete Windows_Hook::Inst();
|
||||||
|
|
||||||
|
if (_Initialized)
|
||||||
{
|
{
|
||||||
|
OverlayFrames.clear();
|
||||||
|
|
||||||
pSrvDescHeap->Release();
|
pSrvDescHeap->Release();
|
||||||
for (UINT i = 0; i < bufferCount; ++i)
|
|
||||||
{
|
|
||||||
pCmdAlloc[i]->Release();
|
|
||||||
pBackBuffer[i]->Release();
|
|
||||||
}
|
|
||||||
pRtvDescHeap->Release();
|
pRtvDescHeap->Release();
|
||||||
delete[]pCmdAlloc;
|
|
||||||
delete[]pBackBuffer;
|
|
||||||
|
|
||||||
ImGui_ImplDX12_InvalidateDeviceObjects();
|
ImGui_ImplDX12_InvalidateDeviceObjects();
|
||||||
ImGui::DestroyContext();
|
ImGui::DestroyContext();
|
||||||
|
|
||||||
initialized = false;
|
_Initialized = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
FreeLibrary(reinterpret_cast<HMODULE>(_library));
|
|
||||||
|
|
||||||
_inst = nullptr;
|
_inst = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -294,26 +408,204 @@ DX12_Hook* DX12_Hook::Inst()
|
||||||
return _inst;
|
return _inst;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* DX12_Hook::get_lib_name() const
|
std::string DX12_Hook::GetLibraryName() const
|
||||||
{
|
{
|
||||||
return DX12_DLL;
|
return LibraryName;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DX12_Hook::loadFunctions(ID3D12CommandQueue* pCommandQueue, IDXGISwapChain *pSwapChain)
|
void DX12_Hook::LoadFunctions(
|
||||||
|
decltype(Present) PresentFcn,
|
||||||
|
decltype(ResizeBuffers) ResizeBuffersFcn,
|
||||||
|
decltype(ResizeTarget) ResizeTargetFcn,
|
||||||
|
decltype(ExecuteCommandLists) ExecuteCommandListsFcn,
|
||||||
|
decltype(Present1) Present1Fcn)
|
||||||
{
|
{
|
||||||
void** vTable;
|
Present = PresentFcn;
|
||||||
|
ResizeBuffers = ResizeBuffersFcn;
|
||||||
|
ResizeTarget = ResizeTargetFcn;
|
||||||
|
|
||||||
vTable = *reinterpret_cast<void***>(pCommandQueue);
|
ExecuteCommandLists = ExecuteCommandListsFcn;
|
||||||
#define LOAD_FUNC(X) (void*&)X = vTable[(int)ID3D12CommandQueueVTable::X]
|
|
||||||
LOAD_FUNC(ExecuteCommandLists);
|
|
||||||
#undef LOAD_FUNC
|
|
||||||
|
|
||||||
vTable = *reinterpret_cast<void***>(pSwapChain);
|
Present1 = Present1Fcn;
|
||||||
#define LOAD_FUNC(X) (void*&)X = vTable[(int)IDXGISwapChainVTable::X]
|
|
||||||
LOAD_FUNC(Present);
|
|
||||||
LOAD_FUNC(ResizeBuffers);
|
|
||||||
LOAD_FUNC(ResizeTarget);
|
|
||||||
#undef LOAD_FUNC
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif//EMU_OVERLAY
|
std::weak_ptr<uint64_t> DX12_Hook::CreateImageResource(const void* image_data, uint32_t width, uint32_t height)
|
||||||
|
{
|
||||||
|
return std::shared_ptr<uint64_t>();
|
||||||
|
//heap_t heap = get_free_texture_heap();
|
||||||
|
//
|
||||||
|
//if (heap.id == -1)
|
||||||
|
// return nullptr;
|
||||||
|
//
|
||||||
|
//HRESULT hr;
|
||||||
|
//
|
||||||
|
//D3D12_HEAP_PROPERTIES props;
|
||||||
|
//memset(&props, 0, sizeof(D3D12_HEAP_PROPERTIES));
|
||||||
|
//props.Type = D3D12_HEAP_TYPE_DEFAULT;
|
||||||
|
//props.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
|
||||||
|
//props.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
|
||||||
|
//
|
||||||
|
//D3D12_RESOURCE_DESC desc;
|
||||||
|
//ZeroMemory(&desc, sizeof(desc));
|
||||||
|
//desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
|
||||||
|
//desc.Alignment = 0;
|
||||||
|
//desc.Width = source->width();
|
||||||
|
//desc.Height = source->height();
|
||||||
|
//desc.DepthOrArraySize = 1;
|
||||||
|
//desc.MipLevels = 1;
|
||||||
|
//desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||||
|
//desc.SampleDesc.Count = 1;
|
||||||
|
//desc.SampleDesc.Quality = 0;
|
||||||
|
//desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
|
||||||
|
//desc.Flags = D3D12_RESOURCE_FLAG_NONE;
|
||||||
|
//
|
||||||
|
//ID3D12Resource* pTexture = NULL;
|
||||||
|
//pDevice->CreateCommittedResource(&props, D3D12_HEAP_FLAG_NONE, &desc,
|
||||||
|
// D3D12_RESOURCE_STATE_COPY_DEST, NULL, IID_PPV_ARGS(&pTexture));
|
||||||
|
//
|
||||||
|
//UINT uploadPitch = (source->width() * 4 + D3D12_TEXTURE_DATA_PITCH_ALIGNMENT - 1u) & ~(D3D12_TEXTURE_DATA_PITCH_ALIGNMENT - 1u);
|
||||||
|
//UINT uploadSize = source->height() * uploadPitch;
|
||||||
|
//desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
|
||||||
|
//desc.Alignment = 0;
|
||||||
|
//desc.Width = uploadSize;
|
||||||
|
//desc.Height = 1;
|
||||||
|
//desc.DepthOrArraySize = 1;
|
||||||
|
//desc.MipLevels = 1;
|
||||||
|
//desc.Format = DXGI_FORMAT_UNKNOWN;
|
||||||
|
//desc.SampleDesc.Count = 1;
|
||||||
|
//desc.SampleDesc.Quality = 0;
|
||||||
|
//desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
|
||||||
|
//desc.Flags = D3D12_RESOURCE_FLAG_NONE;
|
||||||
|
//
|
||||||
|
//props.Type = D3D12_HEAP_TYPE_UPLOAD;
|
||||||
|
//props.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
|
||||||
|
//props.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
|
||||||
|
//
|
||||||
|
//ID3D12Resource* uploadBuffer = NULL;
|
||||||
|
//hr = pDevice->CreateCommittedResource(&props, D3D12_HEAP_FLAG_NONE, &desc,
|
||||||
|
// D3D12_RESOURCE_STATE_GENERIC_READ, NULL, IID_PPV_ARGS(&uploadBuffer));
|
||||||
|
//IM_ASSERT(SUCCEEDED(hr));
|
||||||
|
//
|
||||||
|
//void* mapped = NULL;
|
||||||
|
//D3D12_RANGE range = { 0, uploadSize };
|
||||||
|
//hr = uploadBuffer->Map(0, &range, &mapped);
|
||||||
|
//IM_ASSERT(SUCCEEDED(hr));
|
||||||
|
//for (int y = 0; y < source->height(); y++)
|
||||||
|
// memcpy((void*)((uintptr_t)mapped + y * uploadPitch), reinterpret_cast<uint8_t*>(source->get_raw_pointer()) + y * source->width() * 4, source->width() * 4);
|
||||||
|
//uploadBuffer->Unmap(0, &range);
|
||||||
|
//
|
||||||
|
//D3D12_TEXTURE_COPY_LOCATION srcLocation = {};
|
||||||
|
//srcLocation.pResource = uploadBuffer;
|
||||||
|
//srcLocation.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
|
||||||
|
//srcLocation.PlacedFootprint.Footprint.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||||
|
//srcLocation.PlacedFootprint.Footprint.Width = source->width();
|
||||||
|
//srcLocation.PlacedFootprint.Footprint.Height = source->height();
|
||||||
|
//srcLocation.PlacedFootprint.Footprint.Depth = 1;
|
||||||
|
//srcLocation.PlacedFootprint.Footprint.RowPitch = uploadPitch;
|
||||||
|
//
|
||||||
|
//D3D12_TEXTURE_COPY_LOCATION dstLocation = {};
|
||||||
|
//dstLocation.pResource = pTexture;
|
||||||
|
//dstLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
|
||||||
|
//dstLocation.SubresourceIndex = 0;
|
||||||
|
//
|
||||||
|
//D3D12_RESOURCE_BARRIER barrier = {};
|
||||||
|
//barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
||||||
|
//barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
||||||
|
//barrier.Transition.pResource = pTexture;
|
||||||
|
//barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
|
||||||
|
//barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST;
|
||||||
|
//barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
|
||||||
|
//
|
||||||
|
//ID3D12Fence* fence = NULL;
|
||||||
|
//hr = pDevice->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&fence));
|
||||||
|
//IM_ASSERT(SUCCEEDED(hr));
|
||||||
|
//
|
||||||
|
//HANDLE event = CreateEvent(0, 0, 0, 0);
|
||||||
|
//IM_ASSERT(event != NULL);
|
||||||
|
//
|
||||||
|
//D3D12_COMMAND_QUEUE_DESC queueDesc = {};
|
||||||
|
//queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
|
||||||
|
//queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
|
||||||
|
//queueDesc.NodeMask = 1;
|
||||||
|
//
|
||||||
|
//ID3D12CommandQueue* cmdQueue = NULL;
|
||||||
|
//hr = pDevice->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&cmdQueue));
|
||||||
|
//IM_ASSERT(SUCCEEDED(hr));
|
||||||
|
//
|
||||||
|
//ID3D12CommandAllocator* cmdAlloc = NULL;
|
||||||
|
//hr = pDevice->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&cmdAlloc));
|
||||||
|
//IM_ASSERT(SUCCEEDED(hr));
|
||||||
|
//
|
||||||
|
//ID3D12GraphicsCommandList* cmdList = NULL;
|
||||||
|
//hr = pDevice->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, cmdAlloc, NULL, IID_PPV_ARGS(&cmdList));
|
||||||
|
//IM_ASSERT(SUCCEEDED(hr));
|
||||||
|
//
|
||||||
|
//cmdList->CopyTextureRegion(&dstLocation, 0, 0, 0, &srcLocation, NULL);
|
||||||
|
//cmdList->ResourceBarrier(1, &barrier);
|
||||||
|
//
|
||||||
|
//hr = cmdList->Close();
|
||||||
|
//IM_ASSERT(SUCCEEDED(hr));
|
||||||
|
//
|
||||||
|
//cmdQueue->ExecuteCommandLists(1, (ID3D12CommandList* const*)&cmdList);
|
||||||
|
//hr = cmdQueue->Signal(fence, 1);
|
||||||
|
//IM_ASSERT(SUCCEEDED(hr));
|
||||||
|
//
|
||||||
|
//fence->SetEventOnCompletion(1, event);
|
||||||
|
//WaitForSingleObject(event, INFINITE);
|
||||||
|
//
|
||||||
|
//cmdList->Release();
|
||||||
|
//cmdAlloc->Release();
|
||||||
|
//cmdQueue->Release();
|
||||||
|
//CloseHandle(event);
|
||||||
|
//fence->Release();
|
||||||
|
//uploadBuffer->Release();
|
||||||
|
//
|
||||||
|
//// Create texture view
|
||||||
|
//D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc;
|
||||||
|
//ZeroMemory(&srvDesc, sizeof(srvDesc));
|
||||||
|
//srvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||||
|
//srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
|
||||||
|
//srvDesc.Texture2D.MipLevels = desc.MipLevels;
|
||||||
|
//srvDesc.Texture2D.MostDetailedMip = 0;
|
||||||
|
//srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
|
||||||
|
//
|
||||||
|
//pDevice->CreateShaderResourceView(pTexture, &srvDesc, heap.cpu_handle);
|
||||||
|
//
|
||||||
|
////pSrvDescHeap->Release();
|
||||||
|
////pTexture->Release();
|
||||||
|
//
|
||||||
|
//using gpu_heap_t = decltype(D3D12_GPU_DESCRIPTOR_HANDLE::ptr);
|
||||||
|
//struct texture_t{
|
||||||
|
// gpu_heap_t gpu_handle; // This must be the first member, ImGui will use the content of the pointer as a D3D12_GPU_DESCRIPTOR_HANDLE::ptr
|
||||||
|
// ID3D12Resource* pTexture;
|
||||||
|
// int64_t heap_id;
|
||||||
|
//};
|
||||||
|
//
|
||||||
|
//texture_t* texture_data = new texture_t;
|
||||||
|
//texture_data->gpu_handle = heap.gpu_handle.ptr;
|
||||||
|
//texture_data->pTexture = pTexture;
|
||||||
|
//texture_data->heap_id = heap.id;
|
||||||
|
//
|
||||||
|
//return std::shared_ptr<uint64_t>((uint64_t*)texture_data, [this](uint64_t* handle)
|
||||||
|
//{
|
||||||
|
// if (handle != nullptr)
|
||||||
|
// {
|
||||||
|
// texture_t* pTextureData = reinterpret_cast<texture_t*>(handle);
|
||||||
|
// pTextureData->pTexture->Release();
|
||||||
|
// release_texture_heap(pTextureData->heap_id);
|
||||||
|
//
|
||||||
|
// delete pTextureData;
|
||||||
|
// }
|
||||||
|
//});
|
||||||
|
}
|
||||||
|
|
||||||
|
void DX12_Hook::ReleaseImageResource(std::weak_ptr<uint64_t> resource)
|
||||||
|
{
|
||||||
|
//auto ptr = resource.lock();
|
||||||
|
//if (ptr)
|
||||||
|
//{
|
||||||
|
// auto it = _ImageResources.find(ptr);
|
||||||
|
// if (it != _ImageResources.end())
|
||||||
|
// _ImageResources.erase(it);
|
||||||
|
//}
|
||||||
|
}
|
|
@ -1,60 +1,144 @@
|
||||||
#ifndef __INCLUDED_DX12_HOOK_H__
|
/*
|
||||||
#define __INCLUDED_DX12_HOOK_H__
|
* Copyright (C) Nemirtingas
|
||||||
|
* This file is part of the ingame overlay project
|
||||||
|
*
|
||||||
|
* The ingame overlay project is free software; you can redistribute it
|
||||||
|
* and/or modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* The ingame overlay project 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
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with the ingame overlay project; if not, see
|
||||||
|
* <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
#include "../Base_Hook.h"
|
#pragma once
|
||||||
#ifdef EMU_OVERLAY
|
|
||||||
|
#include "../internal_includes.h"
|
||||||
|
|
||||||
#include <d3d12.h>
|
#include <d3d12.h>
|
||||||
#include <dxgi1_4.h>
|
#include <dxgi1_4.h>
|
||||||
#include "DirectX_VTables.h"
|
|
||||||
|
|
||||||
class DX12_Hook : public Base_Hook
|
class DX12_Hook :
|
||||||
|
public Renderer_Hook,
|
||||||
|
public Base_Hook
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
#define DX12_DLL "d3d12.dll"
|
static constexpr const char *DLL_NAME = "d3d12.dll";
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static DX12_Hook* _inst;
|
static DX12_Hook* _inst;
|
||||||
|
|
||||||
// Variables
|
struct DX12Frame_t
|
||||||
bool hooked;
|
{
|
||||||
bool initialized;
|
D3D12_CPU_DESCRIPTOR_HANDLE RenderTarget = {};
|
||||||
|
ID3D12CommandAllocator* pCmdAlloc = nullptr;
|
||||||
|
ID3D12Resource* pBackBuffer = nullptr;
|
||||||
|
|
||||||
|
inline void Reset()
|
||||||
|
{
|
||||||
|
pCmdAlloc = nullptr;
|
||||||
|
pBackBuffer = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
DX12Frame_t(DX12Frame_t const&) = delete;
|
||||||
|
DX12Frame_t& operator=(DX12Frame_t const&) = delete;
|
||||||
|
|
||||||
|
DX12Frame_t(D3D12_CPU_DESCRIPTOR_HANDLE RenderTarget, ID3D12CommandAllocator* pCmdAlloc, ID3D12Resource* pBackBuffer):
|
||||||
|
RenderTarget(RenderTarget), pCmdAlloc(pCmdAlloc), pBackBuffer(pBackBuffer)
|
||||||
|
{}
|
||||||
|
|
||||||
|
DX12Frame_t(DX12Frame_t&& other) noexcept:
|
||||||
|
RenderTarget(other.RenderTarget), pCmdAlloc(other.pCmdAlloc), pBackBuffer(other.pBackBuffer)
|
||||||
|
{
|
||||||
|
other.Reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
DX12Frame_t& operator=(DX12Frame_t&& other) noexcept
|
||||||
|
{
|
||||||
|
DX12Frame_t tmp(std::move(other));
|
||||||
|
RenderTarget = tmp.RenderTarget;
|
||||||
|
pCmdAlloc = tmp.pCmdAlloc;
|
||||||
|
pBackBuffer = tmp.pBackBuffer;
|
||||||
|
tmp.Reset();
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
~DX12Frame_t()
|
||||||
|
{
|
||||||
|
if (pCmdAlloc != nullptr) pCmdAlloc->Release();
|
||||||
|
if (pBackBuffer != nullptr) pBackBuffer->Release();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Variables
|
||||||
|
bool _Hooked;
|
||||||
|
bool _WindowsHooked;
|
||||||
|
bool _Initialized;
|
||||||
|
|
||||||
|
size_t CommandQueueOffset;
|
||||||
ID3D12CommandQueue* pCmdQueue;
|
ID3D12CommandQueue* pCmdQueue;
|
||||||
UINT bufferCount;
|
ID3D12Device* pDevice;
|
||||||
std::vector<D3D12_CPU_DESCRIPTOR_HANDLE> mainRenderTargets;
|
std::vector<DX12Frame_t> OverlayFrames;
|
||||||
ID3D12CommandAllocator** pCmdAlloc;
|
//std::vector<bool> srvDescHeapBitmap;
|
||||||
ID3D12DescriptorHeap* pSrvDescHeap;
|
ID3D12DescriptorHeap* pSrvDescHeap;
|
||||||
ID3D12GraphicsCommandList* pCmdList;
|
ID3D12GraphicsCommandList* pCmdList;
|
||||||
ID3D12DescriptorHeap* pRtvDescHeap;
|
ID3D12DescriptorHeap* pRtvDescHeap;
|
||||||
ID3D12Resource** pBackBuffer;
|
|
||||||
|
|
||||||
// Functions
|
// Functions
|
||||||
DX12_Hook();
|
DX12_Hook();
|
||||||
|
|
||||||
void resetRenderState();
|
//struct heap_t
|
||||||
void prepareForOverlay(IDXGISwapChain* pSwapChain);
|
//{
|
||||||
|
// D3D12_GPU_DESCRIPTOR_HANDLE gpu_handle;
|
||||||
|
// D3D12_CPU_DESCRIPTOR_HANDLE cpu_handle;
|
||||||
|
// int64_t id;
|
||||||
|
//};
|
||||||
|
//
|
||||||
|
//heap_t get_free_texture_heap();
|
||||||
|
//bool release_texture_heap(int64_t heap_id);
|
||||||
|
|
||||||
|
ID3D12CommandQueue* _FindCommandQueueFromSwapChain(IDXGISwapChain* pSwapChain);
|
||||||
|
|
||||||
|
void _ResetRenderState();
|
||||||
|
void _PrepareForOverlay(IDXGISwapChain* pSwapChain, ID3D12CommandQueue* pCommandQueue);
|
||||||
|
|
||||||
// Hook to render functions
|
// Hook to render functions
|
||||||
static HRESULT STDMETHODCALLTYPE MyPresent(IDXGISwapChain* _this, UINT SyncInterval, UINT Flags);
|
static HRESULT STDMETHODCALLTYPE MyPresent(IDXGISwapChain* _this, UINT SyncInterval, UINT Flags);
|
||||||
static HRESULT STDMETHODCALLTYPE MyResizeTarget(IDXGISwapChain* _this, const DXGI_MODE_DESC* pNewTargetParameters);
|
static HRESULT STDMETHODCALLTYPE MyResizeTarget(IDXGISwapChain* _this, const DXGI_MODE_DESC* pNewTargetParameters);
|
||||||
static HRESULT STDMETHODCALLTYPE MyResizeBuffers(IDXGISwapChain* _this, UINT BufferCount, UINT Width, UINT Height, DXGI_FORMAT NewFormat, UINT SwapChainFlags);
|
static HRESULT STDMETHODCALLTYPE MyResizeBuffers(IDXGISwapChain* _this, UINT BufferCount, UINT Width, UINT Height, DXGI_FORMAT NewFormat, UINT SwapChainFlags);
|
||||||
static void STDMETHODCALLTYPE MyExecuteCommandLists(ID3D12CommandQueue *_this, UINT NumCommandLists, ID3D12CommandList* const* ppCommandLists);
|
static void STDMETHODCALLTYPE MyExecuteCommandLists(ID3D12CommandQueue *_this, UINT NumCommandLists, ID3D12CommandList* const* ppCommandLists);
|
||||||
|
static HRESULT STDMETHODCALLTYPE MyPresent1(IDXGISwapChain1* _this, UINT SyncInterval, UINT Flags, const DXGI_PRESENT_PARAMETERS* pPresentParameters);
|
||||||
|
|
||||||
decltype(&IDXGISwapChain::Present) Present;
|
decltype(&IDXGISwapChain::Present) Present;
|
||||||
decltype(&IDXGISwapChain::ResizeBuffers) ResizeBuffers;
|
decltype(&IDXGISwapChain::ResizeBuffers) ResizeBuffers;
|
||||||
decltype(&IDXGISwapChain::ResizeTarget) ResizeTarget;
|
decltype(&IDXGISwapChain::ResizeTarget) ResizeTarget;
|
||||||
decltype(&ID3D12CommandQueue::ExecuteCommandLists) ExecuteCommandLists;
|
decltype(&ID3D12CommandQueue::ExecuteCommandLists) ExecuteCommandLists;
|
||||||
|
decltype(&IDXGISwapChain1::Present1) Present1;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
std::string LibraryName;
|
||||||
|
|
||||||
virtual ~DX12_Hook();
|
virtual ~DX12_Hook();
|
||||||
|
|
||||||
bool start_hook();
|
virtual bool StartHook(std::function<bool(bool)> key_combination_callback);
|
||||||
|
virtual bool IsStarted();
|
||||||
static DX12_Hook* Inst();
|
static DX12_Hook* Inst();
|
||||||
virtual const char* get_lib_name() const;
|
virtual std::string GetLibraryName() const;
|
||||||
|
|
||||||
void loadFunctions(ID3D12CommandQueue* pCommandQueue, IDXGISwapChain* pSwapChain);
|
void LoadFunctions(
|
||||||
|
decltype(Present) PresentFcn,
|
||||||
|
decltype(ResizeBuffers) ResizeBuffersFcn,
|
||||||
|
decltype(ResizeTarget) ResizeTargetFcn,
|
||||||
|
decltype(ExecuteCommandLists) ExecuteCommandListsFcn,
|
||||||
|
decltype(Present1) Present1Fcn1);
|
||||||
|
|
||||||
|
virtual std::weak_ptr<uint64_t> CreateImageResource(const void* image_data, uint32_t width, uint32_t height);
|
||||||
|
virtual void ReleaseImageResource(std::weak_ptr<uint64_t> resource);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif//EMU_OVERLAY
|
|
||||||
#endif//__INCLUDED_DX12_HOOK_H__
|
|
||||||
|
|
|
@ -1,26 +1,58 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) Nemirtingas
|
||||||
|
* This file is part of the ingame overlay project
|
||||||
|
*
|
||||||
|
* The ingame overlay project is free software; you can redistribute it
|
||||||
|
* and/or modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* The ingame overlay project 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
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with the ingame overlay project; if not, see
|
||||||
|
* <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
#include "DX9_Hook.h"
|
#include "DX9_Hook.h"
|
||||||
#include "Windows_Hook.h"
|
#include "Windows_Hook.h"
|
||||||
#include "../Renderer_Detector.h"
|
#include "DirectX_VTables.h"
|
||||||
#include "../../dll/dll.h"
|
|
||||||
|
|
||||||
#ifdef EMU_OVERLAY
|
|
||||||
|
|
||||||
#include <imgui.h>
|
#include <imgui.h>
|
||||||
#include <impls/windows/imgui_impl_dx9.h>
|
#include <backends/imgui_impl_dx9.h>
|
||||||
|
|
||||||
DX9_Hook* DX9_Hook::_inst = nullptr;
|
DX9_Hook* DX9_Hook::_inst = nullptr;
|
||||||
|
|
||||||
bool DX9_Hook::start_hook()
|
template<typename T>
|
||||||
|
inline void SafeRelease(T*& pUnk)
|
||||||
{
|
{
|
||||||
if (!hooked)
|
if (pUnk != nullptr)
|
||||||
{
|
{
|
||||||
if (!Windows_Hook::Inst()->start_hook())
|
pUnk->Release();
|
||||||
|
pUnk = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DX9_Hook::StartHook(std::function<bool(bool)> key_combination_callback)
|
||||||
|
{
|
||||||
|
if (!_Hooked)
|
||||||
|
{
|
||||||
|
if (Reset == nullptr || Present == nullptr)
|
||||||
|
{
|
||||||
|
SPDLOG_WARN("Failed to hook DirectX 9: Rendering functions missing.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Windows_Hook::Inst()->StartHook(key_combination_callback))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
PRINT_DEBUG("Hooked DirectX 9\n");
|
_WindowsHooked = true;
|
||||||
hooked = true;
|
|
||||||
|
|
||||||
Renderer_Detector::Inst().renderer_found(this);
|
SPDLOG_INFO("Hooked DirectX 9");
|
||||||
|
_Hooked = true;
|
||||||
|
|
||||||
BeginHook();
|
BeginHook();
|
||||||
HookFuncs(
|
HookFuncs(
|
||||||
|
@ -31,57 +63,89 @@ bool DX9_Hook::start_hook()
|
||||||
{
|
{
|
||||||
HookFuncs(
|
HookFuncs(
|
||||||
std::make_pair<void**, void*>(&(PVOID&)PresentEx, &DX9_Hook::MyPresentEx)
|
std::make_pair<void**, void*>(&(PVOID&)PresentEx, &DX9_Hook::MyPresentEx)
|
||||||
//std::make_pair<void**, void*>(&(PVOID&)EndScene, &DX9_Hook::MyEndScene)
|
);
|
||||||
|
}
|
||||||
|
if (SwapChainPresent != nullptr)
|
||||||
|
{
|
||||||
|
HookFuncs(
|
||||||
|
std::make_pair<void**, void*>(&(PVOID&)SwapChainPresent, &DX9_Hook::MySwapChainPresent)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
EndHook();
|
EndHook();
|
||||||
|
|
||||||
get_steam_client()->steam_overlay->HookReady();
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DX9_Hook::resetRenderState()
|
bool DX9_Hook::IsStarted()
|
||||||
{
|
{
|
||||||
if (initialized)
|
return _Hooked;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DX9_Hook::_ResetRenderState()
|
||||||
{
|
{
|
||||||
initialized = false;
|
if (_Initialized)
|
||||||
|
{
|
||||||
|
OverlayHookReady(false);
|
||||||
|
|
||||||
ImGui_ImplDX9_Shutdown();
|
ImGui_ImplDX9_Shutdown();
|
||||||
Windows_Hook::Inst()->resetRenderState();
|
Windows_Hook::Inst()->_ResetRenderState();
|
||||||
ImGui::DestroyContext();
|
ImGui::DestroyContext();
|
||||||
|
|
||||||
|
SafeRelease(_pDevice);
|
||||||
|
|
||||||
|
_LastWindow = nullptr;
|
||||||
|
_Initialized = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to make this function and overlay's proc as short as possible or it might affect game's fps.
|
// Try to make this function and overlay's proc as short as possible or it might affect game's fps.
|
||||||
void DX9_Hook::prepareForOverlay(IDirect3DDevice9 *pDevice)
|
void DX9_Hook::_PrepareForOverlay(IDirect3DDevice9 *pDevice, HWND destWindow)
|
||||||
|
{
|
||||||
|
if (!destWindow)
|
||||||
|
{
|
||||||
|
IDirect3DSwapChain9 *pSwapChain = nullptr;
|
||||||
|
if (pDevice->GetSwapChain(0, &pSwapChain) == D3D_OK)
|
||||||
|
{
|
||||||
|
D3DPRESENT_PARAMETERS params;
|
||||||
|
if (pSwapChain->GetPresentParameters(¶ms) == D3D_OK)
|
||||||
|
{
|
||||||
|
destWindow = params.hDeviceWindow;
|
||||||
|
}
|
||||||
|
|
||||||
|
pSwapChain->Release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Is this necessary anymore?
|
||||||
|
if (!destWindow)
|
||||||
{
|
{
|
||||||
D3DDEVICE_CREATION_PARAMETERS param;
|
D3DDEVICE_CREATION_PARAMETERS param;
|
||||||
pDevice->GetCreationParameters(¶m);
|
pDevice->GetCreationParameters(¶m);
|
||||||
|
destWindow = param.hFocusWindow;
|
||||||
// Workaround to detect if we changed window.
|
|
||||||
if (param.hFocusWindow != Windows_Hook::Inst()->GetGameHwnd())
|
|
||||||
resetRenderState();
|
|
||||||
|
|
||||||
if (!initialized)
|
|
||||||
{
|
|
||||||
ImGui::CreateContext();
|
|
||||||
ImGuiIO& io = ImGui::GetIO();
|
|
||||||
io.IniFilename = NULL;
|
|
||||||
|
|
||||||
ImGui_ImplDX9_Init(pDevice);
|
|
||||||
|
|
||||||
get_steam_client()->steam_overlay->CreateFonts();
|
|
||||||
|
|
||||||
initialized = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ImGui_ImplDX9_NewFrame())
|
// Workaround to detect if we changed window.
|
||||||
{
|
if (destWindow != _LastWindow || _pDevice != pDevice)
|
||||||
Windows_Hook::Inst()->prepareForOverlay(param.hFocusWindow);
|
_ResetRenderState();
|
||||||
|
|
||||||
|
if (!_Initialized)
|
||||||
|
{
|
||||||
|
pDevice->AddRef();
|
||||||
|
_pDevice = pDevice;
|
||||||
|
|
||||||
|
ImGui::CreateContext();
|
||||||
|
ImGui_ImplDX9_Init(pDevice);
|
||||||
|
|
||||||
|
_LastWindow = destWindow;
|
||||||
|
_Initialized = true;
|
||||||
|
OverlayHookReady(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui_ImplDX9_NewFrame() && Windows_Hook::Inst()->_PrepareForOverlay(destWindow))
|
||||||
|
{
|
||||||
ImGui::NewFrame();
|
ImGui::NewFrame();
|
||||||
|
|
||||||
get_steam_client()->steam_overlay->OverlayProc();
|
OverlayProc();
|
||||||
|
|
||||||
ImGui::Render();
|
ImGui::Render();
|
||||||
|
|
||||||
|
@ -91,55 +155,72 @@ void DX9_Hook::prepareForOverlay(IDirect3DDevice9 *pDevice)
|
||||||
|
|
||||||
HRESULT STDMETHODCALLTYPE DX9_Hook::MyReset(IDirect3DDevice9* _this, D3DPRESENT_PARAMETERS* pPresentationParameters)
|
HRESULT STDMETHODCALLTYPE DX9_Hook::MyReset(IDirect3DDevice9* _this, D3DPRESENT_PARAMETERS* pPresentationParameters)
|
||||||
{
|
{
|
||||||
DX9_Hook::Inst()->resetRenderState();
|
auto inst = DX9_Hook::Inst();
|
||||||
return (_this->*DX9_Hook::Inst()->Reset)(pPresentationParameters);
|
inst->_ResetRenderState();
|
||||||
}
|
return (_this->*inst->Reset)(pPresentationParameters);
|
||||||
|
|
||||||
HRESULT STDMETHODCALLTYPE DX9_Hook::MyEndScene(IDirect3DDevice9* _this)
|
|
||||||
{
|
|
||||||
if( !DX9_Hook::Inst()->uses_present )
|
|
||||||
DX9_Hook::Inst()->prepareForOverlay(_this);
|
|
||||||
return (_this->*DX9_Hook::Inst()->EndScene)();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
HRESULT STDMETHODCALLTYPE DX9_Hook::MyPresent(IDirect3DDevice9* _this, CONST RECT* pSourceRect, CONST RECT* pDestRect, HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion)
|
HRESULT STDMETHODCALLTYPE DX9_Hook::MyPresent(IDirect3DDevice9* _this, CONST RECT* pSourceRect, CONST RECT* pDestRect, HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion)
|
||||||
{
|
{
|
||||||
DX9_Hook::Inst()->uses_present = true;
|
auto inst = DX9_Hook::Inst();
|
||||||
DX9_Hook::Inst()->prepareForOverlay(_this);
|
inst->_PrepareForOverlay(_this, hDestWindowOverride);
|
||||||
return (_this->*DX9_Hook::Inst()->Present)(pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion);
|
return (_this->*inst->Present)(pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion);
|
||||||
}
|
}
|
||||||
|
|
||||||
HRESULT STDMETHODCALLTYPE DX9_Hook::MyPresentEx(IDirect3DDevice9Ex* _this, CONST RECT* pSourceRect, CONST RECT* pDestRect, HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion, DWORD dwFlags)
|
HRESULT STDMETHODCALLTYPE DX9_Hook::MyPresentEx(IDirect3DDevice9Ex* _this, CONST RECT* pSourceRect, CONST RECT* pDestRect, HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion, DWORD dwFlags)
|
||||||
{
|
{
|
||||||
DX9_Hook::Inst()->uses_present = true;
|
auto inst = DX9_Hook::Inst();
|
||||||
DX9_Hook::Inst()->prepareForOverlay(_this);
|
inst->_PrepareForOverlay(_this, hDestWindowOverride);
|
||||||
return (_this->*DX9_Hook::Inst()->PresentEx)(pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, dwFlags);
|
return (_this->*inst->PresentEx)(pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, dwFlags);
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT STDMETHODCALLTYPE DX9_Hook::MySwapChainPresent(IDirect3DSwapChain9* _this, CONST RECT* pSourceRect, CONST RECT* pDestRect, HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion, DWORD dwFlags)
|
||||||
|
{
|
||||||
|
IDirect3DDevice9* pDevice;
|
||||||
|
auto inst = DX9_Hook::Inst();
|
||||||
|
|
||||||
|
if (SUCCEEDED(_this->GetDevice(&pDevice)))
|
||||||
|
{
|
||||||
|
HWND destWindow = hDestWindowOverride;
|
||||||
|
if (!destWindow)
|
||||||
|
{
|
||||||
|
D3DPRESENT_PARAMETERS param;
|
||||||
|
if (_this->GetPresentParameters(¶m) == D3D_OK)
|
||||||
|
{
|
||||||
|
destWindow = param.hDeviceWindow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inst->_PrepareForOverlay(pDevice, destWindow);
|
||||||
|
pDevice->Release();
|
||||||
|
}
|
||||||
|
return (_this->*inst->SwapChainPresent)(pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, dwFlags);
|
||||||
}
|
}
|
||||||
|
|
||||||
DX9_Hook::DX9_Hook():
|
DX9_Hook::DX9_Hook():
|
||||||
initialized(false),
|
_Initialized(false),
|
||||||
hooked(false),
|
_Hooked(false),
|
||||||
uses_present(false),
|
_WindowsHooked(false),
|
||||||
EndScene(nullptr),
|
_LastWindow(nullptr),
|
||||||
Present(nullptr),
|
Present(nullptr),
|
||||||
PresentEx(nullptr),
|
PresentEx(nullptr),
|
||||||
Reset(nullptr)
|
Reset(nullptr)
|
||||||
{
|
{
|
||||||
_library = LoadLibrary(DX9_DLL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DX9_Hook::~DX9_Hook()
|
DX9_Hook::~DX9_Hook()
|
||||||
{
|
{
|
||||||
PRINT_DEBUG("DX9 Hook removed\n");
|
SPDLOG_INFO("DX9 Hook removed");
|
||||||
|
|
||||||
if (initialized)
|
if (_WindowsHooked)
|
||||||
|
delete Windows_Hook::Inst();
|
||||||
|
|
||||||
|
if (_Initialized)
|
||||||
{
|
{
|
||||||
ImGui_ImplDX9_InvalidateDeviceObjects();
|
ImGui_ImplDX9_InvalidateDeviceObjects();
|
||||||
ImGui::DestroyContext();
|
ImGui::DestroyContext();
|
||||||
}
|
}
|
||||||
|
|
||||||
FreeLibrary(reinterpret_cast<HMODULE>(_library));
|
|
||||||
|
|
||||||
_inst = nullptr;
|
_inst = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -151,22 +232,94 @@ DX9_Hook* DX9_Hook::Inst()
|
||||||
return _inst;
|
return _inst;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* DX9_Hook::get_lib_name() const
|
std::string DX9_Hook::GetLibraryName() const
|
||||||
{
|
{
|
||||||
return DX9_DLL;
|
return LibraryName;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DX9_Hook::loadFunctions(IDirect3DDevice9* pDevice, bool ex)
|
void DX9_Hook::LoadFunctions(decltype(Present) PresentFcn, decltype(Reset) ResetFcn, decltype(PresentEx) PresentExFcn, decltype(&IDirect3DSwapChain9::Present) SwapChainPresentFcn)
|
||||||
{
|
{
|
||||||
void** vTable = *reinterpret_cast<void***>(pDevice);
|
Present = PresentFcn;
|
||||||
|
Reset = ResetFcn;
|
||||||
|
|
||||||
#define LOAD_FUNC(X) (void*&)X = vTable[(int)IDirect3DDevice9VTable::X]
|
PresentEx = PresentExFcn;
|
||||||
LOAD_FUNC(Reset);
|
|
||||||
LOAD_FUNC(EndScene);
|
SwapChainPresent = SwapChainPresentFcn;
|
||||||
LOAD_FUNC(Present);
|
|
||||||
if (ex)
|
|
||||||
LOAD_FUNC(PresentEx);
|
|
||||||
#undef LOAD_FUNC
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif//EMU_OVERLAY
|
std::weak_ptr<uint64_t> DX9_Hook::CreateImageResource(const void* image_data, uint32_t width, uint32_t height)
|
||||||
|
{
|
||||||
|
IDirect3DTexture9** pTexture = new IDirect3DTexture9*(nullptr);
|
||||||
|
|
||||||
|
_pDevice->CreateTexture(
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
1,
|
||||||
|
D3DUSAGE_DYNAMIC,
|
||||||
|
D3DFMT_A8R8G8B8,
|
||||||
|
D3DPOOL_DEFAULT,
|
||||||
|
pTexture,
|
||||||
|
nullptr
|
||||||
|
);
|
||||||
|
|
||||||
|
if (*pTexture != nullptr)
|
||||||
|
{
|
||||||
|
D3DLOCKED_RECT rect;
|
||||||
|
if (SUCCEEDED((*pTexture)->LockRect(0, &rect, nullptr, D3DLOCK_DISCARD)))
|
||||||
|
{
|
||||||
|
const uint32_t* pixels = reinterpret_cast<const uint32_t*>(image_data);
|
||||||
|
uint8_t* texture_bits = reinterpret_cast<uint8_t*>(rect.pBits);
|
||||||
|
for (int32_t i = 0; i < height; ++i)
|
||||||
|
{
|
||||||
|
for (int32_t j = 0; j < width; ++j)
|
||||||
|
{
|
||||||
|
// RGBA to ARGB Conversion, DX9 doesn't have a RGBA loader
|
||||||
|
uint32_t color = *pixels++;
|
||||||
|
reinterpret_cast<uint32_t*>(texture_bits)[j] = ((color & 0xff) << 16) | (color & 0xff00) | ((color & 0xff0000) >> 16) | (color & 0xff000000);
|
||||||
|
}
|
||||||
|
texture_bits += rect.Pitch;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FAILED((*pTexture)->UnlockRect(0)))
|
||||||
|
{
|
||||||
|
(*pTexture)->Release();
|
||||||
|
delete pTexture;
|
||||||
|
pTexture = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
(*pTexture)->Release();
|
||||||
|
delete pTexture;
|
||||||
|
pTexture = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pTexture == nullptr)
|
||||||
|
return std::shared_ptr<uint64_t>();
|
||||||
|
|
||||||
|
auto ptr = std::shared_ptr<uint64_t>((uint64_t*)pTexture, [](uint64_t* handle)
|
||||||
|
{
|
||||||
|
if (handle != nullptr)
|
||||||
|
{
|
||||||
|
IDirect3DTexture9** resource = reinterpret_cast<IDirect3DTexture9**>(handle);
|
||||||
|
(*resource)->Release();
|
||||||
|
delete resource;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
_ImageResources.emplace(ptr);
|
||||||
|
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DX9_Hook::ReleaseImageResource(std::weak_ptr<uint64_t> resource)
|
||||||
|
{
|
||||||
|
auto ptr = resource.lock();
|
||||||
|
if (ptr)
|
||||||
|
{
|
||||||
|
auto it = _ImageResources.find(ptr);
|
||||||
|
if (it != _ImageResources.end())
|
||||||
|
_ImageResources.erase(it);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,52 +1,75 @@
|
||||||
#ifndef __INCLUDED_DX9_HOOK_H__
|
/*
|
||||||
#define __INCLUDED_DX9_HOOK_H__
|
* Copyright (C) Nemirtingas
|
||||||
|
* This file is part of the ingame overlay project
|
||||||
|
*
|
||||||
|
* The ingame overlay project is free software; you can redistribute it
|
||||||
|
* and/or modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* The ingame overlay project 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
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with the ingame overlay project; if not, see
|
||||||
|
* <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
#include "../Base_Hook.h"
|
#pragma once
|
||||||
#ifdef EMU_OVERLAY
|
|
||||||
|
#include "../internal_includes.h"
|
||||||
|
|
||||||
#include <d3d9.h>
|
#include <d3d9.h>
|
||||||
#include "DirectX_VTables.h"
|
|
||||||
|
|
||||||
class DX9_Hook : public Base_Hook
|
class DX9_Hook :
|
||||||
|
public Renderer_Hook,
|
||||||
|
public Base_Hook
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
#define DX9_DLL "d3d9.dll"
|
static constexpr const char *DLL_NAME = "d3d9.dll";
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static DX9_Hook* _inst;
|
static DX9_Hook* _inst;
|
||||||
|
|
||||||
// Variables
|
// Variables
|
||||||
bool hooked;
|
bool _Hooked;
|
||||||
bool initialized;
|
bool _WindowsHooked;
|
||||||
bool uses_present;
|
bool _Initialized;
|
||||||
|
HWND _LastWindow;
|
||||||
|
IDirect3DDevice9* _pDevice;
|
||||||
|
std::set<std::shared_ptr<uint64_t>> _ImageResources;
|
||||||
|
|
||||||
// Functions
|
// Functions
|
||||||
DX9_Hook();
|
DX9_Hook();
|
||||||
|
|
||||||
void resetRenderState();
|
void _ResetRenderState();
|
||||||
void prepareForOverlay(IDirect3DDevice9* pDevice);
|
void _PrepareForOverlay(IDirect3DDevice9* pDevice, HWND destWindow);
|
||||||
|
|
||||||
// Hook to render functions
|
// Hook to render functions
|
||||||
decltype(&IDirect3DDevice9::Reset) Reset;
|
decltype(&IDirect3DDevice9::Reset) Reset;
|
||||||
decltype(&IDirect3DDevice9::EndScene) EndScene;
|
|
||||||
decltype(&IDirect3DDevice9::Present) Present;
|
decltype(&IDirect3DDevice9::Present) Present;
|
||||||
decltype(&IDirect3DDevice9Ex::PresentEx) PresentEx;
|
decltype(&IDirect3DDevice9Ex::PresentEx) PresentEx;
|
||||||
|
decltype(&IDirect3DSwapChain9::Present) SwapChainPresent;
|
||||||
|
|
||||||
static HRESULT STDMETHODCALLTYPE MyReset(IDirect3DDevice9* _this, D3DPRESENT_PARAMETERS* pPresentationParameters);
|
static HRESULT STDMETHODCALLTYPE MyReset(IDirect3DDevice9* _this, D3DPRESENT_PARAMETERS* pPresentationParameters);
|
||||||
static HRESULT STDMETHODCALLTYPE MyEndScene(IDirect3DDevice9 *_this);
|
|
||||||
static HRESULT STDMETHODCALLTYPE MyPresent(IDirect3DDevice9* _this, CONST RECT* pSourceRect, CONST RECT* pDestRect, HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion);
|
static HRESULT STDMETHODCALLTYPE MyPresent(IDirect3DDevice9* _this, CONST RECT* pSourceRect, CONST RECT* pDestRect, HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion);
|
||||||
static HRESULT STDMETHODCALLTYPE MyPresentEx(IDirect3DDevice9Ex* _this, CONST RECT* pSourceRect, CONST RECT* pDestRect, HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion, DWORD dwFlags);
|
static HRESULT STDMETHODCALLTYPE MyPresentEx(IDirect3DDevice9Ex* _this, CONST RECT* pSourceRect, CONST RECT* pDestRect, HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion, DWORD dwFlags);
|
||||||
|
static HRESULT STDMETHODCALLTYPE MySwapChainPresent(IDirect3DSwapChain9* _this, CONST RECT* pSourceRect, CONST RECT* pDestRect, HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion, DWORD dwFlags);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
std::string LibraryName;
|
||||||
|
|
||||||
virtual ~DX9_Hook();
|
virtual ~DX9_Hook();
|
||||||
|
|
||||||
bool start_hook();
|
virtual bool StartHook(std::function<bool(bool)> key_combination_callback);
|
||||||
|
virtual bool IsStarted();
|
||||||
static DX9_Hook* Inst();
|
static DX9_Hook* Inst();
|
||||||
virtual const char* get_lib_name() const;
|
virtual std::string GetLibraryName() const;
|
||||||
|
|
||||||
void loadFunctions(IDirect3DDevice9 *pDevice, bool ex);
|
void LoadFunctions(decltype(Present) PresentFcn, decltype(Reset) ResetFcn, decltype(PresentEx) PresentExFcn, decltype(&IDirect3DSwapChain9::Present) SwapChainPresentFcn);
|
||||||
|
|
||||||
|
virtual std::weak_ptr<uint64_t> CreateImageResource(const void* image_data, uint32_t width, uint32_t height);
|
||||||
|
virtual void ReleaseImageResource(std::weak_ptr<uint64_t> resource);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif//EMU_OVERLAY
|
|
||||||
|
|
||||||
#endif//__INCLUDED_DX9_HOOK_H__
|
|
||||||
|
|
|
@ -1,6 +1,23 @@
|
||||||
#pragma once
|
/*
|
||||||
|
* Copyright (C) Nemirtingas
|
||||||
|
* This file is part of the ingame overlay project
|
||||||
|
*
|
||||||
|
* The ingame overlay project is free software; you can redistribute it
|
||||||
|
* and/or modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* The ingame overlay project 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
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with the ingame overlay project; if not, see
|
||||||
|
* <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
#include <DXGI.h>
|
#pragma once
|
||||||
|
|
||||||
enum class IDXGISwapChainVTable
|
enum class IDXGISwapChainVTable
|
||||||
{
|
{
|
||||||
|
@ -446,3 +463,44 @@ enum class IDirect3DDevice9VTable
|
||||||
ResetEx,
|
ResetEx,
|
||||||
GetDisplayModeEx,
|
GetDisplayModeEx,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct IDirect3DSwapChain9VTable
|
||||||
|
{
|
||||||
|
enum class Index
|
||||||
|
{
|
||||||
|
// IUnknown
|
||||||
|
QueryInterface,
|
||||||
|
AddRef,
|
||||||
|
Release,
|
||||||
|
|
||||||
|
// IDirect3DSwapChain9
|
||||||
|
Present,
|
||||||
|
GetFrontBufferData,
|
||||||
|
GetBackBuffer,
|
||||||
|
GetRasterStatus,
|
||||||
|
GetDisplayMode,
|
||||||
|
GetDevice,
|
||||||
|
GetPresentParameters,
|
||||||
|
|
||||||
|
// IDirect3DSwapChain9Ex
|
||||||
|
GetLastPresentCount,
|
||||||
|
GetPresentStats,
|
||||||
|
GetDisplayModeEx,
|
||||||
|
};
|
||||||
|
|
||||||
|
decltype(&IDirect3DSwapChain9::QueryInterface) pQueryInterface;
|
||||||
|
decltype(&IDirect3DSwapChain9::AddRef) pAddRef;
|
||||||
|
decltype(&IDirect3DSwapChain9::Release) pRelease;
|
||||||
|
|
||||||
|
decltype(&IDirect3DSwapChain9::Present) pPresent;
|
||||||
|
decltype(&IDirect3DSwapChain9::GetFrontBufferData) pGetFrontBufferData;
|
||||||
|
decltype(&IDirect3DSwapChain9::GetBackBuffer) pGetBackBuffer;
|
||||||
|
decltype(&IDirect3DSwapChain9::GetRasterStatus) pGetRasterStatus;
|
||||||
|
decltype(&IDirect3DSwapChain9::GetDisplayMode) pGetDisplayMode;
|
||||||
|
decltype(&IDirect3DSwapChain9::GetDevice) pGetDevice;
|
||||||
|
decltype(&IDirect3DSwapChain9::GetPresentParameters) pGetPresentParameters;
|
||||||
|
|
||||||
|
decltype(&IDirect3DSwapChain9Ex::GetLastPresentCount) pGetLastPresentCount;
|
||||||
|
decltype(&IDirect3DSwapChain9Ex::GetPresentStats) pGetPresentStats;
|
||||||
|
decltype(&IDirect3DSwapChain9Ex::GetDisplayModeEx) pGetDisplayModeEx;
|
||||||
|
};
|
|
@ -1,35 +1,50 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) Nemirtingas
|
||||||
|
* This file is part of the ingame overlay project
|
||||||
|
*
|
||||||
|
* The ingame overlay project is free software; you can redistribute it
|
||||||
|
* and/or modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* The ingame overlay project 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
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with the ingame overlay project; if not, see
|
||||||
|
* <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
#include "OpenGL_Hook.h"
|
#include "OpenGL_Hook.h"
|
||||||
#include "Windows_Hook.h"
|
#include "Windows_Hook.h"
|
||||||
#include "../Renderer_Detector.h"
|
|
||||||
#include "../../dll/dll.h"
|
|
||||||
|
|
||||||
#ifdef EMU_OVERLAY
|
|
||||||
|
|
||||||
#include <imgui.h>
|
#include <imgui.h>
|
||||||
#include <impls/imgui_impl_opengl3.h>
|
#include <backends/imgui_impl_opengl3.h>
|
||||||
|
|
||||||
#include <GL/glew.h>
|
#include <glad/gl.h>
|
||||||
|
|
||||||
#include "../steam_overlay.h"
|
|
||||||
|
|
||||||
OpenGL_Hook* OpenGL_Hook::_inst = nullptr;
|
OpenGL_Hook* OpenGL_Hook::_inst = nullptr;
|
||||||
|
|
||||||
bool OpenGL_Hook::start_hook()
|
bool OpenGL_Hook::StartHook(std::function<bool(bool)> key_combination_callback)
|
||||||
{
|
{
|
||||||
bool res = true;
|
if (!_Hooked)
|
||||||
if (!hooked)
|
|
||||||
{
|
{
|
||||||
if (!Windows_Hook::Inst()->start_hook())
|
if (wglSwapBuffers == nullptr)
|
||||||
|
{
|
||||||
|
SPDLOG_WARN("Failed to hook OpenGL: Rendering functions missing.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Windows_Hook::Inst()->StartHook(key_combination_callback))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
GLenum err = glewInit();
|
_WindowsHooked = true;
|
||||||
|
|
||||||
if (err == GLEW_OK)
|
SPDLOG_INFO("Hooked OpenGL");
|
||||||
{
|
|
||||||
PRINT_DEBUG("Hooked OpenGL\n");
|
|
||||||
|
|
||||||
hooked = true;
|
_Hooked = true;
|
||||||
Renderer_Detector::Inst().renderer_found(this);
|
|
||||||
|
|
||||||
UnhookAll();
|
UnhookAll();
|
||||||
BeginHook();
|
BeginHook();
|
||||||
|
@ -37,60 +52,53 @@ bool OpenGL_Hook::start_hook()
|
||||||
std::make_pair<void**, void*>(&(PVOID&)wglSwapBuffers, &OpenGL_Hook::MywglSwapBuffers)
|
std::make_pair<void**, void*>(&(PVOID&)wglSwapBuffers, &OpenGL_Hook::MywglSwapBuffers)
|
||||||
);
|
);
|
||||||
EndHook();
|
EndHook();
|
||||||
|
|
||||||
get_steam_client()->steam_overlay->HookReady();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
PRINT_DEBUG("Failed to hook OpenGL\n");
|
|
||||||
/* Problem: glewInit failed, something is seriously wrong. */
|
|
||||||
PRINT_DEBUG("Error: %s\n", glewGetErrorString(err));
|
|
||||||
res = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGL_Hook::resetRenderState()
|
bool OpenGL_Hook::IsStarted()
|
||||||
{
|
{
|
||||||
if (initialized)
|
return _Hooked;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGL_Hook::_ResetRenderState()
|
||||||
{
|
{
|
||||||
|
if (_Initialized)
|
||||||
|
{
|
||||||
|
OverlayHookReady(false);
|
||||||
|
|
||||||
ImGui_ImplOpenGL3_Shutdown();
|
ImGui_ImplOpenGL3_Shutdown();
|
||||||
Windows_Hook::Inst()->resetRenderState();
|
Windows_Hook::Inst()->_ResetRenderState();
|
||||||
ImGui::DestroyContext();
|
ImGui::DestroyContext();
|
||||||
|
|
||||||
initialized = false;
|
last_window = nullptr;
|
||||||
|
_Initialized = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to make this function and overlay's proc as short as possible or it might affect game's fps.
|
// Try to make this function and overlay's proc as short as possible or it might affect game's fps.
|
||||||
void OpenGL_Hook::prepareForOverlay(HDC hDC)
|
void OpenGL_Hook::_PrepareForOverlay(HDC hDC)
|
||||||
{
|
{
|
||||||
HWND hWnd = WindowFromDC(hDC);
|
HWND hWnd = WindowFromDC(hDC);
|
||||||
|
|
||||||
if (hWnd != Windows_Hook::Inst()->GetGameHwnd())
|
if (hWnd != last_window)
|
||||||
resetRenderState();
|
_ResetRenderState();
|
||||||
|
|
||||||
if (!initialized)
|
if (!_Initialized)
|
||||||
{
|
{
|
||||||
ImGui::CreateContext();
|
ImGui::CreateContext();
|
||||||
ImGuiIO& io = ImGui::GetIO();
|
|
||||||
io.IniFilename = NULL;
|
|
||||||
|
|
||||||
ImGui_ImplOpenGL3_Init();
|
ImGui_ImplOpenGL3_Init();
|
||||||
|
|
||||||
get_steam_client()->steam_overlay->CreateFonts();
|
last_window = hWnd;
|
||||||
|
_Initialized = true;
|
||||||
initialized = true;
|
OverlayHookReady(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ImGui_ImplOpenGL3_NewFrame())
|
if (ImGui_ImplOpenGL3_NewFrame() && Windows_Hook::Inst()->_PrepareForOverlay(hWnd))
|
||||||
{
|
{
|
||||||
Windows_Hook::Inst()->prepareForOverlay(hWnd);
|
|
||||||
|
|
||||||
ImGui::NewFrame();
|
ImGui::NewFrame();
|
||||||
|
|
||||||
get_steam_client()->steam_overlay->OverlayProc();
|
OverlayProc();
|
||||||
|
|
||||||
ImGui::Render();
|
ImGui::Render();
|
||||||
|
|
||||||
|
@ -100,30 +108,33 @@ void OpenGL_Hook::prepareForOverlay(HDC hDC)
|
||||||
|
|
||||||
BOOL WINAPI OpenGL_Hook::MywglSwapBuffers(HDC hDC)
|
BOOL WINAPI OpenGL_Hook::MywglSwapBuffers(HDC hDC)
|
||||||
{
|
{
|
||||||
OpenGL_Hook::Inst()->prepareForOverlay(hDC);
|
auto inst = OpenGL_Hook::Inst();
|
||||||
return OpenGL_Hook::Inst()->wglSwapBuffers(hDC);
|
inst->_PrepareForOverlay(hDC);
|
||||||
|
return inst->wglSwapBuffers(hDC);
|
||||||
}
|
}
|
||||||
|
|
||||||
OpenGL_Hook::OpenGL_Hook():
|
OpenGL_Hook::OpenGL_Hook():
|
||||||
initialized(false),
|
_Hooked(false),
|
||||||
hooked(false),
|
_WindowsHooked(false),
|
||||||
|
_Initialized(false),
|
||||||
|
last_window(nullptr),
|
||||||
wglSwapBuffers(nullptr)
|
wglSwapBuffers(nullptr)
|
||||||
{
|
{
|
||||||
_library = LoadLibrary(OPENGL_DLL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
OpenGL_Hook::~OpenGL_Hook()
|
OpenGL_Hook::~OpenGL_Hook()
|
||||||
{
|
{
|
||||||
PRINT_DEBUG("OpenGL Hook removed\n");
|
SPDLOG_INFO("OpenGL Hook removed");
|
||||||
|
|
||||||
if (initialized)
|
if (_WindowsHooked)
|
||||||
|
delete Windows_Hook::Inst();
|
||||||
|
|
||||||
|
if (_Initialized)
|
||||||
{
|
{
|
||||||
ImGui_ImplOpenGL3_Shutdown();
|
ImGui_ImplOpenGL3_Shutdown();
|
||||||
ImGui::DestroyContext();
|
ImGui::DestroyContext();
|
||||||
}
|
}
|
||||||
|
|
||||||
FreeLibrary(reinterpret_cast<HMODULE>(_library));
|
|
||||||
|
|
||||||
_inst = nullptr;
|
_inst = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -135,14 +146,62 @@ OpenGL_Hook* OpenGL_Hook::Inst()
|
||||||
return _inst;
|
return _inst;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* OpenGL_Hook::get_lib_name() const
|
std::string OpenGL_Hook::GetLibraryName() const
|
||||||
{
|
{
|
||||||
return OPENGL_DLL;
|
return LibraryName;
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGL_Hook::loadFunctions(wglSwapBuffers_t pfnwglSwapBuffers)
|
void OpenGL_Hook::LoadFunctions(wglSwapBuffers_t pfnwglSwapBuffers)
|
||||||
{
|
{
|
||||||
wglSwapBuffers = pfnwglSwapBuffers;
|
wglSwapBuffers = pfnwglSwapBuffers;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif//EMU_OVERLAY
|
std::weak_ptr<uint64_t> OpenGL_Hook::CreateImageResource(const void* image_data, uint32_t width, uint32_t height)
|
||||||
|
{
|
||||||
|
GLuint* texture = new GLuint(0);
|
||||||
|
glGenTextures(1, texture);
|
||||||
|
if (glGetError() != GL_NO_ERROR)
|
||||||
|
{
|
||||||
|
delete texture;
|
||||||
|
return std::shared_ptr<uint64_t>(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save old texture id
|
||||||
|
GLint oldTex;
|
||||||
|
glGetIntegerv(GL_TEXTURE_BINDING_2D, &oldTex);
|
||||||
|
|
||||||
|
glBindTexture(GL_TEXTURE_2D, *texture);
|
||||||
|
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
|
|
||||||
|
// Upload pixels into texture
|
||||||
|
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, image_data);
|
||||||
|
|
||||||
|
glBindTexture(GL_TEXTURE_2D, oldTex);
|
||||||
|
|
||||||
|
auto ptr = std::shared_ptr<uint64_t>((uint64_t*)texture, [](uint64_t* handle)
|
||||||
|
{
|
||||||
|
if (handle != nullptr)
|
||||||
|
{
|
||||||
|
GLuint* texture = (GLuint*)handle;
|
||||||
|
glDeleteTextures(1, texture);
|
||||||
|
delete texture;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
_ImageResources.emplace(ptr);
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGL_Hook::ReleaseImageResource(std::weak_ptr<uint64_t> resource)
|
||||||
|
{
|
||||||
|
auto ptr = resource.lock();
|
||||||
|
if (ptr)
|
||||||
|
{
|
||||||
|
auto it = _ImageResources.find(ptr);
|
||||||
|
if (it != _ImageResources.end())
|
||||||
|
_ImageResources.erase(it);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,13 +1,32 @@
|
||||||
#ifndef __INCLUDED_OPENGL_HOOK_H__
|
/*
|
||||||
#define __INCLUDED_OPENGL_HOOK_H__
|
* Copyright (C) Nemirtingas
|
||||||
|
* This file is part of the ingame overlay project
|
||||||
|
*
|
||||||
|
* The ingame overlay project is free software; you can redistribute it
|
||||||
|
* and/or modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* The ingame overlay project 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
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with the ingame overlay project; if not, see
|
||||||
|
* <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
#include "../Base_Hook.h"
|
#pragma once
|
||||||
#ifdef EMU_OVERLAY
|
|
||||||
|
|
||||||
class OpenGL_Hook : public Base_Hook
|
#include "../internal_includes.h"
|
||||||
|
|
||||||
|
class OpenGL_Hook :
|
||||||
|
public Renderer_Hook,
|
||||||
|
public Base_Hook
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
#define OPENGL_DLL "opengl32.dll"
|
static constexpr const char *DLL_NAME = "opengl32.dll";
|
||||||
|
|
||||||
using wglSwapBuffers_t = BOOL(WINAPI*)(HDC);
|
using wglSwapBuffers_t = BOOL(WINAPI*)(HDC);
|
||||||
|
|
||||||
|
@ -15,14 +34,17 @@ private:
|
||||||
static OpenGL_Hook* _inst;
|
static OpenGL_Hook* _inst;
|
||||||
|
|
||||||
// Variables
|
// Variables
|
||||||
bool hooked;
|
bool _Hooked;
|
||||||
bool initialized;
|
bool _WindowsHooked;
|
||||||
|
bool _Initialized;
|
||||||
|
HWND last_window;
|
||||||
|
std::set<std::shared_ptr<uint64_t>> _ImageResources;
|
||||||
|
|
||||||
// Functions
|
// Functions
|
||||||
OpenGL_Hook();
|
OpenGL_Hook();
|
||||||
|
|
||||||
void resetRenderState();
|
void _ResetRenderState();
|
||||||
void prepareForOverlay(HDC hDC);
|
void _PrepareForOverlay(HDC hDC);
|
||||||
|
|
||||||
// Hook to render functions
|
// Hook to render functions
|
||||||
static BOOL WINAPI MywglSwapBuffers(HDC hDC);
|
static BOOL WINAPI MywglSwapBuffers(HDC hDC);
|
||||||
|
@ -30,13 +52,16 @@ private:
|
||||||
wglSwapBuffers_t wglSwapBuffers;
|
wglSwapBuffers_t wglSwapBuffers;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
std::string LibraryName;
|
||||||
|
|
||||||
virtual ~OpenGL_Hook();
|
virtual ~OpenGL_Hook();
|
||||||
|
|
||||||
bool start_hook();
|
virtual bool StartHook(std::function<bool(bool)> key_combination_callback);
|
||||||
|
virtual bool IsStarted();
|
||||||
static OpenGL_Hook* Inst();
|
static OpenGL_Hook* Inst();
|
||||||
virtual const char* get_lib_name() const;
|
virtual std::string GetLibraryName() const;
|
||||||
void loadFunctions(wglSwapBuffers_t pfnwglSwapBuffers);
|
void LoadFunctions(wglSwapBuffers_t pfnwglSwapBuffers);
|
||||||
};
|
|
||||||
|
|
||||||
#endif//EMU_OVERLAY
|
virtual std::weak_ptr<uint64_t> CreateImageResource(const void* image_data, uint32_t width, uint32_t height);
|
||||||
#endif//__INCLUDED_OPENGL_HOOK_H__
|
virtual void ReleaseImageResource(std::weak_ptr<uint64_t> resource);
|
||||||
|
};
|
||||||
|
|
|
@ -0,0 +1,128 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) Nemirtingas
|
||||||
|
* This file is part of the ingame overlay project
|
||||||
|
*
|
||||||
|
* The ingame overlay project is free software; you can redistribute it
|
||||||
|
* and/or modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* The ingame overlay project 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
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with the ingame overlay project; if not, see
|
||||||
|
* <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "Vulkan_Hook.h"
|
||||||
|
#include "Windows_Hook.h"
|
||||||
|
|
||||||
|
#include <imgui.h>
|
||||||
|
#include <backends/imgui_impl_vulkan.h>
|
||||||
|
|
||||||
|
Vulkan_Hook* Vulkan_Hook::_inst = nullptr;
|
||||||
|
|
||||||
|
bool Vulkan_Hook::StartHook(std::function<bool(bool)> key_combination_callback)
|
||||||
|
{
|
||||||
|
SPDLOG_WARN("Vulkan overlay is not yet supported.");
|
||||||
|
return false;
|
||||||
|
if (!_Hooked)
|
||||||
|
{
|
||||||
|
if (vkQueuePresentKHR == nullptr)
|
||||||
|
{
|
||||||
|
SPDLOG_WARN("Failed to hook Vulkan: Rendering functions missing.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Windows_Hook::Inst()->StartHook(key_combination_callback))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
_WindowsHooked = true;
|
||||||
|
|
||||||
|
SPDLOG_INFO("Hooked Vulkan");
|
||||||
|
_Hooked = true;
|
||||||
|
|
||||||
|
BeginHook();
|
||||||
|
HookFuncs(
|
||||||
|
std::make_pair<void**, void*>(&(PVOID&)vkQueuePresentKHR, &Vulkan_Hook::MyvkQueuePresentKHR)
|
||||||
|
);
|
||||||
|
EndHook();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Vulkan_Hook::IsStarted()
|
||||||
|
{
|
||||||
|
return _Hooked;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Vulkan_Hook::_ResetRenderState()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to make this function and overlay's proc as short as possible or it might affect game's fps.
|
||||||
|
void Vulkan_Hook::_PrepareForOverlay()
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
VKAPI_ATTR VkResult VKAPI_CALL Vulkan_Hook::MyvkQueuePresentKHR(VkQueue queue, const VkPresentInfoKHR* pPresentInfo)
|
||||||
|
{
|
||||||
|
auto inst = Vulkan_Hook::Inst();
|
||||||
|
inst->_PrepareForOverlay();
|
||||||
|
return inst->vkQueuePresentKHR(queue, pPresentInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
Vulkan_Hook::Vulkan_Hook():
|
||||||
|
_Hooked(false),
|
||||||
|
_WindowsHooked(false),
|
||||||
|
_Initialized(false),
|
||||||
|
vkQueuePresentKHR(nullptr)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Vulkan_Hook::~Vulkan_Hook()
|
||||||
|
{
|
||||||
|
SPDLOG_INFO("Vulkan_Hook Hook removed");
|
||||||
|
|
||||||
|
if (_WindowsHooked)
|
||||||
|
delete Windows_Hook::Inst();
|
||||||
|
|
||||||
|
if (_Initialized)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
_inst = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vulkan_Hook* Vulkan_Hook::Inst()
|
||||||
|
{
|
||||||
|
if (_inst == nullptr)
|
||||||
|
_inst = new Vulkan_Hook;
|
||||||
|
|
||||||
|
return _inst;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Vulkan_Hook::GetLibraryName() const
|
||||||
|
{
|
||||||
|
return LibraryName;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Vulkan_Hook::LoadFunctions(decltype(::vkQueuePresentKHR)* _vkQueuePresentKHR)
|
||||||
|
{
|
||||||
|
vkQueuePresentKHR = _vkQueuePresentKHR;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::weak_ptr<uint64_t> Vulkan_Hook::CreateImageResource(const void* image_data, uint32_t width, uint32_t height)
|
||||||
|
{
|
||||||
|
return std::shared_ptr<uint64_t>(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Vulkan_Hook::ReleaseImageResource(std::weak_ptr<uint64_t> resource)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,65 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) Nemirtingas
|
||||||
|
* This file is part of the ingame overlay project
|
||||||
|
*
|
||||||
|
* The ingame overlay project is free software; you can redistribute it
|
||||||
|
* and/or modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* The ingame overlay project 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
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with the ingame overlay project; if not, see
|
||||||
|
* <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "../internal_includes.h"
|
||||||
|
|
||||||
|
#include <vulkan/vulkan.h>
|
||||||
|
|
||||||
|
class Vulkan_Hook :
|
||||||
|
public Renderer_Hook,
|
||||||
|
public Base_Hook
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static constexpr const char *DLL_NAME = "vulkan-1.dll";
|
||||||
|
|
||||||
|
private:
|
||||||
|
static Vulkan_Hook* _inst;
|
||||||
|
|
||||||
|
// Variables
|
||||||
|
bool _Hooked;
|
||||||
|
bool _WindowsHooked;
|
||||||
|
bool _Initialized;
|
||||||
|
|
||||||
|
// Functions
|
||||||
|
Vulkan_Hook();
|
||||||
|
|
||||||
|
void _ResetRenderState();
|
||||||
|
void _PrepareForOverlay();
|
||||||
|
|
||||||
|
// Hook to render functions
|
||||||
|
static VKAPI_ATTR VkResult VKAPI_CALL MyvkQueuePresentKHR(VkQueue queue, const VkPresentInfoKHR* pPresentInfo);
|
||||||
|
|
||||||
|
decltype(::vkQueuePresentKHR)* vkQueuePresentKHR;
|
||||||
|
|
||||||
|
public:
|
||||||
|
std::string LibraryName;
|
||||||
|
|
||||||
|
virtual ~Vulkan_Hook();
|
||||||
|
|
||||||
|
virtual bool StartHook(std::function<bool(bool)> key_combination_callback);
|
||||||
|
virtual bool IsStarted();
|
||||||
|
static Vulkan_Hook* Inst();
|
||||||
|
virtual std::string GetLibraryName() const;
|
||||||
|
void LoadFunctions(decltype(::vkQueuePresentKHR)* _vkQueuePresentKHR);
|
||||||
|
|
||||||
|
virtual std::weak_ptr<uint64_t> CreateImageResource(const void* image_data, uint32_t width, uint32_t height);
|
||||||
|
virtual void ReleaseImageResource(std::weak_ptr<uint64_t> resource);
|
||||||
|
};
|
|
@ -1,75 +1,152 @@
|
||||||
#include "Windows_Hook.h"
|
/*
|
||||||
#include "../Renderer_Detector.h"
|
* Copyright (C) Nemirtingas
|
||||||
#include "../../dll/dll.h"
|
* This file is part of the ingame overlay project
|
||||||
|
*
|
||||||
|
* The ingame overlay project is free software; you can redistribute it
|
||||||
|
* and/or modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* The ingame overlay project 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
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with the ingame overlay project; if not, see
|
||||||
|
* <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
#ifdef EMU_OVERLAY
|
#include "Windows_Hook.h"
|
||||||
|
|
||||||
#include <imgui.h>
|
#include <imgui.h>
|
||||||
#include <impls/windows/imgui_impl_win32.h>
|
#include <backends/imgui_impl_win32.h>
|
||||||
|
#include <System/Library.h>
|
||||||
|
|
||||||
extern LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
|
extern LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
|
||||||
|
|
||||||
|
constexpr decltype(Windows_Hook::DLL_NAME) Windows_Hook::DLL_NAME;
|
||||||
|
|
||||||
Windows_Hook* Windows_Hook::_inst = nullptr;
|
Windows_Hook* Windows_Hook::_inst = nullptr;
|
||||||
|
|
||||||
bool Windows_Hook::start_hook()
|
bool Windows_Hook::StartHook(std::function<bool(bool)>& _key_combination_callback)
|
||||||
{
|
{
|
||||||
bool res = true;
|
if (!_Hooked)
|
||||||
if (!hooked)
|
|
||||||
{
|
{
|
||||||
GetRawInputBuffer = ::GetRawInputBuffer;
|
void* hUser32 = System::Library::GetLibraryHandle(DLL_NAME);
|
||||||
GetRawInputData = ::GetRawInputData;
|
if (hUser32 == nullptr)
|
||||||
SetCursorPos = ::SetCursorPos;
|
{
|
||||||
|
SPDLOG_WARN("Failed to hook Windows: Cannot find {}", DLL_NAME);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
PRINT_DEBUG("Hooked Windows\n");
|
System::Library::Library libUser32;
|
||||||
|
LibraryName = System::Library::GetLibraryPath(hUser32);
|
||||||
|
if (!libUser32.OpenLibrary(LibraryName, false))
|
||||||
|
{
|
||||||
|
SPDLOG_WARN("Failed to hook Windows: Cannot load {}", LibraryName);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
GetRawInputBuffer = libUser32.GetSymbol<decltype(::GetRawInputBuffer)>("GetRawInputBuffer");
|
||||||
|
GetRawInputData = libUser32.GetSymbol<decltype(::GetRawInputData)>("GetRawInputData");
|
||||||
|
GetKeyState = libUser32.GetSymbol<decltype(::GetKeyState)>("GetKeyState");
|
||||||
|
GetAsyncKeyState = libUser32.GetSymbol<decltype(::GetAsyncKeyState)>("GetAsyncKeyState");
|
||||||
|
GetKeyboardState = libUser32.GetSymbol<decltype(::GetKeyboardState)>("GetKeyboardState");
|
||||||
|
GetCursorPos = libUser32.GetSymbol<decltype(::GetCursorPos)>("GetCursorPos");
|
||||||
|
SetCursorPos = libUser32.GetSymbol<decltype(::SetCursorPos)>("SetCursorPos");
|
||||||
|
|
||||||
|
if(GetRawInputBuffer == nullptr ||
|
||||||
|
GetRawInputData == nullptr ||
|
||||||
|
GetKeyState == nullptr ||
|
||||||
|
GetAsyncKeyState == nullptr ||
|
||||||
|
GetKeyboardState == nullptr ||
|
||||||
|
GetCursorPos == nullptr ||
|
||||||
|
SetCursorPos == nullptr)
|
||||||
|
{
|
||||||
|
SPDLOG_ERROR("Failed to hook Windows: Events functions missing.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
SPDLOG_INFO("Hooked Windows");
|
||||||
|
_KeyCombinationCallback = std::move(_key_combination_callback);
|
||||||
|
|
||||||
BeginHook();
|
BeginHook();
|
||||||
HookFuncs(
|
HookFuncs(
|
||||||
std::make_pair<void**, void*>(&(PVOID&)GetRawInputBuffer, &Windows_Hook::MyGetRawInputBuffer),
|
std::make_pair<void**, void*>(&(PVOID&)GetRawInputBuffer, &Windows_Hook::MyGetRawInputBuffer),
|
||||||
std::make_pair<void**, void*>(&(PVOID&)GetRawInputData , &Windows_Hook::MyGetRawInputData),
|
std::make_pair<void**, void*>(&(PVOID&)GetRawInputData , &Windows_Hook::MyGetRawInputData),
|
||||||
|
std::make_pair<void**, void*>(&(PVOID&)GetKeyState , &Windows_Hook::MyGetKeyState),
|
||||||
|
std::make_pair<void**, void*>(&(PVOID&)GetAsyncKeyState , &Windows_Hook::MyGetAsyncKeyState),
|
||||||
|
std::make_pair<void**, void*>(&(PVOID&)GetKeyboardState , &Windows_Hook::MyGetKeyboardState),
|
||||||
|
std::make_pair<void**, void*>(&(PVOID&)GetCursorPos , &Windows_Hook::MyGetCursorPos),
|
||||||
std::make_pair<void**, void*>(&(PVOID&)SetCursorPos , &Windows_Hook::MySetCursorPos)
|
std::make_pair<void**, void*>(&(PVOID&)SetCursorPos , &Windows_Hook::MySetCursorPos)
|
||||||
);
|
);
|
||||||
EndHook();
|
EndHook();
|
||||||
|
|
||||||
hooked = true;
|
_Hooked = true;
|
||||||
}
|
}
|
||||||
return res;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Windows_Hook::resetRenderState()
|
void Windows_Hook::_ResetRenderState()
|
||||||
{
|
{
|
||||||
if (initialized)
|
if (_Initialized)
|
||||||
{
|
{
|
||||||
initialized = false;
|
_Initialized = false;
|
||||||
SetWindowLongPtr(_game_hwnd, GWLP_WNDPROC, (LONG_PTR)_game_wndproc);
|
SetWindowLongPtr(_GameHwnd, GWLP_WNDPROC, (LONG_PTR)_GameWndProc);
|
||||||
_game_hwnd = nullptr;
|
_GameHwnd = nullptr;
|
||||||
_game_wndproc = nullptr;
|
_GameWndProc = nullptr;
|
||||||
ImGui_ImplWin32_Shutdown();
|
ImGui_ImplWin32_Shutdown();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Windows_Hook::prepareForOverlay(HWND hWnd)
|
bool Windows_Hook::_PrepareForOverlay(HWND hWnd)
|
||||||
{
|
{
|
||||||
if (!initialized)
|
if (_GameHwnd != hWnd)
|
||||||
|
_ResetRenderState();
|
||||||
|
|
||||||
|
if (!_Initialized)
|
||||||
{
|
{
|
||||||
ImGui_ImplWin32_Init(hWnd);
|
_GameHwnd = hWnd;
|
||||||
|
ImGui_ImplWin32_Init(_GameHwnd);
|
||||||
|
|
||||||
_game_hwnd = hWnd;
|
_GameWndProc = (WNDPROC)SetWindowLongPtr(_GameHwnd, GWLP_WNDPROC, (LONG_PTR)&Windows_Hook::HookWndProc);
|
||||||
_game_wndproc = (WNDPROC)SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)&Windows_Hook::HookWndProc);
|
_Initialized = true;
|
||||||
|
|
||||||
initialized = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_Initialized)
|
||||||
|
{
|
||||||
|
void* current_proc = (void*)GetWindowLongPtr(_GameHwnd, GWLP_WNDPROC);
|
||||||
|
if (current_proc == nullptr)
|
||||||
|
return false;
|
||||||
|
|
||||||
ImGui_ImplWin32_NewFrame();
|
ImGui_ImplWin32_NewFrame();
|
||||||
|
// Read keyboard modifiers inputs
|
||||||
|
auto& io = ImGui::GetIO();
|
||||||
|
|
||||||
|
POINT pos;
|
||||||
|
if (this->GetCursorPos(&pos) && ScreenToClient(hWnd, &pos))
|
||||||
|
{
|
||||||
|
io.MousePos = ImVec2((float)pos.x, (float)pos.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
io.KeyCtrl = (this->GetKeyState(VK_CONTROL) & 0x8000) != 0;
|
||||||
|
io.KeyShift = (this->GetKeyState(VK_SHIFT) & 0x8000) != 0;
|
||||||
|
io.KeyAlt = (this->GetKeyState(VK_MENU) & 0x8000) != 0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
HWND Windows_Hook::GetGameHwnd() const
|
HWND Windows_Hook::GetGameHwnd() const
|
||||||
{
|
{
|
||||||
return _game_hwnd;
|
return _GameHwnd;
|
||||||
}
|
}
|
||||||
|
|
||||||
WNDPROC Windows_Hook::GetGameWndProc() const
|
WNDPROC Windows_Hook::GetGameWndProc() const
|
||||||
{
|
{
|
||||||
return _game_wndproc;
|
return _GameWndProc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -97,29 +174,43 @@ bool IgnoreMsg(UINT uMsg)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RawMouseEvent(RAWINPUT& raw)
|
void RawEvent(RAWINPUT& raw)
|
||||||
{
|
{
|
||||||
if (raw.header.dwType == RIM_TYPEMOUSE)
|
HWND hWnd = Windows_Hook::Inst()->GetGameHwnd();
|
||||||
|
switch(raw.header.dwType)
|
||||||
{
|
{
|
||||||
|
case RIM_TYPEMOUSE:
|
||||||
if (raw.data.mouse.usButtonFlags & RI_MOUSE_LEFT_BUTTON_DOWN)
|
if (raw.data.mouse.usButtonFlags & RI_MOUSE_LEFT_BUTTON_DOWN)
|
||||||
ImGui_ImplWin32_WndProcHandler(Windows_Hook::Inst()->GetGameHwnd(), WM_LBUTTONDOWN, 0, 0);
|
ImGui_ImplWin32_WndProcHandler(hWnd, WM_LBUTTONDOWN, 0, 0);
|
||||||
else if (raw.data.mouse.usButtonFlags & RI_MOUSE_LEFT_BUTTON_UP)
|
if (raw.data.mouse.usButtonFlags & RI_MOUSE_LEFT_BUTTON_UP)
|
||||||
ImGui_ImplWin32_WndProcHandler(Windows_Hook::Inst()->GetGameHwnd(), WM_LBUTTONUP, 0, 0);
|
ImGui_ImplWin32_WndProcHandler(hWnd, WM_LBUTTONUP, 0, 0);
|
||||||
else if (raw.data.mouse.usButtonFlags & RI_MOUSE_MIDDLE_BUTTON_DOWN)
|
if (raw.data.mouse.usButtonFlags & RI_MOUSE_RIGHT_BUTTON_DOWN)
|
||||||
ImGui_ImplWin32_WndProcHandler(Windows_Hook::Inst()->GetGameHwnd(), WM_MBUTTONDOWN, 0, 0);
|
ImGui_ImplWin32_WndProcHandler(hWnd, WM_RBUTTONDOWN, 0, 0);
|
||||||
else if (raw.data.mouse.usButtonFlags & RI_MOUSE_MIDDLE_BUTTON_UP)
|
if (raw.data.mouse.usButtonFlags & RI_MOUSE_RIGHT_BUTTON_UP)
|
||||||
ImGui_ImplWin32_WndProcHandler(Windows_Hook::Inst()->GetGameHwnd(), WM_MBUTTONUP, 0, 0);
|
ImGui_ImplWin32_WndProcHandler(hWnd, WM_RBUTTONUP, 0, 0);
|
||||||
else if (raw.data.mouse.usButtonFlags & RI_MOUSE_RIGHT_BUTTON_DOWN)
|
if (raw.data.mouse.usButtonFlags & RI_MOUSE_MIDDLE_BUTTON_DOWN)
|
||||||
ImGui_ImplWin32_WndProcHandler(Windows_Hook::Inst()->GetGameHwnd(), WM_RBUTTONDOWN, 0, 0);
|
ImGui_ImplWin32_WndProcHandler(hWnd, WM_MBUTTONDOWN, 0, 0);
|
||||||
else if (raw.data.mouse.usButtonFlags & RI_MOUSE_RIGHT_BUTTON_UP)
|
if (raw.data.mouse.usButtonFlags & RI_MOUSE_MIDDLE_BUTTON_UP)
|
||||||
ImGui_ImplWin32_WndProcHandler(Windows_Hook::Inst()->GetGameHwnd(), WM_RBUTTONUP, 0, 0);
|
ImGui_ImplWin32_WndProcHandler(hWnd, WM_MBUTTONUP, 0, 0);
|
||||||
|
if (raw.data.mouse.usButtonFlags & RI_MOUSE_WHEEL)
|
||||||
|
ImGui_ImplWin32_WndProcHandler(hWnd, WM_MOUSEWHEEL, ((WPARAM)raw.data.mouse.usButtonData) << 16, 0);
|
||||||
|
if (raw.data.mouse.usButtonFlags & RI_MOUSE_HWHEEL)
|
||||||
|
ImGui_ImplWin32_WndProcHandler(hWnd, WM_MOUSEHWHEEL, ((WPARAM)raw.data.mouse.usButtonData) << 16, 0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
//case RIM_TYPEKEYBOARD:
|
||||||
|
//ImGui_ImplWin32_WndProcHandler(hWnd, raw.data.keyboard.Message, raw.data.keyboard.VKey, 0);
|
||||||
|
//break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LRESULT CALLBACK Windows_Hook::HookWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
LRESULT CALLBACK Windows_Hook::HookWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||||
{
|
{
|
||||||
Steam_Overlay* overlay = get_steam_client()->steam_overlay;
|
Windows_Hook* inst = Windows_Hook::Inst();
|
||||||
bool show = overlay->ShowOverlay();
|
bool skip_input = inst->_KeyCombinationCallback(false);
|
||||||
|
bool clean_keys = false;
|
||||||
|
if (inst->_Initialized)
|
||||||
|
{
|
||||||
// Is the event is a key press
|
// Is the event is a key press
|
||||||
if (uMsg == WM_KEYDOWN)
|
if (uMsg == WM_KEYDOWN)
|
||||||
{
|
{
|
||||||
|
@ -127,82 +218,163 @@ LRESULT CALLBACK Windows_Hook::HookWndProc(HWND hWnd, UINT uMsg, WPARAM wParam,
|
||||||
if (wParam == VK_TAB && !(lParam & (1 << 30)))
|
if (wParam == VK_TAB && !(lParam & (1 << 30)))
|
||||||
{
|
{
|
||||||
// If Left Shift is pressed
|
// If Left Shift is pressed
|
||||||
if (GetAsyncKeyState(VK_LSHIFT) & (1 << 15))
|
if (inst->GetAsyncKeyState(VK_LSHIFT) & (1 << 15))
|
||||||
{
|
{
|
||||||
show = !overlay->ShowOverlay();
|
if (inst->_KeyCombinationCallback(true))
|
||||||
overlay->ShowOverlay(show);
|
{
|
||||||
|
skip_input = true;
|
||||||
|
// Save the last known cursor pos when opening the overlay
|
||||||
|
// so we can spoof the GetCursorPos return value.
|
||||||
|
inst->GetCursorPos(&inst->_SavedCursorPos);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
clean_keys = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui_ImplWin32_WndProcHandler(hWnd, uMsg, wParam, lParam);
|
if (skip_input && IgnoreMsg(uMsg))
|
||||||
if (show)
|
|
||||||
{
|
{
|
||||||
if (IgnoreMsg(uMsg))
|
ImGui_ImplWin32_WndProcHandler(hWnd, uMsg, wParam, lParam);
|
||||||
|
if (clean_keys)
|
||||||
|
{
|
||||||
|
auto& io = ImGui::GetIO();
|
||||||
|
memset(io.KeysDown, 0, sizeof(io.KeysDown));
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Protect against recursive call of the WindowProc...
|
||||||
|
if (inst->_RecurseCallCount > 16)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
++inst->_RecurseCallCount;
|
||||||
// Call the overlay window procedure
|
// Call the overlay window procedure
|
||||||
return CallWindowProc(Windows_Hook::Inst()->_game_wndproc, hWnd, uMsg, wParam, lParam);
|
auto res = CallWindowProc(Windows_Hook::Inst()->_GameWndProc, hWnd, uMsg, wParam, lParam);
|
||||||
|
--inst->_RecurseCallCount;
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
UINT WINAPI Windows_Hook::MyGetRawInputBuffer(PRAWINPUT pData, PUINT pcbSize, UINT cbSizeHeader)
|
UINT WINAPI Windows_Hook::MyGetRawInputBuffer(PRAWINPUT pData, PUINT pcbSize, UINT cbSizeHeader)
|
||||||
{
|
{
|
||||||
if (pData == nullptr || !get_steam_client()->steam_overlay->ShowOverlay())
|
Windows_Hook* inst = Windows_Hook::Inst();
|
||||||
return Windows_Hook::Inst()->GetRawInputBuffer(pData, pcbSize, cbSizeHeader);
|
int res = inst->GetRawInputBuffer(pData, pcbSize, cbSizeHeader);
|
||||||
|
if (!inst->_Initialized)
|
||||||
|
return res;
|
||||||
|
|
||||||
int num = Windows_Hook::Inst()->GetRawInputBuffer(pData, pcbSize, cbSizeHeader);
|
if (pData != nullptr)
|
||||||
for (int i = 0; i < num; ++i)
|
{
|
||||||
RawMouseEvent(pData[i]);
|
for (int i = 0; i < res; ++i)
|
||||||
|
RawEvent(pData[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!inst->_KeyCombinationCallback(false))
|
||||||
|
return res;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
UINT WINAPI Windows_Hook::MyGetRawInputData(HRAWINPUT hRawInput, UINT uiCommand, LPVOID pData, PUINT pcbSize, UINT cbSizeHeader)
|
UINT WINAPI Windows_Hook::MyGetRawInputData(HRAWINPUT hRawInput, UINT uiCommand, LPVOID pData, PUINT pcbSize, UINT cbSizeHeader)
|
||||||
{
|
{
|
||||||
if (pData == nullptr || !get_steam_client()->steam_overlay->ShowOverlay())
|
Windows_Hook* inst = Windows_Hook::Inst();
|
||||||
return Windows_Hook::Inst()->GetRawInputData(hRawInput, uiCommand, pData, pcbSize, cbSizeHeader);
|
auto res = inst->GetRawInputData(hRawInput, uiCommand, pData, pcbSize, cbSizeHeader);
|
||||||
|
if (!inst->_Initialized || pData == nullptr)
|
||||||
|
return res;
|
||||||
|
|
||||||
Windows_Hook::Inst()->GetRawInputData(hRawInput, uiCommand, pData, pcbSize, cbSizeHeader);
|
if (uiCommand == RID_INPUT && res == sizeof(RAWINPUT))
|
||||||
|
RawEvent(*reinterpret_cast<RAWINPUT*>(pData));
|
||||||
|
|
||||||
RawMouseEvent(*reinterpret_cast<RAWINPUT*>(pData));
|
if (!inst->_KeyCombinationCallback(false))
|
||||||
|
return res;
|
||||||
|
|
||||||
|
memset(pData, 0, *pcbSize);
|
||||||
*pcbSize = 0;
|
*pcbSize = 0;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL WINAPI Windows_Hook::MySetCursorPos(int x, int y)
|
SHORT WINAPI Windows_Hook::MyGetKeyState(int nVirtKey)
|
||||||
{
|
{
|
||||||
if (get_steam_client()->steam_overlay->ShowOverlay()) {
|
Windows_Hook* inst = Windows_Hook::Inst();
|
||||||
POINT p;
|
|
||||||
GetCursorPos(&p);
|
if (inst->_Initialized && inst->_KeyCombinationCallback(false))
|
||||||
x = p.x;
|
return 0;
|
||||||
y = p.y;
|
|
||||||
|
return inst->GetKeyState(nVirtKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Windows_Hook::Inst()->SetCursorPos(x, y);
|
SHORT WINAPI Windows_Hook::MyGetAsyncKeyState(int vKey)
|
||||||
|
{
|
||||||
|
Windows_Hook* inst = Windows_Hook::Inst();
|
||||||
|
|
||||||
|
if (inst->_Initialized && inst->_KeyCombinationCallback(false))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return inst->GetAsyncKeyState(vKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOOL WINAPI Windows_Hook::MyGetKeyboardState(PBYTE lpKeyState)
|
||||||
|
{
|
||||||
|
Windows_Hook* inst = Windows_Hook::Inst();
|
||||||
|
|
||||||
|
if (inst->_Initialized && inst->_KeyCombinationCallback(false))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
return inst->GetKeyboardState(lpKeyState);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL WINAPI Windows_Hook::MyGetCursorPos(LPPOINT lpPoint)
|
||||||
|
{
|
||||||
|
Windows_Hook* inst = Windows_Hook::Inst();
|
||||||
|
|
||||||
|
BOOL res = inst->GetCursorPos(lpPoint);
|
||||||
|
if (inst->_Initialized && inst->_KeyCombinationCallback(false) && lpPoint != nullptr)
|
||||||
|
{
|
||||||
|
*lpPoint = inst->_SavedCursorPos;
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL WINAPI Windows_Hook::MySetCursorPos(int X, int Y)
|
||||||
|
{
|
||||||
|
Windows_Hook* inst = Windows_Hook::Inst();
|
||||||
|
|
||||||
|
if (inst->_Initialized && inst->_KeyCombinationCallback(false))
|
||||||
|
{// That way, it will fail only if the real API fails.
|
||||||
|
// Hides error messages on some Unity debug builds.
|
||||||
|
POINT pos;
|
||||||
|
inst->GetCursorPos(&pos);
|
||||||
|
X = pos.x;
|
||||||
|
Y = pos.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
return inst->SetCursorPos(X, Y);
|
||||||
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
Windows_Hook::Windows_Hook() :
|
Windows_Hook::Windows_Hook() :
|
||||||
initialized(false),
|
_Initialized(false),
|
||||||
hooked(false),
|
_Hooked(false),
|
||||||
_game_hwnd(nullptr),
|
_RecurseCallCount(0),
|
||||||
_game_wndproc(nullptr),
|
_GameHwnd(nullptr),
|
||||||
|
_GameWndProc(nullptr),
|
||||||
GetRawInputBuffer(nullptr),
|
GetRawInputBuffer(nullptr),
|
||||||
GetRawInputData(nullptr)
|
GetRawInputData(nullptr),
|
||||||
|
GetKeyState(nullptr),
|
||||||
|
GetAsyncKeyState(nullptr),
|
||||||
|
GetKeyboardState(nullptr)
|
||||||
{
|
{
|
||||||
//_library = LoadLibrary(DLL_NAME);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Windows_Hook::~Windows_Hook()
|
Windows_Hook::~Windows_Hook()
|
||||||
{
|
{
|
||||||
PRINT_DEBUG("Windows Hook removed\n");
|
SPDLOG_INFO("Windows Hook removed");
|
||||||
|
|
||||||
resetRenderState();
|
_ResetRenderState();
|
||||||
|
|
||||||
//FreeLibrary(reinterpret_cast<HMODULE>(_library));
|
|
||||||
|
|
||||||
_inst = nullptr;
|
_inst = nullptr;
|
||||||
}
|
}
|
||||||
|
@ -215,9 +387,7 @@ Windows_Hook* Windows_Hook::Inst()
|
||||||
return _inst;
|
return _inst;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* Windows_Hook::get_lib_name() const
|
std::string Windows_Hook::GetLibraryName() const
|
||||||
{
|
{
|
||||||
return WINDOWS_DLL;
|
return LibraryName;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif//EMU_OVERLAY
|
|
|
@ -1,52 +1,80 @@
|
||||||
#ifndef __INCLUDED_WINDOWS_HOOK_H__
|
/*
|
||||||
#define __INCLUDED_WINDOWS_HOOK_H__
|
* Copyright (C) Nemirtingas
|
||||||
|
* This file is part of the ingame overlay project
|
||||||
|
*
|
||||||
|
* The ingame overlay project is free software; you can redistribute it
|
||||||
|
* and/or modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* The ingame overlay project 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
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with the ingame overlay project; if not, see
|
||||||
|
* <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
#include "../Base_Hook.h"
|
#pragma once
|
||||||
|
|
||||||
#ifdef __WINDOWS__
|
#include "../internal_includes.h"
|
||||||
#ifdef EMU_OVERLAY
|
|
||||||
|
|
||||||
class Windows_Hook : public Base_Hook
|
class Windows_Hook :
|
||||||
|
public Base_Hook
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
#define WINDOWS_DLL "user32.dll"
|
static constexpr const char* DLL_NAME = "user32.dll";
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static Windows_Hook* _inst;
|
static Windows_Hook* _inst;
|
||||||
|
|
||||||
// Variables
|
// Variables
|
||||||
bool hooked;
|
bool _Hooked;
|
||||||
bool initialized;
|
bool _Initialized;
|
||||||
HWND _game_hwnd;
|
int _RecurseCallCount;
|
||||||
WNDPROC _game_wndproc;
|
HWND _GameHwnd;
|
||||||
|
WNDPROC _GameWndProc;
|
||||||
|
POINT _SavedCursorPos;
|
||||||
|
|
||||||
// Functions
|
// Functions
|
||||||
Windows_Hook();
|
Windows_Hook();
|
||||||
|
|
||||||
// Hook to Windows window messages
|
// Hook to Windows window messages
|
||||||
decltype(GetRawInputBuffer)* GetRawInputBuffer;
|
decltype(::GetRawInputBuffer) *GetRawInputBuffer;
|
||||||
decltype(GetRawInputData)* GetRawInputData;
|
decltype(::GetRawInputData) *GetRawInputData;
|
||||||
decltype(SetCursorPos)* SetCursorPos;
|
decltype(::GetKeyState) *GetKeyState;
|
||||||
|
decltype(::GetAsyncKeyState) *GetAsyncKeyState;
|
||||||
|
decltype(::GetKeyboardState) *GetKeyboardState;
|
||||||
|
decltype(::GetCursorPos) *GetCursorPos;
|
||||||
|
decltype(::SetCursorPos) *SetCursorPos;
|
||||||
|
|
||||||
static LRESULT CALLBACK HookWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
static LRESULT CALLBACK HookWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||||||
static UINT WINAPI MyGetRawInputBuffer(PRAWINPUT pData, PUINT pcbSize, UINT cbSizeHeader);
|
static UINT WINAPI MyGetRawInputBuffer(PRAWINPUT pData, PUINT pcbSize, UINT cbSizeHeader);
|
||||||
static UINT WINAPI MyGetRawInputData(HRAWINPUT hRawInput, UINT uiCommand, LPVOID pData, PUINT pcbSize, UINT cbSizeHeader);
|
static UINT WINAPI MyGetRawInputData(HRAWINPUT hRawInput, UINT uiCommand, LPVOID pData, PUINT pcbSize, UINT cbSizeHeader);
|
||||||
|
static SHORT WINAPI MyGetKeyState(int nVirtKey);
|
||||||
|
static SHORT WINAPI MyGetAsyncKeyState(int vKey);
|
||||||
|
static BOOL WINAPI MyGetKeyboardState(PBYTE lpKeyState);
|
||||||
|
static BOOL WINAPI MyGetCursorPos(LPPOINT lpPoint);
|
||||||
|
static BOOL WINAPI MySetCursorPos(int X, int Y);
|
||||||
|
|
||||||
|
// In (bool): Is toggle wanted
|
||||||
|
// Out(bool): Is the overlay visible, if true, inputs will be disabled
|
||||||
|
std::function<bool(bool)> _KeyCombinationCallback;
|
||||||
|
|
||||||
static BOOL WINAPI MySetCursorPos(int x, int y);
|
|
||||||
public:
|
public:
|
||||||
|
std::string LibraryName;
|
||||||
|
|
||||||
virtual ~Windows_Hook();
|
virtual ~Windows_Hook();
|
||||||
|
|
||||||
void resetRenderState();
|
void _ResetRenderState();
|
||||||
void prepareForOverlay(HWND);
|
bool _PrepareForOverlay(HWND hWnd);
|
||||||
|
|
||||||
HWND GetGameHwnd() const;
|
HWND GetGameHwnd() const;
|
||||||
WNDPROC GetGameWndProc() const;
|
WNDPROC GetGameWndProc() const;
|
||||||
|
|
||||||
bool start_hook();
|
bool StartHook(std::function<bool(bool)>& key_combination_callback);
|
||||||
static Windows_Hook* Inst();
|
static Windows_Hook* Inst();
|
||||||
virtual const char* get_lib_name() const;
|
virtual std::string GetLibraryName() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif//EMU_OVERLAY
|
|
||||||
#endif//__WINDOWS__
|
|
||||||
#endif//__INCLUDED_WINDOWS_HOOK_H__
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue