├── Nox ├── d3d-api │ └── ReadMe.me ├── libOpenGL │ ├── ReagMe.md │ ├── gl-zstencil.c │ ├── gl-shaderparser.h │ ├── gl-indexbuffer.c │ ├── gl-texturecube.c │ ├── gl-helpers.c │ ├── gl-helpers.h │ ├── gl-stagesurf.c │ ├── gl-vertexbuffer.c │ └── gl-texture2d.c ├── graphic-hook │ ├── ReadMe.md │ ├── dxgi-helpers.hpp │ ├── d3d1x_shaders.hpp │ ├── d3d9-patches.hpp │ ├── graphics-hook.h │ ├── gl-decs.h │ ├── dxgi-capture.cpp │ ├── d3d12-capture.cpp │ └── d3d8-capture.cpp ├── Noxcap.def ├── ReadMe.md ├── stdafx.cpp ├── targetver.h ├── obfuscate.h ├── stdafx.h ├── obfuscate.c ├── funchook.h ├── hook-helpers.h ├── ReadMe.txt ├── graphics-hook-info.h ├── Noxcap.vcxproj.filters ├── Noxcap.h ├── funchook.c └── Noxcap.vcxproj ├── NoxCap ├── Nox.h ├── Nox.aps ├── Nox.ico ├── Nox.rc ├── ReadMe.md ├── icon1.ico ├── small.ico ├── resource.h ├── Nox.vcxproj.user ├── RemoteOps.h ├── stdafx.cpp ├── targetver.h ├── obfuscate.h ├── app-helpers.h ├── stdafx.h ├── inject-library.h ├── obfuscate.c ├── Memory.h ├── hook-helpers.h ├── threading-posix.h ├── threading-windows.h ├── sched.c ├── bmem.h ├── app-helpers.c ├── semaphore.c ├── c99defs.h ├── ReadMe.txt ├── threading.h ├── Nox.vcxproj.filters ├── bmem.c ├── threading-windows.c ├── inject-library.c ├── semaphore.h ├── sched.h ├── threading-posix.c ├── nt-stuff.h ├── graphics-hook-info.h └── gl-subsystem.h ├── s1.jpg └── README.md /Nox/d3d-api/ReadMe.me: -------------------------------------------------------------------------------- 1 | APIs for DirectX 2 | -------------------------------------------------------------------------------- /Nox/libOpenGL/ReagMe.md: -------------------------------------------------------------------------------- 1 | Apis for OpenGL 2 | -------------------------------------------------------------------------------- /Nox/graphic-hook/ReadMe.md: -------------------------------------------------------------------------------- 1 | Apis for hook 2 | -------------------------------------------------------------------------------- /NoxCap/Nox.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "resource.h" 4 | -------------------------------------------------------------------------------- /Nox/Noxcap.def: -------------------------------------------------------------------------------- 1 | LIBRARY NOXCAP 2 | EXPORTS 3 | hook_swap_buffers @1 4 | -------------------------------------------------------------------------------- /s1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gbapy/NoxPlayer-Recorder-by-hooking-the-DirectX-OpenGL/HEAD/s1.jpg -------------------------------------------------------------------------------- /NoxCap/Nox.aps: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gbapy/NoxPlayer-Recorder-by-hooking-the-DirectX-OpenGL/HEAD/NoxCap/Nox.aps -------------------------------------------------------------------------------- /NoxCap/Nox.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gbapy/NoxPlayer-Recorder-by-hooking-the-DirectX-OpenGL/HEAD/NoxCap/Nox.ico -------------------------------------------------------------------------------- /NoxCap/Nox.rc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gbapy/NoxPlayer-Recorder-by-hooking-the-DirectX-OpenGL/HEAD/NoxCap/Nox.rc -------------------------------------------------------------------------------- /NoxCap/ReadMe.md: -------------------------------------------------------------------------------- 1 | This is the source code that hooks the DirectX/OpenGL to capture the buffer shown in the NoxPlayer 2 | -------------------------------------------------------------------------------- /NoxCap/icon1.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gbapy/NoxPlayer-Recorder-by-hooking-the-DirectX-OpenGL/HEAD/NoxCap/icon1.ico -------------------------------------------------------------------------------- /NoxCap/small.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gbapy/NoxPlayer-Recorder-by-hooking-the-DirectX-OpenGL/HEAD/NoxCap/small.ico -------------------------------------------------------------------------------- /NoxCap/resource.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gbapy/NoxPlayer-Recorder-by-hooking-the-DirectX-OpenGL/HEAD/NoxCap/resource.h -------------------------------------------------------------------------------- /Nox/ReadMe.md: -------------------------------------------------------------------------------- 1 | This is the source code to communicate with NoxCap and get result from hooked buffer and show it on the screen. 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # NoxPlayer-Recorder 2 | This project captures the screen of the NoxPlayer that is using DirectX/OpenGL for representation of its screen. 3 | ![](s1.jpg) 4 | -------------------------------------------------------------------------------- /NoxCap/Nox.vcxproj.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /Nox/stdafx.cpp: -------------------------------------------------------------------------------- 1 | // stdafx.cpp : source file that includes just the standard includes 2 | // Noxcap.pch will be the pre-compiled header 3 | // stdafx.obj will contain the pre-compiled type information 4 | 5 | #include "stdafx.h" 6 | 7 | // TODO: reference any additional headers you need in STDAFX.H 8 | // and not in this file 9 | -------------------------------------------------------------------------------- /NoxCap/RemoteOps.h: -------------------------------------------------------------------------------- 1 | /* RemoteOps.h */ 2 | 3 | #ifndef REM_OPS_H 4 | #define REM_OPS_H 5 | 6 | HMODULE WINAPI GetRemoteModuleHandle(HANDLE hProcess, LPCSTR lpModuleName); 7 | FARPROC WINAPI GetRemoteProcAddress(HANDLE hProcess, HMODULE hModule, LPCSTR lpProcName, UINT Ordinal = 0, BOOL UseOrdinal = FALSE); 8 | 9 | #endif //REM_OPS_H -------------------------------------------------------------------------------- /NoxCap/stdafx.cpp: -------------------------------------------------------------------------------- 1 | // stdafx.cpp : source file that includes just the standard includes 2 | // Nox.pch will be the pre-compiled header 3 | // stdafx.obj will contain the pre-compiled type information 4 | 5 | #include "stdafx.h" 6 | 7 | // TODO: reference any additional headers you need in STDAFX.H 8 | // and not in this file 9 | -------------------------------------------------------------------------------- /Nox/targetver.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Including SDKDDKVer.h defines the highest available Windows platform. 4 | 5 | // If you wish to build your application for a previous Windows platform, include WinSDKVer.h and 6 | // set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. 7 | 8 | #include 9 | -------------------------------------------------------------------------------- /NoxCap/targetver.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Including SDKDDKVer.h defines the highest available Windows platform. 4 | 5 | // If you wish to build your application for a previous Windows platform, include WinSDKVer.h and 6 | // set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. 7 | 8 | #include 9 | -------------------------------------------------------------------------------- /Nox/graphic-hook/dxgi-helpers.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | static inline DXGI_FORMAT fix_dxgi_format(DXGI_FORMAT format) 4 | { 5 | switch ((unsigned long)format) { 6 | case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: 7 | return DXGI_FORMAT_B8G8R8A8_UNORM; 8 | case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: 9 | return DXGI_FORMAT_R8G8B8A8_UNORM; 10 | } 11 | 12 | return format; 13 | } 14 | -------------------------------------------------------------------------------- /Nox/obfuscate.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #ifdef __cplusplus 6 | extern "C" { 7 | #endif 8 | 9 | /* this is a workaround to A/Vs going crazy whenever certain functions (such as 10 | * OpenProcess) are used */ 11 | extern void *get_obfuscated_func(HMODULE module, const char *str, uint64_t val); 12 | 13 | #ifdef __cplusplus 14 | } 15 | #endif 16 | -------------------------------------------------------------------------------- /NoxCap/obfuscate.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #ifdef __cplusplus 6 | extern "C" { 7 | #endif 8 | 9 | /* this is a workaround to A/Vs going crazy whenever certain functions (such as 10 | * OpenProcess) are used */ 11 | extern void *get_obfuscated_func(HMODULE module, const char *str, uint64_t val); 12 | 13 | #ifdef __cplusplus 14 | } 15 | #endif 16 | -------------------------------------------------------------------------------- /NoxCap/app-helpers.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "stdafx.h" 3 | #include 4 | 5 | #ifdef __cplusplus 6 | extern "C" { 7 | #endif 8 | extern bool is_app(HANDLE process); 9 | extern wchar_t *get_app_sid(HANDLE process); 10 | extern HANDLE open_app_mutex(const wchar_t *sid, const wchar_t *name); 11 | extern HANDLE open_app_event(const wchar_t *sid, const wchar_t *name); 12 | extern HANDLE open_app_map(const wchar_t *sid, const wchar_t *name); 13 | #ifdef __cplusplus 14 | } 15 | #endif -------------------------------------------------------------------------------- /Nox/stdafx.h: -------------------------------------------------------------------------------- 1 | // stdafx.h : include file for standard system include files, 2 | // or project specific include files that are used frequently, but 3 | // are changed infrequently 4 | // 5 | 6 | #pragma once 7 | 8 | #include "targetver.h" 9 | 10 | #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers 11 | // Windows Header Files: 12 | #include 13 | 14 | 15 | 16 | // TODO: reference additional headers your program requires here 17 | -------------------------------------------------------------------------------- /NoxCap/stdafx.h: -------------------------------------------------------------------------------- 1 | // stdafx.h : include file for standard system include files, 2 | // or project specific include files that are used frequently, but 3 | // are changed infrequently 4 | // 5 | 6 | #pragma once 7 | 8 | #include "targetver.h" 9 | 10 | #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers 11 | // Windows Header Files: 12 | #include 13 | 14 | // C RunTime Header Files 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | 21 | // TODO: reference additional headers your program requires here 22 | -------------------------------------------------------------------------------- /Nox/graphic-hook/d3d1x_shaders.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | static const char vertex_shader_string[] = "struct VertData \ 4 | { \ 5 | float4 pos : SV_Position; \ 6 | float2 texCoord : TexCoord0; \ 7 | }; \ 8 | VertData main(VertData input) \ 9 | { \ 10 | VertData output; \ 11 | output.pos = input.pos; \ 12 | output.texCoord = input.texCoord; \ 13 | return output; \ 14 | }"; 15 | 16 | static const char pixel_shader_string[] = "uniform Texture2D diffuseTexture; \ 17 | SamplerState textureSampler \ 18 | { \ 19 | AddressU = Clamp; \ 20 | AddressV = Clamp; \ 21 | Filter = Linear; \ 22 | }; \ 23 | struct VertData \ 24 | { \ 25 | float4 pos : SV_Position; \ 26 | float2 texCoord : TexCoord0; \ 27 | }; \ 28 | float4 main(VertData input) : SV_Target \ 29 | { \ 30 | return diffuseTexture.Sample(textureSampler, input.texCoord); \ 31 | }"; 32 | -------------------------------------------------------------------------------- /NoxCap/inject-library.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | 6 | #define INJECT_ERROR_INJECT_FAILED -1 7 | #define INJECT_ERROR_INVALID_PARAMS -2 8 | #define INJECT_ERROR_OPEN_PROCESS_FAIL -3 9 | #define INJECT_ERROR_UNLIKELY_FAIL -4 10 | 11 | #ifdef __cplusplus 12 | extern "C" { 13 | #endif 14 | extern int inject_library_obf(HANDLE process, const wchar_t *dll, 15 | const char *create_remote_thread_obf, 16 | uint64_t obf1, 17 | const char *write_process_memory_obf, 18 | uint64_t obf2, const char *virtual_alloc_ex_obf, 19 | uint64_t obf3, const char *virtual_free_ex_obf, 20 | uint64_t obf4, const char *load_library_w_obf, 21 | uint64_t obf5); 22 | 23 | extern int inject_library_safe_obf(DWORD thread_id, const wchar_t *dll, 24 | const char *set_windows_hook_ex_obf, 25 | uint64_t obf1); 26 | #ifdef __cplusplus 27 | } 28 | #endif -------------------------------------------------------------------------------- /Nox/obfuscate.c: -------------------------------------------------------------------------------- 1 | #ifdef _MSC_VER 2 | #pragma warning(disable : 4152) /* casting func ptr to void */ 3 | #endif 4 | 5 | #include 6 | #include 7 | #include "obfuscate.h" 8 | 9 | #define LOWER_HALFBYTE(x) ((x)&0xF) 10 | #define UPPER_HALFBYTE(x) (((x) >> 4) & 0xF) 11 | 12 | static void deobfuscate_str(char *str, uint64_t val) 13 | { 14 | uint8_t *dec_val = (uint8_t *)&val; 15 | int i = 0; 16 | 17 | while (*str != 0) { 18 | int pos = i / 2; 19 | bool bottom = (i % 2) == 0; 20 | uint8_t *ch = (uint8_t *)str; 21 | uint8_t xor = bottom ? LOWER_HALFBYTE(dec_val[pos]) 22 | : UPPER_HALFBYTE(dec_val[pos]); 23 | 24 | *ch ^= xor; 25 | 26 | if (++i == sizeof(uint64_t) * 2) 27 | i = 0; 28 | 29 | str++; 30 | } 31 | } 32 | 33 | void *get_obfuscated_func(HMODULE module, const char *str, uint64_t val) 34 | { 35 | char new_name[128]; 36 | strcpy(new_name, str); 37 | deobfuscate_str(new_name, val); 38 | return GetProcAddress(module, new_name); 39 | } 40 | -------------------------------------------------------------------------------- /NoxCap/obfuscate.c: -------------------------------------------------------------------------------- 1 | #ifdef _MSC_VER 2 | #pragma warning(disable : 4152) /* casting func ptr to void */ 3 | #endif 4 | 5 | #include 6 | #include 7 | #include "obfuscate.h" 8 | 9 | #define LOWER_HALFBYTE(x) ((x)&0xF) 10 | #define UPPER_HALFBYTE(x) (((x) >> 4) & 0xF) 11 | 12 | static void deobfuscate_str(char *str, uint64_t val) 13 | { 14 | uint8_t *dec_val = (uint8_t *)&val; 15 | int i = 0; 16 | 17 | while (*str != 0) { 18 | int pos = i / 2; 19 | bool bottom = (i % 2) == 0; 20 | uint8_t *ch = (uint8_t *)str; 21 | uint8_t xor = bottom ? LOWER_HALFBYTE(dec_val[pos]) 22 | : UPPER_HALFBYTE(dec_val[pos]); 23 | 24 | *ch ^= xor; 25 | 26 | if (++i == sizeof(uint64_t) * 2) 27 | i = 0; 28 | 29 | str++; 30 | } 31 | } 32 | 33 | void *get_obfuscated_func(HMODULE module, const char *str, uint64_t val) 34 | { 35 | char new_name[128]; 36 | strcpy(new_name, str); 37 | deobfuscate_str(new_name, val); 38 | return GetProcAddress(module, new_name); 39 | } 40 | -------------------------------------------------------------------------------- /NoxCap/Memory.h: -------------------------------------------------------------------------------- 1 | #include 2 | namespace Memory 3 | { 4 | template 5 | T Read(DWORD address) 6 | { 7 | return *((T*)address); 8 | } 9 | 10 | template 11 | void Write(DWORD address, T value) 12 | { 13 | *((T*)address) = value; 14 | } 15 | 16 | template 17 | DWORD Protect(DWORD address, DWORD prot) 18 | { 19 | DWORD oldProt; 20 | VirtualProtect((LPVOID)address, sizeof(T), prot, &oldProt); 21 | return oldProt; 22 | } 23 | DWORD JumpHook(DWORD hookAt, DWORD newFunc, int size) 24 | { 25 | DWORD newOffset = newFunc - hookAt - 5; // -5 cuz its relative to the next instruction 26 | auto oldProtection = Memory::Protect(hookAt + 1, PAGE_EXECUTE_READWRITE); 27 | Memory::Write(hookAt, 0xE9); //JMP 28 | Memory::Write(hookAt + 1, newOffset); 29 | for (unsigned int i = 5; i < size; i++) //NOP extra bytes so it doesnt corrupt any instructions 30 | Memory::Write(hookAt + i, 0x90); 31 | Memory::Protect(hookAt + 1, oldProtection); 32 | return hookAt + 5; 33 | } 34 | } -------------------------------------------------------------------------------- /Nox/funchook.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #ifdef __cplusplus 7 | extern "C" { 8 | #else 9 | #if defined(_MSC_VER) && !defined(inline) 10 | #define inline __inline 11 | #endif 12 | #endif 13 | 14 | enum hook_type { 15 | HOOKTYPE_FORWARD_OVERWRITE, 16 | HOOKTYPE_FORWARD_CHAIN, 17 | HOOKTYPE_REVERSE_CHAIN 18 | }; 19 | 20 | struct func_hook { 21 | void *call_addr; 22 | 23 | uintptr_t func_addr; /* function being hooked to */ 24 | uintptr_t hook_addr; /* hook function itself */ 25 | void *bounce_addr; 26 | const char *name; 27 | enum hook_type type; 28 | bool is_64bit_jump; 29 | bool hooked; 30 | bool started; 31 | bool attempted_bounce; 32 | uint8_t unhook_data[14]; 33 | uint8_t rehook_data[14]; 34 | }; 35 | 36 | extern void hook_init(struct func_hook *hook, void *func_addr, void *hook_addr, 37 | const char *name); 38 | extern void hook_start(struct func_hook *hook); 39 | extern void do_hook(struct func_hook *hook, bool force); 40 | extern void unhook(struct func_hook *hook); 41 | 42 | static inline void rehook(struct func_hook *hook) 43 | { 44 | do_hook(hook, false); 45 | } 46 | 47 | static inline void force_rehook(struct func_hook *hook) 48 | { 49 | do_hook(hook, true); 50 | } 51 | 52 | #ifdef __cplusplus 53 | } 54 | #endif 55 | -------------------------------------------------------------------------------- /Nox/hook-helpers.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #if !defined(__cplusplus) && !defined(inline) 4 | #define inline __inline 5 | #endif 6 | 7 | #define GC_EVENT_FLAGS (EVENT_MODIFY_STATE | SYNCHRONIZE) 8 | #define GC_MUTEX_FLAGS (SYNCHRONIZE) 9 | 10 | static inline HANDLE create_event(const wchar_t *name) 11 | { 12 | return CreateEventW(NULL, false, false, name); 13 | } 14 | 15 | static inline HANDLE open_event(const wchar_t *name) 16 | { 17 | return OpenEventW(GC_EVENT_FLAGS, false, name); 18 | } 19 | 20 | static inline HANDLE create_mutex(const wchar_t *name) 21 | { 22 | return CreateMutexW(NULL, false, name); 23 | } 24 | 25 | static inline HANDLE open_mutex(const wchar_t *name) 26 | { 27 | return OpenMutexW(GC_MUTEX_FLAGS, false, name); 28 | } 29 | 30 | static inline HANDLE create_event_plus_id(const wchar_t *name, DWORD id) 31 | { 32 | wchar_t new_name[64]; 33 | _snwprintf(new_name, 64, L"%s%lu", name, id); 34 | return create_event(new_name); 35 | } 36 | 37 | static inline HANDLE create_mutex_plus_id(const wchar_t *name, DWORD id) 38 | { 39 | wchar_t new_name[64]; 40 | _snwprintf(new_name, 64, L"%s%lu", name, id); 41 | return create_mutex(new_name); 42 | } 43 | 44 | static inline bool object_signalled(HANDLE event) 45 | { 46 | if (!event) 47 | return false; 48 | 49 | return WaitForSingleObject(event, 0) == WAIT_OBJECT_0; 50 | } 51 | -------------------------------------------------------------------------------- /NoxCap/hook-helpers.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | #if !defined(__cplusplus) && !defined(inline) 5 | #define inline __inline 6 | #endif 7 | 8 | #define GC_EVENT_FLAGS (EVENT_MODIFY_STATE | SYNCHRONIZE) 9 | #define GC_MUTEX_FLAGS (SYNCHRONIZE) 10 | 11 | static inline HANDLE create_event(const wchar_t *name) 12 | { 13 | return CreateEventW(NULL, false, false, name); 14 | } 15 | 16 | static inline HANDLE open_event(const wchar_t *name) 17 | { 18 | return OpenEventW(GC_EVENT_FLAGS, false, name); 19 | } 20 | 21 | static inline HANDLE create_mutex(const wchar_t *name) 22 | { 23 | return CreateMutexW(NULL, false, name); 24 | } 25 | 26 | static inline HANDLE open_mutex(const wchar_t *name) 27 | { 28 | return OpenMutexW(GC_MUTEX_FLAGS, false, name); 29 | } 30 | 31 | static inline HANDLE create_event_plus_id(const wchar_t *name, DWORD id) 32 | { 33 | wchar_t new_name[64]; 34 | _snwprintf(new_name, 64, L"%s%lu", name, id); 35 | return create_event(new_name); 36 | } 37 | 38 | static inline HANDLE create_mutex_plus_id(const wchar_t *name, DWORD id) 39 | { 40 | wchar_t new_name[64]; 41 | _snwprintf(new_name, 64, L"%s%lu", name, id); 42 | return create_mutex(new_name); 43 | } 44 | 45 | static inline bool object_signalled(HANDLE event) 46 | { 47 | if (!event) 48 | return false; 49 | 50 | return WaitForSingleObject(event, 0) == WAIT_OBJECT_0; 51 | } 52 | -------------------------------------------------------------------------------- /NoxCap/threading-posix.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Hugh Bailey 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #pragma once 18 | 19 | static inline long os_atomic_inc_long(volatile long *val) 20 | { 21 | return __sync_add_and_fetch(val, 1); 22 | } 23 | 24 | static inline long os_atomic_dec_long(volatile long *val) 25 | { 26 | return __sync_sub_and_fetch(val, 1); 27 | } 28 | 29 | static inline long os_atomic_set_long(volatile long *ptr, long val) 30 | { 31 | return __sync_lock_test_and_set(ptr, val); 32 | } 33 | 34 | static inline long os_atomic_load_long(const volatile long *ptr) 35 | { 36 | return __atomic_load_n(ptr, __ATOMIC_SEQ_CST); 37 | } 38 | 39 | static inline bool os_atomic_compare_swap_long(volatile long *val, long old_val, 40 | long new_val) 41 | { 42 | return __sync_bool_compare_and_swap(val, old_val, new_val); 43 | } 44 | 45 | static inline bool os_atomic_set_bool(volatile bool *ptr, bool val) 46 | { 47 | return __sync_lock_test_and_set(ptr, val); 48 | } 49 | 50 | static inline bool os_atomic_load_bool(const volatile bool *ptr) 51 | { 52 | return __atomic_load_n(ptr, __ATOMIC_SEQ_CST); 53 | } 54 | -------------------------------------------------------------------------------- /NoxCap/threading-windows.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Hugh Bailey 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include 20 | 21 | static inline long os_atomic_inc_long(volatile long *val) 22 | { 23 | return _InterlockedIncrement(val); 24 | } 25 | 26 | static inline long os_atomic_dec_long(volatile long *val) 27 | { 28 | return _InterlockedDecrement(val); 29 | } 30 | 31 | static inline long os_atomic_set_long(volatile long *ptr, long val) 32 | { 33 | return (long)_InterlockedExchange((volatile long *)ptr, (long)val); 34 | } 35 | 36 | static inline long os_atomic_load_long(const volatile long *ptr) 37 | { 38 | return (long)_InterlockedOr((volatile long *)ptr, 0); 39 | } 40 | 41 | static inline bool os_atomic_compare_swap_long(volatile long *val, long old_val, 42 | long new_val) 43 | { 44 | return _InterlockedCompareExchange(val, new_val, old_val) == old_val; 45 | } 46 | 47 | static inline bool os_atomic_set_bool(volatile bool *ptr, bool val) 48 | { 49 | return !!_InterlockedExchange8((volatile char *)ptr, (char)val); 50 | } 51 | 52 | static inline bool os_atomic_load_bool(const volatile bool *ptr) 53 | { 54 | return !!_InterlockedOr8((volatile char *)ptr, 0); 55 | } 56 | -------------------------------------------------------------------------------- /NoxCap/sched.c: -------------------------------------------------------------------------------- 1 | /* 2 | * sched.c 3 | * 4 | * Description: 5 | * POSIX thread functions that deal with thread scheduling. 6 | * 7 | * -------------------------------------------------------------------------- 8 | * 9 | * Pthreads-win32 - POSIX Threads Library for Win32 10 | * Copyright(C) 1998 John E. Bossom 11 | * Copyright(C) 1999,2005 Pthreads-win32 contributors 12 | * 13 | * Contact Email: rpj@callisto.canberra.edu.au 14 | * 15 | * The current list of contributors is contained 16 | * in the file CONTRIBUTORS included with the source 17 | * code distribution. The list can also be seen at the 18 | * following World Wide Web location: 19 | * http://sources.redhat.com/pthreads-win32/contributors.html 20 | * 21 | * This library is free software; you can redistribute it and/or 22 | * modify it under the terms of the GNU Lesser General Public 23 | * License as published by the Free Software Foundation; either 24 | * version 2 of the License, or (at your option) any later version. 25 | * 26 | * This library is distributed in the hope that it will be useful, 27 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 28 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 29 | * Lesser General Public License for more details. 30 | * 31 | * You should have received a copy of the GNU Lesser General Public 32 | * License along with this library in the file COPYING.LIB; 33 | * if not, write to the Free Software Foundation, Inc., 34 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA 35 | */ 36 | 37 | #include "pthread.h" 38 | #include "implement.h" 39 | #include "sched.h" 40 | 41 | #include "pthread_attr_setschedpolicy.c" 42 | #include "pthread_attr_getschedpolicy.c" 43 | #include "pthread_attr_setschedparam.c" 44 | #include "pthread_attr_getschedparam.c" 45 | #include "pthread_attr_setinheritsched.c" 46 | #include "pthread_attr_getinheritsched.c" 47 | #include "pthread_setschedparam.c" 48 | #include "pthread_getschedparam.c" 49 | #include "sched_get_priority_max.c" 50 | #include "sched_get_priority_min.c" 51 | #include "sched_setscheduler.c" 52 | #include "sched_getscheduler.c" 53 | #include "sched_yield.c" 54 | -------------------------------------------------------------------------------- /Nox/ReadMe.txt: -------------------------------------------------------------------------------- 1 | ======================================================================== 2 | DYNAMIC LINK LIBRARY : Noxcap Project Overview 3 | ======================================================================== 4 | 5 | AppWizard has created this Noxcap DLL for you. 6 | 7 | This file contains a summary of what you will find in each of the files that 8 | make up your Noxcap application. 9 | 10 | 11 | Noxcap.vcxproj 12 | This is the main project file for VC++ projects generated using an Application Wizard. 13 | It contains information about the version of Visual C++ that generated the file, and 14 | information about the platforms, configurations, and project features selected with the 15 | Application Wizard. 16 | 17 | Noxcap.vcxproj.filters 18 | This is the filters file for VC++ projects generated using an Application Wizard. 19 | It contains information about the association between the files in your project 20 | and the filters. This association is used in the IDE to show grouping of files with 21 | similar extensions under a specific node (for e.g. ".cpp" files are associated with the 22 | "Source Files" filter). 23 | 24 | Noxcap.cpp 25 | This is the main DLL source file. 26 | 27 | When created, this DLL does not export any symbols. As a result, it 28 | will not produce a .lib file when it is built. If you wish this project 29 | to be a project dependency of some other project, you will either need to 30 | add code to export some symbols from the DLL so that an export library 31 | will be produced, or you can set the Ignore Input Library property to Yes 32 | on the General propert page of the Linker folder in the project's Property 33 | Pages dialog box. 34 | 35 | ///////////////////////////////////////////////////////////////////////////// 36 | Other standard files: 37 | 38 | StdAfx.h, StdAfx.cpp 39 | These files are used to build a precompiled header (PCH) file 40 | named Noxcap.pch and a precompiled types file named StdAfx.obj. 41 | 42 | ///////////////////////////////////////////////////////////////////////////// 43 | Other notes: 44 | 45 | AppWizard uses "TODO:" comments to indicate parts of the source code you 46 | should add to or customize. 47 | 48 | ///////////////////////////////////////////////////////////////////////////// 49 | -------------------------------------------------------------------------------- /NoxCap/bmem.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013 Hugh Bailey 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #pragma once 18 | 19 | 20 | #include 21 | #include 22 | 23 | #include "c99defs.h" 24 | #ifdef __cplusplus 25 | extern "C" { 26 | #endif 27 | 28 | struct base_allocator { 29 | void *(*malloc)(size_t); 30 | void *(*realloc)(void *, size_t); 31 | void (*free)(void *); 32 | }; 33 | 34 | EXPORT void base_set_allocator(struct base_allocator *defs); 35 | 36 | EXPORT void *bmalloc(size_t size); 37 | EXPORT void *brealloc(void *ptr, size_t size); 38 | EXPORT void bfree(void *ptr); 39 | 40 | EXPORT int base_get_alignment(void); 41 | 42 | EXPORT long bnum_allocs(void); 43 | 44 | EXPORT void *bmemdup(const void *ptr, size_t size); 45 | 46 | static inline void *bzalloc(size_t size) 47 | { 48 | void *mem = bmalloc(size); 49 | if (mem) 50 | memset(mem, 0, size); 51 | return mem; 52 | } 53 | 54 | static inline char *bstrdup_n(const char *str, size_t n) 55 | { 56 | char *dup; 57 | if (!str) 58 | return NULL; 59 | 60 | dup = (char *)bmemdup(str, n + 1); 61 | dup[n] = 0; 62 | 63 | return dup; 64 | } 65 | 66 | static inline wchar_t *bwstrdup_n(const wchar_t *str, size_t n) 67 | { 68 | wchar_t *dup; 69 | if (!str) 70 | return NULL; 71 | 72 | dup = (wchar_t *)bmemdup(str, (n + 1) * sizeof(wchar_t)); 73 | dup[n] = 0; 74 | 75 | return dup; 76 | } 77 | 78 | static inline char *bstrdup(const char *str) 79 | { 80 | if (!str) 81 | return NULL; 82 | 83 | return bstrdup_n(str, strlen(str)); 84 | } 85 | 86 | static inline wchar_t *bwstrdup(const wchar_t *str) 87 | { 88 | if (!str) 89 | return NULL; 90 | 91 | return bwstrdup_n(str, wcslen(str)); 92 | } 93 | 94 | #ifdef __cplusplus 95 | } 96 | #endif 97 | -------------------------------------------------------------------------------- /NoxCap/app-helpers.c: -------------------------------------------------------------------------------- 1 | #ifdef _MSC_VER 2 | #pragma warning(disable : 4152) /* casting func ptr to void */ 3 | #endif 4 | 5 | #include 6 | #include 7 | #include "app-helpers.h" 8 | #include "nt-stuff.h" 9 | 10 | WINADVAPI WINAPI ConvertSidToStringSidW(PSID sid, LPWSTR *str); 11 | wchar_t *get_app_sid(HANDLE process); 12 | bool is_app(HANDLE process); 13 | HANDLE open_app_mutex(const wchar_t *sid, const wchar_t *name); 14 | HANDLE open_app_event(const wchar_t *sid, const wchar_t *name); 15 | HANDLE open_app_map(const wchar_t *sid, const wchar_t *name); 16 | 17 | bool is_app(HANDLE process) 18 | { 19 | DWORD size_ret; 20 | DWORD ret = 0; 21 | HANDLE token; 22 | 23 | if (OpenProcessToken(process, TOKEN_QUERY, &token)) { 24 | BOOL success = GetTokenInformation(token, TokenIsAppContainer, 25 | &ret, sizeof(ret), 26 | &size_ret); 27 | if (!success) { 28 | DWORD error = GetLastError(); 29 | int test = 0; 30 | } 31 | 32 | CloseHandle(token); 33 | } 34 | return !!ret; 35 | } 36 | 37 | wchar_t *get_app_sid(HANDLE process) 38 | { 39 | wchar_t *ret = NULL; 40 | DWORD size_ret; 41 | BOOL success; 42 | HANDLE token; 43 | 44 | if (OpenProcessToken(process, TOKEN_QUERY, &token)) { 45 | DWORD info_len = GetSidLengthRequired(12) + 46 | sizeof(TOKEN_APPCONTAINER_INFORMATION); 47 | 48 | PTOKEN_APPCONTAINER_INFORMATION info = malloc(info_len); 49 | 50 | success = GetTokenInformation(token, TokenAppContainerSid, info, 51 | info_len, &size_ret); 52 | if (success) 53 | ConvertSidToStringSidW(info->TokenAppContainer, &ret); 54 | 55 | free(info); 56 | CloseHandle(token); 57 | } 58 | 59 | return ret; 60 | } 61 | 62 | static const wchar_t *path_format = 63 | L"\\Sessions\\%lu\\AppContainerNamedObjects\\%s\\%s"; 64 | 65 | HANDLE open_app_mutex(const wchar_t *sid, const wchar_t *name) 66 | { 67 | wchar_t path[MAX_PATH]; 68 | DWORD session_id = WTSGetActiveConsoleSessionId(); 69 | _snwprintf(path, MAX_PATH, path_format, session_id, sid, name); 70 | return nt_open_mutex(path); 71 | } 72 | 73 | HANDLE open_app_event(const wchar_t *sid, const wchar_t *name) 74 | { 75 | wchar_t path[MAX_PATH]; 76 | DWORD session_id = WTSGetActiveConsoleSessionId(); 77 | _snwprintf(path, MAX_PATH, path_format, session_id, sid, name); 78 | return nt_open_event(path); 79 | } 80 | 81 | HANDLE open_app_map(const wchar_t *sid, const wchar_t *name) 82 | { 83 | wchar_t path[MAX_PATH]; 84 | DWORD session_id = WTSGetActiveConsoleSessionId(); 85 | _snwprintf(path, MAX_PATH, path_format, session_id, sid, name); 86 | return nt_open_map(path); 87 | } 88 | -------------------------------------------------------------------------------- /NoxCap/semaphore.c: -------------------------------------------------------------------------------- 1 | /* 2 | * ------------------------------------------------------------- 3 | * 4 | * Module: semaphore.c 5 | * 6 | * Purpose: 7 | * Concatenated version of separate modules to allow 8 | * inlining optimisation, which it is assumed can only 9 | * be effective within a single module. 10 | * 11 | * Semaphores aren't actually part of the PThreads standard. 12 | * They are defined by the POSIX Standard: 13 | * 14 | * POSIX 1003.1b-1993 (POSIX.1b) 15 | * 16 | * ------------------------------------------------------------- 17 | * 18 | * -------------------------------------------------------------------------- 19 | * 20 | * Pthreads-win32 - POSIX Threads Library for Win32 21 | * Copyright(C) 1998 John E. Bossom 22 | * Copyright(C) 1999,2005 Pthreads-win32 contributors 23 | * 24 | * Contact Email: rpj@callisto.canberra.edu.au 25 | * 26 | * The current list of contributors is contained 27 | * in the file CONTRIBUTORS included with the source 28 | * code distribution. The list can also be seen at the 29 | * following World Wide Web location: 30 | * http://sources.redhat.com/pthreads-win32/contributors.html 31 | * 32 | * This library is free software; you can redistribute it and/or 33 | * modify it under the terms of the GNU Lesser General Public 34 | * License as published by the Free Software Foundation; either 35 | * version 2 of the License, or (at your option) any later version. 36 | * 37 | * This library is distributed in the hope that it will be useful, 38 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 39 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 40 | * Lesser General Public License for more details. 41 | * 42 | * You should have received a copy of the GNU Lesser General Public 43 | * License along with this library in the file COPYING.LIB; 44 | * if not, write to the Free Software Foundation, Inc., 45 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA 46 | */ 47 | 48 | #if !defined(NEED_FTIME) 49 | # include 50 | #endif 51 | 52 | #include 53 | 54 | #include "pthread.h" 55 | #include "semaphore.h" 56 | #include "implement.h" 57 | 58 | 59 | #include "sem_init.c" 60 | #include "sem_destroy.c" 61 | #include "sem_trywait.c" 62 | #include "sem_wait.c" 63 | #include "sem_timedwait.c" 64 | #include "sem_post.c" 65 | #include "sem_post_multiple.c" 66 | #include "sem_getvalue.c" 67 | #include "sem_open.c" 68 | #include "sem_close.c" 69 | #include "sem_unlink.c" 70 | -------------------------------------------------------------------------------- /NoxCap/c99defs.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013 Hugh Bailey 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #pragma once 18 | 19 | /* 20 | * Contains hacks for getting some C99 stuff working in VC, things like 21 | * bool, inline, stdint 22 | */ 23 | 24 | #define UNUSED_PARAMETER(param) (void)param 25 | 26 | #ifdef _MSC_VER 27 | #define DEPRECATED __declspec(deprecated) 28 | #define FORCE_INLINE __forceinline 29 | #else 30 | #define DEPRECATED __attribute__((deprecated)) 31 | #define FORCE_INLINE inline __attribute__((always_inline)) 32 | #endif 33 | 34 | #ifdef _MSC_VER 35 | 36 | /* Microsoft is one of the most inept companies on the face of the planet. 37 | * The fact that even visual studio 2013 doesn't support the standard 'inline' 38 | * keyword is so incredibly stupid that I just can't imagine what sort of 39 | * incredibly inept moron could possibly be managing the visual C compiler 40 | * project. They should be fired, and legally forbidden to have a job in 41 | * ANYTHING even REMOTELY related to programming. FOREVER. This should also 42 | * apply to the next 10 generations all of their descendants. */ 43 | #ifndef __cplusplus 44 | #define inline __inline 45 | #endif 46 | 47 | #define EXPORT __declspec(dllexport) 48 | #else 49 | #define EXPORT 50 | #endif 51 | 52 | #if _MSC_VER && _MSC_VER < 0x0708 53 | 54 | #include "vc/vc_stdint.h" 55 | #include "vc/vc_stdbool.h" 56 | 57 | #ifndef __off_t_defined 58 | #define __off_t_defined 59 | #if _FILE_OFFSET_BITS == 64 60 | typedef long long off_t; 61 | #else 62 | typedef long off_t; 63 | #endif 64 | typedef int64_t off64_t; 65 | #endif /* __off_t_defined */ 66 | 67 | #define SIZE_T_FORMAT "%u" 68 | 69 | #else 70 | 71 | #include 72 | #include 73 | #include 74 | #include 75 | 76 | #define SIZE_T_FORMAT "%zu" 77 | 78 | #endif /* _MSC_VER */ 79 | -------------------------------------------------------------------------------- /Nox/libOpenGL/gl-zstencil.c: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | Copyright (C) 2013 by Hugh Bailey 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 2 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see . 16 | ******************************************************************************/ 17 | 18 | #include "gl-subsystem.h" 19 | 20 | static bool gl_init_zsbuffer(struct gs_zstencil_buffer *zs, uint32_t width, 21 | uint32_t height) 22 | { 23 | glGenRenderbuffers(1, &zs->buffer); 24 | if (!gl_success("glGenRenderbuffers")) 25 | return false; 26 | 27 | if (!gl_bind_renderbuffer(GL_RENDERBUFFER, zs->buffer)) 28 | return false; 29 | 30 | glRenderbufferStorage(GL_RENDERBUFFER, zs->format, width, height); 31 | if (!gl_success("glRenderbufferStorage")) 32 | return false; 33 | 34 | gl_bind_renderbuffer(GL_RENDERBUFFER, 0); 35 | return true; 36 | } 37 | 38 | static inline GLenum get_attachment(enum gs_zstencil_format format) 39 | { 40 | switch (format) { 41 | case GS_Z16: 42 | return GL_DEPTH_ATTACHMENT; 43 | case GS_Z24_S8: 44 | return GL_DEPTH_STENCIL_ATTACHMENT; 45 | case GS_Z32F: 46 | return GL_DEPTH_ATTACHMENT; 47 | case GS_Z32F_S8X24: 48 | return GL_DEPTH_STENCIL_ATTACHMENT; 49 | case GS_ZS_NONE: 50 | return 0; 51 | } 52 | 53 | return 0; 54 | } 55 | 56 | gs_zstencil_t *device_zstencil_create(gs_device_t *device, uint32_t width, 57 | uint32_t height, 58 | enum gs_zstencil_format format) 59 | { 60 | struct gs_zstencil_buffer *zs; 61 | 62 | zs = bzalloc(sizeof(struct gs_zstencil_buffer)); 63 | zs->format = convert_zstencil_format(format); 64 | zs->attachment = get_attachment(format); 65 | zs->device = device; 66 | 67 | if (!gl_init_zsbuffer(zs, width, height)) { 68 | blog(LOG_ERROR, "device_zstencil_create (GL) failed"); 69 | gs_zstencil_destroy(zs); 70 | return NULL; 71 | } 72 | 73 | return zs; 74 | } 75 | 76 | void gs_zstencil_destroy(gs_zstencil_t *zs) 77 | { 78 | if (zs) { 79 | if (zs->buffer) { 80 | glDeleteRenderbuffers(1, &zs->buffer); 81 | gl_success("glDeleteRenderbuffers"); 82 | } 83 | 84 | bfree(zs); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /NoxCap/ReadMe.txt: -------------------------------------------------------------------------------- 1 | ======================================================================== 2 | WIN32 APPLICATION : Nox Project Overview 3 | ======================================================================== 4 | 5 | AppWizard has created this Nox application for you. 6 | 7 | This file contains a summary of what you will find in each of the files that 8 | make up your Nox application. 9 | 10 | 11 | Nox.vcxproj 12 | This is the main project file for VC++ projects generated using an Application Wizard. 13 | It contains information about the version of Visual C++ that generated the file, and 14 | information about the platforms, configurations, and project features selected with the 15 | Application Wizard. 16 | 17 | Nox.vcxproj.filters 18 | This is the filters file for VC++ projects generated using an Application Wizard. 19 | It contains information about the association between the files in your project 20 | and the filters. This association is used in the IDE to show grouping of files with 21 | similar extensions under a specific node (for e.g. ".cpp" files are associated with the 22 | "Source Files" filter). 23 | 24 | Nox.cpp 25 | This is the main application source file. 26 | 27 | ///////////////////////////////////////////////////////////////////////////// 28 | AppWizard has created the following resources: 29 | 30 | Nox.rc 31 | This is a listing of all of the Microsoft Windows resources that the 32 | program uses. It includes the icons, bitmaps, and cursors that are stored 33 | in the RES subdirectory. This file can be directly edited in Microsoft 34 | Visual C++. 35 | 36 | Resource.h 37 | This is the standard header file, which defines new resource IDs. 38 | Microsoft Visual C++ reads and updates this file. 39 | 40 | Nox.ico 41 | This is an icon file, which is used as the application's icon (32x32). 42 | This icon is included by the main resource file Nox.rc. 43 | 44 | small.ico 45 | This is an icon file, which contains a smaller version (16x16) 46 | of the application's icon. This icon is included by the main resource 47 | file Nox.rc. 48 | 49 | ///////////////////////////////////////////////////////////////////////////// 50 | Other standard files: 51 | 52 | StdAfx.h, StdAfx.cpp 53 | These files are used to build a precompiled header (PCH) file 54 | named Nox.pch and a precompiled types file named StdAfx.obj. 55 | 56 | ///////////////////////////////////////////////////////////////////////////// 57 | Other notes: 58 | 59 | AppWizard uses "TODO:" comments to indicate parts of the source code you 60 | should add to or customize. 61 | 62 | ///////////////////////////////////////////////////////////////////////////// 63 | -------------------------------------------------------------------------------- /NoxCap/threading.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-2014 Hugh Bailey 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #pragma once 18 | 19 | /* 20 | * Allows posix thread usage on windows as well as other operating systems. 21 | * Use this header if you want to make your code more platform independent. 22 | * 23 | * Also provides a custom platform-independent "event" handler via 24 | * pthread conditional waits. 25 | */ 26 | 27 | #include "c99defs.h" 28 | 29 | #ifdef _MSC_VER 30 | #include "pthread.h" 31 | #else 32 | #include 33 | #include 34 | #endif 35 | 36 | #ifdef __cplusplus 37 | extern "C" { 38 | #endif 39 | 40 | #ifdef _WIN32 41 | #include "threading-windows.h" 42 | #else 43 | #include "threading-posix.h" 44 | #endif 45 | 46 | /* this may seem strange, but you can't use it unless it's an initializer */ 47 | static inline void pthread_mutex_init_value(pthread_mutex_t *mutex) 48 | { 49 | pthread_mutex_t init_val = PTHREAD_MUTEX_INITIALIZER; 50 | if (!mutex) 51 | return; 52 | 53 | *mutex = init_val; 54 | } 55 | 56 | enum os_event_type { 57 | OS_EVENT_TYPE_AUTO, 58 | OS_EVENT_TYPE_MANUAL, 59 | }; 60 | 61 | struct os_event_data; 62 | struct os_sem_data; 63 | typedef struct os_event_data os_event_t; 64 | typedef struct os_sem_data os_sem_t; 65 | 66 | EXPORT int os_event_init(os_event_t **event, enum os_event_type type); 67 | EXPORT void os_event_destroy(os_event_t *event); 68 | EXPORT int os_event_wait(os_event_t *event); 69 | EXPORT int os_event_timedwait(os_event_t *event, unsigned long milliseconds); 70 | EXPORT int os_event_try(os_event_t *event); 71 | EXPORT int os_event_signal(os_event_t *event); 72 | EXPORT void os_event_reset(os_event_t *event); 73 | 74 | EXPORT int os_sem_init(os_sem_t **sem, int value); 75 | EXPORT void os_sem_destroy(os_sem_t *sem); 76 | EXPORT int os_sem_post(os_sem_t *sem); 77 | EXPORT int os_sem_wait(os_sem_t *sem); 78 | 79 | EXPORT void os_set_thread_name(const char *name); 80 | 81 | #ifdef _MSC_VER 82 | #define THREAD_LOCAL __declspec(thread) 83 | #else 84 | #define THREAD_LOCAL __thread 85 | #endif 86 | 87 | #ifdef __cplusplus 88 | } 89 | #endif 90 | -------------------------------------------------------------------------------- /Nox/graphics-hook-info.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "hook-helpers.h" 12 | 13 | #define EVENT_CAPTURE_RESTART L"CaptureHook_Restart" 14 | #define EVENT_CAPTURE_STOP L"CaptureHook_Stop" 15 | 16 | #define EVENT_HOOK_READY L"CaptureHook_HookReady" 17 | #define EVENT_HOOK_EXIT L"CaptureHook_Exit" 18 | 19 | #define EVENT_HOOK_INIT L"CaptureHook_Initialize" 20 | 21 | #define WINDOW_HOOK_KEEPALIVE L"CaptureHook_KeepAlive" 22 | 23 | #define MUTEX_TEXTURE1 L"CaptureHook_TextureMutex1" 24 | #define MUTEX_TEXTURE2 L"CaptureHook_TextureMutex2" 25 | 26 | #define SHMEM_HOOK_INFO L"CaptureHook_HookInfo" 27 | #define SHMEM_TEXTURE L"CaptureHook_Texture" 28 | 29 | #define PIPE_NAME "CaptureHook_Pipe" 30 | 31 | #pragma pack(push, 8) 32 | 33 | struct d3d8_offsets { 34 | uint32_t present; 35 | }; 36 | 37 | struct d3d9_offsets { 38 | uint32_t present; 39 | uint32_t present_ex; 40 | uint32_t present_swap; 41 | uint32_t d3d9_clsoff; 42 | uint32_t is_d3d9ex_clsoff; 43 | }; 44 | 45 | struct dxgi_offsets { 46 | uint32_t present; 47 | uint32_t resize; 48 | 49 | uint32_t present1; 50 | }; 51 | 52 | struct ddraw_offsets { 53 | uint32_t surface_create; 54 | uint32_t surface_restore; 55 | uint32_t surface_release; 56 | uint32_t surface_unlock; 57 | uint32_t surface_blt; 58 | uint32_t surface_flip; 59 | uint32_t surface_set_palette; 60 | uint32_t palette_set_entries; 61 | }; 62 | 63 | struct shmem_data { 64 | volatile int last_tex; 65 | uint32_t tex1_offset; 66 | uint32_t tex2_offset; 67 | }; 68 | 69 | struct shtex_data { 70 | uint32_t tex_handle; 71 | }; 72 | 73 | enum capture_type { 74 | CAPTURE_TYPE_MEMORY, 75 | CAPTURE_TYPE_TEXTURE, 76 | }; 77 | 78 | struct graphics_offsets { 79 | struct d3d8_offsets d3d8; 80 | struct d3d9_offsets d3d9; 81 | struct dxgi_offsets dxgi; 82 | struct ddraw_offsets ddraw; 83 | }; 84 | 85 | struct hook_info { 86 | /* capture info */ 87 | enum capture_type type; 88 | uint32_t window; 89 | uint32_t format; 90 | uint32_t cx; 91 | uint32_t cy; 92 | uint32_t base_cx; 93 | uint32_t base_cy; 94 | uint32_t pitch; 95 | uint32_t map_id; 96 | uint32_t map_size; 97 | bool flip; 98 | 99 | /* additional options */ 100 | uint64_t frame_interval; 101 | bool use_scale; 102 | bool force_shmem; 103 | bool capture_overlay; 104 | 105 | /* hook addresses */ 106 | struct graphics_offsets offsets; 107 | }; 108 | 109 | #pragma pack(pop) 110 | 111 | #define GC_MAPPING_FLAGS (FILE_MAP_READ | FILE_MAP_WRITE) 112 | 113 | static inline HANDLE create_hook_info(DWORD id) 114 | { 115 | wchar_t new_name[64]; 116 | _snwprintf(new_name, 64, L"%s%lu", SHMEM_HOOK_INFO, id); 117 | 118 | return CreateFileMappingW(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 119 | sizeof(struct hook_info), new_name); 120 | } 121 | -------------------------------------------------------------------------------- /Nox/libOpenGL/gl-shaderparser.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | Copyright (C) 2013 by Hugh Bailey 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 2 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see . 16 | ******************************************************************************/ 17 | 18 | #pragma once 19 | 20 | /* 21 | * Parses shaders into GLSL. Shaders are almost identical to HLSL 22 | * model 5 so it requires quite a bit of tweaking to convert correctly. 23 | * Takes the parsed shader data, and builds a GLSL string out of it. 24 | */ 25 | 26 | #include 27 | #include 28 | 29 | struct gl_parser_attrib { 30 | struct dstr name; 31 | const char *mapping; 32 | bool input; 33 | }; 34 | 35 | static inline void gl_parser_attrib_init(struct gl_parser_attrib *attr) 36 | { 37 | memset(attr, 0, sizeof(struct gl_parser_attrib)); 38 | } 39 | 40 | static inline void gl_parser_attrib_free(struct gl_parser_attrib *attr) 41 | { 42 | dstr_free(&attr->name); 43 | } 44 | 45 | struct gl_shader_parser { 46 | enum gs_shader_type type; 47 | const char *input_prefix; 48 | const char *output_prefix; 49 | struct shader_parser parser; 50 | struct dstr gl_string; 51 | 52 | DARRAY(uint32_t) texture_samplers; 53 | DARRAY(struct gl_parser_attrib) attribs; 54 | }; 55 | 56 | static inline void gl_shader_parser_init(struct gl_shader_parser *glsp, 57 | enum gs_shader_type type) 58 | { 59 | glsp->type = type; 60 | 61 | if (type == GS_SHADER_VERTEX) { 62 | glsp->input_prefix = "_input_attrib"; 63 | glsp->output_prefix = "_vertex_shader_attrib"; 64 | } else if (type == GS_SHADER_PIXEL) { 65 | glsp->input_prefix = "_vertex_shader_attrib"; 66 | glsp->output_prefix = "_pixel_shader_attrib"; 67 | } 68 | 69 | shader_parser_init(&glsp->parser); 70 | dstr_init(&glsp->gl_string); 71 | da_init(glsp->texture_samplers); 72 | da_init(glsp->attribs); 73 | } 74 | 75 | static inline void gl_shader_parser_free(struct gl_shader_parser *glsp) 76 | { 77 | size_t i; 78 | for (i = 0; i < glsp->attribs.num; i++) 79 | gl_parser_attrib_free(glsp->attribs.array + i); 80 | 81 | da_free(glsp->attribs); 82 | da_free(glsp->texture_samplers); 83 | dstr_free(&glsp->gl_string); 84 | shader_parser_free(&glsp->parser); 85 | } 86 | 87 | extern bool gl_shader_parse(struct gl_shader_parser *glsp, 88 | const char *shader_str, const char *file); 89 | -------------------------------------------------------------------------------- /NoxCap/Nox.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | Header Files 23 | 24 | 25 | Header Files 26 | 27 | 28 | Header Files 29 | 30 | 31 | Header Files 32 | 33 | 34 | Header Files 35 | 36 | 37 | Header Files 38 | 39 | 40 | Header Files 41 | 42 | 43 | Header Files 44 | 45 | 46 | Header Files 47 | 48 | 49 | Header Files 50 | 51 | 52 | Header Files 53 | 54 | 55 | 56 | 57 | Source Files 58 | 59 | 60 | Source Files 61 | 62 | 63 | Source Files 64 | 65 | 66 | Source Files 67 | 68 | 69 | Source Files 70 | 71 | 72 | Source Files 73 | 74 | 75 | 76 | 77 | Resource Files 78 | 79 | 80 | 81 | 82 | Resource Files 83 | 84 | 85 | Resource Files 86 | 87 | 88 | Resource Files 89 | 90 | 91 | -------------------------------------------------------------------------------- /Nox/libOpenGL/gl-indexbuffer.c: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | Copyright (C) 2013 by Hugh Bailey 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 2 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see . 16 | ******************************************************************************/ 17 | 18 | #include "gl-subsystem.h" 19 | 20 | static inline bool init_ib(struct gs_index_buffer *ib) 21 | { 22 | GLenum usage = ib->dynamic ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW; 23 | bool success; 24 | 25 | success = gl_create_buffer(GL_ELEMENT_ARRAY_BUFFER, &ib->buffer, 26 | ib->size, ib->data, usage); 27 | 28 | if (!ib->dynamic) { 29 | bfree(ib->data); 30 | ib->data = NULL; 31 | } 32 | 33 | return success; 34 | } 35 | 36 | gs_indexbuffer_t *device_indexbuffer_create(gs_device_t *device, 37 | enum gs_index_type type, 38 | void *indices, size_t num, 39 | uint32_t flags) 40 | { 41 | struct gs_index_buffer *ib = bzalloc(sizeof(struct gs_index_buffer)); 42 | size_t width = type == GS_UNSIGNED_LONG ? 4 : 2; 43 | 44 | ib->device = device; 45 | ib->data = indices; 46 | ib->dynamic = flags & GS_DYNAMIC; 47 | ib->num = num; 48 | ib->width = width; 49 | ib->size = width * num; 50 | ib->type = type; 51 | ib->gl_type = type == GS_UNSIGNED_LONG ? GL_UNSIGNED_INT 52 | : GL_UNSIGNED_SHORT; 53 | 54 | if (!init_ib(ib)) { 55 | blog(LOG_ERROR, "device_indexbuffer_create (GL) failed"); 56 | gs_indexbuffer_destroy(ib); 57 | return NULL; 58 | } 59 | 60 | return ib; 61 | } 62 | 63 | void gs_indexbuffer_destroy(gs_indexbuffer_t *ib) 64 | { 65 | if (ib) { 66 | if (ib->buffer) 67 | gl_delete_buffers(1, &ib->buffer); 68 | 69 | bfree(ib->data); 70 | bfree(ib); 71 | } 72 | } 73 | 74 | static inline void gs_indexbuffer_flush_internal(gs_indexbuffer_t *ib, 75 | const void *data) 76 | { 77 | if (!ib->dynamic) { 78 | blog(LOG_ERROR, "Index buffer is not dynamic"); 79 | goto fail; 80 | } 81 | 82 | if (!update_buffer(GL_ELEMENT_ARRAY_BUFFER, ib->buffer, data, ib->size)) 83 | goto fail; 84 | 85 | return; 86 | 87 | fail: 88 | blog(LOG_ERROR, "gs_indexbuffer_flush (GL) failed"); 89 | } 90 | 91 | void gs_indexbuffer_flush(gs_indexbuffer_t *ib) 92 | { 93 | gs_indexbuffer_flush_internal(ib, ib->data); 94 | } 95 | 96 | void gs_indexbuffer_flush_direct(gs_indexbuffer_t *ib, const void *data) 97 | { 98 | gs_indexbuffer_flush_internal(ib, data); 99 | } 100 | 101 | void *gs_indexbuffer_get_data(const gs_indexbuffer_t *ib) 102 | { 103 | return ib->data; 104 | } 105 | 106 | size_t gs_indexbuffer_get_num_indices(const gs_indexbuffer_t *ib) 107 | { 108 | return ib->num; 109 | } 110 | 111 | enum gs_index_type gs_indexbuffer_get_type(const gs_indexbuffer_t *ib) 112 | { 113 | return ib->type; 114 | } 115 | 116 | void device_load_indexbuffer(gs_device_t *device, gs_indexbuffer_t *ib) 117 | { 118 | device->cur_index_buffer = ib; 119 | } 120 | -------------------------------------------------------------------------------- /NoxCap/bmem.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013 Hugh Bailey 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include 18 | #include 19 | //#include "base.h" 20 | #include "bmem.h" 21 | //#include "platform.h" 22 | #include "threading.h" 23 | 24 | /* 25 | * NOTE: totally jacked the mem alignment trick from ffmpeg, credit to them: 26 | * http://www.ffmpeg.org/ 27 | */ 28 | 29 | #define ALIGNMENT 32 30 | 31 | /* TODO: use memalign for non-windows systems */ 32 | #if defined(_WIN32) 33 | #define ALIGNED_MALLOC 1 34 | #else 35 | #define ALIGNMENT_HACK 1 36 | #endif 37 | 38 | static void *a_malloc(size_t size) 39 | { 40 | #ifdef ALIGNED_MALLOC 41 | return _aligned_malloc(size, ALIGNMENT); 42 | #elif ALIGNMENT_HACK 43 | void *ptr = NULL; 44 | long diff; 45 | 46 | ptr = malloc(size + ALIGNMENT); 47 | if (ptr) { 48 | diff = ((~(long)ptr) & (ALIGNMENT - 1)) + 1; 49 | ptr = (char *)ptr + diff; 50 | ((char *)ptr)[-1] = (char)diff; 51 | } 52 | 53 | return ptr; 54 | #else 55 | return malloc(size); 56 | #endif 57 | } 58 | 59 | static void *a_realloc(void *ptr, size_t size) 60 | { 61 | #ifdef ALIGNED_MALLOC 62 | return _aligned_realloc(ptr, size, ALIGNMENT); 63 | #elif ALIGNMENT_HACK 64 | long diff; 65 | 66 | if (!ptr) 67 | return a_malloc(size); 68 | diff = ((char *)ptr)[-1]; 69 | ptr = realloc((char *)ptr - diff, size + diff); 70 | if (ptr) 71 | ptr = (char *)ptr + diff; 72 | return ptr; 73 | #else 74 | return realloc(ptr, size); 75 | #endif 76 | } 77 | 78 | static void a_free(void *ptr) 79 | { 80 | #ifdef ALIGNED_MALLOC 81 | _aligned_free(ptr); 82 | #elif ALIGNMENT_HACK 83 | if (ptr) 84 | free((char *)ptr - ((char *)ptr)[-1]); 85 | #else 86 | free(ptr); 87 | #endif 88 | } 89 | 90 | static struct base_allocator alloc = {a_malloc, a_realloc, a_free}; 91 | static long num_allocs = 0; 92 | 93 | void base_set_allocator(struct base_allocator *defs) 94 | { 95 | memcpy(&alloc, defs, sizeof(struct base_allocator)); 96 | } 97 | 98 | void *bmalloc(size_t size) 99 | { 100 | void *ptr = alloc.malloc(size); 101 | if (!ptr && !size) 102 | ptr = alloc.malloc(1); 103 | if (!ptr) { 104 | os_breakpoint(); 105 | bcrash("Out of memory while trying to allocate %lu bytes", 106 | (unsigned long)size); 107 | } 108 | 109 | os_atomic_inc_long(&num_allocs); 110 | return ptr; 111 | } 112 | 113 | void *brealloc(void *ptr, size_t size) 114 | { 115 | if (!ptr) 116 | os_atomic_inc_long(&num_allocs); 117 | 118 | ptr = alloc.realloc(ptr, size); 119 | if (!ptr && !size) 120 | ptr = alloc.realloc(ptr, 1); 121 | if (!ptr) { 122 | os_breakpoint(); 123 | bcrash("Out of memory while trying to allocate %lu bytes", 124 | (unsigned long)size); 125 | } 126 | 127 | return ptr; 128 | } 129 | 130 | void bfree(void *ptr) 131 | { 132 | if (ptr) 133 | os_atomic_dec_long(&num_allocs); 134 | alloc.free(ptr); 135 | } 136 | 137 | long bnum_allocs(void) 138 | { 139 | return num_allocs; 140 | } 141 | 142 | int base_get_alignment(void) 143 | { 144 | return ALIGNMENT; 145 | } 146 | 147 | void *bmemdup(const void *ptr, size_t size) 148 | { 149 | void *out = bmalloc(size); 150 | if (size) 151 | memcpy(out, ptr, size); 152 | 153 | return out; 154 | } 155 | -------------------------------------------------------------------------------- /Nox/Noxcap.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | Header Files 23 | 24 | 25 | Header Files 26 | 27 | 28 | Header Files 29 | 30 | 31 | Header Files 32 | 33 | 34 | Header Files 35 | 36 | 37 | Header Files 38 | 39 | 40 | Header Files 41 | 42 | 43 | Header Files 44 | 45 | 46 | Header Files 47 | 48 | 49 | Header Files 50 | 51 | 52 | Header Files 53 | 54 | 55 | Header Files 56 | 57 | 58 | Header Files 59 | 60 | 61 | Header Files 62 | 63 | 64 | Header Files 65 | 66 | 67 | 68 | 69 | Source Files 70 | 71 | 72 | Source Files 73 | 74 | 75 | Source Files 76 | 77 | 78 | Source Files 79 | 80 | 81 | Source Files 82 | 83 | 84 | Source Files 85 | 86 | 87 | Source Files 88 | 89 | 90 | Source Files 91 | 92 | 93 | Source Files 94 | 95 | 96 | Source Files 97 | 98 | 99 | Source Files 100 | 101 | 102 | -------------------------------------------------------------------------------- /Nox/libOpenGL/gl-texturecube.c: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | Copyright (C) 2013 by Hugh Bailey 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 2 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see . 16 | ******************************************************************************/ 17 | 18 | #include "gl-subsystem.h" 19 | 20 | static inline bool upload_texture_cube(struct gs_texture_cube *tex, 21 | const uint8_t **data) 22 | { 23 | uint32_t row_size = tex->size * gs_get_format_bpp(tex->base.format); 24 | uint32_t tex_size = tex->size * row_size / 8; 25 | uint32_t num_levels = tex->base.levels; 26 | bool compressed = gs_is_compressed_format(tex->base.format); 27 | GLenum gl_type = get_gl_format_type(tex->base.format); 28 | bool success = true; 29 | uint32_t i; 30 | 31 | if (!num_levels) 32 | num_levels = gs_get_total_levels(tex->size, tex->size); 33 | 34 | for (i = 0; i < 6; i++) { 35 | GLenum target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + i; 36 | 37 | if (!gl_bind_texture(target, tex->base.texture)) 38 | success = false; 39 | 40 | if (!gl_init_face(target, gl_type, num_levels, 41 | tex->base.gl_format, 42 | tex->base.gl_internal_format, compressed, 43 | tex->size, tex->size, tex_size, &data)) 44 | success = false; 45 | 46 | if (!gl_bind_texture(target, 0)) 47 | success = false; 48 | 49 | if (data) 50 | data++; 51 | } 52 | 53 | glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAX_LEVEL, num_levels); 54 | if (!gl_success("glTexParameteri")) 55 | success = false; 56 | 57 | return success; 58 | } 59 | 60 | gs_texture_t *device_cubetexture_create(gs_device_t *device, uint32_t size, 61 | enum gs_color_format color_format, 62 | uint32_t levels, const uint8_t **data, 63 | uint32_t flags) 64 | { 65 | struct gs_texture_cube *tex = bzalloc(sizeof(struct gs_texture_cube)); 66 | tex->base.device = device; 67 | tex->base.type = GS_TEXTURE_CUBE; 68 | tex->base.format = color_format; 69 | tex->base.levels = levels; 70 | tex->base.gl_format = convert_gs_format(color_format); 71 | tex->base.gl_internal_format = convert_gs_internal_format(color_format); 72 | tex->base.gl_target = GL_TEXTURE_CUBE_MAP; 73 | tex->base.is_render_target = (flags & GS_RENDER_TARGET) != 0; 74 | tex->base.gen_mipmaps = (flags & GS_BUILD_MIPMAPS) != 0; 75 | tex->size = size; 76 | 77 | if (!gl_gen_textures(1, &tex->base.texture)) 78 | goto fail; 79 | if (!upload_texture_cube(tex, data)) 80 | goto fail; 81 | 82 | return (gs_texture_t *)tex; 83 | 84 | fail: 85 | gs_cubetexture_destroy((gs_texture_t *)tex); 86 | blog(LOG_ERROR, "device_cubetexture_create (GL) failed"); 87 | return NULL; 88 | } 89 | 90 | void gs_cubetexture_destroy(gs_texture_t *tex) 91 | { 92 | if (!tex) 93 | return; 94 | 95 | if (tex->texture) 96 | gl_delete_textures(1, &tex->texture); 97 | 98 | if (tex->fbo) 99 | fbo_info_destroy(tex->fbo); 100 | 101 | bfree(tex); 102 | } 103 | 104 | static inline bool is_texture_cube(const gs_texture_t *tex, const char *func) 105 | { 106 | bool is_texcube = tex->type == GS_TEXTURE_CUBE; 107 | if (!is_texcube) 108 | blog(LOG_ERROR, "%s (GL) failed: Not a cubemap texture", func); 109 | return is_texcube; 110 | } 111 | 112 | uint32_t gs_cubetexture_get_size(const gs_texture_t *cubetex) 113 | { 114 | const struct gs_texture_cube *cube = 115 | (const struct gs_texture_cube *)cubetex; 116 | 117 | if (!is_texture_cube(cubetex, "gs_cubetexture_get_size")) 118 | return 0; 119 | 120 | return cube->size; 121 | } 122 | 123 | enum gs_color_format 124 | gs_cubetexture_get_color_format(const gs_texture_t *cubetex) 125 | { 126 | return cubetex->format; 127 | } 128 | -------------------------------------------------------------------------------- /Nox/graphic-hook/d3d9-patches.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #ifdef __MINGW32__ 6 | #include 7 | #ifndef TRYLEVEL_NONE 8 | #ifndef __MINGW64__ 9 | #define NO_SEH_MINGW 10 | #endif 11 | #ifndef __try 12 | #define __try 13 | #endif 14 | #ifndef __except 15 | #define __except (x) if (0) 16 | #endif 17 | #endif 18 | #endif 19 | 20 | static inline int safe_memcmp(const void *p1, const void *p2, size_t size) 21 | { 22 | 23 | // Disabled exceptions on mingw-w64 as it is broken 24 | #ifndef __MINGW32__ 25 | #ifdef NO_SEH_MINGW 26 | __try1(EXCEPTION_EXECUTE_HANDLER) 27 | #else 28 | __try 29 | #endif 30 | #endif 31 | { 32 | return memcmp(p1, p2, size); 33 | } 34 | // Disabled exceptions on mingw-w64 as it is broken 35 | #ifndef __MINGW32__ 36 | #ifdef NO_SEH_MINGW 37 | __except1 38 | #else 39 | __except (EXCEPTION_EXECUTE_HANDLER) 40 | #endif 41 | { 42 | return -1; 43 | } 44 | #endif 45 | } 46 | 47 | struct patch_info { 48 | size_t size; 49 | const BYTE *data; 50 | }; 51 | 52 | #define NEW_PATCH(x) \ 53 | { \ 54 | sizeof(x), (x) \ 55 | } 56 | #define MAX_PATCH_SIZE 2 57 | 58 | static const BYTE force_jump[] = {0xEB}; 59 | static const BYTE ignore_jump[] = {0x90, 0x90}; 60 | 61 | #ifdef _WIN64 62 | 63 | #define NUM_VERS (16) 64 | #define CMP_SIZE (13) 65 | 66 | 67 | #else 68 | 69 | #define NUM_VERS (16) 70 | #define CMP_SIZE (12) 71 | 72 | static const uintptr_t patch_offset[NUM_VERS] = { 73 | 0x79AA6, //win7 - 6.1.7601.16562 74 | 0x79C9E, //win7 - 6.1.7600.16385 75 | 0x79D96, //win7 - 6.1.7601.17514 76 | 0x7F9BD, //win8.1 - 6.3.9431.00000 77 | 0x8A3F4, //win8.1 - 6.3.9600.16404 78 | 0x8B15F, //win10 - 10.0.10240.16384 79 | 0x8B19F, //win10 - 10.0.10162.0 80 | 0x8B83F, //win10 - 10.0.10240.16412 81 | 0x8E9F7, //win8.1 - 6.3.9600.17095 82 | 0x8F00F, //win8.1 - 6.3.9600.17085 83 | 0x8FBB1, //win8.1 - 6.3.9600.16384 84 | 0x90264, //win8.1 - 6.3.9600.17415 85 | 0x90C3A, //win10 - 10.0.10586.494 86 | 0x90C57, //win10 - 10.0.10586.0 87 | 0x96673, //win10 - 10.0.14393.0 88 | 0x166A08 //win8 - 6.2.9200.16384 89 | }; 90 | 91 | static const uint8_t patch_cmp[NUM_VERS][CMP_SIZE] = { 92 | {0x8b, 0x89, 0xe8, 0x29, 0x00, 0x00, 0x39, 0xb9, 0x80, 0x4b, 0x00, 93 | 0x00}, 94 | {0x8b, 0x89, 0xe8, 0x29, 0x00, 0x00, 0x39, 0xb9, 0x80, 0x4b, 0x00, 95 | 0x00}, 96 | {0x8b, 0x89, 0xe8, 0x29, 0x00, 0x00, 0x39, 0xb9, 0x80, 0x4b, 0x00, 97 | 0x00}, 98 | {0x8b, 0x80, 0xe8, 0x29, 0x00, 0x00, 0x39, 0xb0, 0x40, 0x4c, 0x00, 99 | 0x00}, 100 | {0x80, 0xe8, 0x29, 0x00, 0x00, 0x83, 0xb8, 0x40, 0x4c, 0x00, 0x00, 101 | 0x00}, 102 | {0x81, 0xe8, 0x29, 0x00, 0x00, 0x83, 0xb8, 0xa0, 0x4c, 0x00, 0x00, 103 | 0x00}, 104 | {0x81, 0xe8, 0x29, 0x00, 0x00, 0x83, 0xb8, 0xa0, 0x4c, 0x00, 0x00, 105 | 0x00}, 106 | {0x81, 0xe8, 0x29, 0x00, 0x00, 0x83, 0xb8, 0xa0, 0x4c, 0x00, 0x00, 107 | 0x00}, 108 | {0x80, 0xe8, 0x29, 0x00, 0x00, 0x83, 0xb8, 0x40, 0x4c, 0x00, 0x00, 109 | 0x00}, 110 | {0x80, 0xe8, 0x29, 0x00, 0x00, 0x83, 0xb8, 0x40, 0x4c, 0x00, 0x00, 111 | 0x00}, 112 | {0x80, 0xe8, 0x29, 0x00, 0x00, 0x83, 0xb8, 0x40, 0x4c, 0x00, 0x00, 113 | 0x00}, 114 | {0x87, 0xe8, 0x29, 0x00, 0x00, 0x83, 0xb8, 0x40, 0x4c, 0x00, 0x00, 115 | 0x00}, 116 | {0x81, 0x18, 0x2a, 0x00, 0x00, 0x83, 0xb8, 0xa0, 0x4c, 0x00, 0x00, 117 | 0x00}, 118 | {0x81, 0x18, 0x2a, 0x00, 0x00, 0x83, 0xb8, 0xa0, 0x4c, 0x00, 0x00, 119 | 0x00}, 120 | {0x81, 0x18, 0x2a, 0x00, 0x00, 0x83, 0xb8, 0xa8, 0x4c, 0x00, 0x00, 121 | 0x00}, 122 | {0x8b, 0x80, 0xe8, 0x29, 0x00, 0x00, 0x39, 0x90, 0xb0, 0x4b, 0x00, 123 | 0x00}, 124 | }; 125 | 126 | static const struct patch_info patch[NUM_VERS] = { 127 | NEW_PATCH(force_jump), NEW_PATCH(force_jump), NEW_PATCH(force_jump), 128 | NEW_PATCH(force_jump), NEW_PATCH(force_jump), NEW_PATCH(ignore_jump), 129 | NEW_PATCH(ignore_jump), NEW_PATCH(ignore_jump), NEW_PATCH(force_jump), 130 | NEW_PATCH(force_jump), NEW_PATCH(force_jump), NEW_PATCH(ignore_jump), 131 | NEW_PATCH(ignore_jump), NEW_PATCH(ignore_jump), NEW_PATCH(ignore_jump), 132 | NEW_PATCH(force_jump), 133 | }; 134 | 135 | #endif 136 | 137 | static inline int get_d3d9_patch(HMODULE d3d9) 138 | { 139 | uint8_t *addr = (uint8_t *)d3d9; 140 | for (int i = 0; i < NUM_VERS; i++) { 141 | int ret = safe_memcmp(addr + patch_offset[i], patch_cmp[i], 142 | CMP_SIZE); 143 | if (ret == 0) 144 | return i; 145 | } 146 | 147 | return -1; 148 | } 149 | 150 | static inline uint8_t *get_d3d9_patch_addr(HMODULE d3d9, int patch) 151 | { 152 | if (patch == -1) 153 | return nullptr; 154 | 155 | uint8_t *addr = (uint8_t *)d3d9; 156 | return addr + patch_offset[patch] + CMP_SIZE; 157 | } 158 | -------------------------------------------------------------------------------- /NoxCap/threading-windows.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014 Hugh Bailey 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include "bmem.h" 18 | #include "threading.h" 19 | 20 | #define WIN32_LEAN_AND_MEAN 21 | #include 22 | 23 | #ifdef __MINGW32__ 24 | #include 25 | #ifndef TRYLEVEL_NONE 26 | #ifndef __MINGW64__ 27 | #define NO_SEH_MINGW 28 | #endif 29 | #ifndef __try 30 | #define __try 31 | #endif 32 | #ifndef __except 33 | #define __except (x) if (0) 34 | #endif 35 | #endif 36 | #endif 37 | 38 | int os_event_init(os_event_t **event, enum os_event_type type) 39 | { 40 | HANDLE handle; 41 | 42 | handle = CreateEvent(NULL, (type == OS_EVENT_TYPE_MANUAL), FALSE, NULL); 43 | if (!handle) 44 | return -1; 45 | 46 | *event = (os_event_t *)handle; 47 | return 0; 48 | } 49 | 50 | void os_event_destroy(os_event_t *event) 51 | { 52 | if (event) 53 | CloseHandle((HANDLE)event); 54 | } 55 | 56 | int os_event_wait(os_event_t *event) 57 | { 58 | DWORD code; 59 | 60 | if (!event) 61 | return EINVAL; 62 | 63 | code = WaitForSingleObject((HANDLE)event, INFINITE); 64 | if (code != WAIT_OBJECT_0) 65 | return EINVAL; 66 | 67 | return 0; 68 | } 69 | 70 | int os_event_timedwait(os_event_t *event, unsigned long milliseconds) 71 | { 72 | DWORD code; 73 | 74 | if (!event) 75 | return EINVAL; 76 | 77 | code = WaitForSingleObject((HANDLE)event, milliseconds); 78 | if (code == WAIT_TIMEOUT) 79 | return ETIMEDOUT; 80 | else if (code != WAIT_OBJECT_0) 81 | return EINVAL; 82 | 83 | return 0; 84 | } 85 | 86 | int os_event_try(os_event_t *event) 87 | { 88 | DWORD code; 89 | 90 | if (!event) 91 | return EINVAL; 92 | 93 | code = WaitForSingleObject((HANDLE)event, 0); 94 | if (code == WAIT_TIMEOUT) 95 | return EAGAIN; 96 | else if (code != WAIT_OBJECT_0) 97 | return EINVAL; 98 | 99 | return 0; 100 | } 101 | 102 | int os_event_signal(os_event_t *event) 103 | { 104 | if (!event) 105 | return EINVAL; 106 | 107 | if (!SetEvent((HANDLE)event)) 108 | return EINVAL; 109 | 110 | return 0; 111 | } 112 | 113 | void os_event_reset(os_event_t *event) 114 | { 115 | if (!event) 116 | return; 117 | 118 | ResetEvent((HANDLE)event); 119 | } 120 | 121 | int os_sem_init(os_sem_t **sem, int value) 122 | { 123 | HANDLE handle = CreateSemaphore(NULL, (LONG)value, 0x7FFFFFFF, NULL); 124 | if (!handle) 125 | return -1; 126 | 127 | *sem = (os_sem_t *)handle; 128 | return 0; 129 | } 130 | 131 | void os_sem_destroy(os_sem_t *sem) 132 | { 133 | if (sem) 134 | CloseHandle((HANDLE)sem); 135 | } 136 | 137 | int os_sem_post(os_sem_t *sem) 138 | { 139 | if (!sem) 140 | return -1; 141 | return ReleaseSemaphore((HANDLE)sem, 1, NULL) ? 0 : -1; 142 | } 143 | 144 | int os_sem_wait(os_sem_t *sem) 145 | { 146 | DWORD ret; 147 | 148 | if (!sem) 149 | return -1; 150 | ret = WaitForSingleObject((HANDLE)sem, INFINITE); 151 | return (ret == WAIT_OBJECT_0) ? 0 : -1; 152 | } 153 | 154 | #define VC_EXCEPTION 0x406D1388 155 | 156 | #pragma pack(push, 8) 157 | struct vs_threadname_info { 158 | DWORD type; /* 0x1000 */ 159 | const char *name; 160 | DWORD thread_id; 161 | DWORD flags; 162 | }; 163 | #pragma pack(pop) 164 | 165 | #define THREADNAME_INFO_SIZE \ 166 | (sizeof(struct vs_threadname_info) / sizeof(ULONG_PTR)) 167 | 168 | void os_set_thread_name(const char *name) 169 | { 170 | #ifdef __MINGW32__ 171 | UNUSED_PARAMETER(name); 172 | #else 173 | struct vs_threadname_info info; 174 | info.type = 0x1000; 175 | info.name = name; 176 | info.thread_id = GetCurrentThreadId(); 177 | info.flags = 0; 178 | 179 | #ifdef NO_SEH_MINGW 180 | __try1(EXCEPTION_EXECUTE_HANDLER) 181 | { 182 | #else 183 | __try { 184 | #endif 185 | RaiseException(VC_EXCEPTION, 0, THREADNAME_INFO_SIZE, 186 | (ULONG_PTR *)&info); 187 | #ifdef NO_SEH_MINGW 188 | } 189 | __except1{ 190 | #else 191 | } __except (EXCEPTION_EXECUTE_HANDLER) { 192 | #endif 193 | } 194 | #endif 195 | } 196 | -------------------------------------------------------------------------------- /NoxCap/inject-library.c: -------------------------------------------------------------------------------- 1 | #ifdef _MSC_VER 2 | #pragma warning(disable : 4152) /* casting func ptr to void */ 3 | #endif 4 | 5 | #include 6 | #include 7 | #include "obfuscate.h" 8 | #include "inject-library.h" 9 | 10 | typedef HANDLE(WINAPI *create_remote_thread_t)(HANDLE, LPSECURITY_ATTRIBUTES, 11 | SIZE_T, LPTHREAD_START_ROUTINE, 12 | LPVOID, DWORD, LPDWORD); 13 | typedef BOOL(WINAPI *write_process_memory_t)(HANDLE, LPVOID, LPCVOID, SIZE_T, 14 | SIZE_T *); 15 | typedef LPVOID(WINAPI *virtual_alloc_ex_t)(HANDLE, LPVOID, SIZE_T, DWORD, 16 | DWORD); 17 | typedef BOOL(WINAPI *virtual_free_ex_t)(HANDLE, LPVOID, SIZE_T, DWORD); 18 | 19 | int inject_library_obf(HANDLE process, const wchar_t *dll, 20 | const char *create_remote_thread_obf, uint64_t obf1, 21 | const char *write_process_memory_obf, uint64_t obf2, 22 | const char *virtual_alloc_ex_obf, uint64_t obf3, 23 | const char *virtual_free_ex_obf, uint64_t obf4, 24 | const char *load_library_w_obf, uint64_t obf5) 25 | { 26 | int ret = INJECT_ERROR_UNLIKELY_FAIL; 27 | DWORD last_error = 0; 28 | bool success = false; 29 | size_t written_size; 30 | DWORD thread_id; 31 | HANDLE thread = NULL; 32 | size_t size; 33 | void *mem; 34 | 35 | /* -------------------------------- */ 36 | 37 | HMODULE kernel32 = GetModuleHandleW(L"KERNEL32"); 38 | create_remote_thread_t create_remote_thread; 39 | write_process_memory_t write_process_memory; 40 | virtual_alloc_ex_t virtual_alloc_ex; 41 | virtual_free_ex_t virtual_free_ex; 42 | FARPROC load_library_w; 43 | 44 | create_remote_thread = 45 | get_obfuscated_func(kernel32, create_remote_thread_obf, obf1); 46 | write_process_memory = 47 | get_obfuscated_func(kernel32, write_process_memory_obf, obf2); 48 | virtual_alloc_ex = 49 | get_obfuscated_func(kernel32, virtual_alloc_ex_obf, obf3); 50 | virtual_free_ex = 51 | get_obfuscated_func(kernel32, virtual_free_ex_obf, obf4); 52 | load_library_w = 53 | get_obfuscated_func(kernel32, load_library_w_obf, obf5); 54 | 55 | /* -------------------------------- */ 56 | 57 | size = (wcslen(dll) + 1) * sizeof(wchar_t); 58 | mem = virtual_alloc_ex(process, NULL, size, MEM_RESERVE | MEM_COMMIT, 59 | PAGE_READWRITE); 60 | if (!mem) { 61 | goto fail; 62 | } 63 | 64 | success = write_process_memory(process, mem, dll, size, &written_size); 65 | if (!success) { 66 | goto fail; 67 | } 68 | 69 | thread = create_remote_thread(process, NULL, 0, 70 | (LPTHREAD_START_ROUTINE)load_library_w, 71 | mem, 0, &thread_id); 72 | if (!thread) { 73 | goto fail; 74 | } 75 | 76 | if (WaitForSingleObject(thread, 4000) == WAIT_OBJECT_0) { 77 | DWORD code; 78 | GetExitCodeThread(thread, &code); 79 | ret = (code != 0) ? 0 : INJECT_ERROR_INJECT_FAILED; 80 | 81 | SetLastError(0); 82 | } 83 | 84 | fail: 85 | if (ret == INJECT_ERROR_UNLIKELY_FAIL) { 86 | last_error = GetLastError(); 87 | } 88 | if (thread) { 89 | CloseHandle(thread); 90 | } 91 | if (mem) { 92 | virtual_free_ex(process, mem, 0, MEM_RELEASE); 93 | } 94 | if (last_error != 0) { 95 | SetLastError(last_error); 96 | } 97 | 98 | return ret; 99 | } 100 | 101 | /* ------------------------------------------------------------------------- */ 102 | 103 | typedef HHOOK(WINAPI *set_windows_hook_ex_t)(int, HOOKPROC, HINSTANCE, DWORD); 104 | 105 | #define RETRY_INTERVAL_MS 500 106 | #define TOTAL_RETRY_TIME_MS 4000 107 | #define RETRY_COUNT (TOTAL_RETRY_TIME_MS / RETRY_INTERVAL_MS) 108 | 109 | int inject_library_safe_obf(DWORD thread_id, const wchar_t *dll, 110 | const char *set_windows_hook_ex_obf, uint64_t obf1) 111 | { 112 | HMODULE user32 = GetModuleHandleW(L"USER32"); 113 | set_windows_hook_ex_t set_windows_hook_ex; 114 | HMODULE lib = LoadLibraryW(dll); 115 | LPVOID proc; 116 | HHOOK hook; 117 | size_t i; 118 | 119 | if (!lib || !user32) { 120 | return INJECT_ERROR_UNLIKELY_FAIL; 121 | } 122 | 123 | #ifdef _WIN64 124 | proc = GetProcAddress(lib, "dummy_debug_proc"); 125 | #else 126 | proc = GetProcAddress(lib, "_dummy_debug_proc@12"); 127 | #endif 128 | 129 | if (!proc) { 130 | return INJECT_ERROR_UNLIKELY_FAIL; 131 | } 132 | 133 | set_windows_hook_ex = 134 | get_obfuscated_func(user32, set_windows_hook_ex_obf, obf1); 135 | 136 | hook = set_windows_hook_ex(WH_GETMESSAGE, proc, lib, thread_id); 137 | if (!hook) { 138 | return GetLastError(); 139 | } 140 | 141 | /* SetWindowsHookEx does not inject the library in to the target 142 | * process unless the event associated with it has occurred, so 143 | * repeatedly send the hook message to start the hook at small 144 | * intervals to signal to SetWindowsHookEx to process the message and 145 | * therefore inject the library in to the target process. Repeating 146 | * this is mostly just a precaution. */ 147 | 148 | for (i = 0; i < RETRY_COUNT; i++) { 149 | Sleep(RETRY_INTERVAL_MS); 150 | PostThreadMessage(thread_id, WM_USER + 432, 0, (LPARAM)hook); 151 | } 152 | return 0; 153 | } 154 | -------------------------------------------------------------------------------- /NoxCap/semaphore.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Module: semaphore.h 3 | * 4 | * Purpose: 5 | * Semaphores aren't actually part of the PThreads standard. 6 | * They are defined by the POSIX Standard: 7 | * 8 | * POSIX 1003.1b-1993 (POSIX.1b) 9 | * 10 | * -------------------------------------------------------------------------- 11 | * 12 | * Pthreads-win32 - POSIX Threads Library for Win32 13 | * Copyright(C) 1998 John E. Bossom 14 | * Copyright(C) 1999,2005 Pthreads-win32 contributors 15 | * 16 | * Contact Email: rpj@callisto.canberra.edu.au 17 | * 18 | * The current list of contributors is contained 19 | * in the file CONTRIBUTORS included with the source 20 | * code distribution. The list can also be seen at the 21 | * following World Wide Web location: 22 | * http://sources.redhat.com/pthreads-win32/contributors.html 23 | * 24 | * This library is free software; you can redistribute it and/or 25 | * modify it under the terms of the GNU Lesser General Public 26 | * License as published by the Free Software Foundation; either 27 | * version 2 of the License, or (at your option) any later version. 28 | * 29 | * This library is distributed in the hope that it will be useful, 30 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 31 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 32 | * Lesser General Public License for more details. 33 | * 34 | * You should have received a copy of the GNU Lesser General Public 35 | * License along with this library in the file COPYING.LIB; 36 | * if not, write to the Free Software Foundation, Inc., 37 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA 38 | */ 39 | #if !defined( SEMAPHORE_H ) 40 | #define SEMAPHORE_H 41 | 42 | #undef PTW32_SEMAPHORE_LEVEL 43 | 44 | #if defined(_POSIX_SOURCE) 45 | #define PTW32_SEMAPHORE_LEVEL 0 46 | /* Early POSIX */ 47 | #endif 48 | 49 | #if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199309 50 | #undef PTW32_SEMAPHORE_LEVEL 51 | #define PTW32_SEMAPHORE_LEVEL 1 52 | /* Include 1b, 1c and 1d */ 53 | #endif 54 | 55 | #if defined(INCLUDE_NP) 56 | #undef PTW32_SEMAPHORE_LEVEL 57 | #define PTW32_SEMAPHORE_LEVEL 2 58 | /* Include Non-Portable extensions */ 59 | #endif 60 | 61 | #define PTW32_SEMAPHORE_LEVEL_MAX 3 62 | 63 | #if !defined(PTW32_SEMAPHORE_LEVEL) 64 | #define PTW32_SEMAPHORE_LEVEL PTW32_SEMAPHORE_LEVEL_MAX 65 | /* Include everything */ 66 | #endif 67 | 68 | #if defined(__GNUC__) && ! defined (__declspec) 69 | # error Please upgrade your GNU compiler to one that supports __declspec. 70 | #endif 71 | 72 | /* 73 | * When building the library, you should define PTW32_BUILD so that 74 | * the variables/functions are exported correctly. When using the library, 75 | * do NOT define PTW32_BUILD, and then the variables/functions will 76 | * be imported correctly. 77 | */ 78 | #if !defined(PTW32_STATIC_LIB) 79 | # if defined(PTW32_BUILD) 80 | # define PTW32_DLLPORT __declspec (dllexport) 81 | # else 82 | # define PTW32_DLLPORT 83 | # endif 84 | #else 85 | # define PTW32_DLLPORT 86 | #endif 87 | 88 | /* 89 | * This is a duplicate of what is in the autoconf config.h, 90 | * which is only used when building the pthread-win32 libraries. 91 | */ 92 | 93 | #if !defined(PTW32_CONFIG_H) 94 | # if defined(WINCE) 95 | # define NEED_ERRNO 96 | # define NEED_SEM 97 | # endif 98 | # if defined(__MINGW64__) 99 | # define HAVE_STRUCT_TIMESPEC 100 | # define HAVE_MODE_T 101 | # elif defined(_UWIN) || defined(__MINGW32__) 102 | # define HAVE_MODE_T 103 | # endif 104 | #endif 105 | 106 | /* 107 | * 108 | */ 109 | 110 | #if PTW32_SEMAPHORE_LEVEL >= PTW32_SEMAPHORE_LEVEL_MAX 111 | #if defined(NEED_ERRNO) 112 | #include "need_errno.h" 113 | #else 114 | #include 115 | #endif 116 | #endif /* PTW32_SEMAPHORE_LEVEL >= PTW32_SEMAPHORE_LEVEL_MAX */ 117 | 118 | #define _POSIX_SEMAPHORES 119 | 120 | #if defined(__cplusplus) 121 | extern "C" 122 | { 123 | #endif /* __cplusplus */ 124 | 125 | #if !defined(HAVE_MODE_T) 126 | typedef unsigned int mode_t; 127 | #endif 128 | 129 | 130 | typedef struct sem_t_ * sem_t; 131 | 132 | PTW32_DLLPORT int __cdecl sem_init (sem_t * sem, 133 | int pshared, 134 | unsigned int value); 135 | 136 | PTW32_DLLPORT int __cdecl sem_destroy (sem_t * sem); 137 | 138 | PTW32_DLLPORT int __cdecl sem_trywait (sem_t * sem); 139 | 140 | PTW32_DLLPORT int __cdecl sem_wait (sem_t * sem); 141 | 142 | PTW32_DLLPORT int __cdecl sem_timedwait (sem_t * sem, 143 | const struct timespec * abstime); 144 | 145 | PTW32_DLLPORT int __cdecl sem_post (sem_t * sem); 146 | 147 | PTW32_DLLPORT int __cdecl sem_post_multiple (sem_t * sem, 148 | int count); 149 | 150 | PTW32_DLLPORT int __cdecl sem_open (const char * name, 151 | int oflag, 152 | mode_t mode, 153 | unsigned int value); 154 | 155 | PTW32_DLLPORT int __cdecl sem_close (sem_t * sem); 156 | 157 | PTW32_DLLPORT int __cdecl sem_unlink (const char * name); 158 | 159 | PTW32_DLLPORT int __cdecl sem_getvalue (sem_t * sem, 160 | int * sval); 161 | 162 | #if defined(__cplusplus) 163 | } /* End of extern "C" */ 164 | #endif /* __cplusplus */ 165 | 166 | #undef PTW32_SEMAPHORE_LEVEL 167 | #undef PTW32_SEMAPHORE_LEVEL_MAX 168 | 169 | #endif /* !SEMAPHORE_H */ 170 | -------------------------------------------------------------------------------- /Nox/libOpenGL/gl-helpers.c: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | Copyright (C) 2013 by Hugh Bailey 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 2 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see . 16 | ******************************************************************************/ 17 | 18 | #include "gl-subsystem.h" 19 | 20 | bool gl_init_face(GLenum target, GLenum type, uint32_t num_levels, 21 | GLenum format, GLint internal_format, bool compressed, 22 | uint32_t width, uint32_t height, uint32_t size, 23 | const uint8_t ***p_data) 24 | { 25 | bool success = true; 26 | const uint8_t **data = p_data ? *p_data : NULL; 27 | uint32_t i; 28 | 29 | for (i = 0; i < num_levels; i++) { 30 | if (compressed) { 31 | glCompressedTexImage2D(target, i, internal_format, 32 | width, height, 0, size, 33 | data ? *data : NULL); 34 | if (!gl_success("glCompressedTexImage2D")) 35 | success = false; 36 | 37 | } else { 38 | glTexImage2D(target, i, internal_format, width, height, 39 | 0, format, type, data ? *data : NULL); 40 | if (!gl_success("glTexImage2D")) 41 | success = false; 42 | } 43 | 44 | if (data) 45 | data++; 46 | 47 | size /= 4; 48 | width /= 2; 49 | height /= 2; 50 | 51 | if (width == 0) 52 | width = 1; 53 | if (height == 0) 54 | height = 1; 55 | } 56 | 57 | if (data) 58 | *p_data = data; 59 | return success; 60 | } 61 | 62 | static bool gl_copy_fbo(struct gs_texture *dst, uint32_t dst_x, uint32_t dst_y, 63 | struct gs_texture *src, uint32_t src_x, uint32_t src_y, 64 | uint32_t width, uint32_t height) 65 | { 66 | struct fbo_info *fbo = get_fbo(src, width, height); 67 | GLint last_fbo; 68 | bool success = false; 69 | 70 | if (!fbo) 71 | return false; 72 | 73 | if (!gl_get_integer_v(GL_READ_FRAMEBUFFER_BINDING, &last_fbo)) 74 | return false; 75 | if (!gl_bind_framebuffer(GL_READ_FRAMEBUFFER, fbo->fbo)) 76 | return false; 77 | if (!gl_bind_texture(dst->gl_target, dst->texture)) 78 | goto fail; 79 | 80 | glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + 0, 81 | src->gl_target, src->texture, 0); 82 | if (!gl_success("glFrameBufferTexture2D")) 83 | goto fail; 84 | 85 | glReadBuffer(GL_COLOR_ATTACHMENT0 + 0); 86 | if (!gl_success("glReadBuffer")) 87 | goto fail; 88 | 89 | glCopyTexSubImage2D(dst->gl_target, 0, dst_x, dst_y, src_x, src_y, 90 | width, height); 91 | if (!gl_success("glCopyTexSubImage2D")) 92 | goto fail; 93 | 94 | success = true; 95 | 96 | fail: 97 | if (!gl_bind_texture(dst->gl_target, 0)) 98 | success = false; 99 | if (!gl_bind_framebuffer(GL_READ_FRAMEBUFFER, last_fbo)) 100 | success = false; 101 | 102 | return success; 103 | } 104 | 105 | bool gl_copy_texture(struct gs_device *device, struct gs_texture *dst, 106 | uint32_t dst_x, uint32_t dst_y, struct gs_texture *src, 107 | uint32_t src_x, uint32_t src_y, uint32_t width, 108 | uint32_t height) 109 | { 110 | bool success = false; 111 | 112 | if (device->copy_type == COPY_TYPE_ARB) { 113 | glCopyImageSubData(src->texture, src->gl_target, 0, src_x, 114 | src_y, 0, dst->texture, dst->gl_target, 0, 115 | dst_x, dst_y, 0, width, height, 1); 116 | success = gl_success("glCopyImageSubData"); 117 | 118 | } else if (device->copy_type == COPY_TYPE_NV) { 119 | glCopyImageSubDataNV(src->texture, src->gl_target, 0, src_x, 120 | src_y, 0, dst->texture, dst->gl_target, 0, 121 | dst_x, dst_y, 0, width, height, 1); 122 | success = gl_success("glCopyImageSubDataNV"); 123 | 124 | } else if (device->copy_type == COPY_TYPE_FBO_BLIT) { 125 | success = gl_copy_fbo(dst, dst_x, dst_y, src, src_x, src_y, 126 | width, height); 127 | if (!success) 128 | blog(LOG_ERROR, "gl_copy_texture failed"); 129 | } 130 | 131 | return success; 132 | } 133 | 134 | bool gl_create_buffer(GLenum target, GLuint *buffer, GLsizeiptr size, 135 | const GLvoid *data, GLenum usage) 136 | { 137 | bool success; 138 | if (!gl_gen_buffers(1, buffer)) 139 | return false; 140 | if (!gl_bind_buffer(target, *buffer)) 141 | return false; 142 | 143 | glBufferData(target, size, data, usage); 144 | success = gl_success("glBufferData"); 145 | 146 | gl_bind_buffer(target, 0); 147 | return success; 148 | } 149 | 150 | bool update_buffer(GLenum target, GLuint buffer, const void *data, size_t size) 151 | { 152 | void *ptr; 153 | bool success = true; 154 | 155 | if (!gl_bind_buffer(target, buffer)) 156 | return false; 157 | 158 | /* glMapBufferRange with these flags will actually give far better 159 | * performance than a plain glMapBuffer call */ 160 | ptr = glMapBufferRange(target, 0, size, 161 | GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT); 162 | success = gl_success("glMapBufferRange"); 163 | if (success && ptr) { 164 | memcpy(ptr, data, size); 165 | glUnmapBuffer(target); 166 | } 167 | 168 | gl_bind_buffer(target, 0); 169 | return success; 170 | } 171 | -------------------------------------------------------------------------------- /NoxCap/sched.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Module: sched.h 3 | * 4 | * Purpose: 5 | * Provides an implementation of POSIX realtime extensions 6 | * as defined in 7 | * 8 | * POSIX 1003.1b-1993 (POSIX.1b) 9 | * 10 | * -------------------------------------------------------------------------- 11 | * 12 | * Pthreads-win32 - POSIX Threads Library for Win32 13 | * Copyright(C) 1998 John E. Bossom 14 | * Copyright(C) 1999,2005 Pthreads-win32 contributors 15 | * 16 | * Contact Email: rpj@callisto.canberra.edu.au 17 | * 18 | * The current list of contributors is contained 19 | * in the file CONTRIBUTORS included with the source 20 | * code distribution. The list can also be seen at the 21 | * following World Wide Web location: 22 | * http://sources.redhat.com/pthreads-win32/contributors.html 23 | * 24 | * This library is free software; you can redistribute it and/or 25 | * modify it under the terms of the GNU Lesser General Public 26 | * License as published by the Free Software Foundation; either 27 | * version 2 of the License, or (at your option) any later version. 28 | * 29 | * This library is distributed in the hope that it will be useful, 30 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 31 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 32 | * Lesser General Public License for more details. 33 | * 34 | * You should have received a copy of the GNU Lesser General Public 35 | * License along with this library in the file COPYING.LIB; 36 | * if not, write to the Free Software Foundation, Inc., 37 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA 38 | */ 39 | #if !defined(_SCHED_H) 40 | #define _SCHED_H 41 | 42 | #undef PTW32_SCHED_LEVEL 43 | 44 | #if defined(_POSIX_SOURCE) 45 | #define PTW32_SCHED_LEVEL 0 46 | /* Early POSIX */ 47 | #endif 48 | 49 | #if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199309 50 | #undef PTW32_SCHED_LEVEL 51 | #define PTW32_SCHED_LEVEL 1 52 | /* Include 1b, 1c and 1d */ 53 | #endif 54 | 55 | #if defined(INCLUDE_NP) 56 | #undef PTW32_SCHED_LEVEL 57 | #define PTW32_SCHED_LEVEL 2 58 | /* Include Non-Portable extensions */ 59 | #endif 60 | 61 | #define PTW32_SCHED_LEVEL_MAX 3 62 | 63 | #if ( defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112 ) || !defined(PTW32_SCHED_LEVEL) 64 | #define PTW32_SCHED_LEVEL PTW32_SCHED_LEVEL_MAX 65 | /* Include everything */ 66 | #endif 67 | 68 | 69 | #if defined(__GNUC__) && !defined(__declspec) 70 | # error Please upgrade your GNU compiler to one that supports __declspec. 71 | #endif 72 | 73 | /* 74 | * When building the library, you should define PTW32_BUILD so that 75 | * the variables/functions are exported correctly. When using the library, 76 | * do NOT define PTW32_BUILD, and then the variables/functions will 77 | * be imported correctly. 78 | */ 79 | #if !defined(PTW32_STATIC_LIB) 80 | # if defined(PTW32_BUILD) 81 | # define PTW32_DLLPORT __declspec (dllexport) 82 | # else 83 | # define PTW32_DLLPORT 84 | # endif 85 | #else 86 | # define PTW32_DLLPORT 87 | #endif 88 | 89 | /* 90 | * This is a duplicate of what is in the autoconf config.h, 91 | * which is only used when building the pthread-win32 libraries. 92 | */ 93 | 94 | #if !defined(PTW32_CONFIG_H) 95 | # if defined(WINCE) 96 | # define NEED_ERRNO 97 | # define NEED_SEM 98 | # endif 99 | # if defined(__MINGW64__) 100 | # define HAVE_STRUCT_TIMESPEC 101 | # define HAVE_MODE_T 102 | # elif defined(_UWIN) || defined(__MINGW32__) 103 | # define HAVE_MODE_T 104 | # endif 105 | #endif 106 | 107 | /* 108 | * 109 | */ 110 | 111 | #if PTW32_SCHED_LEVEL >= PTW32_SCHED_LEVEL_MAX 112 | #if defined(NEED_ERRNO) 113 | #include "need_errno.h" 114 | #else 115 | #include 116 | #endif 117 | #endif /* PTW32_SCHED_LEVEL >= PTW32_SCHED_LEVEL_MAX */ 118 | 119 | #if (defined(__MINGW64__) || defined(__MINGW32__)) || defined(_UWIN) 120 | # if PTW32_SCHED_LEVEL >= PTW32_SCHED_LEVEL_MAX 121 | /* For pid_t */ 122 | # include 123 | /* Required by Unix 98 */ 124 | # include 125 | # else 126 | typedef int pid_t; 127 | # endif 128 | #else 129 | typedef int pid_t; 130 | #endif 131 | 132 | /* Thread scheduling policies */ 133 | 134 | enum { 135 | SCHED_OTHER = 0, 136 | SCHED_FIFO, 137 | SCHED_RR, 138 | SCHED_MIN = SCHED_OTHER, 139 | SCHED_MAX = SCHED_RR 140 | }; 141 | 142 | struct sched_param { 143 | int sched_priority; 144 | }; 145 | 146 | #if defined(__cplusplus) 147 | extern "C" 148 | { 149 | #endif /* __cplusplus */ 150 | 151 | PTW32_DLLPORT int __cdecl sched_yield (void); 152 | 153 | PTW32_DLLPORT int __cdecl sched_get_priority_min (int policy); 154 | 155 | PTW32_DLLPORT int __cdecl sched_get_priority_max (int policy); 156 | 157 | PTW32_DLLPORT int __cdecl sched_setscheduler (pid_t pid, int policy); 158 | 159 | PTW32_DLLPORT int __cdecl sched_getscheduler (pid_t pid); 160 | 161 | /* 162 | * Note that this macro returns ENOTSUP rather than 163 | * ENOSYS as might be expected. However, returning ENOSYS 164 | * should mean that sched_get_priority_{min,max} are 165 | * not implemented as well as sched_rr_get_interval. 166 | * This is not the case, since we just don't support 167 | * round-robin scheduling. Therefore I have chosen to 168 | * return the same value as sched_setscheduler when 169 | * SCHED_RR is passed to it. 170 | */ 171 | #define sched_rr_get_interval(_pid, _interval) \ 172 | ( errno = ENOTSUP, (int) -1 ) 173 | 174 | 175 | #if defined(__cplusplus) 176 | } /* End of extern "C" */ 177 | #endif /* __cplusplus */ 178 | 179 | #undef PTW32_SCHED_LEVEL 180 | #undef PTW32_SCHED_LEVEL_MAX 181 | 182 | #endif /* !_SCHED_H */ 183 | 184 | -------------------------------------------------------------------------------- /Nox/Noxcap.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | //#include "graphics-hook-config.h" 4 | 5 | #ifdef _MSC_VER 6 | /* conversion from data/function pointer */ 7 | #pragma warning(disable : 4152) 8 | #endif 9 | 10 | #include "graphics-hook-info.h" 11 | #include 12 | 13 | #ifdef __cplusplus 14 | extern "C" { 15 | #else 16 | #if defined(_MSC_VER) && !defined(inline) 17 | #define inline __inline 18 | #endif 19 | #endif 20 | 21 | #define NUM_BUFFERS 3 22 | 23 | extern void hlog(const char *format, ...); 24 | extern void hlog_hr(const char *text, HRESULT hr); 25 | static inline const char *get_process_name(void); 26 | static inline HMODULE get_system_module(const char *module); 27 | static inline HMODULE load_system_library(const char *module); 28 | extern uint64_t os_gettime_ns(void); 29 | 30 | static inline bool capture_active(void); 31 | static inline bool capture_ready(void); 32 | static inline bool capture_should_stop(void); 33 | static inline bool capture_should_init(void); 34 | 35 | extern void shmem_copy_data(size_t idx, void *volatile data); 36 | extern bool shmem_texture_data_lock(int idx); 37 | extern void shmem_texture_data_unlock(int idx); 38 | 39 | extern bool hook_ddraw(void); 40 | extern bool hook_d3d8(void); 41 | extern bool hook_d3d9(void); 42 | extern bool hook_dxgi(void); 43 | extern bool hook_gl(void); 44 | 45 | extern void d3d10_capture(void *swap, void *backbuffer, bool capture_overlay); 46 | extern void d3d10_free(void); 47 | extern void d3d11_capture(void *swap, void *backbuffer, bool capture_overlay); 48 | extern void d3d11_free(void); 49 | 50 | #if COMPILE_D3D12_HOOK 51 | extern void d3d12_capture(void *swap, void *backbuffer, bool capture_overlay); 52 | extern void d3d12_free(void); 53 | #endif 54 | 55 | extern uint8_t *get_d3d1x_vertex_shader(size_t *size); 56 | extern uint8_t *get_d3d1x_pixel_shader(size_t *size); 57 | 58 | extern bool rehook_gl(void); 59 | 60 | extern bool capture_init_shtex(struct shtex_data **data, HWND window, 61 | uint32_t base_cx, uint32_t base_cy, uint32_t cx, 62 | uint32_t cy, uint32_t format, bool flip, 63 | uintptr_t handle); 64 | extern bool capture_init_shmem(struct shmem_data **data, HWND window, 65 | uint32_t base_cx, uint32_t base_cy, uint32_t cx, 66 | uint32_t cy, uint32_t pitch, uint32_t format, 67 | bool flip); 68 | extern void capture_free(void); 69 | 70 | extern struct hook_info *global_hook_info; 71 | 72 | struct vertex { 73 | struct { 74 | float x, y, z, w; 75 | } pos; 76 | struct { 77 | float u, v; 78 | } tex; 79 | }; 80 | 81 | static inline bool duplicate_handle(HANDLE *dst, HANDLE src) 82 | { 83 | return !!DuplicateHandle(GetCurrentProcess(), src, GetCurrentProcess(), 84 | dst, 0, false, DUPLICATE_SAME_ACCESS); 85 | } 86 | 87 | static inline void *get_offset_addr(HMODULE module, uint32_t offset) 88 | { 89 | return (void *)((uintptr_t)module + (uintptr_t)offset); 90 | } 91 | 92 | /* ------------------------------------------------------------------------- */ 93 | 94 | extern HANDLE signal_restart; 95 | extern HANDLE signal_stop; 96 | extern HANDLE signal_ready; 97 | extern HANDLE signal_exit; 98 | extern HANDLE tex_mutexes[2]; 99 | extern char system_path[MAX_PATH]; 100 | extern char process_name[MAX_PATH]; 101 | extern wchar_t keepalive_name[64]; 102 | extern HWND dummy_window; 103 | extern volatile bool active; 104 | 105 | static inline const char *get_process_name(void) 106 | { 107 | return process_name; 108 | } 109 | 110 | static inline HMODULE get_system_module(const char *module) 111 | { 112 | char base_path[MAX_PATH]; 113 | 114 | strcpy(base_path, system_path); 115 | strcat(base_path, "\\"); 116 | strcat(base_path, module); 117 | return GetModuleHandleA(base_path); 118 | } 119 | 120 | static inline uint32_t module_size(HMODULE module) 121 | { 122 | MODULEINFO info; 123 | bool success = !!GetModuleInformation(GetCurrentProcess(), module, 124 | &info, sizeof(info)); 125 | return success ? info.SizeOfImage : 0; 126 | } 127 | 128 | static inline HMODULE load_system_library(const char *name) 129 | { 130 | char base_path[MAX_PATH]; 131 | HMODULE module; 132 | 133 | strcpy(base_path, system_path); 134 | strcat(base_path, "\\"); 135 | strcat(base_path, name); 136 | 137 | module = GetModuleHandleA(base_path); 138 | if (module) 139 | return module; 140 | 141 | return LoadLibraryA(base_path); 142 | } 143 | 144 | static inline bool capture_alive(void) 145 | { 146 | HANDLE handle = OpenMutexW(SYNCHRONIZE, false, keepalive_name); 147 | CloseHandle(handle); 148 | 149 | if (handle) 150 | return true; 151 | 152 | return GetLastError() != ERROR_FILE_NOT_FOUND; 153 | } 154 | 155 | static inline bool capture_active(void) 156 | { 157 | return active; 158 | } 159 | 160 | static inline bool frame_ready(uint64_t interval) 161 | { 162 | static uint64_t last_time = 0; 163 | uint64_t elapsed; 164 | uint64_t t; 165 | 166 | if (!interval) { 167 | return true; 168 | } 169 | 170 | t = os_gettime_ns(); 171 | elapsed = t - last_time; 172 | 173 | if (elapsed < interval) { 174 | return false; 175 | } 176 | 177 | last_time = (elapsed > interval * 2) ? t : last_time + interval; 178 | return true; 179 | } 180 | 181 | static inline bool capture_ready(void) 182 | { 183 | return capture_active() && 184 | frame_ready(global_hook_info->frame_interval); 185 | } 186 | 187 | static inline bool capture_stopped(void) 188 | { 189 | return WaitForSingleObject(signal_stop, 0) == WAIT_OBJECT_0; 190 | } 191 | 192 | static inline bool capture_restarted(void) 193 | { 194 | return WaitForSingleObject(signal_restart, 0) == WAIT_OBJECT_0; 195 | } 196 | 197 | static inline bool capture_should_stop(void) 198 | { 199 | bool stop_requested = false; 200 | 201 | if (capture_active()) { 202 | static uint64_t last_keepalive_check = 0; 203 | uint64_t cur_time = os_gettime_ns(); 204 | bool alive = true; 205 | 206 | if (cur_time - last_keepalive_check > 5000000000) { 207 | alive = capture_alive(); 208 | last_keepalive_check = cur_time; 209 | } 210 | 211 | stop_requested = capture_stopped() || !alive; 212 | } 213 | 214 | return stop_requested; 215 | } 216 | 217 | extern bool init_pipe(void); 218 | 219 | static inline bool capture_should_init(void) 220 | { 221 | if (!capture_active() && capture_restarted()) { 222 | if (capture_alive()) { 223 | return true; 224 | } 225 | } 226 | 227 | return false; 228 | } 229 | 230 | #ifdef __cplusplus 231 | } 232 | #endif 233 | -------------------------------------------------------------------------------- /Nox/graphic-hook/graphics-hook.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | //#include "graphics-hook-config.h" 4 | 5 | #ifdef _MSC_VER 6 | /* conversion from data/function pointer */ 7 | #pragma warning(disable : 4152) 8 | #endif 9 | 10 | #include "../graphics-hook-info.h" 11 | #include 12 | 13 | #ifdef __cplusplus 14 | extern "C" { 15 | #else 16 | #if defined(_MSC_VER) && !defined(inline) 17 | #define inline __inline 18 | #endif 19 | #endif 20 | 21 | #define NUM_BUFFERS 3 22 | 23 | extern void hlog(const char *format, ...); 24 | extern void hlog_hr(const char *text, HRESULT hr); 25 | static inline const char *get_process_name(void); 26 | static inline HMODULE get_system_module(const char *module); 27 | static inline HMODULE load_system_library(const char *module); 28 | extern uint64_t os_gettime_ns(void); 29 | 30 | static inline bool capture_active(void); 31 | static inline bool capture_ready(void); 32 | static inline bool capture_should_stop(void); 33 | static inline bool capture_should_init(void); 34 | 35 | extern void shmem_copy_data(size_t idx, void *volatile data); 36 | extern bool shmem_texture_data_lock(int idx); 37 | extern void shmem_texture_data_unlock(int idx); 38 | 39 | extern bool hook_ddraw(void); 40 | extern bool hook_d3d8(void); 41 | extern bool hook_d3d9(void); 42 | extern bool hook_dxgi(void); 43 | extern bool hook_gl(void); 44 | 45 | extern void d3d10_capture(void *swap, void *backbuffer, bool capture_overlay); 46 | extern void d3d10_free(void); 47 | extern void d3d11_capture(void *swap, void *backbuffer, bool capture_overlay); 48 | extern void d3d11_free(void); 49 | 50 | #if COMPILE_D3D12_HOOK 51 | extern void d3d12_capture(void *swap, void *backbuffer, bool capture_overlay); 52 | extern void d3d12_free(void); 53 | #endif 54 | 55 | extern uint8_t *get_d3d1x_vertex_shader(size_t *size); 56 | extern uint8_t *get_d3d1x_pixel_shader(size_t *size); 57 | 58 | extern bool rehook_gl(void); 59 | 60 | extern bool capture_init_shtex(struct shtex_data **data, HWND window, 61 | uint32_t base_cx, uint32_t base_cy, uint32_t cx, 62 | uint32_t cy, uint32_t format, bool flip, 63 | uintptr_t handle); 64 | extern bool capture_init_shmem(struct shmem_data **data, HWND window, 65 | uint32_t base_cx, uint32_t base_cy, uint32_t cx, 66 | uint32_t cy, uint32_t pitch, uint32_t format, 67 | bool flip); 68 | extern void capture_free(void); 69 | 70 | extern struct hook_info *global_hook_info; 71 | 72 | struct vertex { 73 | struct { 74 | float x, y, z, w; 75 | } pos; 76 | struct { 77 | float u, v; 78 | } tex; 79 | }; 80 | 81 | static inline bool duplicate_handle(HANDLE *dst, HANDLE src) 82 | { 83 | return !!DuplicateHandle(GetCurrentProcess(), src, GetCurrentProcess(), 84 | dst, 0, false, DUPLICATE_SAME_ACCESS); 85 | } 86 | 87 | static inline void *get_offset_addr(HMODULE module, uint32_t offset) 88 | { 89 | return (void *)((uintptr_t)module + (uintptr_t)offset); 90 | } 91 | 92 | /* ------------------------------------------------------------------------- */ 93 | 94 | extern HANDLE signal_restart; 95 | extern HANDLE signal_stop; 96 | extern HANDLE signal_ready; 97 | extern HANDLE signal_exit; 98 | extern HANDLE tex_mutexes[2]; 99 | extern char system_path[MAX_PATH]; 100 | extern char process_name[MAX_PATH]; 101 | extern wchar_t keepalive_name[64]; 102 | extern HWND dummy_window; 103 | extern volatile bool active; 104 | 105 | static inline const char *get_process_name(void) 106 | { 107 | return process_name; 108 | } 109 | 110 | static inline HMODULE get_system_module(const char *module) 111 | { 112 | char base_path[MAX_PATH]; 113 | 114 | strcpy(base_path, system_path); 115 | strcat(base_path, "\\"); 116 | strcat(base_path, module); 117 | return GetModuleHandleA(base_path); 118 | } 119 | 120 | static inline uint32_t module_size(HMODULE module) 121 | { 122 | MODULEINFO info; 123 | bool success = !!GetModuleInformation(GetCurrentProcess(), module, 124 | &info, sizeof(info)); 125 | return success ? info.SizeOfImage : 0; 126 | } 127 | 128 | static inline HMODULE load_system_library(const char *name) 129 | { 130 | char base_path[MAX_PATH]; 131 | HMODULE module; 132 | 133 | strcpy(base_path, system_path); 134 | strcat(base_path, "\\"); 135 | strcat(base_path, name); 136 | 137 | module = GetModuleHandleA(base_path); 138 | if (module) 139 | return module; 140 | 141 | return LoadLibraryA(base_path); 142 | } 143 | 144 | static inline bool capture_alive(void) 145 | { 146 | HANDLE handle = OpenMutexW(SYNCHRONIZE, false, keepalive_name); 147 | CloseHandle(handle); 148 | 149 | if (handle) 150 | return true; 151 | 152 | return GetLastError() != ERROR_FILE_NOT_FOUND; 153 | } 154 | 155 | static inline bool capture_active(void) 156 | { 157 | return active; 158 | } 159 | 160 | static inline bool frame_ready(uint64_t interval) 161 | { 162 | static uint64_t last_time = 0; 163 | uint64_t elapsed; 164 | uint64_t t; 165 | 166 | if (!interval) { 167 | return true; 168 | } 169 | 170 | t = os_gettime_ns(); 171 | elapsed = t - last_time; 172 | 173 | if (elapsed < interval) { 174 | return false; 175 | } 176 | 177 | last_time = (elapsed > interval * 2) ? t : last_time + interval; 178 | return true; 179 | } 180 | 181 | static inline bool capture_ready(void) 182 | { 183 | return capture_active() && 184 | frame_ready(global_hook_info->frame_interval); 185 | } 186 | 187 | static inline bool capture_stopped(void) 188 | { 189 | return WaitForSingleObject(signal_stop, 0) == WAIT_OBJECT_0; 190 | } 191 | 192 | static inline bool capture_restarted(void) 193 | { 194 | return WaitForSingleObject(signal_restart, 0) == WAIT_OBJECT_0; 195 | } 196 | 197 | static inline bool capture_should_stop(void) 198 | { 199 | bool stop_requested = false; 200 | 201 | if (capture_active()) { 202 | static uint64_t last_keepalive_check = 0; 203 | uint64_t cur_time = os_gettime_ns(); 204 | bool alive = true; 205 | 206 | if (cur_time - last_keepalive_check > 5000000000) { 207 | alive = capture_alive(); 208 | last_keepalive_check = cur_time; 209 | } 210 | 211 | stop_requested = capture_stopped() || !alive; 212 | } 213 | 214 | return stop_requested; 215 | } 216 | 217 | extern bool init_pipe(void); 218 | 219 | static inline bool capture_should_init(void) 220 | { 221 | if (!capture_active() && capture_restarted()) { 222 | if (capture_alive()) { 223 | return true; 224 | } 225 | } 226 | 227 | return false; 228 | } 229 | 230 | #ifdef __cplusplus 231 | } 232 | #endif 233 | -------------------------------------------------------------------------------- /Nox/libOpenGL/gl-helpers.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | Copyright (C) 2013 by Hugh Bailey 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 2 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see . 16 | ******************************************************************************/ 17 | 18 | #pragma once 19 | 20 | static const char *gl_error_to_str(GLenum errorcode) 21 | { 22 | static const struct { 23 | GLenum error; 24 | const char *str; 25 | } err_to_str[] = { 26 | { 27 | GL_INVALID_ENUM, 28 | "GL_INVALID_ENUM", 29 | }, 30 | { 31 | GL_INVALID_VALUE, 32 | "GL_INVALID_VALUE", 33 | }, 34 | { 35 | GL_INVALID_OPERATION, 36 | "GL_INVALID_OPERATION", 37 | }, 38 | { 39 | GL_INVALID_FRAMEBUFFER_OPERATION, 40 | "GL_INVALID_FRAMEBUFFER_OPERATION", 41 | }, 42 | { 43 | GL_OUT_OF_MEMORY, 44 | "GL_OUT_OF_MEMORY", 45 | }, 46 | { 47 | GL_STACK_UNDERFLOW, 48 | "GL_STACK_UNDERFLOW", 49 | }, 50 | { 51 | GL_STACK_OVERFLOW, 52 | "GL_STACK_OVERFLOW", 53 | }, 54 | }; 55 | for (size_t i = 0; i < sizeof(err_to_str) / sizeof(*err_to_str); i++) { 56 | if (err_to_str[i].error == errorcode) 57 | return err_to_str[i].str; 58 | } 59 | return "Unknown"; 60 | } 61 | 62 | /* 63 | * Okay, so GL error handling is.. unclean to work with. I don't want 64 | * to have to keep typing out the same stuff over and over again do I'll just 65 | * make a bunch of helper functions to make it a bit easier to handle errors 66 | */ 67 | 68 | static inline bool gl_success(const char *funcname) 69 | { 70 | GLenum errorcode = glGetError(); 71 | if (errorcode != GL_NO_ERROR) { 72 | int attempts = 8; 73 | do { 74 | blog(LOG_ERROR, 75 | "%s failed, glGetError returned %s(0x%X)", 76 | funcname, gl_error_to_str(errorcode), errorcode); 77 | errorcode = glGetError(); 78 | 79 | --attempts; 80 | if (attempts == 0) { 81 | blog(LOG_ERROR, 82 | "Too many GL errors, moving on"); 83 | break; 84 | } 85 | } while (errorcode != GL_NO_ERROR); 86 | return false; 87 | } 88 | 89 | return true; 90 | } 91 | 92 | static inline bool gl_gen_textures(GLsizei num_texture, GLuint *textures) 93 | { 94 | glGenTextures(num_texture, textures); 95 | return gl_success("glGenTextures"); 96 | } 97 | 98 | static inline bool gl_bind_texture(GLenum target, GLuint texture) 99 | { 100 | glBindTexture(target, texture); 101 | return gl_success("glBindTexture"); 102 | } 103 | 104 | static inline void gl_delete_textures(GLsizei num_buffers, GLuint *buffers) 105 | { 106 | glDeleteTextures(num_buffers, buffers); 107 | gl_success("glDeleteTextures"); 108 | } 109 | 110 | static inline bool gl_gen_buffers(GLsizei num_buffers, GLuint *buffers) 111 | { 112 | glGenBuffers(num_buffers, buffers); 113 | return gl_success("glGenBuffers"); 114 | } 115 | 116 | static inline bool gl_bind_buffer(GLenum target, GLuint buffer) 117 | { 118 | glBindBuffer(target, buffer); 119 | return gl_success("glBindBuffer"); 120 | } 121 | 122 | static inline void gl_delete_buffers(GLsizei num_buffers, GLuint *buffers) 123 | { 124 | glDeleteBuffers(num_buffers, buffers); 125 | gl_success("glDeleteBuffers"); 126 | } 127 | 128 | static inline bool gl_gen_vertex_arrays(GLsizei num_arrays, GLuint *arrays) 129 | { 130 | glGenVertexArrays(num_arrays, arrays); 131 | return gl_success("glGenVertexArrays"); 132 | } 133 | 134 | static inline bool gl_bind_vertex_array(GLuint array) 135 | { 136 | glBindVertexArray(array); 137 | return gl_success("glBindVertexArray"); 138 | } 139 | 140 | static inline void gl_delete_vertex_arrays(GLsizei num_arrays, GLuint *arrays) 141 | { 142 | glDeleteVertexArrays(num_arrays, arrays); 143 | gl_success("glDeleteVertexArrays"); 144 | } 145 | 146 | static inline bool gl_bind_renderbuffer(GLenum target, GLuint buffer) 147 | { 148 | glBindRenderbuffer(target, buffer); 149 | return gl_success("glBindRendebuffer"); 150 | } 151 | 152 | static inline bool gl_bind_framebuffer(GLenum target, GLuint buffer) 153 | { 154 | glBindFramebuffer(target, buffer); 155 | return gl_success("glBindFramebuffer"); 156 | } 157 | 158 | static inline bool gl_tex_param_f(GLenum target, GLenum param, GLfloat val) 159 | { 160 | glTexParameterf(target, param, val); 161 | return gl_success("glTexParameterf"); 162 | } 163 | 164 | static inline bool gl_tex_param_i(GLenum target, GLenum param, GLint val) 165 | { 166 | glTexParameteri(target, param, val); 167 | return gl_success("glTexParameteri"); 168 | } 169 | 170 | static inline bool gl_active_texture(GLenum texture_id) 171 | { 172 | glActiveTexture(texture_id); 173 | return gl_success("glActiveTexture"); 174 | } 175 | 176 | static inline bool gl_enable(GLenum capability) 177 | { 178 | glEnable(capability); 179 | return gl_success("glEnable"); 180 | } 181 | 182 | static inline bool gl_disable(GLenum capability) 183 | { 184 | glDisable(capability); 185 | return gl_success("glDisable"); 186 | } 187 | 188 | static inline bool gl_cull_face(GLenum faces) 189 | { 190 | glCullFace(faces); 191 | return gl_success("glCullFace"); 192 | } 193 | 194 | static inline bool gl_get_integer_v(GLenum pname, GLint *params) 195 | { 196 | glGetIntegerv(pname, params); 197 | return gl_success("glGetIntegerv"); 198 | } 199 | 200 | extern bool gl_init_face(GLenum target, GLenum type, uint32_t num_levels, 201 | GLenum format, GLint internal_format, bool compressed, 202 | uint32_t width, uint32_t height, uint32_t size, 203 | const uint8_t ***p_data); 204 | 205 | extern bool gl_copy_texture(struct gs_device *device, struct gs_texture *dst, 206 | uint32_t dst_x, uint32_t dst_y, 207 | struct gs_texture *src, uint32_t src_x, 208 | uint32_t src_y, uint32_t width, uint32_t height); 209 | 210 | extern bool gl_create_buffer(GLenum target, GLuint *buffer, GLsizeiptr size, 211 | const GLvoid *data, GLenum usage); 212 | 213 | extern bool update_buffer(GLenum target, GLuint buffer, const void *data, 214 | size_t size); 215 | -------------------------------------------------------------------------------- /NoxCap/threading-posix.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014 Hugh Bailey 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #if defined(__APPLE__) || defined(__MINGW32__) 18 | #include 19 | #endif 20 | #ifdef __APPLE__ 21 | #include 22 | #include 23 | #include 24 | #else 25 | #define _GNU_SOURCE 26 | #include "semaphore.h" 27 | #endif 28 | 29 | #if defined(__FreeBSD__) 30 | #include 31 | #endif 32 | 33 | #include "bmem.h" 34 | #include "threading.h" 35 | 36 | struct os_event_data { 37 | pthread_mutex_t mutex; 38 | pthread_cond_t cond; 39 | volatile bool signalled; 40 | bool manual; 41 | }; 42 | 43 | int os_event_init(os_event_t **event, enum os_event_type type) 44 | { 45 | int code = 0; 46 | 47 | struct os_event_data *data = bzalloc(sizeof(struct os_event_data)); 48 | 49 | if ((code = pthread_mutex_init(&data->mutex, NULL)) < 0) { 50 | bfree(data); 51 | return code; 52 | } 53 | 54 | if ((code = pthread_cond_init(&data->cond, NULL)) < 0) { 55 | pthread_mutex_destroy(&data->mutex); 56 | bfree(data); 57 | return code; 58 | } 59 | 60 | data->manual = (type == OS_EVENT_TYPE_MANUAL); 61 | data->signalled = false; 62 | *event = data; 63 | 64 | return 0; 65 | } 66 | 67 | void os_event_destroy(os_event_t *event) 68 | { 69 | if (event) { 70 | pthread_mutex_destroy(&event->mutex); 71 | pthread_cond_destroy(&event->cond); 72 | bfree(event); 73 | } 74 | } 75 | 76 | int os_event_wait(os_event_t *event) 77 | { 78 | int code = 0; 79 | pthread_mutex_lock(&event->mutex); 80 | if (!event->signalled) 81 | code = pthread_cond_wait(&event->cond, &event->mutex); 82 | 83 | if (code == 0) { 84 | if (!event->manual) 85 | event->signalled = false; 86 | pthread_mutex_unlock(&event->mutex); 87 | } 88 | 89 | return code; 90 | } 91 | 92 | static inline void add_ms_to_ts(struct timespec *ts, unsigned long milliseconds) 93 | { 94 | ts->tv_sec += milliseconds / 1000; 95 | ts->tv_nsec += (milliseconds % 1000) * 1000000; 96 | if (ts->tv_nsec > 1000000000) { 97 | ts->tv_sec += 1; 98 | ts->tv_nsec -= 1000000000; 99 | } 100 | } 101 | 102 | int os_event_timedwait(os_event_t *event, unsigned long milliseconds) 103 | { 104 | int code = 0; 105 | pthread_mutex_lock(&event->mutex); 106 | if (!event->signalled) { 107 | struct timespec ts; 108 | #if defined(__APPLE__) || defined(__MINGW32__) 109 | struct timeval tv; 110 | gettimeofday(&tv, NULL); 111 | ts.tv_sec = tv.tv_sec; 112 | ts.tv_nsec = tv.tv_usec * 1000; 113 | #else 114 | clock_gettime(CLOCK_REALTIME, &ts); 115 | #endif 116 | add_ms_to_ts(&ts, milliseconds); 117 | code = pthread_cond_timedwait(&event->cond, &event->mutex, &ts); 118 | } 119 | 120 | if (code == 0) { 121 | if (!event->manual) 122 | event->signalled = false; 123 | } 124 | 125 | pthread_mutex_unlock(&event->mutex); 126 | 127 | return code; 128 | } 129 | 130 | int os_event_try(os_event_t *event) 131 | { 132 | int ret = EAGAIN; 133 | 134 | pthread_mutex_lock(&event->mutex); 135 | if (event->signalled) { 136 | if (!event->manual) 137 | event->signalled = false; 138 | ret = 0; 139 | } 140 | pthread_mutex_unlock(&event->mutex); 141 | 142 | return ret; 143 | } 144 | 145 | int os_event_signal(os_event_t *event) 146 | { 147 | int code = 0; 148 | 149 | pthread_mutex_lock(&event->mutex); 150 | code = pthread_cond_signal(&event->cond); 151 | event->signalled = true; 152 | pthread_mutex_unlock(&event->mutex); 153 | 154 | return code; 155 | } 156 | 157 | void os_event_reset(os_event_t *event) 158 | { 159 | pthread_mutex_lock(&event->mutex); 160 | event->signalled = false; 161 | pthread_mutex_unlock(&event->mutex); 162 | } 163 | 164 | #ifdef __APPLE__ 165 | 166 | struct os_sem_data { 167 | semaphore_t sem; 168 | task_t task; 169 | }; 170 | 171 | int os_sem_init(os_sem_t **sem, int value) 172 | { 173 | semaphore_t new_sem; 174 | task_t task = mach_task_self(); 175 | 176 | if (semaphore_create(task, &new_sem, 0, value) != KERN_SUCCESS) 177 | return -1; 178 | 179 | *sem = bzalloc(sizeof(struct os_sem_data)); 180 | if (!*sem) 181 | return -2; 182 | 183 | (*sem)->sem = new_sem; 184 | (*sem)->task = task; 185 | return 0; 186 | } 187 | 188 | void os_sem_destroy(os_sem_t *sem) 189 | { 190 | if (sem) { 191 | semaphore_destroy(sem->task, sem->sem); 192 | bfree(sem); 193 | } 194 | } 195 | 196 | int os_sem_post(os_sem_t *sem) 197 | { 198 | if (!sem) 199 | return -1; 200 | return (semaphore_signal(sem->sem) == KERN_SUCCESS) ? 0 : -1; 201 | } 202 | 203 | int os_sem_wait(os_sem_t *sem) 204 | { 205 | if (!sem) 206 | return -1; 207 | return (semaphore_wait(sem->sem) == KERN_SUCCESS) ? 0 : -1; 208 | } 209 | 210 | #else 211 | 212 | struct os_sem_data { 213 | sem_t sem; 214 | }; 215 | 216 | int os_sem_init(os_sem_t **sem, int value) 217 | { 218 | sem_t new_sem; 219 | int ret = sem_init(&new_sem, 0, value); 220 | if (ret != 0) 221 | return ret; 222 | 223 | *sem = bzalloc(sizeof(struct os_sem_data)); 224 | (*sem)->sem = new_sem; 225 | return 0; 226 | } 227 | 228 | void os_sem_destroy(os_sem_t *sem) 229 | { 230 | if (sem) { 231 | sem_destroy(&sem->sem); 232 | bfree(sem); 233 | } 234 | } 235 | 236 | int os_sem_post(os_sem_t *sem) 237 | { 238 | if (!sem) 239 | return -1; 240 | return sem_post(&sem->sem); 241 | } 242 | 243 | int os_sem_wait(os_sem_t *sem) 244 | { 245 | if (!sem) 246 | return -1; 247 | return sem_wait(&sem->sem); 248 | } 249 | 250 | #endif 251 | 252 | void os_set_thread_name(const char *name) 253 | { 254 | #if defined(__APPLE__) 255 | pthread_setname_np(name); 256 | #elif defined(__FreeBSD__) 257 | pthread_set_name_np(pthread_self(), name); 258 | #elif defined(__GLIBC__) && !defined(__MINGW32__) 259 | if (strlen(name) <= 15) { 260 | pthread_setname_np(pthread_self(), name); 261 | } else { 262 | char *thread_name = bstrdup_n(name, 15); 263 | pthread_setname_np(pthread_self(), thread_name); 264 | bfree(thread_name); 265 | } 266 | #endif 267 | } 268 | -------------------------------------------------------------------------------- /NoxCap/nt-stuff.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #define THREAD_STATE_WAITING 5 6 | #define THREAD_WAIT_REASON_SUSPENDED 5 7 | 8 | typedef struct _OBS_SYSTEM_PROCESS_INFORMATION2 { 9 | ULONG NextEntryOffset; 10 | ULONG ThreadCount; 11 | BYTE Reserved1[48]; 12 | PVOID Reserved2[3]; 13 | HANDLE UniqueProcessId; 14 | PVOID Reserved3; 15 | ULONG HandleCount; 16 | BYTE Reserved4[4]; 17 | PVOID Reserved5[11]; 18 | SIZE_T PeakPagefileUsage; 19 | SIZE_T PrivatePageCount; 20 | LARGE_INTEGER Reserved6[6]; 21 | } OBS_SYSTEM_PROCESS_INFORMATION2; 22 | 23 | typedef struct _OBS_SYSTEM_THREAD_INFORMATION { 24 | FILETIME KernelTime; 25 | FILETIME UserTime; 26 | FILETIME CreateTime; 27 | DWORD WaitTime; 28 | PVOID Address; 29 | HANDLE UniqueProcessId; 30 | HANDLE UniqueThreadId; 31 | DWORD Priority; 32 | DWORD BasePriority; 33 | DWORD ContextSwitches; 34 | DWORD ThreadState; 35 | DWORD WaitReason; 36 | DWORD Reserved1; 37 | } OBS_SYSTEM_THREAD_INFORMATION; 38 | 39 | #ifndef NT_SUCCESS 40 | #define NT_SUCCESS(status) ((NTSTATUS)(status) >= 0) 41 | #endif 42 | 43 | #define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xC0000004L) 44 | 45 | #define init_named_attribs(o, name) \ 46 | do { \ 47 | (o)->Length = sizeof(*(o)); \ 48 | (o)->ObjectName = name; \ 49 | (o)->RootDirectory = NULL; \ 50 | (o)->Attributes = 0; \ 51 | (o)->SecurityDescriptor = NULL; \ 52 | (o)->SecurityQualityOfService = NULL; \ 53 | } while (false) 54 | 55 | typedef void(WINAPI *RTLINITUNICODESTRINGFUNC)(PCUNICODE_STRING pstr, 56 | const wchar_t *lpstrName); 57 | typedef NTSTATUS(WINAPI *NTOPENFUNC)(PHANDLE phandle, ACCESS_MASK access, 58 | POBJECT_ATTRIBUTES objattr); 59 | typedef ULONG(WINAPI *RTLNTSTATUSTODOSERRORFUNC)(NTSTATUS status); 60 | typedef NTSTATUS(WINAPI *NTQUERYSYSTEMINFORMATIONFUNC)(SYSTEM_INFORMATION_CLASS, 61 | PVOID, ULONG, PULONG); 62 | 63 | static FARPROC get_nt_func(const char *name) 64 | { 65 | static bool initialized = false; 66 | static HANDLE ntdll = NULL; 67 | if (!initialized) { 68 | ntdll = GetModuleHandleW(L"ntdll"); 69 | initialized = true; 70 | } 71 | 72 | return GetProcAddress(ntdll, name); 73 | } 74 | 75 | static void nt_set_last_error(NTSTATUS status) 76 | { 77 | static bool initialized = false; 78 | static RTLNTSTATUSTODOSERRORFUNC func = NULL; 79 | 80 | if (!initialized) { 81 | func = (RTLNTSTATUSTODOSERRORFUNC)get_nt_func( 82 | "RtlNtStatusToDosError"); 83 | initialized = true; 84 | } 85 | 86 | if (func) 87 | SetLastError(func(status)); 88 | } 89 | 90 | static void rtl_init_str(UNICODE_STRING *unistr, const wchar_t *str) 91 | { 92 | static bool initialized = false; 93 | static RTLINITUNICODESTRINGFUNC func = NULL; 94 | 95 | if (!initialized) { 96 | func = (RTLINITUNICODESTRINGFUNC)get_nt_func( 97 | "RtlInitUnicodeString"); 98 | initialized = true; 99 | } 100 | 101 | if (func) 102 | func(unistr, str); 103 | } 104 | 105 | static NTSTATUS nt_query_information(SYSTEM_INFORMATION_CLASS info_class, 106 | PVOID info, ULONG info_len, PULONG ret_len) 107 | { 108 | static bool initialized = false; 109 | static NTQUERYSYSTEMINFORMATIONFUNC func = NULL; 110 | 111 | if (!initialized) { 112 | func = (NTQUERYSYSTEMINFORMATIONFUNC)get_nt_func( 113 | "NtQuerySystemInformation"); 114 | initialized = true; 115 | } 116 | 117 | if (func) 118 | return func(info_class, info, info_len, ret_len); 119 | return (NTSTATUS)-1; 120 | } 121 | 122 | static bool thread_is_suspended(DWORD process_id, DWORD thread_id) 123 | { 124 | ULONG size = 4096; 125 | bool suspended = false; 126 | void *data = malloc(size); 127 | 128 | for (;;) { 129 | NTSTATUS stat = nt_query_information(SystemProcessInformation, 130 | data, size, &size); 131 | if (NT_SUCCESS(stat)) 132 | break; 133 | 134 | if (stat != STATUS_INFO_LENGTH_MISMATCH) { 135 | goto fail; 136 | } 137 | 138 | free(data); 139 | size += 1024; 140 | data = malloc(size); 141 | } 142 | 143 | OBS_SYSTEM_PROCESS_INFORMATION2 *spi = data; 144 | 145 | for (;;) { 146 | if (spi->UniqueProcessId == (HANDLE)(DWORD_PTR)process_id) { 147 | break; 148 | } 149 | 150 | ULONG offset = spi->NextEntryOffset; 151 | if (!offset) 152 | goto fail; 153 | 154 | spi = (OBS_SYSTEM_PROCESS_INFORMATION2 *)((BYTE *)spi + offset); 155 | } 156 | 157 | OBS_SYSTEM_THREAD_INFORMATION *sti; 158 | OBS_SYSTEM_THREAD_INFORMATION *info = NULL; 159 | sti = (OBS_SYSTEM_THREAD_INFORMATION *)((BYTE *)spi + sizeof(*spi)); 160 | 161 | for (ULONG i = 0; i < spi->ThreadCount; i++) { 162 | if (sti[i].UniqueThreadId == (HANDLE)(DWORD_PTR)thread_id) { 163 | info = &sti[i]; 164 | break; 165 | } 166 | } 167 | 168 | if (info) { 169 | suspended = info->ThreadState == THREAD_STATE_WAITING && 170 | info->WaitReason == THREAD_WAIT_REASON_SUSPENDED; 171 | } 172 | 173 | fail: 174 | free(data); 175 | return suspended; 176 | } 177 | 178 | #define MAKE_NT_OPEN_FUNC(func_name, nt_name, access) \ 179 | static HANDLE func_name(const wchar_t *name) \ 180 | { \ 181 | static bool initialized = false; \ 182 | static NTOPENFUNC open = NULL; \ 183 | HANDLE handle; \ 184 | NTSTATUS status; \ 185 | UNICODE_STRING unistr; \ 186 | OBJECT_ATTRIBUTES attr; \ 187 | \ 188 | if (!initialized) { \ 189 | open = (NTOPENFUNC)get_nt_func(#nt_name); \ 190 | initialized = true; \ 191 | } \ 192 | \ 193 | if (!open) \ 194 | return NULL; \ 195 | \ 196 | rtl_init_str(&unistr, name); \ 197 | init_named_attribs(&attr, &unistr); \ 198 | \ 199 | status = open(&handle, access, &attr); \ 200 | if (NT_SUCCESS(status)) \ 201 | return handle; \ 202 | nt_set_last_error(status); \ 203 | return NULL; \ 204 | } 205 | 206 | MAKE_NT_OPEN_FUNC(nt_open_mutex, NtOpenMutant, SYNCHRONIZE) 207 | MAKE_NT_OPEN_FUNC(nt_open_event, NtOpenEvent, EVENT_MODIFY_STATE | SYNCHRONIZE) 208 | MAKE_NT_OPEN_FUNC(nt_open_map, NtOpenSection, FILE_MAP_READ | FILE_MAP_WRITE) 209 | -------------------------------------------------------------------------------- /Nox/graphic-hook/gl-decs.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | typedef unsigned int GLenum; 4 | typedef unsigned int GLbitfield; 5 | typedef unsigned int GLuint; 6 | typedef int GLint; 7 | typedef int GLsizei; 8 | typedef unsigned char GLboolean; 9 | typedef signed char GLbyte; 10 | typedef short GLshort; 11 | typedef unsigned char GLubyte; 12 | typedef unsigned short GLushort; 13 | typedef unsigned long GLulong; 14 | typedef float GLfloat; 15 | typedef float GLclampf; 16 | typedef double GLdouble; 17 | typedef double GLclampd; 18 | typedef void GLvoid; 19 | typedef ptrdiff_t GLintptrARB; 20 | typedef ptrdiff_t GLsizeiptrARB; 21 | 22 | #define GL_FRONT 0x0404 23 | #define GL_BACK 0x0405 24 | 25 | #define GL_INVALID_OPERATION 0x0502 26 | 27 | #define GL_UNSIGNED_BYTE 0x1401 28 | 29 | #define GL_RGB 0x1907 30 | #define GL_RGBA 0x1908 31 | 32 | #define GL_BGR 0x80E0 33 | #define GL_BGRA 0x80E1 34 | 35 | #define GL_NEAREST 0x2600 36 | #define GL_LINEAR 0x2601 37 | 38 | #define GL_READ_ONLY 0x88B8 39 | #define GL_WRITE_ONLY 0x88B9 40 | #define GL_READ_WRITE 0x88BA 41 | #define GL_BUFFER_ACCESS 0x88BB 42 | #define GL_BUFFER_MAPPED 0x88BC 43 | #define GL_BUFFER_MAP_POINTER 0x88BD 44 | #define GL_STREAM_DRAW 0x88E0 45 | #define GL_STREAM_READ 0x88E1 46 | #define GL_STREAM_COPY 0x88E2 47 | #define GL_STATIC_DRAW 0x88E4 48 | #define GL_STATIC_READ 0x88E5 49 | #define GL_STATIC_COPY 0x88E6 50 | #define GL_DYNAMIC_DRAW 0x88E8 51 | #define GL_DYNAMIC_READ 0x88E9 52 | #define GL_DYNAMIC_COPY 0x88EA 53 | #define GL_PIXEL_PACK_BUFFER 0x88EB 54 | #define GL_PIXEL_UNPACK_BUFFER 0x88EC 55 | #define GL_PIXEL_PACK_BUFFER_BINDING 0x88ED 56 | #define GL_PIXEL_UNPACK_BUFFER_BINDING 0x88EF 57 | 58 | #define GL_TEXTURE_2D 0x0DE1 59 | #define GL_TEXTURE_BINDING_2D 0x8069 60 | #define GL_DRAW_FRAMEBUFFER_BINDING 0x8CA6 61 | 62 | #define WGL_ACCESS_READ_ONLY_NV 0x0000 63 | #define WGL_ACCESS_READ_WRITE_NV 0x0001 64 | #define WGL_ACCESS_WRITE_DISCARD_NV 0x0002 65 | 66 | #define GL_READ_FRAMEBUFFER 0x8CA8 67 | #define GL_DRAW_FRAMEBUFFER 0x8CA9 68 | #define GL_COLOR_BUFFER_BIT 0x00004000 69 | #define GL_COLOR_ATTACHMENT0 0x8CE0 70 | #define GL_COLOR_ATTACHMENT1 0x8CE1 71 | 72 | typedef void(WINAPI *GLTEXIMAGE2DPROC)(GLenum target, GLint level, 73 | GLint internal_format, GLsizei width, 74 | GLsizei height, GLint border, 75 | GLenum format, GLenum type, 76 | const GLvoid *data); 77 | typedef void(WINAPI *GLGETTEXIMAGEPROC)(GLenum target, GLint level, 78 | GLenum format, GLenum type, 79 | GLvoid *img); 80 | typedef void(WINAPI *GLREADBUFFERPROC)(GLenum); 81 | typedef void(WINAPI *GLDRAWBUFFERPROC)(GLenum mode); 82 | typedef void(WINAPI *GLGETINTEGERVPROC)(GLenum pname, GLint *params); 83 | typedef GLenum(WINAPI *GLGETERRORPROC)(); 84 | typedef BOOL(WINAPI *WGLSWAPLAYERBUFFERSPROC)(HDC, UINT); 85 | typedef BOOL(WINAPI *WGLSWAPBUFFERSPROC)(HDC); 86 | typedef BOOL(WINAPI *WGLDELETECONTEXTPROC)(HGLRC); 87 | typedef PROC(WINAPI *WGLGETPROCADDRESSPROC)(LPCSTR); 88 | typedef BOOL(WINAPI *WGLMAKECURRENTPROC)(HDC, HGLRC); 89 | typedef HDC(WINAPI *WGLGETCURRENTDCPROC)(); 90 | typedef HGLRC(WINAPI *WGLGETCURRENTCONTEXTPROC)(); 91 | typedef HGLRC(WINAPI *WGLCREATECONTEXTPROC)(HDC); 92 | typedef void(WINAPI *GLBUFFERDATAARBPROC)(GLenum target, GLsizeiptrARB size, 93 | const GLvoid *data, GLenum usage); 94 | typedef void(WINAPI *GLDELETEBUFFERSARBPROC)(GLsizei n, const GLuint *buffers); 95 | typedef void(WINAPI *GLDELETETEXTURESPROC)(GLsizei n, const GLuint *buffers); 96 | typedef void(WINAPI *GLGENBUFFERSARBPROC)(GLsizei n, GLuint *buffers); 97 | typedef void(WINAPI *GLGENTEXTURESPROC)(GLsizei n, GLuint *textures); 98 | typedef GLvoid *(WINAPI *GLMAPBUFFERPROC)(GLenum target, GLenum access); 99 | typedef GLboolean(WINAPI *GLUNMAPBUFFERPROC)(GLenum target); 100 | typedef void(WINAPI *GLBINDBUFFERPROC)(GLenum target, GLuint buffer); 101 | typedef void(WINAPI *GLBINDTEXTUREPROC)(GLenum target, GLuint texture); 102 | typedef void(WINAPI *GLGENFRAMEBUFFERSPROC)(GLsizei n, GLuint *buffers); 103 | typedef void(WINAPI *GLDELETEFRAMEBUFFERSPROC)(GLsizei n, GLuint *framebuffers); 104 | typedef void(WINAPI *GLBINDFRAMEBUFFERPROC)(GLenum target, GLuint framebuffer); 105 | typedef void(WINAPI *GLBLITFRAMEBUFFERPROC)(GLint srcX0, GLint srcY0, 106 | GLint srcX1, GLint srcY1, 107 | GLint dstX0, GLint dstY0, 108 | GLint dstX1, GLint dstY1, 109 | GLbitfield mask, GLenum filter); 110 | typedef void(WINAPI *GLFRAMEBUFFERTEXTURE2DPROC)(GLenum target, 111 | GLenum attachment, 112 | GLenum textarget, 113 | GLuint texture, GLint level); 114 | typedef BOOL(WINAPI *WGLSETRESOURCESHAREHANDLENVPROC)(void *, HANDLE); 115 | typedef HANDLE(WINAPI *WGLDXOPENDEVICENVPROC)(void *); 116 | typedef BOOL(WINAPI *WGLDXCLOSEDEVICENVPROC)(HANDLE); 117 | typedef HANDLE(WINAPI *WGLDXREGISTEROBJECTNVPROC)(HANDLE, void *, GLuint, 118 | GLenum, GLenum); 119 | typedef BOOL(WINAPI *WGLDXUNREGISTEROBJECTNVPROC)(HANDLE, HANDLE); 120 | typedef BOOL(WINAPI *WGLDXOBJECTACCESSNVPROC)(HANDLE, GLenum); 121 | typedef BOOL(WINAPI *WGLDXLOCKOBJECTSNVPROC)(HANDLE, GLint, HANDLE *); 122 | typedef BOOL(WINAPI *WGLDXUNLOCKOBJECTSNVPROC)(HANDLE, GLint, HANDLE *); 123 | 124 | 125 | 126 | static GLTEXIMAGE2DPROC glTexImage2D = NULL; 127 | static GLGETTEXIMAGEPROC glGetTexImage = NULL; 128 | static GLREADBUFFERPROC glReadBuffer = NULL; 129 | static GLDRAWBUFFERPROC glDrawBuffer = NULL; 130 | static GLGETINTEGERVPROC glGetIntegerv = NULL; 131 | static GLGETERRORPROC glGetError = NULL; 132 | static WGLGETPROCADDRESSPROC jimglGetProcAddress = NULL; 133 | static WGLMAKECURRENTPROC jimglMakeCurrent = NULL; 134 | static WGLGETCURRENTDCPROC jimglGetCurrentDC = NULL; 135 | static WGLGETCURRENTCONTEXTPROC jimglGetCurrentContext = NULL; 136 | static GLBUFFERDATAARBPROC glBufferData = NULL; 137 | static GLDELETEBUFFERSARBPROC glDeleteBuffers = NULL; 138 | static GLDELETETEXTURESPROC glDeleteTextures = NULL; 139 | static GLGENBUFFERSARBPROC glGenBuffers = NULL; 140 | static GLGENTEXTURESPROC glGenTextures = NULL; 141 | static GLMAPBUFFERPROC glMapBuffer = NULL; 142 | static GLUNMAPBUFFERPROC glUnmapBuffer = NULL; 143 | static GLBINDBUFFERPROC glBindBuffer = NULL; 144 | static GLBINDTEXTUREPROC glBindTexture = NULL; 145 | static GLGENFRAMEBUFFERSPROC glGenFramebuffers = NULL; 146 | static GLDELETEFRAMEBUFFERSPROC glDeleteFramebuffers = NULL; 147 | static GLBINDFRAMEBUFFERPROC glBindFramebuffer = NULL; 148 | static GLBLITFRAMEBUFFERPROC glBlitFramebuffer = NULL; 149 | static GLFRAMEBUFFERTEXTURE2DPROC glFramebufferTexture2D = NULL; 150 | 151 | static WGLSETRESOURCESHAREHANDLENVPROC jimglDXSetResourceShareHandleNV = NULL; 152 | static WGLDXOPENDEVICENVPROC jimglDXOpenDeviceNV = NULL; 153 | static WGLDXCLOSEDEVICENVPROC jimglDXCloseDeviceNV = NULL; 154 | static WGLDXREGISTEROBJECTNVPROC jimglDXRegisterObjectNV = NULL; 155 | static WGLDXUNREGISTEROBJECTNVPROC jimglDXUnregisterObjectNV = NULL; 156 | static WGLDXOBJECTACCESSNVPROC jimglDXObjectAccessNV = NULL; 157 | static WGLDXLOCKOBJECTSNVPROC jimglDXLockObjectsNV = NULL; 158 | static WGLDXUNLOCKOBJECTSNVPROC jimglDXUnlockObjectsNV = NULL; 159 | 160 | -------------------------------------------------------------------------------- /Nox/graphic-hook/dxgi-capture.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "d3d1x_shaders.hpp" 7 | #include "graphics-hook.h" 8 | #include "../funchook.h" 9 | 10 | #if COMPILE_D3D12_HOOK 11 | #include 12 | #endif 13 | 14 | typedef HRESULT(STDMETHODCALLTYPE *resize_buffers_t)(IDXGISwapChain *, UINT, 15 | UINT, UINT, DXGI_FORMAT, 16 | UINT); 17 | typedef HRESULT(STDMETHODCALLTYPE *present_t)(IDXGISwapChain *, UINT, UINT); 18 | typedef HRESULT(STDMETHODCALLTYPE *present1_t)(IDXGISwapChain1 *, UINT, UINT, 19 | const DXGI_PRESENT_PARAMETERS *); 20 | 21 | static struct func_hook resize_buffers; 22 | static struct func_hook present; 23 | static struct func_hook present1; 24 | 25 | static struct dxgi_swap_data data = {}; 26 | 27 | static bool setup_dxgi(IDXGISwapChain *swap) 28 | { 29 | IUnknown *device; 30 | HRESULT hr; 31 | 32 | hr = swap->GetDevice(__uuidof(ID3D11Device), (void **)&device); 33 | if (SUCCEEDED(hr)) { 34 | ID3D11Device *d3d11 = reinterpret_cast(device); 35 | D3D_FEATURE_LEVEL level = d3d11->GetFeatureLevel(); 36 | device->Release(); 37 | 38 | if (level >= D3D_FEATURE_LEVEL_11_0) { 39 | data.swap = swap; 40 | data.capture = d3d11_capture; 41 | data.free = d3d11_free; 42 | return true; 43 | } 44 | } 45 | 46 | hr = swap->GetDevice(__uuidof(ID3D10Device), (void **)&device); 47 | if (SUCCEEDED(hr)) { 48 | data.swap = swap; 49 | data.capture = d3d10_capture; 50 | data.free = d3d10_free; 51 | device->Release(); 52 | return true; 53 | } 54 | 55 | hr = swap->GetDevice(__uuidof(ID3D11Device), (void **)&device); 56 | if (SUCCEEDED(hr)) { 57 | data.swap = swap; 58 | data.capture = d3d11_capture; 59 | data.free = d3d11_free; 60 | device->Release(); 61 | return true; 62 | } 63 | 64 | #if COMPILE_D3D12_HOOK 65 | hr = swap->GetDevice(__uuidof(ID3D12Device), (void **)&device); 66 | if (SUCCEEDED(hr)) { 67 | data.swap = swap; 68 | data.capture = d3d12_capture; 69 | data.free = d3d12_free; 70 | device->Release(); 71 | return true; 72 | } 73 | #endif 74 | 75 | return false; 76 | } 77 | 78 | static bool resize_buffers_called = false; 79 | 80 | static HRESULT STDMETHODCALLTYPE hook_resize_buffers(IDXGISwapChain *swap, 81 | UINT buffer_count, 82 | UINT width, UINT height, 83 | DXGI_FORMAT format, 84 | UINT flags) 85 | { 86 | HRESULT hr; 87 | 88 | if (!!data.free) 89 | data.free(); 90 | 91 | data.swap = nullptr; 92 | data.free = nullptr; 93 | data.capture = nullptr; 94 | 95 | unhook(&resize_buffers); 96 | resize_buffers_t call = (resize_buffers_t)resize_buffers.call_addr; 97 | hr = call(swap, buffer_count, width, height, format, flags); 98 | rehook(&resize_buffers); 99 | 100 | resize_buffers_called = true; 101 | 102 | return hr; 103 | } 104 | 105 | static inline IUnknown *get_dxgi_backbuffer(IDXGISwapChain *swap) 106 | { 107 | IDXGIResource *res = nullptr; 108 | HRESULT hr; 109 | 110 | hr = swap->GetBuffer(0, __uuidof(IUnknown), (void **)&res); 111 | if (FAILED(hr)) 112 | hlog_hr("get_dxgi_backbuffer: GetBuffer failed", hr); 113 | 114 | return res; 115 | } 116 | 117 | static HRESULT STDMETHODCALLTYPE hook_present(IDXGISwapChain *swap, 118 | UINT sync_interval, UINT flags) 119 | { 120 | IUnknown *backbuffer = nullptr; 121 | bool capture_overlay = global_hook_info->capture_overlay; 122 | bool test_draw = (flags & DXGI_PRESENT_TEST) != 0; 123 | bool capture; 124 | HRESULT hr; 125 | 126 | if (!data.swap && !capture_active()) { 127 | setup_dxgi(swap); 128 | } 129 | 130 | capture = !test_draw && swap == data.swap && !!data.capture; 131 | if (capture && !capture_overlay) { 132 | backbuffer = get_dxgi_backbuffer(swap); 133 | 134 | if (!!backbuffer) { 135 | data.capture(swap, backbuffer, capture_overlay); 136 | backbuffer->Release(); 137 | } 138 | } 139 | 140 | unhook(&present); 141 | present_t call = (present_t)present.call_addr; 142 | hr = call(swap, sync_interval, flags); 143 | rehook(&present); 144 | 145 | if (capture && capture_overlay) { 146 | /* 147 | * It seems that the first call to Present after ResizeBuffers 148 | * will cause the backbuffer to be invalidated, so do not 149 | * perform the post-overlay capture if ResizeBuffers has 150 | * recently been called. (The backbuffer returned by 151 | * get_dxgi_backbuffer *will* be invalid otherwise) 152 | */ 153 | if (resize_buffers_called) { 154 | resize_buffers_called = false; 155 | } else { 156 | backbuffer = get_dxgi_backbuffer(swap); 157 | 158 | if (!!backbuffer) { 159 | data.capture(swap, backbuffer, capture_overlay); 160 | backbuffer->Release(); 161 | } 162 | } 163 | } 164 | 165 | return hr; 166 | } 167 | 168 | static HRESULT STDMETHODCALLTYPE 169 | hook_present1(IDXGISwapChain1 *swap, UINT sync_interval, UINT flags, 170 | const DXGI_PRESENT_PARAMETERS *params) 171 | { 172 | IUnknown *backbuffer = nullptr; 173 | bool capture_overlay = global_hook_info->capture_overlay; 174 | bool test_draw = (flags & DXGI_PRESENT_TEST) != 0; 175 | bool capture; 176 | HRESULT hr; 177 | 178 | if (!data.swap && !capture_active()) { 179 | setup_dxgi(swap); 180 | } 181 | 182 | capture = !test_draw && swap == data.swap && !!data.capture; 183 | if (capture && !capture_overlay) { 184 | backbuffer = get_dxgi_backbuffer(swap); 185 | 186 | if (!!backbuffer) { 187 | DXGI_SWAP_CHAIN_DESC1 desc; 188 | swap->GetDesc1(&desc); 189 | data.capture(swap, backbuffer, capture_overlay); 190 | backbuffer->Release(); 191 | } 192 | } 193 | 194 | unhook(&present1); 195 | present1_t call = (present1_t)present1.call_addr; 196 | hr = call(swap, sync_interval, flags, params); 197 | rehook(&present1); 198 | 199 | if (capture && capture_overlay) { 200 | if (resize_buffers_called) { 201 | resize_buffers_called = false; 202 | } else { 203 | backbuffer = get_dxgi_backbuffer(swap); 204 | 205 | if (!!backbuffer) { 206 | data.capture(swap, backbuffer, capture_overlay); 207 | backbuffer->Release(); 208 | } 209 | } 210 | } 211 | 212 | return hr; 213 | } 214 | 215 | static pD3DCompile get_compiler(void) 216 | { 217 | pD3DCompile compile = nullptr; 218 | char d3dcompiler[40] = {}; 219 | int ver = 49; 220 | 221 | while (ver > 30) { 222 | sprintf_s(d3dcompiler, 40, "D3DCompiler_%02d.dll", ver); 223 | 224 | HMODULE module = LoadLibraryA(d3dcompiler); 225 | if (module) { 226 | compile = (pD3DCompile)GetProcAddress(module, 227 | "D3DCompile"); 228 | if (compile) { 229 | break; 230 | } 231 | } 232 | 233 | ver--; 234 | } 235 | 236 | return compile; 237 | } 238 | 239 | static uint8_t vertex_shader_data[1024]; 240 | static uint8_t pixel_shader_data[1024]; 241 | static size_t vertex_shader_size = 0; 242 | static size_t pixel_shader_size = 0; 243 | 244 | uint8_t *get_d3d1x_vertex_shader(size_t *size) 245 | { 246 | *size = vertex_shader_size; 247 | return vertex_shader_data; 248 | } 249 | 250 | uint8_t *get_d3d1x_pixel_shader(size_t *size) 251 | { 252 | *size = pixel_shader_size; 253 | return pixel_shader_data; 254 | } 255 | -------------------------------------------------------------------------------- /Nox/libOpenGL/gl-stagesurf.c: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | Copyright (C) 2013 by Hugh Bailey 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 2 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see . 16 | ******************************************************************************/ 17 | 18 | #include "gl-subsystem.h" 19 | 20 | static bool create_pixel_pack_buffer(struct gs_stage_surface *surf) 21 | { 22 | GLsizeiptr size; 23 | bool success = true; 24 | 25 | if (!gl_gen_buffers(1, &surf->pack_buffer)) 26 | return false; 27 | 28 | if (!gl_bind_buffer(GL_PIXEL_PACK_BUFFER, surf->pack_buffer)) 29 | return false; 30 | 31 | size = surf->width * surf->bytes_per_pixel; 32 | size = (size + 3) & 0xFFFFFFFC; /* align width to 4-byte boundary */ 33 | size *= surf->height; 34 | 35 | glBufferData(GL_PIXEL_PACK_BUFFER, size, 0, GL_DYNAMIC_READ); 36 | if (!gl_success("glBufferData")) 37 | success = false; 38 | 39 | if (!gl_bind_buffer(GL_PIXEL_PACK_BUFFER, 0)) 40 | success = false; 41 | 42 | return success; 43 | } 44 | 45 | gs_stagesurf_t *device_stagesurface_create(gs_device_t *device, uint32_t width, 46 | uint32_t height, 47 | enum gs_color_format color_format) 48 | { 49 | struct gs_stage_surface *surf; 50 | surf = bzalloc(sizeof(struct gs_stage_surface)); 51 | surf->device = device; 52 | surf->format = color_format; 53 | surf->width = width; 54 | surf->height = height; 55 | surf->gl_format = convert_gs_format(color_format); 56 | surf->gl_internal_format = convert_gs_internal_format(color_format); 57 | surf->gl_type = get_gl_format_type(color_format); 58 | surf->bytes_per_pixel = gs_get_format_bpp(color_format) / 8; 59 | 60 | if (!create_pixel_pack_buffer(surf)) { 61 | blog(LOG_ERROR, "device_stagesurface_create (GL) failed"); 62 | gs_stagesurface_destroy(surf); 63 | return NULL; 64 | } 65 | 66 | return surf; 67 | } 68 | 69 | void gs_stagesurface_destroy(gs_stagesurf_t *stagesurf) 70 | { 71 | if (stagesurf) { 72 | if (stagesurf->pack_buffer) 73 | gl_delete_buffers(1, &stagesurf->pack_buffer); 74 | 75 | bfree(stagesurf); 76 | } 77 | } 78 | 79 | static bool can_stage(struct gs_stage_surface *dst, struct gs_texture_2d *src) 80 | { 81 | if (!src) { 82 | blog(LOG_ERROR, "Source texture is NULL"); 83 | return false; 84 | } 85 | 86 | if (src->base.type != GS_TEXTURE_2D) { 87 | blog(LOG_ERROR, "Source texture must be a 2D texture"); 88 | return false; 89 | } 90 | 91 | if (!dst) { 92 | blog(LOG_ERROR, "Destination surface is NULL"); 93 | return false; 94 | } 95 | 96 | if (src->base.format != dst->format) { 97 | blog(LOG_ERROR, "Source and destination formats do not match"); 98 | return false; 99 | } 100 | 101 | if (src->width != dst->width || src->height != dst->height) { 102 | blog(LOG_ERROR, "Source and destination must have the same " 103 | "dimensions"); 104 | return false; 105 | } 106 | 107 | return true; 108 | } 109 | 110 | #ifdef __APPLE__ 111 | 112 | /* Apparently for mac, PBOs won't do an asynchronous transfer unless you use 113 | * FBOs along with glReadPixels, which is really dumb. */ 114 | void device_stage_texture(gs_device_t *device, gs_stagesurf_t *dst, 115 | gs_texture_t *src) 116 | { 117 | struct gs_texture_2d *tex2d = (struct gs_texture_2d *)src; 118 | struct fbo_info *fbo; 119 | GLint last_fbo; 120 | bool success = false; 121 | 122 | if (!can_stage(dst, tex2d)) 123 | goto failed; 124 | 125 | if (!gl_bind_buffer(GL_PIXEL_PACK_BUFFER, dst->pack_buffer)) 126 | goto failed; 127 | 128 | fbo = get_fbo(src, dst->width, dst->height); 129 | 130 | if (!gl_get_integer_v(GL_READ_FRAMEBUFFER_BINDING, &last_fbo)) 131 | goto failed_unbind_buffer; 132 | if (!gl_bind_framebuffer(GL_READ_FRAMEBUFFER, fbo->fbo)) 133 | goto failed_unbind_buffer; 134 | 135 | glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + 0, 136 | src->gl_target, src->texture, 0); 137 | if (!gl_success("glFrameBufferTexture2D")) 138 | goto failed_unbind_all; 139 | 140 | glReadPixels(0, 0, dst->width, dst->height, dst->gl_format, 141 | dst->gl_type, 0); 142 | if (!gl_success("glReadPixels")) 143 | goto failed_unbind_all; 144 | 145 | success = true; 146 | 147 | failed_unbind_all: 148 | gl_bind_framebuffer(GL_READ_FRAMEBUFFER, last_fbo); 149 | 150 | failed_unbind_buffer: 151 | gl_bind_buffer(GL_PIXEL_PACK_BUFFER, 0); 152 | 153 | failed: 154 | if (!success) 155 | blog(LOG_ERROR, "device_stage_texture (GL) failed"); 156 | 157 | UNUSED_PARAMETER(device); 158 | } 159 | 160 | #else 161 | 162 | void device_stage_texture(gs_device_t *device, gs_stagesurf_t *dst, 163 | gs_texture_t *src) 164 | { 165 | struct gs_texture_2d *tex2d = (struct gs_texture_2d *)src; 166 | if (!can_stage(dst, tex2d)) 167 | goto failed; 168 | 169 | if (!gl_bind_buffer(GL_PIXEL_PACK_BUFFER, dst->pack_buffer)) 170 | goto failed; 171 | if (!gl_bind_texture(GL_TEXTURE_2D, tex2d->base.texture)) 172 | goto failed; 173 | 174 | glGetTexImage(GL_TEXTURE_2D, 0, dst->gl_format, dst->gl_type, 0); 175 | if (!gl_success("glGetTexImage")) 176 | goto failed; 177 | 178 | gl_bind_texture(GL_TEXTURE_2D, 0); 179 | gl_bind_buffer(GL_PIXEL_PACK_BUFFER, 0); 180 | return; 181 | 182 | failed: 183 | gl_bind_buffer(GL_PIXEL_PACK_BUFFER, 0); 184 | gl_bind_texture(GL_TEXTURE_2D, 0); 185 | blog(LOG_ERROR, "device_stage_texture (GL) failed"); 186 | 187 | UNUSED_PARAMETER(device); 188 | } 189 | 190 | #endif 191 | 192 | uint32_t gs_stagesurface_get_width(const gs_stagesurf_t *stagesurf) 193 | { 194 | return stagesurf->width; 195 | } 196 | 197 | uint32_t gs_stagesurface_get_height(const gs_stagesurf_t *stagesurf) 198 | { 199 | return stagesurf->height; 200 | } 201 | 202 | enum gs_color_format 203 | gs_stagesurface_get_color_format(const gs_stagesurf_t *stagesurf) 204 | { 205 | return stagesurf->format; 206 | } 207 | 208 | bool gs_stagesurface_map(gs_stagesurf_t *stagesurf, uint8_t **data, 209 | uint32_t *linesize) 210 | { 211 | if (!gl_bind_buffer(GL_PIXEL_PACK_BUFFER, stagesurf->pack_buffer)) 212 | goto fail; 213 | 214 | *data = glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_ONLY); 215 | if (!gl_success("glMapBuffer")) 216 | goto fail; 217 | 218 | gl_bind_buffer(GL_PIXEL_PACK_BUFFER, 0); 219 | 220 | *linesize = stagesurf->bytes_per_pixel * stagesurf->width; 221 | return true; 222 | 223 | fail: 224 | blog(LOG_ERROR, "stagesurf_map (GL) failed"); 225 | return false; 226 | } 227 | 228 | void gs_stagesurface_unmap(gs_stagesurf_t *stagesurf) 229 | { 230 | if (!gl_bind_buffer(GL_PIXEL_PACK_BUFFER, stagesurf->pack_buffer)) 231 | return; 232 | 233 | glUnmapBuffer(GL_PIXEL_PACK_BUFFER); 234 | gl_success("glUnmapBuffer"); 235 | 236 | gl_bind_buffer(GL_PIXEL_PACK_BUFFER, 0); 237 | } 238 | -------------------------------------------------------------------------------- /NoxCap/graphics-hook-info.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "hook-helpers.h" 9 | 10 | #define EVENT_CAPTURE_RESTART L"CaptureHook_Restart" 11 | #define EVENT_CAPTURE_STOP L"CaptureHook_Stop" 12 | 13 | #define EVENT_HOOK_READY L"CaptureHook_HookReady" 14 | #define EVENT_HOOK_EXIT L"CaptureHook_Exit" 15 | 16 | #define EVENT_HOOK_INIT L"CaptureHook_Initialize" 17 | 18 | #define WINDOW_HOOK_KEEPALIVE L"CaptureHook_KeepAlive" 19 | 20 | #define MUTEX_TEXTURE1 L"CaptureHook_TextureMutex1" 21 | #define MUTEX_TEXTURE2 L"CaptureHook_TextureMutex2" 22 | 23 | #define SHMEM_HOOK_INFO L"CaptureHook_HookInfo" 24 | #define SHMEM_TEXTURE L"CaptureHook_Texture" 25 | 26 | #define PIPE_NAME "CaptureHook_Pipe" 27 | 28 | #pragma pack(push, 8) 29 | 30 | struct d3d8_offsets { 31 | uint32_t present; 32 | }; 33 | 34 | struct d3d9_offsets { 35 | uint32_t present; 36 | uint32_t present_ex; 37 | uint32_t present_swap; 38 | uint32_t d3d9_clsoff; 39 | uint32_t is_d3d9ex_clsoff; 40 | }; 41 | 42 | struct dxgi_offsets { 43 | uint32_t present; 44 | uint32_t resize; 45 | 46 | uint32_t present1; 47 | }; 48 | 49 | struct ddraw_offsets { 50 | uint32_t surface_create; 51 | uint32_t surface_restore; 52 | uint32_t surface_release; 53 | uint32_t surface_unlock; 54 | uint32_t surface_blt; 55 | uint32_t surface_flip; 56 | uint32_t surface_set_palette; 57 | uint32_t palette_set_entries; 58 | }; 59 | 60 | struct shmem_data { 61 | volatile int last_tex; 62 | uint32_t tex1_offset; 63 | uint32_t tex2_offset; 64 | }; 65 | 66 | struct shtex_data { 67 | uint32_t tex_handle; 68 | }; 69 | 70 | enum capture_type { 71 | CAPTURE_TYPE_MEMORY, 72 | CAPTURE_TYPE_TEXTURE, 73 | }; 74 | 75 | struct graphics_offsets { 76 | struct d3d8_offsets d3d8; 77 | struct d3d9_offsets d3d9; 78 | struct dxgi_offsets dxgi; 79 | struct ddraw_offsets ddraw; 80 | }; 81 | 82 | struct hook_info { 83 | /* capture info */ 84 | enum capture_type type; 85 | uint32_t window; 86 | uint32_t format; 87 | uint32_t cx; 88 | uint32_t cy; 89 | uint32_t base_cx; 90 | uint32_t base_cy; 91 | uint32_t pitch; 92 | uint32_t map_id; 93 | uint32_t map_size; 94 | bool flip; 95 | 96 | /* additional options */ 97 | uint64_t frame_interval; 98 | bool use_scale; 99 | bool force_shmem; 100 | bool capture_overlay; 101 | 102 | /* hook addresses */ 103 | struct graphics_offsets offsets; 104 | }; 105 | 106 | typedef enum DXGI_FORMAT 107 | { 108 | DXGI_FORMAT_UNKNOWN = 0, 109 | DXGI_FORMAT_R32G32B32A32_TYPELESS = 1, 110 | DXGI_FORMAT_R32G32B32A32_FLOAT = 2, 111 | DXGI_FORMAT_R32G32B32A32_UINT = 3, 112 | DXGI_FORMAT_R32G32B32A32_SINT = 4, 113 | DXGI_FORMAT_R32G32B32_TYPELESS = 5, 114 | DXGI_FORMAT_R32G32B32_FLOAT = 6, 115 | DXGI_FORMAT_R32G32B32_UINT = 7, 116 | DXGI_FORMAT_R32G32B32_SINT = 8, 117 | DXGI_FORMAT_R16G16B16A16_TYPELESS = 9, 118 | DXGI_FORMAT_R16G16B16A16_FLOAT = 10, 119 | DXGI_FORMAT_R16G16B16A16_UNORM = 11, 120 | DXGI_FORMAT_R16G16B16A16_UINT = 12, 121 | DXGI_FORMAT_R16G16B16A16_SNORM = 13, 122 | DXGI_FORMAT_R16G16B16A16_SINT = 14, 123 | DXGI_FORMAT_R32G32_TYPELESS = 15, 124 | DXGI_FORMAT_R32G32_FLOAT = 16, 125 | DXGI_FORMAT_R32G32_UINT = 17, 126 | DXGI_FORMAT_R32G32_SINT = 18, 127 | DXGI_FORMAT_R32G8X24_TYPELESS = 19, 128 | DXGI_FORMAT_D32_FLOAT_S8X24_UINT = 20, 129 | DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS = 21, 130 | DXGI_FORMAT_X32_TYPELESS_G8X24_UINT = 22, 131 | DXGI_FORMAT_R10G10B10A2_TYPELESS = 23, 132 | DXGI_FORMAT_R10G10B10A2_UNORM = 24, 133 | DXGI_FORMAT_R10G10B10A2_UINT = 25, 134 | DXGI_FORMAT_R11G11B10_FLOAT = 26, 135 | DXGI_FORMAT_R8G8B8A8_TYPELESS = 27, 136 | DXGI_FORMAT_R8G8B8A8_UNORM = 28, 137 | DXGI_FORMAT_R8G8B8A8_UNORM_SRGB = 29, 138 | DXGI_FORMAT_R8G8B8A8_UINT = 30, 139 | DXGI_FORMAT_R8G8B8A8_SNORM = 31, 140 | DXGI_FORMAT_R8G8B8A8_SINT = 32, 141 | DXGI_FORMAT_R16G16_TYPELESS = 33, 142 | DXGI_FORMAT_R16G16_FLOAT = 34, 143 | DXGI_FORMAT_R16G16_UNORM = 35, 144 | DXGI_FORMAT_R16G16_UINT = 36, 145 | DXGI_FORMAT_R16G16_SNORM = 37, 146 | DXGI_FORMAT_R16G16_SINT = 38, 147 | DXGI_FORMAT_R32_TYPELESS = 39, 148 | DXGI_FORMAT_D32_FLOAT = 40, 149 | DXGI_FORMAT_R32_FLOAT = 41, 150 | DXGI_FORMAT_R32_UINT = 42, 151 | DXGI_FORMAT_R32_SINT = 43, 152 | DXGI_FORMAT_R24G8_TYPELESS = 44, 153 | DXGI_FORMAT_D24_UNORM_S8_UINT = 45, 154 | DXGI_FORMAT_R24_UNORM_X8_TYPELESS = 46, 155 | DXGI_FORMAT_X24_TYPELESS_G8_UINT = 47, 156 | DXGI_FORMAT_R8G8_TYPELESS = 48, 157 | DXGI_FORMAT_R8G8_UNORM = 49, 158 | DXGI_FORMAT_R8G8_UINT = 50, 159 | DXGI_FORMAT_R8G8_SNORM = 51, 160 | DXGI_FORMAT_R8G8_SINT = 52, 161 | DXGI_FORMAT_R16_TYPELESS = 53, 162 | DXGI_FORMAT_R16_FLOAT = 54, 163 | DXGI_FORMAT_D16_UNORM = 55, 164 | DXGI_FORMAT_R16_UNORM = 56, 165 | DXGI_FORMAT_R16_UINT = 57, 166 | DXGI_FORMAT_R16_SNORM = 58, 167 | DXGI_FORMAT_R16_SINT = 59, 168 | DXGI_FORMAT_R8_TYPELESS = 60, 169 | DXGI_FORMAT_R8_UNORM = 61, 170 | DXGI_FORMAT_R8_UINT = 62, 171 | DXGI_FORMAT_R8_SNORM = 63, 172 | DXGI_FORMAT_R8_SINT = 64, 173 | DXGI_FORMAT_A8_UNORM = 65, 174 | DXGI_FORMAT_R1_UNORM = 66, 175 | DXGI_FORMAT_R9G9B9E5_SHAREDEXP = 67, 176 | DXGI_FORMAT_R8G8_B8G8_UNORM = 68, 177 | DXGI_FORMAT_G8R8_G8B8_UNORM = 69, 178 | DXGI_FORMAT_BC1_TYPELESS = 70, 179 | DXGI_FORMAT_BC1_UNORM = 71, 180 | DXGI_FORMAT_BC1_UNORM_SRGB = 72, 181 | DXGI_FORMAT_BC2_TYPELESS = 73, 182 | DXGI_FORMAT_BC2_UNORM = 74, 183 | DXGI_FORMAT_BC2_UNORM_SRGB = 75, 184 | DXGI_FORMAT_BC3_TYPELESS = 76, 185 | DXGI_FORMAT_BC3_UNORM = 77, 186 | DXGI_FORMAT_BC3_UNORM_SRGB = 78, 187 | DXGI_FORMAT_BC4_TYPELESS = 79, 188 | DXGI_FORMAT_BC4_UNORM = 80, 189 | DXGI_FORMAT_BC4_SNORM = 81, 190 | DXGI_FORMAT_BC5_TYPELESS = 82, 191 | DXGI_FORMAT_BC5_UNORM = 83, 192 | DXGI_FORMAT_BC5_SNORM = 84, 193 | DXGI_FORMAT_B5G6R5_UNORM = 85, 194 | DXGI_FORMAT_B5G5R5A1_UNORM = 86, 195 | DXGI_FORMAT_B8G8R8A8_UNORM = 87, 196 | DXGI_FORMAT_B8G8R8X8_UNORM = 88, 197 | DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM = 89, 198 | DXGI_FORMAT_B8G8R8A8_TYPELESS = 90, 199 | DXGI_FORMAT_B8G8R8A8_UNORM_SRGB = 91, 200 | DXGI_FORMAT_B8G8R8X8_TYPELESS = 92, 201 | DXGI_FORMAT_B8G8R8X8_UNORM_SRGB = 93, 202 | DXGI_FORMAT_BC6H_TYPELESS = 94, 203 | DXGI_FORMAT_BC6H_UF16 = 95, 204 | DXGI_FORMAT_BC6H_SF16 = 96, 205 | DXGI_FORMAT_BC7_TYPELESS = 97, 206 | DXGI_FORMAT_BC7_UNORM = 98, 207 | DXGI_FORMAT_BC7_UNORM_SRGB = 99, 208 | DXGI_FORMAT_AYUV = 100, 209 | DXGI_FORMAT_Y410 = 101, 210 | DXGI_FORMAT_Y416 = 102, 211 | DXGI_FORMAT_NV12 = 103, 212 | DXGI_FORMAT_P010 = 104, 213 | DXGI_FORMAT_P016 = 105, 214 | DXGI_FORMAT_420_OPAQUE = 106, 215 | DXGI_FORMAT_YUY2 = 107, 216 | DXGI_FORMAT_Y210 = 108, 217 | DXGI_FORMAT_Y216 = 109, 218 | DXGI_FORMAT_NV11 = 110, 219 | DXGI_FORMAT_AI44 = 111, 220 | DXGI_FORMAT_IA44 = 112, 221 | DXGI_FORMAT_P8 = 113, 222 | DXGI_FORMAT_A8P8 = 114, 223 | DXGI_FORMAT_B4G4R4A4_UNORM = 115, 224 | 225 | DXGI_FORMAT_P208 = 130, 226 | DXGI_FORMAT_V208 = 131, 227 | DXGI_FORMAT_V408 = 132, 228 | 229 | 230 | DXGI_FORMAT_FORCE_UINT = 0xffffffff 231 | } DXGI_FORMAT; 232 | 233 | #pragma pack(pop) 234 | 235 | #define GC_MAPPING_FLAGS (FILE_MAP_READ | FILE_MAP_WRITE) 236 | 237 | static inline HANDLE create_hook_info(DWORD id) 238 | { 239 | wchar_t new_name[64]; 240 | _snwprintf(new_name, 64, L"%s%lu", SHMEM_HOOK_INFO, id); 241 | 242 | return CreateFileMappingW(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 243 | sizeof(struct hook_info), new_name); 244 | } 245 | -------------------------------------------------------------------------------- /Nox/funchook.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "funchook.h" 4 | 5 | #define JMP_64_SIZE 14 6 | #define JMP_32_SIZE 5 7 | 8 | #define X86_NOP 0x90 9 | #define X86_JMP_NEG_5 0xF9EB 10 | 11 | static inline void fix_permissions(void *addr, size_t size) 12 | { 13 | DWORD protect_val; 14 | VirtualProtect(addr, size, PAGE_EXECUTE_READWRITE, &protect_val); 15 | } 16 | 17 | void hook_init(struct func_hook *hook, void *func_addr, void *hook_addr, 18 | const char *name) 19 | { 20 | memset(hook, 0, sizeof(*hook)); 21 | 22 | hook->func_addr = (uintptr_t)func_addr; 23 | hook->hook_addr = (uintptr_t)hook_addr; 24 | hook->name = name; 25 | 26 | fix_permissions((void *)(hook->func_addr - JMP_32_SIZE), 27 | JMP_64_SIZE + JMP_32_SIZE); 28 | 29 | memcpy(hook->unhook_data, func_addr, JMP_64_SIZE); 30 | } 31 | 32 | static inline size_t patch_size(struct func_hook *hook) 33 | { 34 | return hook->is_64bit_jump ? JMP_64_SIZE : JMP_32_SIZE; 35 | } 36 | 37 | static const uint8_t longjmp64[6] = {0xFF, 0x25, 0x00, 0x00, 0x00, 0x00}; 38 | 39 | static inline void rehook64(struct func_hook *hook) 40 | { 41 | uint8_t data[JMP_64_SIZE]; 42 | uintptr_t *ptr_loc = (uintptr_t *)((uint8_t *)data + sizeof(longjmp64)); 43 | 44 | fix_permissions((void *)hook->func_addr, JMP_64_SIZE); 45 | 46 | memcpy(data, (void *)hook->func_addr, JMP_64_SIZE); 47 | memcpy(data, longjmp64, sizeof(longjmp64)); 48 | *ptr_loc = hook->hook_addr; 49 | 50 | hook->call_addr = (void *)hook->func_addr; 51 | hook->type = HOOKTYPE_FORWARD_OVERWRITE; 52 | hook->hooked = true; 53 | 54 | memcpy((void *)hook->func_addr, data, JMP_64_SIZE); 55 | } 56 | 57 | static inline void hook_reverse_new(struct func_hook *hook, uint8_t *p) 58 | { 59 | hook->call_addr = (void *)(hook->func_addr + 2); 60 | hook->type = HOOKTYPE_REVERSE_CHAIN; 61 | hook->hooked = true; 62 | 63 | p[0] = 0xE9; 64 | *((uint32_t *)&p[1]) = (uint32_t)(hook->hook_addr - hook->func_addr); 65 | *((uint16_t *)&p[5]) = X86_JMP_NEG_5; 66 | } 67 | 68 | static inline void hook_reverse_chain(struct func_hook *hook, uint8_t *p) 69 | { 70 | if (hook->type != HOOKTYPE_FORWARD_OVERWRITE) 71 | return; 72 | 73 | hook->call_addr = (void *)(hook->func_addr + *((int32_t *)&p[1])); 74 | hook->type = HOOKTYPE_REVERSE_CHAIN; 75 | hook->hooked = true; 76 | 77 | *((uint32_t *)&p[1]) = (uint32_t)(hook->hook_addr - hook->func_addr); 78 | } 79 | 80 | static inline void hook_forward_chain(struct func_hook *hook, uint8_t *p, 81 | intptr_t offset) 82 | { 83 | int32_t cur_offset = *(int32_t *)&p[6]; 84 | 85 | if (hook->type != HOOKTYPE_FORWARD_OVERWRITE) 86 | return; 87 | 88 | hook->call_addr = (void *)(hook->func_addr + JMP_32_SIZE + cur_offset); 89 | hook->type = HOOKTYPE_FORWARD_CHAIN; 90 | hook->hooked = true; 91 | 92 | *((int32_t *)&p[6]) = (int32_t)offset; 93 | } 94 | 95 | static inline void hook_forward_overwrite(struct func_hook *hook, 96 | intptr_t offset) 97 | { 98 | uint8_t *ptr = (uint8_t *)hook->func_addr; 99 | 100 | hook->call_addr = (void *)hook->func_addr; 101 | hook->type = HOOKTYPE_FORWARD_OVERWRITE; 102 | hook->hooked = true; 103 | 104 | *(ptr++) = 0xE9; 105 | *((int32_t *)ptr) = (int32_t)offset; 106 | } 107 | 108 | static inline void rehook32(struct func_hook *hook, bool force, intptr_t offset) 109 | { 110 | fix_permissions((void *)(hook->func_addr - JMP_32_SIZE), 111 | JMP_32_SIZE * 2); 112 | 113 | if (force || !hook->started) { 114 | uint8_t *p = (uint8_t *)hook->func_addr - JMP_32_SIZE; 115 | size_t nop_count = 0; 116 | 117 | /* check for reverse chain hook availability */ 118 | for (size_t i = 0; i < JMP_32_SIZE; i++) { 119 | if (p[i] == X86_NOP) 120 | nop_count++; 121 | } 122 | 123 | if (nop_count == JMP_32_SIZE && p[5] == 0x8B && p[6] == 0xFF) { 124 | hook_reverse_new(hook, p); 125 | 126 | } else if (p[0] == 0xE9 && 127 | *(uint16_t *)&p[5] == X86_JMP_NEG_5) { 128 | hook_reverse_chain(hook, p); 129 | 130 | } else if (p[5] == 0xE9) { 131 | hook_forward_chain(hook, p, offset); 132 | 133 | } else if (hook->type != HOOKTYPE_FORWARD_OVERWRITE) { 134 | hook->type = HOOKTYPE_FORWARD_OVERWRITE; 135 | } 136 | 137 | hook->started = true; 138 | } 139 | 140 | if (hook->type == HOOKTYPE_FORWARD_OVERWRITE) { 141 | hook_forward_overwrite(hook, offset); 142 | } 143 | } 144 | 145 | /* 146 | * Creates memory close to the target function, used to force the actual hook 147 | * to use a 32bit jump instead of a 64bit jump, thus preventing the chance of 148 | * overwriting adjacent functions, which can cause a crash. (by R1CH) 149 | */ 150 | static void setup_64bit_bounce(struct func_hook *hook, intptr_t *offset) 151 | { 152 | MEMORY_BASIC_INFORMATION mbi; 153 | uintptr_t address; 154 | uintptr_t newdiff; 155 | SYSTEM_INFO si; 156 | bool success; 157 | int pagesize; 158 | int i; 159 | 160 | success = VirtualQueryEx(GetCurrentProcess(), 161 | (const void *)hook->func_addr, &mbi, 162 | sizeof(mbi)); 163 | if (!success) 164 | return; 165 | 166 | GetSystemInfo(&si); 167 | pagesize = (int)si.dwAllocationGranularity; 168 | 169 | address = (uintptr_t)mbi.AllocationBase - pagesize; 170 | for (i = 0; i < 256; i++, address -= pagesize) { 171 | hook->bounce_addr = VirtualAlloc((LPVOID)address, pagesize, 172 | MEM_RESERVE | MEM_COMMIT, 173 | PAGE_EXECUTE_READWRITE); 174 | if (hook->bounce_addr) 175 | break; 176 | } 177 | 178 | if (!hook->bounce_addr) { 179 | address = (uintptr_t)mbi.AllocationBase + mbi.RegionSize + 180 | pagesize; 181 | for (i = 0; i < 256; i++, address += pagesize) { 182 | hook->bounce_addr = 183 | VirtualAlloc((LPVOID)address, pagesize, 184 | MEM_RESERVE | MEM_COMMIT, 185 | PAGE_EXECUTE_READWRITE); 186 | if (hook->bounce_addr) 187 | break; 188 | } 189 | } 190 | 191 | if (!hook->bounce_addr) 192 | return; 193 | 194 | if ((hook->func_addr + 5) > (uintptr_t)hook->bounce_addr) 195 | newdiff = hook->func_addr + 5 - (uintptr_t)hook->bounce_addr; 196 | else 197 | newdiff = (uintptr_t)hook->bounce_addr - hook->func_addr + 5; 198 | 199 | if (newdiff <= 0x7ffffff0) { 200 | uint8_t *addr = (uint8_t *)hook->bounce_addr; 201 | 202 | FillMemory(hook->bounce_addr, pagesize, 0xCC); 203 | 204 | *(addr++) = 0xFF; 205 | *(addr++) = 0x25; 206 | *((uint32_t *)addr) = 0; 207 | *((uint64_t *)(addr + 4)) = hook->hook_addr; 208 | 209 | hook->hook_addr = (uint64_t)hook->bounce_addr; 210 | *offset = hook->hook_addr - hook->func_addr - JMP_32_SIZE; 211 | hook->is_64bit_jump = false; 212 | } 213 | } 214 | 215 | void do_hook(struct func_hook *hook, bool force) 216 | { 217 | intptr_t offset; 218 | 219 | if (!force && hook->hooked) 220 | return; 221 | 222 | /* copy back the memory that was previously encountered to preserve 223 | * the current hook and any newer hooks on top */ 224 | if (hook->started && !force) { 225 | uintptr_t addr; 226 | size_t size; 227 | 228 | if (hook->type == HOOKTYPE_REVERSE_CHAIN) { 229 | addr = hook->func_addr - JMP_32_SIZE; 230 | size = JMP_32_SIZE; 231 | } else { 232 | addr = hook->func_addr; 233 | size = patch_size(hook); 234 | } 235 | 236 | memcpy((void *)addr, hook->rehook_data, size); 237 | hook->hooked = true; 238 | return; 239 | } 240 | 241 | offset = hook->hook_addr - hook->func_addr - JMP_32_SIZE; 242 | 243 | #ifdef _WIN64 244 | hook->is_64bit_jump = (llabs(offset) >= 0x7fffffff); 245 | 246 | if (hook->is_64bit_jump) { 247 | if (!hook->attempted_bounce) { 248 | hook->attempted_bounce = true; 249 | setup_64bit_bounce(hook, &offset); 250 | } 251 | 252 | if (hook->is_64bit_jump) { 253 | rehook64(hook); 254 | return; 255 | } 256 | } 257 | #endif 258 | 259 | rehook32(hook, force, offset); 260 | } 261 | 262 | void unhook(struct func_hook *hook) 263 | { 264 | uintptr_t addr; 265 | size_t size; 266 | if (!hook->hooked) 267 | return; 268 | 269 | if (hook->type == HOOKTYPE_REVERSE_CHAIN) { 270 | size = JMP_32_SIZE; 271 | addr = (hook->func_addr - JMP_32_SIZE); 272 | } else { 273 | size = patch_size(hook); 274 | addr = hook->func_addr; 275 | } 276 | 277 | fix_permissions((void *)addr, size); 278 | memcpy(hook->rehook_data, (void *)addr, size); 279 | 280 | if (hook->type == HOOKTYPE_FORWARD_OVERWRITE) 281 | memcpy((void *)hook->func_addr, hook->unhook_data, size); 282 | 283 | hook->hooked = false; 284 | } 285 | -------------------------------------------------------------------------------- /Nox/libOpenGL/gl-vertexbuffer.c: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | Copyright (C) 2013 by Hugh Bailey 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 2 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see . 16 | ******************************************************************************/ 17 | 18 | #include 19 | #include "gl-subsystem.h" 20 | 21 | static bool create_buffers(struct gs_vertex_buffer *vb) 22 | { 23 | GLenum usage = vb->dynamic ? GL_STREAM_DRAW : GL_STATIC_DRAW; 24 | size_t i; 25 | 26 | if (!gl_create_buffer(GL_ARRAY_BUFFER, &vb->vertex_buffer, 27 | vb->data->num * sizeof(struct vec3), 28 | vb->data->points, usage)) 29 | return false; 30 | 31 | if (vb->data->normals) { 32 | if (!gl_create_buffer(GL_ARRAY_BUFFER, &vb->normal_buffer, 33 | vb->data->num * sizeof(struct vec3), 34 | vb->data->normals, usage)) 35 | return false; 36 | } 37 | 38 | if (vb->data->tangents) { 39 | if (!gl_create_buffer(GL_ARRAY_BUFFER, &vb->tangent_buffer, 40 | vb->data->num * sizeof(struct vec3), 41 | vb->data->tangents, usage)) 42 | return false; 43 | } 44 | 45 | if (vb->data->colors) { 46 | if (!gl_create_buffer(GL_ARRAY_BUFFER, &vb->color_buffer, 47 | vb->data->num * sizeof(uint32_t), 48 | vb->data->colors, usage)) 49 | return false; 50 | } 51 | 52 | da_reserve(vb->uv_buffers, vb->data->num_tex); 53 | da_reserve(vb->uv_sizes, vb->data->num_tex); 54 | 55 | for (i = 0; i < vb->data->num_tex; i++) { 56 | GLuint tex_buffer; 57 | struct gs_tvertarray *tv = vb->data->tvarray + i; 58 | size_t size = vb->data->num * sizeof(float) * tv->width; 59 | 60 | if (!gl_create_buffer(GL_ARRAY_BUFFER, &tex_buffer, size, 61 | tv->array, usage)) 62 | return false; 63 | 64 | da_push_back(vb->uv_buffers, &tex_buffer); 65 | da_push_back(vb->uv_sizes, &tv->width); 66 | } 67 | 68 | if (!vb->dynamic) { 69 | gs_vbdata_destroy(vb->data); 70 | vb->data = NULL; 71 | } 72 | 73 | if (!gl_gen_vertex_arrays(1, &vb->vao)) 74 | return false; 75 | 76 | return true; 77 | } 78 | 79 | gs_vertbuffer_t *device_vertexbuffer_create(gs_device_t *device, 80 | struct gs_vb_data *data, 81 | uint32_t flags) 82 | { 83 | struct gs_vertex_buffer *vb = bzalloc(sizeof(struct gs_vertex_buffer)); 84 | vb->device = device; 85 | vb->data = data; 86 | vb->num = data->num; 87 | vb->dynamic = flags & GS_DYNAMIC; 88 | 89 | if (!create_buffers(vb)) { 90 | blog(LOG_ERROR, "device_vertexbuffer_create (GL) failed"); 91 | gs_vertexbuffer_destroy(vb); 92 | return NULL; 93 | } 94 | 95 | return vb; 96 | } 97 | 98 | void gs_vertexbuffer_destroy(gs_vertbuffer_t *vb) 99 | { 100 | if (vb) { 101 | if (vb->vertex_buffer) 102 | gl_delete_buffers(1, &vb->vertex_buffer); 103 | if (vb->normal_buffer) 104 | gl_delete_buffers(1, &vb->normal_buffer); 105 | if (vb->tangent_buffer) 106 | gl_delete_buffers(1, &vb->tangent_buffer); 107 | if (vb->color_buffer) 108 | gl_delete_buffers(1, &vb->color_buffer); 109 | if (vb->uv_buffers.num) 110 | gl_delete_buffers((GLsizei)vb->uv_buffers.num, 111 | vb->uv_buffers.array); 112 | 113 | if (vb->vao) 114 | gl_delete_vertex_arrays(1, &vb->vao); 115 | 116 | da_free(vb->uv_sizes); 117 | da_free(vb->uv_buffers); 118 | gs_vbdata_destroy(vb->data); 119 | 120 | bfree(vb); 121 | } 122 | } 123 | 124 | static inline void gs_vertexbuffer_flush_internal(gs_vertbuffer_t *vb, 125 | const struct gs_vb_data *data) 126 | { 127 | size_t i; 128 | size_t num_tex = data->num_tex < vb->data->num_tex ? data->num_tex 129 | : vb->data->num_tex; 130 | 131 | if (!vb->dynamic) { 132 | blog(LOG_ERROR, "vertex buffer is not dynamic"); 133 | goto failed; 134 | } 135 | 136 | if (data->points) { 137 | if (!update_buffer(GL_ARRAY_BUFFER, vb->vertex_buffer, 138 | data->points, 139 | data->num * sizeof(struct vec3))) 140 | goto failed; 141 | } 142 | 143 | if (vb->normal_buffer && data->normals) { 144 | if (!update_buffer(GL_ARRAY_BUFFER, vb->normal_buffer, 145 | data->normals, 146 | data->num * sizeof(struct vec3))) 147 | goto failed; 148 | } 149 | 150 | if (vb->tangent_buffer && data->tangents) { 151 | if (!update_buffer(GL_ARRAY_BUFFER, vb->tangent_buffer, 152 | data->tangents, 153 | data->num * sizeof(struct vec3))) 154 | goto failed; 155 | } 156 | 157 | if (vb->color_buffer && data->colors) { 158 | if (!update_buffer(GL_ARRAY_BUFFER, vb->color_buffer, 159 | data->colors, data->num * sizeof(uint32_t))) 160 | goto failed; 161 | } 162 | 163 | for (i = 0; i < num_tex; i++) { 164 | GLuint buffer = vb->uv_buffers.array[i]; 165 | struct gs_tvertarray *tv = data->tvarray + i; 166 | size_t size = data->num * tv->width * sizeof(float); 167 | 168 | if (!update_buffer(GL_ARRAY_BUFFER, buffer, tv->array, size)) 169 | goto failed; 170 | } 171 | 172 | return; 173 | 174 | failed: 175 | blog(LOG_ERROR, "gs_vertexbuffer_flush (GL) failed"); 176 | } 177 | 178 | void gs_vertexbuffer_flush(gs_vertbuffer_t *vb) 179 | { 180 | gs_vertexbuffer_flush_internal(vb, vb->data); 181 | } 182 | 183 | void gs_vertexbuffer_flush_direct(gs_vertbuffer_t *vb, 184 | const struct gs_vb_data *data) 185 | { 186 | gs_vertexbuffer_flush_internal(vb, data); 187 | } 188 | 189 | struct gs_vb_data *gs_vertexbuffer_get_data(const gs_vertbuffer_t *vb) 190 | { 191 | return vb->data; 192 | } 193 | 194 | static inline GLuint get_vb_buffer(struct gs_vertex_buffer *vb, 195 | enum attrib_type type, size_t index, 196 | GLint *width, GLenum *gl_type) 197 | { 198 | *gl_type = GL_FLOAT; 199 | *width = 4; 200 | 201 | if (type == ATTRIB_POSITION) { 202 | return vb->vertex_buffer; 203 | } else if (type == ATTRIB_NORMAL) { 204 | return vb->normal_buffer; 205 | } else if (type == ATTRIB_TANGENT) { 206 | return vb->tangent_buffer; 207 | } else if (type == ATTRIB_COLOR) { 208 | *gl_type = GL_UNSIGNED_BYTE; 209 | return vb->color_buffer; 210 | } else if (type == ATTRIB_TEXCOORD) { 211 | if (vb->uv_buffers.num <= index) 212 | return 0; 213 | 214 | *width = (GLint)vb->uv_sizes.array[index]; 215 | return vb->uv_buffers.array[index]; 216 | } 217 | 218 | return 0; 219 | } 220 | 221 | static bool load_vb_buffer(struct shader_attrib *attrib, 222 | struct gs_vertex_buffer *vb, GLint id) 223 | { 224 | GLenum type; 225 | GLint width; 226 | GLuint buffer; 227 | bool success = true; 228 | 229 | buffer = get_vb_buffer(vb, attrib->type, attrib->index, &width, &type); 230 | if (!buffer) { 231 | blog(LOG_ERROR, "Vertex buffer does not have the required " 232 | "inputs for vertex shader"); 233 | return false; 234 | } 235 | 236 | if (!gl_bind_buffer(GL_ARRAY_BUFFER, buffer)) 237 | return false; 238 | 239 | glVertexAttribPointer(id, width, type, GL_TRUE, 0, 0); 240 | if (!gl_success("glVertexAttribPointer")) 241 | success = false; 242 | 243 | glEnableVertexAttribArray(id); 244 | if (!gl_success("glEnableVertexAttribArray")) 245 | success = false; 246 | 247 | if (!gl_bind_buffer(GL_ARRAY_BUFFER, 0)) 248 | success = false; 249 | 250 | return success; 251 | } 252 | 253 | bool load_vb_buffers(struct gs_program *program, struct gs_vertex_buffer *vb, 254 | struct gs_index_buffer *ib) 255 | { 256 | struct gs_shader *shader = program->vertex_shader; 257 | size_t i; 258 | 259 | if (!gl_bind_vertex_array(vb->vao)) 260 | return false; 261 | 262 | for (i = 0; i < shader->attribs.num; i++) { 263 | struct shader_attrib *attrib = shader->attribs.array + i; 264 | if (!load_vb_buffer(attrib, vb, program->attribs.array[i])) 265 | return false; 266 | } 267 | 268 | if (ib && !gl_bind_buffer(GL_ELEMENT_ARRAY_BUFFER, ib->buffer)) 269 | return false; 270 | 271 | return true; 272 | } 273 | 274 | void device_load_vertexbuffer(gs_device_t *device, gs_vertbuffer_t *vb) 275 | { 276 | device->cur_vertex_buffer = vb; 277 | } 278 | -------------------------------------------------------------------------------- /Nox/libOpenGL/gl-texture2d.c: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | Copyright (C) 2013 by Hugh Bailey 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 2 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see . 16 | ******************************************************************************/ 17 | 18 | #include "gl-subsystem.h" 19 | 20 | static bool upload_texture_2d(struct gs_texture_2d *tex, const uint8_t **data) 21 | { 22 | uint32_t row_size = tex->width * gs_get_format_bpp(tex->base.format); 23 | uint32_t tex_size = tex->height * row_size / 8; 24 | uint32_t num_levels = tex->base.levels; 25 | bool compressed = gs_is_compressed_format(tex->base.format); 26 | bool success; 27 | 28 | if (!num_levels) 29 | num_levels = gs_get_total_levels(tex->width, tex->height); 30 | 31 | if (!gl_bind_texture(GL_TEXTURE_2D, tex->base.texture)) 32 | return false; 33 | 34 | success = gl_init_face(GL_TEXTURE_2D, tex->base.gl_type, num_levels, 35 | tex->base.gl_format, 36 | tex->base.gl_internal_format, compressed, 37 | tex->width, tex->height, tex_size, &data); 38 | 39 | if (!gl_tex_param_i(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 40 | num_levels - 1)) 41 | success = false; 42 | if (!gl_bind_texture(GL_TEXTURE_2D, 0)) 43 | success = false; 44 | 45 | return success; 46 | } 47 | 48 | static bool create_pixel_unpack_buffer(struct gs_texture_2d *tex) 49 | { 50 | GLsizeiptr size; 51 | bool success = true; 52 | 53 | if (!gl_gen_buffers(1, &tex->unpack_buffer)) 54 | return false; 55 | 56 | if (!gl_bind_buffer(GL_PIXEL_UNPACK_BUFFER, tex->unpack_buffer)) 57 | return false; 58 | 59 | size = tex->width * gs_get_format_bpp(tex->base.format); 60 | if (!gs_is_compressed_format(tex->base.format)) { 61 | size /= 8; 62 | size = (size + 3) & 0xFFFFFFFC; 63 | size *= tex->height; 64 | } else { 65 | size *= tex->height; 66 | size /= 8; 67 | } 68 | 69 | glBufferData(GL_PIXEL_UNPACK_BUFFER, size, 0, GL_DYNAMIC_DRAW); 70 | if (!gl_success("glBufferData")) 71 | success = false; 72 | 73 | if (!gl_bind_buffer(GL_PIXEL_UNPACK_BUFFER, 0)) 74 | success = false; 75 | 76 | return success; 77 | } 78 | 79 | gs_texture_t *device_texture_create(gs_device_t *device, uint32_t width, 80 | uint32_t height, 81 | enum gs_color_format color_format, 82 | uint32_t levels, const uint8_t **data, 83 | uint32_t flags) 84 | { 85 | struct gs_texture_2d *tex = bzalloc(sizeof(struct gs_texture_2d)); 86 | tex->base.device = device; 87 | tex->base.type = GS_TEXTURE_2D; 88 | tex->base.format = color_format; 89 | tex->base.levels = levels; 90 | tex->base.gl_format = convert_gs_format(color_format); 91 | tex->base.gl_internal_format = convert_gs_internal_format(color_format); 92 | tex->base.gl_type = get_gl_format_type(color_format); 93 | tex->base.gl_target = GL_TEXTURE_2D; 94 | tex->base.is_dynamic = (flags & GS_DYNAMIC) != 0; 95 | tex->base.is_render_target = (flags & GS_RENDER_TARGET) != 0; 96 | tex->base.is_dummy = (flags & GS_GL_DUMMYTEX) != 0; 97 | tex->base.gen_mipmaps = (flags & GS_BUILD_MIPMAPS) != 0; 98 | tex->width = width; 99 | tex->height = height; 100 | 101 | if (!gl_gen_textures(1, &tex->base.texture)) 102 | goto fail; 103 | 104 | if (!tex->base.is_dummy) { 105 | if (tex->base.is_dynamic && !create_pixel_unpack_buffer(tex)) 106 | goto fail; 107 | if (!upload_texture_2d(tex, data)) 108 | goto fail; 109 | } else { 110 | if (!gl_bind_texture(GL_TEXTURE_2D, tex->base.texture)) 111 | goto fail; 112 | 113 | uint32_t row_size = 114 | tex->width * gs_get_format_bpp(tex->base.format); 115 | uint32_t tex_size = tex->height * row_size / 8; 116 | bool compressed = gs_is_compressed_format(tex->base.format); 117 | bool did_init = gl_init_face(GL_TEXTURE_2D, tex->base.gl_type, 118 | 1, tex->base.gl_format, 119 | tex->base.gl_internal_format, 120 | compressed, tex->width, 121 | tex->height, tex_size, NULL); 122 | did_init = 123 | gl_tex_param_i(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); 124 | 125 | bool did_unbind = gl_bind_texture(GL_TEXTURE_2D, 0); 126 | if (!did_init || !did_unbind) 127 | goto fail; 128 | } 129 | 130 | return (gs_texture_t *)tex; 131 | 132 | fail: 133 | gs_texture_destroy((gs_texture_t *)tex); 134 | blog(LOG_ERROR, "device_texture_create (GL) failed"); 135 | return NULL; 136 | } 137 | 138 | static inline bool is_texture_2d(const gs_texture_t *tex, const char *func) 139 | { 140 | bool is_tex2d = tex->type == GS_TEXTURE_2D; 141 | if (!is_tex2d) 142 | blog(LOG_ERROR, "%s (GL) failed: Not a 2D texture", func); 143 | return is_tex2d; 144 | } 145 | 146 | void gs_texture_destroy(gs_texture_t *tex) 147 | { 148 | struct gs_texture_2d *tex2d = (struct gs_texture_2d *)tex; 149 | if (!tex) 150 | return; 151 | 152 | if (!is_texture_2d(tex, "gs_texture_destroy")) 153 | return; 154 | 155 | if (tex->cur_sampler) 156 | gs_samplerstate_destroy(tex->cur_sampler); 157 | 158 | if (!tex->is_dummy && tex->is_dynamic && tex2d->unpack_buffer) 159 | gl_delete_buffers(1, &tex2d->unpack_buffer); 160 | 161 | if (tex->texture) 162 | gl_delete_textures(1, &tex->texture); 163 | 164 | if (tex->fbo) 165 | fbo_info_destroy(tex->fbo); 166 | 167 | bfree(tex); 168 | } 169 | 170 | uint32_t gs_texture_get_width(const gs_texture_t *tex) 171 | { 172 | const struct gs_texture_2d *tex2d = (const struct gs_texture_2d *)tex; 173 | if (!is_texture_2d(tex, "gs_texture_get_width")) 174 | return 0; 175 | 176 | return tex2d->width; 177 | } 178 | 179 | uint32_t gs_texture_get_height(const gs_texture_t *tex) 180 | { 181 | const struct gs_texture_2d *tex2d = (const struct gs_texture_2d *)tex; 182 | if (!is_texture_2d(tex, "gs_texture_get_height")) 183 | return 0; 184 | 185 | return tex2d->height; 186 | } 187 | 188 | enum gs_color_format gs_texture_get_color_format(const gs_texture_t *tex) 189 | { 190 | return tex->format; 191 | } 192 | 193 | bool gs_texture_map(gs_texture_t *tex, uint8_t **ptr, uint32_t *linesize) 194 | { 195 | struct gs_texture_2d *tex2d = (struct gs_texture_2d *)tex; 196 | 197 | if (!is_texture_2d(tex, "gs_texture_map")) 198 | goto fail; 199 | 200 | if (!tex2d->base.is_dynamic) { 201 | blog(LOG_ERROR, "Texture is not dynamic"); 202 | goto fail; 203 | } 204 | 205 | if (!gl_bind_buffer(GL_PIXEL_UNPACK_BUFFER, tex2d->unpack_buffer)) 206 | goto fail; 207 | 208 | *ptr = glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY); 209 | if (!gl_success("glMapBuffer")) 210 | goto fail; 211 | 212 | gl_bind_buffer(GL_PIXEL_UNPACK_BUFFER, 0); 213 | 214 | *linesize = tex2d->width * gs_get_format_bpp(tex->format) / 8; 215 | *linesize = (*linesize + 3) & 0xFFFFFFFC; 216 | return true; 217 | 218 | fail: 219 | blog(LOG_ERROR, "gs_texture_map (GL) failed"); 220 | return false; 221 | } 222 | 223 | void gs_texture_unmap(gs_texture_t *tex) 224 | { 225 | struct gs_texture_2d *tex2d = (struct gs_texture_2d *)tex; 226 | if (!is_texture_2d(tex, "gs_texture_unmap")) 227 | goto failed; 228 | 229 | if (!gl_bind_buffer(GL_PIXEL_UNPACK_BUFFER, tex2d->unpack_buffer)) 230 | goto failed; 231 | 232 | glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER); 233 | if (!gl_success("glUnmapBuffer")) 234 | goto failed; 235 | 236 | if (!gl_bind_texture(GL_TEXTURE_2D, tex2d->base.texture)) 237 | goto failed; 238 | 239 | glTexImage2D(GL_TEXTURE_2D, 0, tex->gl_internal_format, tex2d->width, 240 | tex2d->height, 0, tex->gl_format, tex->gl_type, 0); 241 | if (!gl_success("glTexImage2D")) 242 | goto failed; 243 | 244 | gl_bind_buffer(GL_PIXEL_UNPACK_BUFFER, 0); 245 | gl_bind_texture(GL_TEXTURE_2D, 0); 246 | return; 247 | 248 | failed: 249 | gl_bind_buffer(GL_PIXEL_UNPACK_BUFFER, 0); 250 | gl_bind_texture(GL_TEXTURE_2D, 0); 251 | blog(LOG_ERROR, "gs_texture_unmap (GL) failed"); 252 | } 253 | 254 | bool gs_texture_is_rect(const gs_texture_t *tex) 255 | { 256 | const struct gs_texture_2d *tex2d = (const struct gs_texture_2d *)tex; 257 | if (!is_texture_2d(tex, "gs_texture_unmap")) { 258 | blog(LOG_ERROR, "gs_texture_is_rect (GL) failed"); 259 | return false; 260 | } 261 | 262 | return tex2d->base.gl_target == GL_TEXTURE_RECTANGLE; 263 | } 264 | 265 | void *gs_texture_get_obj(gs_texture_t *tex) 266 | { 267 | struct gs_texture_2d *tex2d = (struct gs_texture_2d *)tex; 268 | if (!is_texture_2d(tex, "gs_texture_unmap")) { 269 | blog(LOG_ERROR, "gs_texture_get_obj (GL) failed"); 270 | return NULL; 271 | } 272 | 273 | return &tex2d->base.texture; 274 | } 275 | -------------------------------------------------------------------------------- /Nox/graphic-hook/d3d12-capture.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "graphics-hook.h" 3 | 4 | #if COMPILE_D3D12_HOOK 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #include "dxgi-helpers.hpp" 11 | #include "../funchook.h" 12 | 13 | #define MAX_BACKBUFFERS 8 14 | 15 | struct d3d12_data { 16 | ID3D12Device *device; /* do not release */ 17 | uint32_t base_cx; 18 | uint32_t base_cy; 19 | uint32_t cx; 20 | uint32_t cy; 21 | DXGI_FORMAT format; 22 | bool using_shtex; 23 | bool using_scale; 24 | bool multisampled; 25 | bool dxgi_1_4; 26 | 27 | ID3D11Device *device11; 28 | ID3D11DeviceContext *context11; 29 | ID3D11On12Device *device11on12; 30 | 31 | union { 32 | struct { 33 | struct shtex_data *shtex_info; 34 | ID3D11Resource *backbuffer11[MAX_BACKBUFFERS]; 35 | UINT backbuffer_count; 36 | UINT cur_backbuffer; 37 | ID3D11Texture2D *copy_tex; 38 | HANDLE handle; 39 | }; 40 | }; 41 | }; 42 | 43 | static struct d3d12_data data = {}; 44 | 45 | void d3d12_free(void) 46 | { 47 | if (data.copy_tex) 48 | data.copy_tex->Release(); 49 | for (size_t i = 0; i < data.backbuffer_count; i++) { 50 | if (data.backbuffer11[i]) 51 | data.backbuffer11[i]->Release(); 52 | } 53 | if (data.device11) 54 | data.device11->Release(); 55 | if (data.context11) 56 | data.context11->Release(); 57 | if (data.device11on12) 58 | data.device11on12->Release(); 59 | 60 | capture_free(); 61 | 62 | memset(&data, 0, sizeof(data)); 63 | 64 | hlog("----------------- d3d12 capture freed ----------------"); 65 | } 66 | 67 | struct bb_info { 68 | ID3D12Resource *backbuffer[MAX_BACKBUFFERS]; 69 | UINT count; 70 | }; 71 | 72 | static bool create_d3d12_tex(bb_info &bb) 73 | { 74 | D3D11_RESOURCE_FLAGS rf11 = {}; 75 | HRESULT hr; 76 | 77 | if (!bb.count) 78 | return false; 79 | 80 | data.backbuffer_count = bb.count; 81 | 82 | for (UINT i = 0; i < bb.count; i++) { 83 | hr = data.device11on12->CreateWrappedResource( 84 | bb.backbuffer[i], &rf11, 85 | D3D12_RESOURCE_STATE_COPY_SOURCE, 86 | D3D12_RESOURCE_STATE_PRESENT, __uuidof(ID3D11Resource), 87 | (void **)&data.backbuffer11[i]); 88 | if (FAILED(hr)) { 89 | hlog_hr("create_d3d12_tex: failed to create " 90 | "backbuffer11", 91 | hr); 92 | return false; 93 | } 94 | } 95 | 96 | D3D11_TEXTURE2D_DESC desc11 = {}; 97 | desc11.Width = data.cx; 98 | desc11.Height = data.cy; 99 | desc11.MipLevels = 1; 100 | desc11.ArraySize = 1; 101 | desc11.Format = data.format; 102 | desc11.SampleDesc.Count = 1; 103 | desc11.BindFlags = D3D11_BIND_SHADER_RESOURCE; 104 | desc11.MiscFlags = D3D11_RESOURCE_MISC_SHARED; 105 | 106 | hr = data.device11->CreateTexture2D(&desc11, nullptr, &data.copy_tex); 107 | if (FAILED(hr)) { 108 | hlog_hr("create_d3d12_tex: creation of d3d11 copy tex failed", 109 | hr); 110 | return false; 111 | } 112 | 113 | for (UINT i = 0; i < bb.count; i++) { 114 | data.device11on12->ReleaseWrappedResources( 115 | &data.backbuffer11[i], 1); 116 | } 117 | 118 | IDXGIResource *dxgi_res; 119 | hr = data.copy_tex->QueryInterface(__uuidof(IDXGIResource), 120 | (void **)&dxgi_res); 121 | if (FAILED(hr)) { 122 | hlog_hr("create_d3d12_tex: failed to query " 123 | "IDXGIResource interface from texture", 124 | hr); 125 | return false; 126 | } 127 | 128 | hr = dxgi_res->GetSharedHandle(&data.handle); 129 | dxgi_res->Release(); 130 | if (FAILED(hr)) { 131 | hlog_hr("create_d3d12_tex: failed to get shared handle", hr); 132 | return false; 133 | } 134 | 135 | return true; 136 | } 137 | 138 | typedef PFN_D3D11ON12_CREATE_DEVICE create_11_on_12_t; 139 | 140 | static bool d3d12_init_11on12(void) 141 | { 142 | static HMODULE d3d11 = nullptr; 143 | static create_11_on_12_t create_11_on_12 = nullptr; 144 | static bool initialized_11 = false; 145 | static bool initialized_func = false; 146 | HRESULT hr; 147 | 148 | if (!initialized_11 && !d3d11) { 149 | d3d11 = load_system_library("d3d11.dll"); 150 | if (!d3d11) { 151 | hlog("d3d12_init_11on12: failed to load d3d11"); 152 | } 153 | initialized_11 = true; 154 | } 155 | 156 | if (!d3d11) { 157 | return false; 158 | } 159 | 160 | if (!initialized_func && !create_11_on_12) { 161 | create_11_on_12 = (create_11_on_12_t)GetProcAddress( 162 | d3d11, "D3D11On12CreateDevice"); 163 | if (!create_11_on_12) { 164 | hlog("d3d12_init_11on12: Failed to get " 165 | "D3D11On12CreateDevice address"); 166 | } 167 | 168 | initialized_func = true; 169 | } 170 | 171 | if (!create_11_on_12) { 172 | return false; 173 | } 174 | 175 | hr = create_11_on_12(data.device, 0, nullptr, 0, nullptr, 0, 0, 176 | &data.device11, &data.context11, nullptr); 177 | if (FAILED(hr)) { 178 | hlog_hr("d3d12_init_11on12: failed to create 11 device", hr); 179 | return false; 180 | } 181 | 182 | data.device11->QueryInterface(__uuidof(ID3D11On12Device), 183 | (void **)&data.device11on12); 184 | if (FAILED(hr)) { 185 | hlog_hr("d3d12_init_11on12: failed to query 11on12 device", hr); 186 | return false; 187 | } 188 | 189 | return true; 190 | } 191 | 192 | static bool d3d12_shtex_init(HWND window, bb_info &bb) 193 | { 194 | if (!d3d12_init_11on12()) { 195 | return false; 196 | } 197 | if (!create_d3d12_tex(bb)) { 198 | return false; 199 | } 200 | if (!capture_init_shtex(&data.shtex_info, window, data.base_cx, 201 | data.base_cy, data.cx, data.cy, data.format, 202 | false, (uintptr_t)data.handle)) { 203 | return false; 204 | } 205 | 206 | hlog("d3d12 shared texture capture successful"); 207 | return true; 208 | } 209 | 210 | static inline bool d3d12_init_format(IDXGISwapChain *swap, HWND &window, 211 | bb_info &bb) 212 | { 213 | DXGI_SWAP_CHAIN_DESC desc; 214 | IDXGISwapChain3 *swap3; 215 | HRESULT hr; 216 | 217 | hr = swap->GetDesc(&desc); 218 | if (FAILED(hr)) { 219 | hlog_hr("d3d12_init_format: swap->GetDesc failed", hr); 220 | return false; 221 | } 222 | 223 | data.format = fix_dxgi_format(desc.BufferDesc.Format); 224 | data.multisampled = desc.SampleDesc.Count > 1; 225 | window = desc.OutputWindow; 226 | data.base_cx = desc.BufferDesc.Width; 227 | data.base_cy = desc.BufferDesc.Height; 228 | 229 | hr = swap->QueryInterface(__uuidof(IDXGISwapChain3), (void **)&swap3); 230 | if (SUCCEEDED(hr)) { 231 | data.dxgi_1_4 = true; 232 | hlog("We're DXGI1.4 boys!"); 233 | swap3->Release(); 234 | } 235 | 236 | hlog("Buffer count: %d, swap effect: %d", (int)desc.BufferCount, 237 | (int)desc.SwapEffect); 238 | 239 | bb.count = desc.SwapEffect == DXGI_SWAP_EFFECT_DISCARD 240 | ? 1 241 | : desc.BufferCount; 242 | 243 | if (bb.count == 1) 244 | data.dxgi_1_4 = false; 245 | 246 | if (bb.count > MAX_BACKBUFFERS) { 247 | hlog("Somehow it's using more than the max backbuffers. " 248 | "Not sure why anyone would do that."); 249 | bb.count = 1; 250 | data.dxgi_1_4 = false; 251 | } 252 | 253 | for (UINT i = 0; i < bb.count; i++) { 254 | hr = swap->GetBuffer(i, __uuidof(ID3D12Resource), 255 | (void **)&bb.backbuffer[i]); 256 | if (SUCCEEDED(hr)) { 257 | bb.backbuffer[i]->Release(); 258 | } else { 259 | return false; 260 | } 261 | } 262 | 263 | if (data.using_scale) { 264 | data.cx = global_hook_info->cx; 265 | data.cy = global_hook_info->cy; 266 | } else { 267 | data.cx = desc.BufferDesc.Width; 268 | data.cy = desc.BufferDesc.Height; 269 | } 270 | return true; 271 | } 272 | 273 | static void d3d12_init(IDXGISwapChain *swap) 274 | { 275 | bool success = true; 276 | bb_info bb = {}; 277 | HWND window; 278 | HRESULT hr; 279 | 280 | data.using_scale = global_hook_info->use_scale; 281 | 282 | hr = swap->GetDevice(__uuidof(ID3D12Device), (void **)&data.device); 283 | if (FAILED(hr)) { 284 | hlog_hr("d3d12_init: failed to get device from swap", hr); 285 | return; 286 | } 287 | 288 | data.device->Release(); 289 | 290 | if (!d3d12_init_format(swap, window, bb)) { 291 | return; 292 | } 293 | if (data.using_scale) { 294 | hlog("d3d12_init: scaling currently unsupported; ignoring"); 295 | } 296 | if (success) { 297 | if (global_hook_info->force_shmem) { 298 | hlog("d3d12_init: shared memory capture currently " 299 | "unsupported; ignoring"); 300 | } 301 | 302 | success = d3d12_shtex_init(window, bb); 303 | } 304 | 305 | if (!success) 306 | d3d12_free(); 307 | } 308 | 309 | static inline void d3d12_copy_texture(ID3D11Resource *dst, ID3D11Resource *src) 310 | { 311 | if (data.multisampled) { 312 | data.context11->ResolveSubresource(dst, 0, src, 0, data.format); 313 | } else { 314 | data.context11->CopyResource(dst, src); 315 | } 316 | } 317 | 318 | static inline void d3d12_shtex_capture(IDXGISwapChain *swap, 319 | bool capture_overlay) 320 | { 321 | bool dxgi_1_4 = data.dxgi_1_4; 322 | UINT cur_idx; 323 | 324 | if (dxgi_1_4) { 325 | IDXGISwapChain3 *swap3 = 326 | reinterpret_cast(swap); 327 | cur_idx = swap3->GetCurrentBackBufferIndex(); 328 | if (!capture_overlay) { 329 | if (++cur_idx >= data.backbuffer_count) 330 | cur_idx = 0; 331 | } 332 | } else { 333 | cur_idx = data.cur_backbuffer; 334 | } 335 | 336 | ID3D11Resource *backbuffer = data.backbuffer11[cur_idx]; 337 | 338 | data.device11on12->AcquireWrappedResources(&backbuffer, 1); 339 | d3d12_copy_texture(data.copy_tex, backbuffer); 340 | data.device11on12->ReleaseWrappedResources(&backbuffer, 1); 341 | data.context11->Flush(); 342 | 343 | if (!dxgi_1_4) { 344 | if (++data.cur_backbuffer >= data.backbuffer_count) 345 | data.cur_backbuffer = 0; 346 | } 347 | } 348 | 349 | void d3d12_capture(void *swap_ptr, void *, bool capture_overlay) 350 | { 351 | IDXGISwapChain *swap = (IDXGISwapChain *)swap_ptr; 352 | 353 | if (capture_should_stop()) { 354 | d3d12_free(); 355 | } 356 | if (capture_should_init()) { 357 | d3d12_init(swap); 358 | } 359 | if (capture_ready()) { 360 | d3d12_shtex_capture(swap, capture_overlay); 361 | } 362 | } 363 | 364 | #endif 365 | -------------------------------------------------------------------------------- /NoxCap/gl-subsystem.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | Copyright (C) 2013 by Hugh Bailey 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 2 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see . 16 | ******************************************************************************/ 17 | 18 | #pragma once 19 | #include 20 | 21 | struct gl_platform; 22 | struct gl_windowinfo; 23 | 24 | enum copy_type { COPY_TYPE_ARB, COPY_TYPE_NV, COPY_TYPE_FBO_BLIT }; 25 | 26 | 27 | #define GS_MAX_TEXTURES 8 28 | 29 | 30 | typedef struct gs_shader gs_shader_t; 31 | typedef struct gs_device gs_device_t; 32 | typedef struct gs_sampler_state gs_samplerstate_t; 33 | typedef struct gs_texture gs_texture_t; 34 | typedef struct gs_zstencil_buffer gs_zstencil_t; 35 | typedef struct gs_vertex_buffer gs_vertbuffer_t; 36 | typedef struct gs_index_buffer gs_indexbuffer_t; 37 | typedef struct gs_swap_chain gs_swapchain_t; 38 | 39 | 40 | typedef unsigned int GLuint; 41 | typedef int GLint; 42 | typedef unsigned int GLenum; 43 | 44 | 45 | 46 | enum gs_texture_type { 47 | GS_TEXTURE_2D, 48 | GS_TEXTURE_3D, 49 | GS_TEXTURE_CUBE, 50 | }; 51 | 52 | 53 | enum attrib_type { 54 | ATTRIB_POSITION, 55 | ATTRIB_NORMAL, 56 | ATTRIB_TANGENT, 57 | ATTRIB_COLOR, 58 | ATTRIB_TEXCOORD, 59 | ATTRIB_TARGET 60 | }; 61 | 62 | struct shader_attrib { 63 | char *name; 64 | size_t index; 65 | enum attrib_type type; 66 | }; 67 | 68 | 69 | #define DARRAY_INVALID ((size_t)-1) 70 | #define DARRAY(type) \ 71 | union { \ 72 | struct darray da; \ 73 | struct { \ 74 | type *array; \ 75 | size_t num; \ 76 | size_t capacity; \ 77 | }; \ 78 | } 79 | 80 | struct darray { 81 | void *array; 82 | size_t num; 83 | size_t capacity; 84 | }; 85 | 86 | struct gs_sampler_state { 87 | gs_device_t *device; 88 | volatile long ref; 89 | 90 | GLint min_filter; 91 | GLint mag_filter; 92 | GLint address_u; 93 | GLint address_v; 94 | GLint address_w; 95 | GLint max_anisotropy; 96 | }; 97 | 98 | 99 | struct gs_shader { 100 | gs_device_t *device; 101 | enum gs_shader_type type; 102 | GLuint obj; 103 | 104 | struct gs_shader_param *viewproj; 105 | struct gs_shader_param *world; 106 | 107 | DARRAY(struct shader_attrib) attribs; 108 | DARRAY(struct gs_shader_param) params; 109 | DARRAY(gs_samplerstate_t *) samplers; 110 | }; 111 | 112 | enum gs_shader_param_type { 113 | GS_SHADER_PARAM_UNKNOWN, 114 | GS_SHADER_PARAM_BOOL, 115 | GS_SHADER_PARAM_FLOAT, 116 | GS_SHADER_PARAM_INT, 117 | GS_SHADER_PARAM_STRING, 118 | GS_SHADER_PARAM_VEC2, 119 | GS_SHADER_PARAM_VEC3, 120 | GS_SHADER_PARAM_VEC4, 121 | GS_SHADER_PARAM_INT2, 122 | GS_SHADER_PARAM_INT3, 123 | GS_SHADER_PARAM_INT4, 124 | GS_SHADER_PARAM_MATRIX4X4, 125 | GS_SHADER_PARAM_TEXTURE, 126 | }; 127 | 128 | struct gs_shader_param { 129 | enum gs_shader_param_type type; 130 | 131 | char *name; 132 | gs_shader_t *shader; 133 | gs_samplerstate_t *next_sampler; 134 | GLint texture_id; 135 | size_t sampler_id; 136 | int array_count; 137 | 138 | struct gs_texture *texture; 139 | 140 | DARRAY(unsigned char) cur_value; 141 | DARRAY(unsigned char) def_value; 142 | BOOL changed; 143 | }; 144 | 145 | struct program_param { 146 | GLint obj; 147 | struct gs_shader_param *param; 148 | }; 149 | 150 | struct gs_program { 151 | gs_device_t *device; 152 | GLuint obj; 153 | struct gs_shader *vertex_shader; 154 | struct gs_shader *pixel_shader; 155 | 156 | DARRAY(struct program_param) params; 157 | DARRAY(GLint) attribs; 158 | 159 | struct gs_program **prev_next; 160 | struct gs_program *next; 161 | }; 162 | 163 | extern struct gs_program *gs_program_create(struct gs_device *device); 164 | extern void gs_program_destroy(struct gs_program *program); 165 | extern void program_update_params(struct gs_program *shader); 166 | 167 | struct gs_vertex_buffer { 168 | GLuint vao; 169 | GLuint vertex_buffer; 170 | GLuint normal_buffer; 171 | GLuint tangent_buffer; 172 | GLuint color_buffer; 173 | DARRAY(GLuint) uv_buffers; 174 | DARRAY(size_t) uv_sizes; 175 | 176 | gs_device_t *device; 177 | size_t num; 178 | BOOL dynamic; 179 | struct gs_vb_data *data; 180 | }; 181 | 182 | extern BOOL load_vb_buffers(struct gs_program *program, 183 | struct gs_vertex_buffer *vb, 184 | struct gs_index_buffer *ib); 185 | 186 | struct gs_index_buffer { 187 | GLuint buffer; 188 | enum gs_index_type type; 189 | GLuint gl_type; 190 | 191 | gs_device_t *device; 192 | void *data; 193 | size_t num; 194 | size_t width; 195 | size_t size; 196 | BOOL dynamic; 197 | }; 198 | 199 | struct gs_texture { 200 | gs_device_t *device; 201 | enum gs_texture_type type; 202 | enum gs_color_format format; 203 | GLenum gl_format; 204 | GLenum gl_target; 205 | GLenum gl_internal_format; 206 | GLenum gl_type; 207 | GLuint texture; 208 | uint32_t levels; 209 | BOOL is_dynamic; 210 | BOOL is_render_target; 211 | BOOL is_dummy; 212 | BOOL gen_mipmaps; 213 | 214 | gs_samplerstate_t *cur_sampler; 215 | struct fbo_info *fbo; 216 | }; 217 | 218 | struct gs_texture_2d { 219 | struct gs_texture base; 220 | 221 | uint32_t width; 222 | uint32_t height; 223 | BOOL gen_mipmaps; 224 | GLuint unpack_buffer; 225 | }; 226 | 227 | struct gs_texture_cube { 228 | struct gs_texture base; 229 | 230 | uint32_t size; 231 | }; 232 | 233 | struct gs_stage_surface { 234 | gs_device_t *device; 235 | 236 | enum gs_color_format format; 237 | uint32_t width; 238 | uint32_t height; 239 | 240 | uint32_t bytes_per_pixel; 241 | GLenum gl_format; 242 | GLint gl_internal_format; 243 | GLenum gl_type; 244 | GLuint pack_buffer; 245 | }; 246 | 247 | struct gs_zstencil_buffer { 248 | gs_device_t *device; 249 | GLuint buffer; 250 | GLuint attachment; 251 | GLenum format; 252 | }; 253 | 254 | struct fbo_info { 255 | GLuint fbo; 256 | uint32_t width; 257 | uint32_t height; 258 | enum gs_color_format format; 259 | 260 | gs_texture_t *cur_render_target; 261 | int cur_render_side; 262 | gs_zstencil_t *cur_zstencil_buffer; 263 | }; 264 | 265 | struct gs_window { 266 | #if defined(_WIN32) 267 | void *hwnd; 268 | #elif defined(__APPLE__) 269 | __unsafe_unretained id view; 270 | #elif defined(__linux__) || defined(__FreeBSD__) 271 | /* I'm not sure how portable defining id to uint32_t is. */ 272 | uint32_t id; 273 | void *display; 274 | #endif 275 | }; 276 | 277 | enum gs_color_format { 278 | GS_UNKNOWN, 279 | GS_A8, 280 | GS_R8, 281 | GS_RGBA, 282 | GS_BGRX, 283 | GS_BGRA, 284 | GS_R10G10B10A2, 285 | GS_RGBA16, 286 | GS_R16, 287 | GS_RGBA16F, 288 | GS_RGBA32F, 289 | GS_RG16F, 290 | GS_RG32F, 291 | GS_R16F, 292 | GS_R32F, 293 | GS_DXT1, 294 | GS_DXT3, 295 | GS_DXT5, 296 | GS_R8G8, 297 | }; 298 | 299 | enum gs_zstencil_format { 300 | GS_ZS_NONE, 301 | GS_Z16, 302 | GS_Z24_S8, 303 | GS_Z32F, 304 | GS_Z32F_S8X24, 305 | }; 306 | 307 | 308 | struct gs_init_data { 309 | struct gs_window window; 310 | uint32_t cx, cy; 311 | uint32_t num_backbuffers; 312 | enum gs_color_format format; 313 | enum gs_zstencil_format zsformat; 314 | uint32_t adapter; 315 | }; 316 | 317 | struct gs_swap_chain { 318 | gs_device_t *device; 319 | struct gl_windowinfo *wi; 320 | struct gs_init_data info; 321 | }; 322 | struct gs_rect { 323 | int x; 324 | int y; 325 | int cx; 326 | int cy; 327 | }; 328 | 329 | typedef union __declspec(intrin_type) __declspec(align(16)) __m128 { 330 | float m128_f32[4]; 331 | unsigned __int64 m128_u64[2]; 332 | __int8 m128_i8[16]; 333 | __int16 m128_i16[8]; 334 | __int32 m128_i32[4]; 335 | __int64 m128_i64[2]; 336 | unsigned __int8 m128_u8[16]; 337 | unsigned __int16 m128_u16[8]; 338 | unsigned __int32 m128_u32[4]; 339 | } __m128; 340 | 341 | struct vec4 { 342 | union { 343 | struct { 344 | float x, y, z, w; 345 | }; 346 | float ptr[4]; 347 | __m128 m; 348 | }; 349 | }; 350 | 351 | struct matrix4 { 352 | struct vec4 x, y, z, t; 353 | }; 354 | 355 | struct gs_device { 356 | struct gl_platform *plat; 357 | enum copy_type copy_type; 358 | 359 | GLuint empty_vao; 360 | 361 | gs_texture_t *cur_render_target; 362 | gs_zstencil_t *cur_zstencil_buffer; 363 | int cur_render_side; 364 | gs_texture_t *cur_textures[GS_MAX_TEXTURES]; 365 | gs_samplerstate_t *cur_samplers[GS_MAX_TEXTURES]; 366 | gs_vertbuffer_t *cur_vertex_buffer; 367 | gs_indexbuffer_t *cur_index_buffer; 368 | gs_shader_t *cur_vertex_shader; 369 | gs_shader_t *cur_pixel_shader; 370 | gs_swapchain_t *cur_swap; 371 | struct gs_program *cur_program; 372 | 373 | struct gs_program *first_program; 374 | 375 | enum gs_cull_mode cur_cull_mode; 376 | struct gs_rect cur_viewport; 377 | 378 | struct matrix4 cur_proj; 379 | struct matrix4 cur_view; 380 | struct matrix4 cur_viewproj; 381 | 382 | DARRAY(struct matrix4) proj_stack; 383 | 384 | struct fbo_info *cur_fbo; 385 | }; 386 | 387 | extern struct fbo_info *get_fbo(gs_texture_t *tex, uint32_t width, 388 | uint32_t height); 389 | 390 | extern void gl_update(gs_device_t *device); 391 | 392 | extern struct gl_platform *gl_platform_create(gs_device_t *device, 393 | uint32_t adapter); 394 | extern void gl_platform_destroy(struct gl_platform *platform); 395 | 396 | extern BOOL gl_platform_init_swapchain(struct gs_swap_chain *swap); 397 | extern void gl_platform_cleanup_swapchain(struct gs_swap_chain *swap); 398 | 399 | extern struct gl_windowinfo * 400 | gl_windowinfo_create(const struct gs_init_data *info); 401 | extern void gl_windowinfo_destroy(struct gl_windowinfo *wi); 402 | 403 | extern void gl_getclientsize(const struct gs_swap_chain *swap, uint32_t *width, 404 | uint32_t *height); 405 | -------------------------------------------------------------------------------- /Nox/Noxcap.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Debug 10 | x64 11 | 12 | 13 | Release 14 | Win32 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | {5FA3E3CD-46E5-4FF6-B648-73228D99586A} 23 | Win32Proj 24 | Noxcap 25 | Noxcap 26 | 27 | 28 | 29 | DynamicLibrary 30 | true 31 | v120 32 | Unicode 33 | 34 | 35 | DynamicLibrary 36 | true 37 | v120 38 | Unicode 39 | 40 | 41 | DynamicLibrary 42 | false 43 | v120 44 | true 45 | Unicode 46 | 47 | 48 | DynamicLibrary 49 | false 50 | v120 51 | true 52 | Unicode 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | true 72 | $(ProjectName) 73 | $(SolutionDir)$(Configuration)\ 74 | 75 | 76 | true 77 | $(ProjectName) 78 | 79 | 80 | false 81 | 82 | 83 | false 84 | 85 | 86 | 87 | NotUsing 88 | Level3 89 | Disabled 90 | _DEBUG;_WINDOWS;_USRDLL;NOXCAP_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) 91 | true 92 | 93 | 94 | Windows 95 | true 96 | 97 | 98 | MachineX64 99 | 100 | 101 | 102 | 103 | NotUsing 104 | Level3 105 | Disabled 106 | _DEBUG;_WINDOWS;_USRDLL;NOXCAP_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) 107 | true 108 | 109 | 110 | Windows 111 | true 112 | 113 | 114 | 115 | 116 | 117 | 118 | Level3 119 | Use 120 | MaxSpeed 121 | true 122 | true 123 | WIN32;NDEBUG;_WINDOWS;_USRDLL;NOXCAP_EXPORTS;%(PreprocessorDefinitions) 124 | true 125 | 126 | 127 | Windows 128 | true 129 | true 130 | true 131 | 132 | 133 | 134 | 135 | Level3 136 | NotUsing 137 | MaxSpeed 138 | true 139 | true 140 | _WINDOWS;_USRDLL;NOXCAP_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) 141 | true 142 | 143 | 144 | Windows 145 | true 146 | true 147 | true 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | Create 183 | Create 184 | Create 185 | Create 186 | 187 | 188 | 189 | 190 | 191 | -------------------------------------------------------------------------------- /Nox/graphic-hook/d3d8-capture.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "../d3d8-api/d3d8.h" 4 | #include "graphics-hook.h" 5 | #include "../funchook.h" 6 | 7 | typedef HRESULT(STDMETHODCALLTYPE *reset_t)(IDirect3DDevice8 *, 8 | D3DPRESENT_PARAMETERS *); 9 | typedef HRESULT(STDMETHODCALLTYPE *present_t)(IDirect3DDevice8 *, CONST RECT *, 10 | CONST RECT *, HWND, 11 | CONST RGNDATA *); 12 | 13 | static struct func_hook present; 14 | static struct func_hook reset; 15 | 16 | struct d3d8_data { 17 | HMODULE d3d8; 18 | uint32_t cx; 19 | uint32_t cy; 20 | D3DFORMAT d3d8_format; 21 | DXGI_FORMAT dxgi_format; 22 | 23 | struct shmem_data *shmem_info; 24 | HWND window; 25 | uint32_t pitch; 26 | IDirect3DSurface8 *copy_surfaces[NUM_BUFFERS]; 27 | bool surface_locked[NUM_BUFFERS]; 28 | int cur_surface; 29 | int copy_wait; 30 | }; 31 | 32 | static d3d8_data data = {}; 33 | 34 | static DXGI_FORMAT d3d8_to_dxgi_format(D3DFORMAT format) 35 | { 36 | switch ((unsigned long)format) { 37 | case D3DFMT_X1R5G5B5: 38 | case D3DFMT_A1R5G5B5: 39 | return DXGI_FORMAT_B5G5R5A1_UNORM; 40 | case D3DFMT_R5G6B5: 41 | return DXGI_FORMAT_B5G6R5_UNORM; 42 | case D3DFMT_A8R8G8B8: 43 | return DXGI_FORMAT_B8G8R8A8_UNORM; 44 | case D3DFMT_X8R8G8B8: 45 | return DXGI_FORMAT_B8G8R8X8_UNORM; 46 | } 47 | 48 | return DXGI_FORMAT_UNKNOWN; 49 | } 50 | 51 | static IDirect3DSurface8 *d3d8_get_backbuffer(IDirect3DDevice8 *device) 52 | { 53 | IDirect3DSurface8 *backbuffer; 54 | HRESULT hr; 55 | 56 | hr = device->GetRenderTarget(&backbuffer); 57 | if (FAILED(hr)) { 58 | hlog_hr("d3d8_get_backbuffer: Failed to get backbuffer", hr); 59 | backbuffer = nullptr; 60 | } 61 | 62 | return backbuffer; 63 | } 64 | 65 | static bool d3d8_get_window_handle(IDirect3DDevice8 *device) 66 | { 67 | D3DDEVICE_CREATION_PARAMETERS parameters; 68 | HRESULT hr; 69 | hr = device->GetCreationParameters(¶meters); 70 | if (FAILED(hr)) { 71 | hlog_hr("d3d8_get_window_handle: Failed to get " 72 | "device creation parameters", 73 | hr); 74 | return false; 75 | } 76 | 77 | data.window = parameters.hFocusWindow; 78 | 79 | return true; 80 | } 81 | 82 | static bool d3d8_init_format_backbuffer(IDirect3DDevice8 *device) 83 | { 84 | IDirect3DSurface8 *backbuffer; 85 | D3DSURFACE_DESC desc; 86 | HRESULT hr; 87 | 88 | if (!d3d8_get_window_handle(device)) 89 | return false; 90 | 91 | backbuffer = d3d8_get_backbuffer(device); 92 | if (!backbuffer) 93 | return false; 94 | 95 | hr = backbuffer->GetDesc(&desc); 96 | backbuffer->Release(); 97 | if (FAILED(hr)) { 98 | hlog_hr("d3d8_init_format_backbuffer: Failed to get " 99 | "backbuffer descriptor", 100 | hr); 101 | return false; 102 | } 103 | 104 | data.d3d8_format = desc.Format; 105 | data.dxgi_format = d3d8_to_dxgi_format(desc.Format); 106 | data.cx = desc.Width; 107 | data.cy = desc.Height; 108 | 109 | return true; 110 | } 111 | 112 | static bool d3d8_shmem_init_buffer(IDirect3DDevice8 *device, int idx) 113 | { 114 | HRESULT hr; 115 | 116 | hr = device->CreateImageSurface(data.cx, data.cy, data.d3d8_format, 117 | &data.copy_surfaces[idx]); 118 | if (FAILED(hr)) { 119 | hlog_hr("d3d8_shmem_init_buffer: Failed to create surface", hr); 120 | return false; 121 | } 122 | 123 | if (idx == 0) { 124 | D3DLOCKED_RECT rect; 125 | hr = data.copy_surfaces[0]->LockRect(&rect, nullptr, 126 | D3DLOCK_READONLY); 127 | if (FAILED(hr)) { 128 | hlog_hr("d3d8_shmem_init_buffer: Failed to lock buffer", 129 | hr); 130 | return false; 131 | } 132 | 133 | data.pitch = rect.Pitch; 134 | data.copy_surfaces[0]->UnlockRect(); 135 | } 136 | 137 | return true; 138 | } 139 | 140 | static bool d3d8_shmem_init(IDirect3DDevice8 *device) 141 | { 142 | for (int i = 0; i < NUM_BUFFERS; i++) { 143 | if (!d3d8_shmem_init_buffer(device, i)) { 144 | return false; 145 | } 146 | } 147 | if (!capture_init_shmem(&data.shmem_info, data.window, data.cx, data.cy, 148 | data.cx, data.cy, data.pitch, data.dxgi_format, 149 | false)) { 150 | return false; 151 | } 152 | 153 | hlog("d3d8 memory capture successful"); 154 | return true; 155 | } 156 | 157 | static void d3d8_free() 158 | { 159 | capture_free(); 160 | 161 | for (size_t i = 0; i < NUM_BUFFERS; i++) { 162 | if (data.copy_surfaces[i]) { 163 | if (data.surface_locked[i]) 164 | data.copy_surfaces[i]->UnlockRect(); 165 | data.copy_surfaces[i]->Release(); 166 | } 167 | } 168 | 169 | memset(&data, 0, sizeof(data)); 170 | 171 | hlog("----------------- d3d8 capture freed -----------------"); 172 | } 173 | 174 | static void d3d8_init(IDirect3DDevice8 *device) 175 | { 176 | data.d3d8 = get_system_module("d3d8.dll"); 177 | 178 | if (!d3d8_init_format_backbuffer(device)) 179 | return; 180 | 181 | if (!d3d8_shmem_init(device)) 182 | d3d8_free(); 183 | } 184 | 185 | static void d3d8_shmem_capture_copy(int idx) 186 | { 187 | IDirect3DSurface8 *target = data.copy_surfaces[idx]; 188 | D3DLOCKED_RECT rect; 189 | HRESULT hr; 190 | 191 | if (data.surface_locked[idx]) 192 | return; 193 | 194 | hr = target->LockRect(&rect, nullptr, D3DLOCK_READONLY); 195 | if (SUCCEEDED(hr)) { 196 | shmem_copy_data(idx, rect.pBits); 197 | } 198 | } 199 | 200 | static void d3d8_shmem_capture(IDirect3DDevice8 *device, 201 | IDirect3DSurface8 *backbuffer) 202 | { 203 | int cur_surface; 204 | int next_surface; 205 | HRESULT hr; 206 | 207 | cur_surface = data.cur_surface; 208 | next_surface = (cur_surface == NUM_BUFFERS - 1) ? 0 : cur_surface + 1; 209 | 210 | if (data.copy_wait < NUM_BUFFERS - 1) { 211 | data.copy_wait++; 212 | } else { 213 | IDirect3DSurface8 *src = backbuffer; 214 | IDirect3DSurface8 *dst = data.copy_surfaces[cur_surface]; 215 | 216 | if (shmem_texture_data_lock(next_surface)) { 217 | dst->UnlockRect(); 218 | data.surface_locked[next_surface] = false; 219 | shmem_texture_data_unlock(next_surface); 220 | } 221 | 222 | hr = device->CopyRects(src, nullptr, 0, dst, nullptr); 223 | if (SUCCEEDED(hr)) { 224 | d3d8_shmem_capture_copy(cur_surface); 225 | } 226 | } 227 | 228 | data.cur_surface = next_surface; 229 | } 230 | 231 | static void d3d8_capture(IDirect3DDevice8 *device, 232 | IDirect3DSurface8 *backbuffer) 233 | { 234 | if (capture_should_stop()) { 235 | d3d8_free(); 236 | } 237 | if (capture_should_init()) { 238 | d3d8_init(device); 239 | } 240 | if (capture_ready()) { 241 | d3d8_shmem_capture(device, backbuffer); 242 | } 243 | } 244 | 245 | static HRESULT STDMETHODCALLTYPE hook_reset(IDirect3DDevice8 *device, 246 | D3DPRESENT_PARAMETERS *parameters) 247 | { 248 | HRESULT hr; 249 | 250 | if (capture_active()) 251 | d3d8_free(); 252 | 253 | unhook(&reset); 254 | reset_t call = (reset_t)reset.call_addr; 255 | hr = call(device, parameters); 256 | rehook(&reset); 257 | 258 | return hr; 259 | } 260 | 261 | static bool hooked_reset = false; 262 | 263 | static void setup_reset_hooks(IDirect3DDevice8 *device) 264 | { 265 | uintptr_t *vtable = *(uintptr_t **)device; 266 | 267 | hook_init(&reset, (void *)vtable[14], (void *)hook_reset, 268 | "IDirect3DDevice8::Reset"); 269 | rehook(&reset); 270 | 271 | hooked_reset = true; 272 | } 273 | 274 | static HRESULT STDMETHODCALLTYPE hook_present(IDirect3DDevice8 *device, 275 | CONST RECT *src_rect, 276 | CONST RECT *dst_rect, 277 | HWND override_window, 278 | CONST RGNDATA *dirty_region) 279 | { 280 | IDirect3DSurface8 *backbuffer; 281 | HRESULT hr; 282 | 283 | if (!hooked_reset) 284 | setup_reset_hooks(device); 285 | 286 | backbuffer = d3d8_get_backbuffer(device); 287 | if (backbuffer) { 288 | d3d8_capture(device, backbuffer); 289 | backbuffer->Release(); 290 | } 291 | 292 | unhook(&present); 293 | present_t call = (present_t)present.call_addr; 294 | hr = call(device, src_rect, dst_rect, override_window, dirty_region); 295 | rehook(&present); 296 | 297 | return hr; 298 | } 299 | 300 | typedef IDirect3D8 *(WINAPI *d3d8create_t)(UINT); 301 | 302 | static bool manually_get_d3d8_present_addr(HMODULE d3d8_module, 303 | void **present_addr) 304 | { 305 | d3d8create_t create; 306 | D3DPRESENT_PARAMETERS pp; 307 | HRESULT hr; 308 | 309 | IDirect3DDevice8 *device; 310 | IDirect3D8 *d3d8; 311 | 312 | hlog("D3D8 value invalid, manually obtaining"); 313 | 314 | create = (d3d8create_t)GetProcAddress(d3d8_module, "Direct3DCreate8"); 315 | if (!create) { 316 | hlog("Failed to load Direct3DCreate8"); 317 | return false; 318 | } 319 | 320 | d3d8 = create(D3D_SDK_VERSION); 321 | if (!d3d8) { 322 | hlog("Failed to create D3D8 context"); 323 | return false; 324 | } 325 | 326 | memset(&pp, 0, sizeof(pp)); 327 | pp.Windowed = true; 328 | pp.SwapEffect = D3DSWAPEFFECT_FLIP; 329 | pp.BackBufferFormat = D3DFMT_A8R8G8B8; 330 | pp.BackBufferWidth = 2; 331 | pp.BackBufferHeight = 2; 332 | pp.BackBufferCount = 1; 333 | pp.hDeviceWindow = dummy_window; 334 | 335 | hr = d3d8->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, 336 | dummy_window, 337 | D3DCREATE_HARDWARE_VERTEXPROCESSING, &pp, 338 | &device); 339 | d3d8->Release(); 340 | 341 | if (SUCCEEDED(hr)) { 342 | uintptr_t *vtable = *(uintptr_t **)device; 343 | *present_addr = (void *)vtable[15]; 344 | 345 | device->Release(); 346 | } else { 347 | hlog("Failed to create D3D8 device"); 348 | return false; 349 | } 350 | 351 | return true; 352 | } 353 | 354 | bool hook_d3d8(void) 355 | { 356 | HMODULE d3d8_module = get_system_module("d3d8.dll"); 357 | void *present_addr = nullptr; 358 | 359 | if (!d3d8_module) { 360 | return false; 361 | } 362 | if (!manually_get_d3d8_present_addr(d3d8_module, 363 | &present_addr)) { 364 | hlog("Failed to get D3D8 value"); 365 | return true; 366 | } 367 | /* 368 | d3d8_size = module_size(d3d8_module); 369 | 370 | if (global_hook_info->offsets.d3d8.present < d3d8_size) { 371 | present_addr = get_offset_addr( 372 | d3d8_module, global_hook_info->offsets.d3d8.present); 373 | } else { 374 | if (!dummy_window) { 375 | return false; 376 | } 377 | 378 | if (!manually_get_d3d8_present_addr(d3d8_module, 379 | &present_addr)) { 380 | hlog("Failed to get D3D8 value"); 381 | return true; 382 | } 383 | } 384 | */ 385 | if (!present_addr) { 386 | hlog("Invalid D3D8 value"); 387 | return true; 388 | } 389 | 390 | hook_init(&present, present_addr, (void *)hook_present, 391 | "IDirect3DDevice8::Present"); 392 | 393 | rehook(&present); 394 | 395 | hlog("Hooked D3D8"); 396 | return true; 397 | } 398 | --------------------------------------------------------------------------------