Wayland: initialize surface and render to video
This commit is contained in:
@@ -22,6 +22,7 @@ include(CMakeDependentOption)
|
||||
|
||||
if(UNIX)
|
||||
option(WICKED_LINUX_TEMPLATE "Build WickedEngine Linux template" ON)
|
||||
option(WAYLAND_BACKEND "Build WickedEngine Wayland backend" ON)
|
||||
elseif(WIN32)
|
||||
option(WICKED_WINDOWS_TEMPLATE "Build WickedEngine Windows template" ON)
|
||||
endif()
|
||||
|
||||
@@ -132,7 +132,8 @@ void Example_ImGui::Initialize()
|
||||
#ifdef _WIN32
|
||||
ImGui_ImplWin32_Init(window);
|
||||
#elif defined(SDL2)
|
||||
ImGui_ImplSDL2_InitForVulkan(window);
|
||||
IM_ASSERT(window.type == wi::platform::LinuxWindow::eSDLWindow);
|
||||
ImGui_ImplSDL2_InitForVulkan(window.sdl_window);
|
||||
#endif
|
||||
|
||||
IM_ASSERT(io.BackendRendererUserData == NULL && "Already initialized a renderer backend!");
|
||||
|
||||
@@ -23,10 +23,10 @@
|
||||
#endif
|
||||
|
||||
|
||||
#include "../WickedEngine/wiProfiler.h"
|
||||
#include "../WickedEngine/wiBacklog.h"
|
||||
#include "../WickedEngine/wiPrimitive.h"
|
||||
#include "../WickedEngine/wiRenderPath3D.h"
|
||||
#include "wiProfiler.h"
|
||||
#include "wiBacklog.h"
|
||||
#include "wiPrimitive.h"
|
||||
#include "wiRenderPath3D.h"
|
||||
#include "../Editor/ModelImporter.h"
|
||||
|
||||
#include <fstream>
|
||||
@@ -174,7 +174,8 @@ void Example_ImGui::Initialize()
|
||||
hWnd = window;
|
||||
ImGui_ImplWin32_Init(window);
|
||||
#elif defined(SDL2)
|
||||
ImGui_ImplSDL2_InitForVulkan(window);
|
||||
IM_ASSERT(window.type == wi::platform::LinuxWindow::eSDLWindow);
|
||||
ImGui_ImplSDL2_InitForVulkan(window.sdl_window);
|
||||
#endif
|
||||
|
||||
IM_ASSERT(io.BackendRendererUserData == NULL && "Already initialized a renderer backend!");
|
||||
@@ -457,7 +458,7 @@ void Example_ImGuiRenderer::Update(float dt)
|
||||
ImGui_Impl_CreateDeviceObjects();
|
||||
}
|
||||
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
ImGui_ImplWin32_NewFrame();
|
||||
#elif defined(SDL2)
|
||||
@@ -681,7 +682,7 @@ void Example_ImGuiRenderer::Update(float dt)
|
||||
bool bUseChild = false;
|
||||
if (use_fixed_height > 0) bUseChild = true;
|
||||
if(bUseChild) ImGui::BeginChild("##objectsc", ImVec2(0.0f, use_fixed_height), false, ImGuiWindowFlags_None); //ImGuiWindowFlags_AlwaysVerticalScrollbar
|
||||
|
||||
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
Entity e = scene.objects.GetEntity(i);
|
||||
@@ -1029,7 +1030,7 @@ void Example_ImGuiRenderer::Update(float dt)
|
||||
ImGui::EndTabBar();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (ImGui::CollapsingHeader(ICON_MD_SETTINGS " Settings", ImGuiTreeNodeFlags_None)) //ImGuiTreeNodeFlags_DefaultOpen
|
||||
{
|
||||
ImGui::SetCursorPos(ImGui::GetCursorPos() + ImVec2(0.0f, 3.0f));
|
||||
@@ -1390,7 +1391,7 @@ void Example_ImGuiRenderer::Update(float dt)
|
||||
if (ImGui::Selectable(lua_history[i].c_str(), is_selected)) {
|
||||
#ifdef _WIN32
|
||||
strcpy_s(lua, lua_history[i].c_str());
|
||||
#elif __linux__
|
||||
#elif __linux__
|
||||
strcpy(lua, lua_history[i].c_str());
|
||||
#endif
|
||||
bSetKeyBoardFocus = true;
|
||||
@@ -1489,7 +1490,7 @@ void Example_ImGuiRenderer::Update(float dt)
|
||||
}
|
||||
|
||||
float movespeed = CAMERAMOVESPEED;
|
||||
|
||||
|
||||
if (imgui_io.KeyShift)
|
||||
{
|
||||
movespeed *= 3.0; //Speed up camera.
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "sdl2.h"
|
||||
#include "Wayland/wiWaylandBackend.h"
|
||||
#include "Wayland/wiWaylandWindow.h"
|
||||
#include <wiPlatform.h>
|
||||
|
||||
int sdl_loop(Tests &tests)
|
||||
{
|
||||
@@ -61,7 +64,7 @@ int sdl_loop(Tests &tests)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
int main_sdl2(int argc, char *argv[])
|
||||
{
|
||||
Tests tests;
|
||||
// TODO: Place code here.
|
||||
@@ -89,3 +92,45 @@ int main(int argc, char *argv[])
|
||||
SDL_Quit();
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void wayland_loop(wi::wayland::Backend &wwbackend, Tests &tests)
|
||||
{
|
||||
bool quit = false;
|
||||
wwbackend.window.on_close = [&quit](wi::wayland::Window*w) { quit = false; };
|
||||
|
||||
while(!quit)
|
||||
{
|
||||
tests.Run();
|
||||
if (wwbackend.dispatch() < 0)
|
||||
break;
|
||||
if (wwbackend.window.AcceptDesiredDimensions())
|
||||
tests.SetWindow(&wwbackend.window);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool main_wayland(int argc, char *argv[])
|
||||
{
|
||||
wi::wayland::Backend wwbackend;
|
||||
if (!wwbackend.Init())
|
||||
return false;
|
||||
if (!wwbackend.CreateWindow("Wicked Engine Tests"))
|
||||
return false;
|
||||
|
||||
Tests tests;
|
||||
tests.SetWindow(&wwbackend.window);
|
||||
wayland_loop(wwbackend, tests);
|
||||
|
||||
wwbackend.window.Deinit();
|
||||
wwbackend.DeInit();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
// Attempt to initialize wayland backend
|
||||
if (!main_wayland(argc, argv))
|
||||
main_sdl2(argc, argv);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
[Buildset]
|
||||
BuildItems=@Variant(\x00\x00\x00\t\x00\x00\x00\x00\x01\x00\x00\x00\x0b\x00\x00\x00\x00\x01\x00\x00\x00\x18\x00W\x00i\x00c\x00k\x00e\x00d\x00E\x00n\x00g\x00i\x00n\x00e)
|
||||
|
||||
[CMake]
|
||||
Build Directory Count=1
|
||||
Current Build Directory Index-Host System=0
|
||||
|
||||
[CMake][CMake Build Directory 0]
|
||||
Build Directory Path=/home/matteo/projects/WickedEngine/WickedEngine/cmake-build-debug
|
||||
Build Type=Debug
|
||||
CMake Binary=/usr/bin/cmake
|
||||
CMake Executable=/usr/bin/cmake
|
||||
Environment Profile=
|
||||
Extra Arguments=
|
||||
Install Directory=/usr/local
|
||||
Runtime=Host System
|
||||
|
||||
[Project]
|
||||
VersionControlSupport=kdevgit
|
||||
@@ -47,6 +47,54 @@ else ()
|
||||
if((${SDL_VERSION_MAJOR} GREATER_EQUAL 2) AND (${SDL2_VERSION_MINOR} GREATER_EQUAL 0) AND (${SDL2_VERSION_PATCH} GREATER_EQUAL 14))
|
||||
add_compile_definitions(SDL2_FEATURE_CONTROLLER_LED=1)
|
||||
endif()
|
||||
|
||||
if (WAYLAND_BACKEND)
|
||||
|
||||
find_package(PkgConfig REQUIRED)
|
||||
pkg_check_modules(WAYLAND_CLIENT REQUIRED wayland-client)
|
||||
pkg_check_modules(WAYLAND_SCANNER REQUIRED wayland-scanner)
|
||||
pkg_check_modules(WAYLAND_PROTOCOLS REQUIRED wayland-protocols)
|
||||
# Get variables
|
||||
pkg_get_variable(WAYLAND_SCANNER_BIN wayland-scanner wayland_scanner)
|
||||
pkg_get_variable(WAYLAND_PROTOCOLS_DATADIR wayland-protocols pkgdatadir)
|
||||
################################################################################################################
|
||||
# Wayland protocol generated code
|
||||
function(GENERATE_XDG_PROTOCOLS)
|
||||
# GENERATE XDG PROTOCOLS SOURCES
|
||||
set(XDG_PROTOCOLS_SOURCES)
|
||||
set(XDG_PROTOCOLS_HEADERS)
|
||||
foreach(XML ${ARGN})
|
||||
get_filename_component(XML_NAME "${XML}" NAME_WE)
|
||||
MESSAGE("Generating C source code for ${XML} -> ${XML_NAME}")
|
||||
add_custom_command(COMMAND ${WAYLAND_SCANNER_BIN}
|
||||
ARGS private-code "${XML}" "${CMAKE_CURRENT_BINARY_DIR}/${XML_NAME}.c"
|
||||
DEPENDS "${XML}"
|
||||
OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${XML_NAME}.c"
|
||||
COMMENT "Generating \"${XML_NAME}\" protocol private code."
|
||||
)
|
||||
list(APPEND XDG_PROTOCOLS_SOURCES "${CMAKE_CURRENT_BINARY_DIR}/${XML_NAME}.c")
|
||||
|
||||
add_custom_command(COMMAND ${WAYLAND_SCANNER_BIN}
|
||||
ARGS client-header "${XML}" "${CMAKE_CURRENT_BINARY_DIR}/${XML_NAME}.h"
|
||||
DEPENDS "${XML}"
|
||||
OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${XML_NAME}.h"
|
||||
COMMENT "Generating \"${XML_NAME}\" protocol header."
|
||||
)
|
||||
list(APPEND XDG_PROTOCOLS_HEADERS "${CMAKE_CURRENT_BINARY_DIR}/${XML_NAME}.h")
|
||||
set(XDG_PROTOCOLS_SOURCES ${XDG_PROTOCOLS_SOURCES} PARENT_SCOPE)
|
||||
set(XDG_PROTOCOLS_HEADERS ${XDG_PROTOCOLS_HEADERS} PARENT_SCOPE)
|
||||
endforeach()
|
||||
endfunction()
|
||||
|
||||
GENERATE_XDG_PROTOCOLS(
|
||||
"${WAYLAND_PROTOCOLS_DATADIR}/stable/xdg-shell/xdg-shell.xml"
|
||||
"${WAYLAND_PROTOCOLS_DATADIR}/unstable/xdg-decoration/xdg-decoration-unstable-v1.xml"
|
||||
)
|
||||
file(GLOB WAYLAND_SOURCES CONFIGURE_DEPENDS Wayland/*.cpp)
|
||||
file(GLOB WAYLAND_HEADERS CONFIGURE_DEPENDS Wayland/*.h)
|
||||
set(WAYLAND_SOURCES ${WAYLAND_SOURCES} ${XDG_PROTOCOLS_SOURCES})
|
||||
set(WAYLAND_HEADERS ${WAYLAND_HEADERS} ${XDG_PROTOCOLS_HEADERS})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
add_subdirectory(LUA)
|
||||
@@ -64,6 +112,8 @@ list(REMOVE_ITEM SOURCE_FILES offlineshadercompiler.cpp)
|
||||
add_library(${TARGET_NAME} ${WICKED_LIBRARY_TYPE}
|
||||
${SOURCE_FILES}
|
||||
${HEADER_FILES}
|
||||
${WAYLAND_SOURCES}
|
||||
${WAYLAND_HEADERS}
|
||||
)
|
||||
|
||||
if(MSVC)
|
||||
@@ -71,7 +121,7 @@ if(MSVC)
|
||||
endif()
|
||||
|
||||
add_library(WickedEngine ALIAS ${TARGET_NAME})
|
||||
set_target_properties(${TARGET_NAME} PROPERTIES PUBLIC_HEADER "${HEADER_FILES}")
|
||||
set_target_properties(${TARGET_NAME} PROPERTIES PUBLIC_HEADER "${HEADER_FILES} ${WAYLAND_HEADERS}")
|
||||
|
||||
target_include_directories(${TARGET_NAME} SYSTEM PUBLIC
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
|
||||
@@ -106,12 +156,15 @@ else ()
|
||||
|
||||
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
||||
target_compile_options(${TARGET_NAME} PRIVATE
|
||||
# C and C++ warnings
|
||||
-Wuninitialized
|
||||
#-Wwrite-strings
|
||||
#-Winit-self
|
||||
#-Wreturn-type
|
||||
#-Wreorder
|
||||
#-Werror=delete-non-virtual-dtor
|
||||
# C++ only warnings
|
||||
#$<$<COMPILE_LANGUAGE:CXX>:-Wreorder>
|
||||
#$<$<COMPILE_LANGUAGE:CXX>:-Werror=delete-non-virtual-dtor>
|
||||
# Treat warnings as errors
|
||||
#-Werror
|
||||
#uncomment this to stop the compilation at the first error
|
||||
# -Wfatal-errors
|
||||
@@ -120,19 +173,37 @@ else ()
|
||||
# add some warnings and set them as errors
|
||||
# read more details here: https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html
|
||||
target_compile_options(${TARGET_NAME} PRIVATE
|
||||
# C and C++ warnings
|
||||
-Wuninitialized
|
||||
-Wmaybe-uninitialized
|
||||
-Wwrite-strings
|
||||
-Winit-self
|
||||
-Wreturn-type
|
||||
-Wreorder
|
||||
-Werror=delete-non-virtual-dtor
|
||||
# C++ only warnings
|
||||
$<$<COMPILE_LANGUAGE:CXX>:-Wreorder>
|
||||
$<$<COMPILE_LANGUAGE:CXX>:-Werror=delete-non-virtual-dtor>
|
||||
# Treat warnings as errors
|
||||
-Werror
|
||||
#uncomment this to stop the compilation at the first error
|
||||
# -Wfatal-errors
|
||||
)
|
||||
endif()
|
||||
|
||||
|
||||
if (WAYLAND_BACKEND)
|
||||
target_include_directories(${TARGET_NAME}
|
||||
PUBLIC ${WAYLAND_CLIENT_INCLUDE_DIRS}
|
||||
# PRIVATE ${WAYLAND_CURSOR_INCLUDE_DIRS}
|
||||
PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>
|
||||
# PUBLIC $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/WickedEngine>
|
||||
)
|
||||
|
||||
target_link_libraries(${TARGET_NAME}
|
||||
PUBLIC ${WAYLAND_CLIENT_LIBRARIES}
|
||||
# PRIVATE ${WAYLAND_CURSOR_LIBRARIES}
|
||||
)
|
||||
endif()
|
||||
|
||||
target_link_libraries(${TARGET_NAME} PRIVATE dl)
|
||||
|
||||
set(LIBDXCOMPILER "libdxcompiler.so")
|
||||
|
||||
@@ -0,0 +1,141 @@
|
||||
#include "wiWaylandBackend.h"
|
||||
#include "wiWaylandUtils.h"
|
||||
#include <wayland/wayland-client-core.h>
|
||||
#include <wayland/wayland-client-protocol.h>
|
||||
#include <wayland/wayland-client.h>
|
||||
#include <iostream>
|
||||
|
||||
#include "xdg-shell.h"
|
||||
#include "xdg-decoration-unstable-v1.h"
|
||||
|
||||
|
||||
using namespace wi::wayland;
|
||||
|
||||
/// functions callbacks - START
|
||||
extern "C" void registry_global(void *data, wl_registry *raw_registry, uint32_t id, const char* interface, uint32_t version)
|
||||
{
|
||||
Backend *backend = static_cast<Backend*>(data);
|
||||
backend->registry_event_add(id, interface, version);
|
||||
}
|
||||
|
||||
extern "C" void registry_global_remove(void *data, wl_registry *raw_registry, uint32_t id)
|
||||
{
|
||||
Backend *backend = static_cast<Backend*>(data);
|
||||
backend->registry_event_remove(id);
|
||||
}
|
||||
|
||||
extern "C" void window_manager_pong(void *data, struct xdg_wm_base *xdg_wm_base, uint32_t serial)
|
||||
{
|
||||
Backend *backend = static_cast<Backend*>(data);
|
||||
backend->window_manager_pong(serial);
|
||||
}
|
||||
|
||||
/// functions callbacks - END
|
||||
|
||||
bool Backend::Init()
|
||||
{
|
||||
const char* name = nullptr;
|
||||
display = wl_display_connect(name);
|
||||
if (display == nullptr) {std::cerr<<"wl_display_connect failed"<<std::endl; return false;}
|
||||
registry = wl_display_get_registry(display);
|
||||
if (registry == nullptr) {std::cerr<<"wl_display_get_registry failed"<<std::endl; return false;}
|
||||
if (!init_registry()) {std::cerr<<"init registry failed"<<std::endl; return false;}
|
||||
|
||||
if (!bind_compositor()) {std::cerr<<"bind compositor failed"<<std::endl; return false;}
|
||||
if (!registry_has("xdg_wm_base")) {std::cerr<<"XDG WM BASE not found"<<std::endl; return false;}
|
||||
if (!bind_xdg_wm_base()) {std::cerr<<"bind xdg_wm_base failed"<<std::endl; return false;}
|
||||
if (!init_window_manager()) {std::cerr<<"xdg_wm_base init failed"<<std::endl; return false;}
|
||||
if (!bind_decoration_manager()) {std::cerr<<"bind decoration_manager failed"<<std::endl;} //optional, being "unstable" API
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Backend::init_registry()
|
||||
{
|
||||
registry_listener.global = &::registry_global;
|
||||
registry_listener.global_remove = &::registry_global_remove;
|
||||
wl_registry_add_listener(registry, &this->registry_listener, this);
|
||||
|
||||
dispatch();
|
||||
roundtrip();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Backend::registry_has(const char* interface_name) const
|
||||
{
|
||||
return registry_map.find(interface_name) != registry_map.end();
|
||||
}
|
||||
|
||||
bool Backend::bind_compositor()
|
||||
{
|
||||
compositor = bind<wl_compositor>("wl_compositor", &wl_compositor_interface);
|
||||
return compositor != nullptr;
|
||||
}
|
||||
|
||||
bool Backend::bind_xdg_wm_base()
|
||||
{
|
||||
window_manager = this->bind<xdg_wm_base>("xdg_wm_base", &xdg_wm_base_interface);
|
||||
return window_manager != nullptr;
|
||||
}
|
||||
|
||||
bool Backend::bind_decoration_manager()
|
||||
{
|
||||
decoration_manager = this->bind<zxdg_decoration_manager_v1>(
|
||||
"zxdg_decoration_manager_v1", &zxdg_decoration_manager_v1_interface);
|
||||
return window_manager != nullptr;
|
||||
}
|
||||
|
||||
bool Backend::init_window_manager()
|
||||
{
|
||||
window_manager_listener.ping = &::window_manager_pong;
|
||||
xdg_wm_base_add_listener(window_manager, &window_manager_listener, this);
|
||||
return true;
|
||||
}
|
||||
|
||||
void Backend::DeInit()
|
||||
{
|
||||
safe_delete(decoration_manager, zxdg_decoration_manager_v1_destroy);
|
||||
safe_delete(window_manager, xdg_wm_base_destroy);
|
||||
safe_delete(compositor, wl_compositor_destroy);
|
||||
// registry needs to be killed before, otherwhise the application will crash
|
||||
safe_delete(registry, wl_registry_destroy);
|
||||
safe_delete(display, wl_display_disconnect);
|
||||
}
|
||||
|
||||
bool Backend::CreateWindow(const char* title)
|
||||
{
|
||||
return window.Init(this, title);
|
||||
}
|
||||
|
||||
int Backend::dispatch()
|
||||
{
|
||||
return wl_display_dispatch(display);
|
||||
}
|
||||
|
||||
int Backend::roundtrip()
|
||||
{
|
||||
return wl_display_roundtrip(display);
|
||||
}
|
||||
|
||||
void Backend::registry_event_add(uint32_t id, const char* interface, uint32_t version)
|
||||
{
|
||||
std::cout << "Registry has " << interface << std::endl;
|
||||
registry_map[interface] = std::make_pair(id, version);
|
||||
}
|
||||
|
||||
void Backend::registry_event_remove(uint32_t id)
|
||||
{
|
||||
for (auto it = registry_map.begin(); it != registry_map.end(); ++it) {
|
||||
if (it->second.first == id) {
|
||||
registry_map.erase(it);
|
||||
return;
|
||||
}
|
||||
}
|
||||
std::clog << "Registry removal failed, not found: " << id << std::endl;
|
||||
}
|
||||
|
||||
void Backend::window_manager_pong(uint32_t serial)
|
||||
{
|
||||
xdg_wm_base_pong(window_manager, serial);
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
#pragma once
|
||||
#include "wiWaylandWindow.h"
|
||||
#include <wayland/wayland-client.h>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
|
||||
#include "xdg-decoration-unstable-v1.h"
|
||||
#include "xdg-shell.h"
|
||||
|
||||
extern "C" {
|
||||
struct xdg_wm_base;
|
||||
struct zxdg_decoration_manager_v1;
|
||||
}
|
||||
|
||||
namespace wi::wayland {
|
||||
|
||||
class Window;
|
||||
|
||||
class Backend {
|
||||
private:
|
||||
wl_display* display = nullptr;
|
||||
wl_registry* registry = nullptr;
|
||||
wl_registry_listener registry_listener;
|
||||
// interface name -> id, version
|
||||
std::map<std::string, std::pair<uint32_t, uint32_t>> registry_map;
|
||||
|
||||
wl_compositor* compositor = nullptr;
|
||||
xdg_wm_base* window_manager = nullptr;
|
||||
xdg_wm_base_listener window_manager_listener;
|
||||
zxdg_decoration_manager_v1 *decoration_manager = nullptr;
|
||||
|
||||
public:
|
||||
Window window;
|
||||
|
||||
public:
|
||||
Backend() = default;
|
||||
bool Init();
|
||||
~Backend() { DeInit(); }
|
||||
void DeInit();
|
||||
|
||||
bool CreateWindow(const char* title);
|
||||
|
||||
int dispatch();
|
||||
int roundtrip();
|
||||
|
||||
// callbacks
|
||||
void registry_event_add(uint32_t id, const char* interface, uint32_t version);
|
||||
void registry_event_remove(uint32_t id);
|
||||
void window_manager_pong(uint32_t serial);
|
||||
|
||||
private:
|
||||
bool init_registry();
|
||||
bool registry_has(const char* interface_name) const;
|
||||
|
||||
template<typename T>
|
||||
T* bind(const char* interface_name, const struct wl_interface *interface, uint32_t version = -1)
|
||||
{
|
||||
std::pair<uint32_t, uint32_t> reg = registry_map.at(interface_name);
|
||||
if (version < 0) {
|
||||
version = reg.second;
|
||||
} else {
|
||||
version = 1;
|
||||
}
|
||||
void* r = wl_registry_bind(registry, reg.first, interface, version);
|
||||
if (r == nullptr) {
|
||||
std::clog<< "ERROR loading interface \"" << interface_name << '"' << std::endl;
|
||||
}
|
||||
return static_cast<T*>(r);
|
||||
}
|
||||
bool bind_compositor();
|
||||
bool bind_xdg_wm_base();
|
||||
bool bind_decoration_manager();
|
||||
|
||||
bool init_window_manager();
|
||||
|
||||
friend class Window;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
namespace wi::wayland {
|
||||
|
||||
template<typename T>
|
||||
void safe_delete(T*& ptr, void(&deleter)(T*))
|
||||
{
|
||||
if (ptr != nullptr)
|
||||
{
|
||||
deleter(ptr);
|
||||
ptr = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,215 @@
|
||||
#include "wiWaylandWindow.h"
|
||||
#include "wiWaylandBackend.h"
|
||||
#include "wayland-client-protocol.h"
|
||||
#include "wiWaylandUtils.h"
|
||||
#include "xdg-decoration-unstable-v1.h"
|
||||
#include "xdg-shell.h"
|
||||
#include <iostream>
|
||||
|
||||
#define VK_NO_PROTOTYPES
|
||||
#include "Utility/vulkan/vulkan.h"
|
||||
#include "Utility/vulkan/vulkan_wayland.h"
|
||||
#include "Utility/volk.h"
|
||||
|
||||
using namespace wi::wayland;
|
||||
|
||||
extern "C" void _static_on_redraw(void *data,
|
||||
wl_callback *wl_callback,
|
||||
uint32_t time)
|
||||
{
|
||||
static_cast<Window*>(data)->on_redraw(wl_callback, time);
|
||||
}
|
||||
|
||||
extern "C" void _static_on_enter(void *data,
|
||||
wl_surface *wl_surface,
|
||||
wl_output *output)
|
||||
{
|
||||
static_cast<Window*>(data)->on_enter(output);
|
||||
}
|
||||
|
||||
extern "C" void _static_on_leave(void *data,
|
||||
wl_surface *wl_surface,
|
||||
wl_output *output)
|
||||
{
|
||||
static_cast<Window*>(data)->on_leave(output);
|
||||
}
|
||||
|
||||
extern "C" void _static_xdg_surface_configure(void* data, xdg_surface* raw, uint32_t serial)
|
||||
{
|
||||
static_cast<Window*>(data)->on_xdg_surface_ack_configure(serial);
|
||||
}
|
||||
|
||||
extern "C" void _static_toplevel_close(void *data, xdg_toplevel *xdg_toplevel)
|
||||
{
|
||||
static_cast<Window*>(data)->on_toplevel_close();
|
||||
}
|
||||
|
||||
extern "C" void _static_toplevel_configure(void *data,
|
||||
xdg_toplevel *xdg_toplevel,
|
||||
int32_t width,
|
||||
int32_t height,
|
||||
wl_array *states)
|
||||
{
|
||||
static_cast<Window*>(data)->on_toplevel_configure(width, height, states);
|
||||
}
|
||||
|
||||
extern "C" void _static_toplevel_configure_bounds(void *data,
|
||||
xdg_toplevel *xdg_toplevel,
|
||||
int32_t width,
|
||||
int32_t height)
|
||||
{
|
||||
static_cast<Window*>(data)->on_toplevel_configure_bounds(width, height);
|
||||
}
|
||||
|
||||
void Window::on_enter(wl_output *output)
|
||||
{}
|
||||
|
||||
void Window::on_leave(wl_output *output)
|
||||
{}
|
||||
|
||||
void Window::on_redraw(wl_callback *wl_callback, uint32_t time)
|
||||
{
|
||||
if(frame_callback != nullptr) {
|
||||
wl_callback_destroy(frame_callback);
|
||||
frame_callback = nullptr;
|
||||
}
|
||||
if (on_redraw_callback)
|
||||
on_redraw_callback(this);
|
||||
}
|
||||
|
||||
void Window::on_xdg_surface_ack_configure(uint32_t serial)
|
||||
{
|
||||
xdg_surface_ack_configure(XDGsurface, serial);
|
||||
}
|
||||
|
||||
void Window::on_toplevel_close()
|
||||
{
|
||||
if (on_close) on_close(this);
|
||||
}
|
||||
|
||||
void Window::on_toplevel_configure(int32_t width, int32_t height, wl_array* states)
|
||||
{
|
||||
desired_width = width;
|
||||
desired_height = height;
|
||||
}
|
||||
|
||||
void Window::on_toplevel_configure_bounds(int32_t width, int32_t height)
|
||||
{}
|
||||
|
||||
|
||||
bool Window::Init(Backend* backend, const char* title)
|
||||
{
|
||||
this->backend = backend;
|
||||
|
||||
// Surface
|
||||
WLsurface = wl_compositor_create_surface(backend->compositor);
|
||||
if (WLsurface == nullptr) {std::cerr << "Could not create surface from compositor" << std::endl; return false;}
|
||||
WLsurface_listener.enter = &_static_on_enter;
|
||||
WLsurface_listener.leave = &_static_on_leave;
|
||||
frame_listener.done = &_static_on_redraw;
|
||||
wl_surface_add_listener(WLsurface, &WLsurface_listener, this);
|
||||
|
||||
// XDG Surface
|
||||
XDGsurface = xdg_wm_base_get_xdg_surface(backend->window_manager, WLsurface);
|
||||
if (XDGsurface == nullptr) {std::cerr << "Could not create XDG surface from WL surface" << std::endl; return false;}
|
||||
XDGsurface_listener.configure = &_static_xdg_surface_configure;
|
||||
xdg_surface_add_listener(XDGsurface, &XDGsurface_listener, this);
|
||||
|
||||
// Top Level
|
||||
toplevel = xdg_surface_get_toplevel(XDGsurface);
|
||||
if (toplevel == nullptr) {std::cerr << "Could not create XDG surface from WL surface" << std::endl; return false;}
|
||||
toplevel_listener.close = &_static_toplevel_close;
|
||||
toplevel_listener.configure = &_static_toplevel_configure;
|
||||
toplevel_listener.configure_bounds = &_static_toplevel_configure_bounds;
|
||||
xdg_toplevel_add_listener(toplevel, &toplevel_listener, this);
|
||||
|
||||
// DecorationManager
|
||||
toplevel_decoration = zxdg_decoration_manager_v1_get_toplevel_decoration(backend->decoration_manager, toplevel);
|
||||
if (toplevel_decoration != nullptr)
|
||||
{
|
||||
zxdg_toplevel_decoration_v1_set_mode(toplevel_decoration, ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE);
|
||||
}
|
||||
|
||||
SetTitle(title);
|
||||
return true;
|
||||
}
|
||||
|
||||
void Window::Deinit()
|
||||
{
|
||||
safe_delete(frame_callback, wl_callback_destroy);
|
||||
safe_delete(toplevel_decoration, zxdg_toplevel_decoration_v1_destroy);
|
||||
safe_delete(toplevel, xdg_toplevel_destroy);
|
||||
safe_delete(XDGsurface, xdg_surface_destroy);
|
||||
safe_delete(WLsurface, wl_surface_destroy);
|
||||
}
|
||||
|
||||
void Window::SetTitle(const char* title)
|
||||
{
|
||||
if (title == nullptr)
|
||||
return;
|
||||
if (toplevel == nullptr)
|
||||
return;
|
||||
xdg_toplevel_set_title(toplevel, title);
|
||||
}
|
||||
|
||||
void Window::GetWindowCurrentSize(int32_t *width, int32_t *height)
|
||||
{
|
||||
*width = current_width;
|
||||
*height = current_height;
|
||||
}
|
||||
|
||||
bool Window::HasPendingResize() const
|
||||
{
|
||||
return desired_height > 0 || desired_height > 0;
|
||||
}
|
||||
|
||||
bool Window::AcceptDesiredDimensions()
|
||||
{
|
||||
const bool has_pending_resize = HasPendingResize();
|
||||
if (desired_width > 0)
|
||||
{
|
||||
current_width = desired_width;
|
||||
desired_width = 0;
|
||||
}
|
||||
if (desired_height > 0)
|
||||
{
|
||||
current_height = desired_height;
|
||||
desired_height = 0;
|
||||
}
|
||||
return has_pending_resize;
|
||||
}
|
||||
|
||||
void Window::SetFullscreen(bool fullscreen)
|
||||
{
|
||||
if (fullscreen)
|
||||
{
|
||||
// wl_output output;
|
||||
// xdg_toplevel_set_fullscreen(toplevel, &output);
|
||||
}
|
||||
else
|
||||
{
|
||||
xdg_toplevel_unset_fullscreen(toplevel);
|
||||
}
|
||||
}
|
||||
|
||||
VkResult Window::CreateVulkanSurface(VkInstance instance, VkSurfaceKHR* VKsurface)
|
||||
{
|
||||
PFN_vkCreateWaylandSurfaceKHR vkCreateWaylandSurfaceKHR =
|
||||
(PFN_vkCreateWaylandSurfaceKHR)vkGetInstanceProcAddr(
|
||||
instance,
|
||||
"vkCreateWaylandSurfaceKHR");
|
||||
|
||||
VkWaylandSurfaceCreateInfoKHR createInfo {};
|
||||
createInfo.sType = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR;
|
||||
createInfo.pNext = nullptr;
|
||||
createInfo.flags = 0;
|
||||
createInfo.display = backend->display;
|
||||
createInfo.surface = WLsurface;
|
||||
|
||||
const VkAllocationCallbacks* allocator = nullptr;
|
||||
|
||||
VkResult res = vkCreateWaylandSurfaceKHR(instance, &createInfo, allocator, VKsurface);
|
||||
|
||||
backend->roundtrip();
|
||||
return res;
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
#pragma once
|
||||
#include "wayland-client-core.h"
|
||||
#include "wayland-client-protocol.h"
|
||||
#include "xdg-decoration-unstable-v1.h"
|
||||
#include "xdg-shell.h"
|
||||
#include <functional>
|
||||
|
||||
#define VK_NO_PROTOTYPES
|
||||
#include "Utility/vulkan/vulkan.h"
|
||||
// #include "Utility/volk.h"
|
||||
|
||||
extern "C" {
|
||||
struct xdg_wm_base;
|
||||
struct zxdg_decoration_manager_v1;
|
||||
}
|
||||
|
||||
namespace wi::wayland {
|
||||
|
||||
class Backend;
|
||||
|
||||
class Window {
|
||||
private:
|
||||
// reference variables
|
||||
Backend* backend = nullptr;
|
||||
|
||||
// OWN variables
|
||||
wl_surface *WLsurface = nullptr;
|
||||
xdg_surface *XDGsurface = nullptr;
|
||||
xdg_toplevel *toplevel = nullptr;
|
||||
zxdg_toplevel_decoration_v1* toplevel_decoration = nullptr;
|
||||
|
||||
wl_callback* frame_callback = nullptr;
|
||||
wl_surface_listener WLsurface_listener;
|
||||
wl_callback_listener frame_listener;
|
||||
xdg_surface_listener XDGsurface_listener;
|
||||
xdg_toplevel_listener toplevel_listener;
|
||||
|
||||
int32_t current_width = 800;
|
||||
int32_t current_height = 600;
|
||||
int32_t desired_width = 0;
|
||||
int32_t desired_height = 0;
|
||||
|
||||
public:
|
||||
std::function<void(Window* window)> on_redraw_callback;
|
||||
std::function<void(Window* window)> on_close;
|
||||
|
||||
public:
|
||||
~Window() { Deinit(); }
|
||||
void Deinit();
|
||||
|
||||
Window() = default;
|
||||
bool Init(Backend* backend, const char* title = nullptr);
|
||||
void SetTitle(const char* title);
|
||||
void GetWindowCurrentSize(int32_t* width, int32_t* height);
|
||||
bool HasPendingResize() const;
|
||||
bool AcceptDesiredDimensions();
|
||||
void SetFullscreen(bool fullscreen);
|
||||
|
||||
VkResult CreateVulkanSurface(VkInstance instance, VkSurfaceKHR* VKSurface);
|
||||
|
||||
// callbacks
|
||||
void on_enter(wl_output *output);
|
||||
void on_leave(wl_output *output);
|
||||
void on_redraw(wl_callback *wl_callback, uint32_t time);
|
||||
void on_xdg_surface_ack_configure(uint32_t serial);
|
||||
void on_toplevel_close();
|
||||
void on_toplevel_configure(int32_t width, int32_t height, wl_array *states);
|
||||
void on_toplevel_configure_bounds(int32_t width, int32_t height);
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
#include <wiECS.h>
|
||||
module;
|
||||
|
||||
#include "WickedEngine.h"
|
||||
|
||||
export module wicked_engine;
|
||||
|
||||
export namespace wi
|
||||
{
|
||||
using wi::Application;
|
||||
using wi::GPUBVH;
|
||||
using wi::EmittedParticleSystem;
|
||||
using wi::HairParticleSystem;
|
||||
using wi::Ocean;
|
||||
using wi::Sprite;
|
||||
using wi::SpriteFont;
|
||||
using wi::Archive;
|
||||
using wi::Color;
|
||||
using wi::FadeManager;
|
||||
using wi::Resource;
|
||||
using wi::SpinLock;
|
||||
using wi::Timer;
|
||||
using wi::Canvas;
|
||||
|
||||
namespace ecs
|
||||
{
|
||||
using wi::ecs::Entity;
|
||||
using wi::ecs::INVALID_ENTITY;
|
||||
}
|
||||
|
||||
namespace gui
|
||||
{
|
||||
using wi::gui::GUI;
|
||||
using wi::gui::EventArgs;
|
||||
using wi::gui::Widget;
|
||||
using wi::gui::Button;
|
||||
using wi::gui::Label;
|
||||
using wi::gui::TextInputField;
|
||||
using wi::gui::Slider;
|
||||
using wi::gui::CheckBox;
|
||||
using wi::gui::ComboBox;
|
||||
using wi::gui::Window;
|
||||
using wi::gui::ColorPicker;
|
||||
using wi::gui::TreeList;
|
||||
}
|
||||
|
||||
namespace primitive
|
||||
{
|
||||
using wi::primitive::AABB;
|
||||
using wi::primitive::Sphere;
|
||||
using wi::primitive::Capsule;
|
||||
using wi::primitive::Ray;
|
||||
using wi::primitive::Frustum;
|
||||
using wi::primitive::Hitbox2D;
|
||||
}
|
||||
|
||||
namespace font
|
||||
{
|
||||
using wi::font::Params;
|
||||
using wi::font::Alignment;
|
||||
}
|
||||
|
||||
namespace image
|
||||
{
|
||||
using wi::image::Params;
|
||||
using wi::image::STENCILMODE;
|
||||
using wi::image::STENCILREFMODE;
|
||||
using wi::image::SAMPLEMODE;
|
||||
using wi::image::QUALITY;
|
||||
}
|
||||
|
||||
namespace eventhandler
|
||||
{
|
||||
using wi::eventhandler::EVENT_THREAD_SAFE_POINT;
|
||||
using wi::eventhandler::EVENT_RELOAD_SHADERS;
|
||||
using wi::eventhandler::EVENT_SET_VSYNC;
|
||||
}
|
||||
|
||||
namespace math
|
||||
{
|
||||
using wi::math::IDENTITY_MATRIX;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
[Project]
|
||||
CreatedFrom=CMakeLists.txt
|
||||
Manager=KDevCMakeManager
|
||||
Name=WickedEngine
|
||||
@@ -0,0 +1,365 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2017-2019, Feral Interactive
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of Feral Interactive nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
#ifndef CLIENT_GAMEMODE_H
|
||||
#define CLIENT_GAMEMODE_H
|
||||
/*
|
||||
* GameMode supports the following client functions
|
||||
* Requests are refcounted in the daemon
|
||||
*
|
||||
* int gamemode_request_start() - Request gamemode starts
|
||||
* 0 if the request was sent successfully
|
||||
* -1 if the request failed
|
||||
*
|
||||
* int gamemode_request_end() - Request gamemode ends
|
||||
* 0 if the request was sent successfully
|
||||
* -1 if the request failed
|
||||
*
|
||||
* GAMEMODE_AUTO can be defined to make the above two functions apply during static init and
|
||||
* destruction, as appropriate. In this configuration, errors will be printed to stderr
|
||||
*
|
||||
* int gamemode_query_status() - Query the current status of gamemode
|
||||
* 0 if gamemode is inactive
|
||||
* 1 if gamemode is active
|
||||
* 2 if gamemode is active and this client is registered
|
||||
* -1 if the query failed
|
||||
*
|
||||
* int gamemode_request_start_for(pid_t pid) - Request gamemode starts for another process
|
||||
* 0 if the request was sent successfully
|
||||
* -1 if the request failed
|
||||
* -2 if the request was rejected
|
||||
*
|
||||
* int gamemode_request_end_for(pid_t pid) - Request gamemode ends for another process
|
||||
* 0 if the request was sent successfully
|
||||
* -1 if the request failed
|
||||
* -2 if the request was rejected
|
||||
*
|
||||
* int gamemode_query_status_for(pid_t pid) - Query status of gamemode for another process
|
||||
* 0 if gamemode is inactive
|
||||
* 1 if gamemode is active
|
||||
* 2 if gamemode is active and this client is registered
|
||||
* -1 if the query failed
|
||||
*
|
||||
* const char* gamemode_error_string() - Get an error string
|
||||
* returns a string describing any of the above errors
|
||||
*
|
||||
* Note: All the above requests can be blocking - dbus requests can and will block while the daemon
|
||||
* handles the request. It is not recommended to make these calls in performance critical code
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
static char internal_gamemode_client_error_string[512] = { 0 };
|
||||
|
||||
/**
|
||||
* Load libgamemode dynamically to dislodge us from most dependencies.
|
||||
* This allows clients to link and/or use this regardless of runtime.
|
||||
* See SDL3 for an example of the reasoning behind this in terms of
|
||||
* dynamic versioning as well.
|
||||
*/
|
||||
static volatile int internal_libgamemode_loaded = 1;
|
||||
|
||||
/* Typedefs for the functions to load */
|
||||
typedef int (*api_call_return_int)(void);
|
||||
typedef const char *(*api_call_return_cstring)(void);
|
||||
typedef int (*api_call_pid_return_int)(pid_t);
|
||||
|
||||
/* Storage for functors */
|
||||
static api_call_return_int REAL_internal_gamemode_request_start = NULL;
|
||||
static api_call_return_int REAL_internal_gamemode_request_end = NULL;
|
||||
static api_call_return_int REAL_internal_gamemode_query_status = NULL;
|
||||
static api_call_return_cstring REAL_internal_gamemode_error_string = NULL;
|
||||
static api_call_pid_return_int REAL_internal_gamemode_request_start_for = NULL;
|
||||
static api_call_pid_return_int REAL_internal_gamemode_request_end_for = NULL;
|
||||
static api_call_pid_return_int REAL_internal_gamemode_query_status_for = NULL;
|
||||
|
||||
/**
|
||||
* Internal helper to perform the symbol binding safely.
|
||||
*
|
||||
* Returns 0 on success and -1 on failure
|
||||
*/
|
||||
__attribute__((always_inline)) static inline int internal_bind_libgamemode_symbol(
|
||||
void *handle, const char *name, void **out_func, size_t func_size, bool required)
|
||||
{
|
||||
void *symbol_lookup = NULL;
|
||||
char *dl_error = NULL;
|
||||
|
||||
/* Safely look up the symbol */
|
||||
symbol_lookup = dlsym(handle, name);
|
||||
dl_error = dlerror();
|
||||
if (required && (dl_error || !symbol_lookup)) {
|
||||
snprintf(internal_gamemode_client_error_string,
|
||||
sizeof(internal_gamemode_client_error_string),
|
||||
"dlsym failed - %s",
|
||||
dl_error);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Have the symbol correctly, copy it to make it usable */
|
||||
memcpy(out_func, &symbol_lookup, func_size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads libgamemode and needed functions
|
||||
*
|
||||
* Returns 0 on success and -1 on failure
|
||||
*/
|
||||
__attribute__((always_inline)) static inline int internal_load_libgamemode(void)
|
||||
{
|
||||
/* We start at 1, 0 is a success and -1 is a fail */
|
||||
if (internal_libgamemode_loaded != 1) {
|
||||
return internal_libgamemode_loaded;
|
||||
}
|
||||
|
||||
/* Anonymous struct type to define our bindings */
|
||||
struct binding {
|
||||
const char *name;
|
||||
void **functor;
|
||||
size_t func_size;
|
||||
bool required;
|
||||
} bindings[] = {
|
||||
{ "real_gamemode_request_start",
|
||||
(void **)&REAL_internal_gamemode_request_start,
|
||||
sizeof(REAL_internal_gamemode_request_start),
|
||||
true },
|
||||
{ "real_gamemode_request_end",
|
||||
(void **)&REAL_internal_gamemode_request_end,
|
||||
sizeof(REAL_internal_gamemode_request_end),
|
||||
true },
|
||||
{ "real_gamemode_query_status",
|
||||
(void **)&REAL_internal_gamemode_query_status,
|
||||
sizeof(REAL_internal_gamemode_query_status),
|
||||
false },
|
||||
{ "real_gamemode_error_string",
|
||||
(void **)&REAL_internal_gamemode_error_string,
|
||||
sizeof(REAL_internal_gamemode_error_string),
|
||||
true },
|
||||
{ "real_gamemode_request_start_for",
|
||||
(void **)&REAL_internal_gamemode_request_start_for,
|
||||
sizeof(REAL_internal_gamemode_request_start_for),
|
||||
false },
|
||||
{ "real_gamemode_request_end_for",
|
||||
(void **)&REAL_internal_gamemode_request_end_for,
|
||||
sizeof(REAL_internal_gamemode_request_end_for),
|
||||
false },
|
||||
{ "real_gamemode_query_status_for",
|
||||
(void **)&REAL_internal_gamemode_query_status_for,
|
||||
sizeof(REAL_internal_gamemode_query_status_for),
|
||||
false },
|
||||
};
|
||||
|
||||
void *libgamemode = NULL;
|
||||
|
||||
/* Try and load libgamemode */
|
||||
libgamemode = dlopen("libgamemode.so.0", RTLD_NOW);
|
||||
if (!libgamemode) {
|
||||
/* Attempt to load unversioned library for compatibility with older
|
||||
* versions (as of writing, there are no ABI changes between the two -
|
||||
* this may need to change if ever ABI-breaking changes are made) */
|
||||
libgamemode = dlopen("libgamemode.so", RTLD_NOW);
|
||||
if (!libgamemode) {
|
||||
snprintf(internal_gamemode_client_error_string,
|
||||
sizeof(internal_gamemode_client_error_string),
|
||||
"dlopen failed - %s",
|
||||
dlerror());
|
||||
internal_libgamemode_loaded = -1;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Attempt to bind all symbols */
|
||||
for (size_t i = 0; i < sizeof(bindings) / sizeof(bindings[0]); i++) {
|
||||
struct binding *binder = &bindings[i];
|
||||
|
||||
if (internal_bind_libgamemode_symbol(libgamemode,
|
||||
binder->name,
|
||||
binder->functor,
|
||||
binder->func_size,
|
||||
binder->required)) {
|
||||
internal_libgamemode_loaded = -1;
|
||||
return -1;
|
||||
};
|
||||
}
|
||||
|
||||
/* Success */
|
||||
internal_libgamemode_loaded = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Redirect to the real libgamemode
|
||||
*/
|
||||
__attribute__((always_inline)) static inline const char *gamemode_error_string(void)
|
||||
{
|
||||
/* If we fail to load the system gamemode, or we have an error string already, return our error
|
||||
* string instead of diverting to the system version */
|
||||
if (internal_load_libgamemode() < 0 || internal_gamemode_client_error_string[0] != '\0') {
|
||||
return internal_gamemode_client_error_string;
|
||||
}
|
||||
|
||||
return REAL_internal_gamemode_error_string();
|
||||
}
|
||||
|
||||
/**
|
||||
* Redirect to the real libgamemode
|
||||
* Allow automatically requesting game mode
|
||||
* Also prints errors as they happen.
|
||||
*/
|
||||
#ifdef GAMEMODE_AUTO
|
||||
__attribute__((constructor))
|
||||
#else
|
||||
__attribute__((always_inline)) static inline
|
||||
#endif
|
||||
int gamemode_request_start(void)
|
||||
{
|
||||
/* Need to load gamemode */
|
||||
if (internal_load_libgamemode() < 0) {
|
||||
#ifdef GAMEMODE_AUTO
|
||||
fprintf(stderr, "gamemodeauto: %s\n", gamemode_error_string());
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (REAL_internal_gamemode_request_start() < 0) {
|
||||
#ifdef GAMEMODE_AUTO
|
||||
fprintf(stderr, "gamemodeauto: %s\n", gamemode_error_string());
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Redirect to the real libgamemode */
|
||||
#ifdef GAMEMODE_AUTO
|
||||
__attribute__((destructor))
|
||||
#else
|
||||
__attribute__((always_inline)) static inline
|
||||
#endif
|
||||
int gamemode_request_end(void)
|
||||
{
|
||||
/* Need to load gamemode */
|
||||
if (internal_load_libgamemode() < 0) {
|
||||
#ifdef GAMEMODE_AUTO
|
||||
fprintf(stderr, "gamemodeauto: %s\n", gamemode_error_string());
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (REAL_internal_gamemode_request_end() < 0) {
|
||||
#ifdef GAMEMODE_AUTO
|
||||
fprintf(stderr, "gamemodeauto: %s\n", gamemode_error_string());
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Redirect to the real libgamemode */
|
||||
__attribute__((always_inline)) static inline int gamemode_query_status(void)
|
||||
{
|
||||
/* Need to load gamemode */
|
||||
if (internal_load_libgamemode() < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (REAL_internal_gamemode_query_status == NULL) {
|
||||
snprintf(internal_gamemode_client_error_string,
|
||||
sizeof(internal_gamemode_client_error_string),
|
||||
"gamemode_query_status missing (older host?)");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return REAL_internal_gamemode_query_status();
|
||||
}
|
||||
|
||||
/* Redirect to the real libgamemode */
|
||||
__attribute__((always_inline)) static inline int gamemode_request_start_for(pid_t pid)
|
||||
{
|
||||
/* Need to load gamemode */
|
||||
if (internal_load_libgamemode() < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (REAL_internal_gamemode_request_start_for == NULL) {
|
||||
snprintf(internal_gamemode_client_error_string,
|
||||
sizeof(internal_gamemode_client_error_string),
|
||||
"gamemode_request_start_for missing (older host?)");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return REAL_internal_gamemode_request_start_for(pid);
|
||||
}
|
||||
|
||||
/* Redirect to the real libgamemode */
|
||||
__attribute__((always_inline)) static inline int gamemode_request_end_for(pid_t pid)
|
||||
{
|
||||
/* Need to load gamemode */
|
||||
if (internal_load_libgamemode() < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (REAL_internal_gamemode_request_end_for == NULL) {
|
||||
snprintf(internal_gamemode_client_error_string,
|
||||
sizeof(internal_gamemode_client_error_string),
|
||||
"gamemode_request_end_for missing (older host?)");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return REAL_internal_gamemode_request_end_for(pid);
|
||||
}
|
||||
|
||||
/* Redirect to the real libgamemode */
|
||||
__attribute__((always_inline)) static inline int gamemode_query_status_for(pid_t pid)
|
||||
{
|
||||
/* Need to load gamemode */
|
||||
if (internal_load_libgamemode() < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (REAL_internal_gamemode_query_status_for == NULL) {
|
||||
snprintf(internal_gamemode_client_error_string,
|
||||
sizeof(internal_gamemode_client_error_string),
|
||||
"gamemode_query_status_for missing (older host?)");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return REAL_internal_gamemode_query_status_for(pid);
|
||||
}
|
||||
|
||||
#endif // CLIENT_GAMEMODE_H
|
||||
@@ -743,7 +743,10 @@ namespace wi
|
||||
}
|
||||
|
||||
#elif defined(PLATFORM_LINUX)
|
||||
SDL_SetWindowFullscreen(window, fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
|
||||
if (window.type == platform::LinuxWindow::eSDLWindow)
|
||||
SDL_SetWindowFullscreen(window.sdl_window, fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
|
||||
else if (window.type == platform::LinuxWindow::eWaylandWindow)
|
||||
window.wl_window->SetFullscreen(fullscreen);
|
||||
#endif // PLATFORM_WINDOWS_DESKTOP
|
||||
}
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@ namespace wi
|
||||
bool allow_hdr = true;
|
||||
wi::graphics::SwapChain swapChain;
|
||||
wi::Canvas canvas;
|
||||
wi::platform::window_type window;
|
||||
wi::platform::window_type window = nullptr;
|
||||
|
||||
// Runs the main engine loop
|
||||
void Run();
|
||||
@@ -75,13 +75,13 @@ namespace wi
|
||||
|
||||
// This is where the critical initializations happen (before any rendering or anything else)
|
||||
virtual void Initialize();
|
||||
// This is where application-wide updates get executed once per frame.
|
||||
// This is where application-wide updates get executed once per frame.
|
||||
// RenderPath::Update is also called from here for the active component
|
||||
virtual void Update(float dt);
|
||||
// This is where application-wide updates get executed in a fixed timestep based manner.
|
||||
// This is where application-wide updates get executed in a fixed timestep based manner.
|
||||
// RenderPath::FixedUpdate is also called from here for the active component
|
||||
virtual void FixedUpdate();
|
||||
// This is where application-wide rendering happens to offscreen buffers.
|
||||
// This is where application-wide rendering happens to offscreen buffers.
|
||||
// RenderPath::Render is also called from here for the active component
|
||||
virtual void Render();
|
||||
// This is where the application will render to the screen (backbuffer). It must render to the provided command list.
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "wiGraphicsDevice_Vulkan.h"
|
||||
#include <wiPlatform.h>
|
||||
|
||||
#ifdef WICKEDENGINE_BUILD_VULKAN
|
||||
#include "wiHelper.h"
|
||||
@@ -23,6 +24,7 @@
|
||||
#ifdef SDL2
|
||||
#include <SDL2/SDL_vulkan.h>
|
||||
#include "sdl2.h"
|
||||
#include "Utility/vulkan/vulkan_wayland.h"
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
@@ -605,7 +607,7 @@ namespace vulkan_internal
|
||||
}
|
||||
|
||||
VKAPI_ATTR VkBool32 VKAPI_CALL debugUtilsMessengerCallback(
|
||||
VkDebugUtilsMessageSeverityFlagBitsEXT message_severity,
|
||||
VkDebugUtilsMessageSeverityFlagBitsEXT message_severity,
|
||||
VkDebugUtilsMessageTypeFlagsEXT message_type,
|
||||
const VkDebugUtilsMessengerCallbackDataEXT* callback_data,
|
||||
void* user_data)
|
||||
@@ -2442,18 +2444,25 @@ using namespace vulkan_internal;
|
||||
instanceExtensions.push_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
|
||||
#elif SDL2
|
||||
{
|
||||
uint32_t extensionCount;
|
||||
SDL_Vulkan_GetInstanceExtensions(window, &extensionCount, nullptr);
|
||||
wi::vector<const char *> extensionNames_sdl(extensionCount);
|
||||
SDL_Vulkan_GetInstanceExtensions(window, &extensionCount, extensionNames_sdl.data());
|
||||
instanceExtensions.reserve(instanceExtensions.size() + extensionNames_sdl.size());
|
||||
for (auto& x : extensionNames_sdl)
|
||||
if (window.type == platform::LinuxWindow::eSDLWindow)
|
||||
{
|
||||
instanceExtensions.push_back(x);
|
||||
uint32_t extensionCount;
|
||||
SDL_Vulkan_GetInstanceExtensions(window.sdl_window, &extensionCount, nullptr);
|
||||
wi::vector<const char *> extensionNames_sdl(extensionCount);
|
||||
SDL_Vulkan_GetInstanceExtensions(window.sdl_window, &extensionCount, extensionNames_sdl.data());
|
||||
instanceExtensions.reserve(instanceExtensions.size() + extensionNames_sdl.size());
|
||||
for (auto& x : extensionNames_sdl)
|
||||
{
|
||||
instanceExtensions.push_back(x);
|
||||
}
|
||||
}
|
||||
else if (window.type == platform::LinuxWindow::eWaylandWindow)
|
||||
{
|
||||
instanceExtensions.push_back(VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME);
|
||||
}
|
||||
}
|
||||
#endif // _WIN32
|
||||
|
||||
|
||||
if (validationMode != ValidationMode::Disabled)
|
||||
{
|
||||
// Determine the optimal validation layers to enable that are necessary for useful debugging
|
||||
@@ -2966,7 +2975,7 @@ using namespace vulkan_internal;
|
||||
queueFamiliesVideo[i].sType = VK_STRUCTURE_TYPE_QUEUE_FAMILY_VIDEO_PROPERTIES_KHR;
|
||||
}
|
||||
vkGetPhysicalDeviceQueueFamilyProperties2(physicalDevice, &queueFamilyCount, queueFamilies.data());
|
||||
|
||||
|
||||
// Query base queue families:
|
||||
for (uint32_t i = 0; i < queueFamilyCount; ++i)
|
||||
{
|
||||
@@ -3211,7 +3220,7 @@ using namespace vulkan_internal;
|
||||
|
||||
res = vmaCreateBuffer(allocationhandler->allocator, &bufferInfo, &allocInfo, &nullBuffer, &nullBufferAllocation, nullptr);
|
||||
assert(res == VK_SUCCESS);
|
||||
|
||||
|
||||
VkBufferViewCreateInfo viewInfo = {};
|
||||
viewInfo.sType = VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO;
|
||||
viewInfo.format = VK_FORMAT_R32G32B32A32_SFLOAT;
|
||||
@@ -3680,7 +3689,7 @@ using namespace vulkan_internal;
|
||||
res = vkGetPipelineCacheData(device, pipelineCache, &size, nullptr);
|
||||
assert(res == VK_SUCCESS);
|
||||
|
||||
// Get data of pipeline cache
|
||||
// Get data of pipeline cache
|
||||
wi::vector<uint8_t> data(size);
|
||||
res = vkGetPipelineCacheData(device, pipelineCache, &size, data.data());
|
||||
assert(res == VK_SUCCESS);
|
||||
@@ -3688,7 +3697,7 @@ using namespace vulkan_internal;
|
||||
// Write pipeline cache data to a file in binary format
|
||||
wi::helper::FileWrite(get_shader_cache_path(), data.data(), size);
|
||||
|
||||
// Destroy Vulkan pipeline cache
|
||||
// Destroy Vulkan pipeline cache
|
||||
vkDestroyPipelineCache(device, pipelineCache, nullptr);
|
||||
pipelineCache = VK_NULL_HANDLE;
|
||||
}
|
||||
@@ -3725,9 +3734,15 @@ using namespace vulkan_internal;
|
||||
res = vkCreateWin32SurfaceKHR(instance, &createInfo, nullptr, &internal_state->surface);
|
||||
assert(res == VK_SUCCESS);
|
||||
#elif SDL2
|
||||
if (!SDL_Vulkan_CreateSurface(window, instance, &internal_state->surface))
|
||||
if (window.type == platform::LinuxWindow::eSDLWindow) {
|
||||
if (!SDL_Vulkan_CreateSurface(window.sdl_window, instance, &internal_state->surface))
|
||||
{
|
||||
throw sdl2::SDLError("Error creating a vulkan surface");
|
||||
}
|
||||
}
|
||||
else if (window.type == platform::LinuxWindow::eWaylandWindow)
|
||||
{
|
||||
throw sdl2::SDLError("Error creating a vulkan surface");
|
||||
assert(window.wl_window->CreateVulkanSurface(instance, &internal_state->surface) == VK_SUCCESS);
|
||||
}
|
||||
#else
|
||||
#error WICKEDENGINE VULKAN DEVICE ERROR: PLATFORM NOT SUPPORTED
|
||||
@@ -4071,7 +4086,7 @@ using namespace vulkan_internal;
|
||||
dependencyInfo.pBufferMemoryBarriers = &barrier;
|
||||
|
||||
vkCmdPipelineBarrier2(cmd.transitionCommandBuffer, &dependencyInfo);
|
||||
|
||||
|
||||
copyAllocator.submit(cmd);
|
||||
}
|
||||
}
|
||||
@@ -5445,7 +5460,7 @@ using namespace vulkan_internal;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
VkPipelineLayoutCreateInfo pipelineLayoutInfo = {};
|
||||
@@ -6423,7 +6438,7 @@ using namespace vulkan_internal;
|
||||
info.referencePictureFormat = info.pictureFormat;
|
||||
info.pVideoProfile = &video_capability_h264.profile;
|
||||
info.pStdHeaderVersion = &video_capability_h264.video_capabilities.stdHeaderVersion;
|
||||
|
||||
|
||||
res = vkCreateVideoSessionKHR(device, &info, nullptr, &internal_state->video_session);
|
||||
assert(res == VK_SUCCESS);
|
||||
|
||||
@@ -7030,7 +7045,7 @@ using namespace vulkan_internal;
|
||||
VkResult res = vkGetRayTracingShaderGroupHandlesKHR(device, to_internal(rtpso)->pipeline, group_index, 1, SHADER_IDENTIFIER_SIZE, dest);
|
||||
assert(res == VK_SUCCESS);
|
||||
}
|
||||
|
||||
|
||||
void GraphicsDevice_Vulkan::SetName(GPUResource* pResource, const char* name) const
|
||||
{
|
||||
if (!debugUtils || pResource == nullptr || !pResource->IsValid())
|
||||
@@ -7374,7 +7389,7 @@ using namespace vulkan_internal;
|
||||
}
|
||||
allocationhandler->destroylocker.unlock();
|
||||
|
||||
// Destroy Vulkan pipeline cache
|
||||
// Destroy Vulkan pipeline cache
|
||||
vkDestroyPipelineCache(device, pipelineCache, nullptr);
|
||||
pipelineCache = VK_NULL_HANDLE;
|
||||
|
||||
@@ -7696,7 +7711,7 @@ using namespace vulkan_internal;
|
||||
assert(0);
|
||||
}
|
||||
commandlist.prev_swapchains.push_back(*swapchain);
|
||||
|
||||
|
||||
VkRenderingInfo info = {};
|
||||
info.sType = VK_STRUCTURE_TYPE_RENDERING_INFO;
|
||||
info.renderArea.offset.x = 0;
|
||||
@@ -7935,7 +7950,7 @@ using namespace vulkan_internal;
|
||||
barrier.newLayout = _ConvertImageLayout(image.layout);
|
||||
|
||||
assert(barrier.newLayout != VK_IMAGE_LAYOUT_UNDEFINED);
|
||||
|
||||
|
||||
barrier.srcStageMask = _ConvertPipelineStage(image.layout_before);
|
||||
barrier.dstStageMask = _ConvertPipelineStage(image.layout);
|
||||
barrier.srcAccessMask = _ParseResourceState(image.layout_before);
|
||||
@@ -9088,7 +9103,7 @@ using namespace vulkan_internal;
|
||||
raygen.deviceAddress += desc->ray_generation.offset;
|
||||
raygen.size = desc->ray_generation.size;
|
||||
raygen.stride = raygen.size; // raygen specifically must be size == stride
|
||||
|
||||
|
||||
VkStridedDeviceAddressRegionKHR miss = {};
|
||||
miss.deviceAddress = desc->miss.buffer ? to_internal(desc->miss.buffer)->address : 0;
|
||||
miss.deviceAddress += desc->miss.offset;
|
||||
@@ -9113,8 +9128,8 @@ using namespace vulkan_internal;
|
||||
&miss,
|
||||
&hitgroup,
|
||||
&callable,
|
||||
desc->width,
|
||||
desc->height,
|
||||
desc->width,
|
||||
desc->height,
|
||||
desc->depth
|
||||
);
|
||||
}
|
||||
|
||||
@@ -18,6 +18,9 @@
|
||||
|
||||
#define VK_NO_PROTOTYPES
|
||||
#include "Utility/vulkan/vulkan.h"
|
||||
#ifdef SDL2
|
||||
#include "Utility/vulkan/vulkan_wayland.h"
|
||||
#endif
|
||||
#include "Utility/volk.h"
|
||||
#include "Utility/vk_mem_alloc.h"
|
||||
|
||||
|
||||
+24
-22
@@ -80,7 +80,7 @@ namespace wi::input
|
||||
const KeyboardState& GetKeyboardState() { return keyboard; }
|
||||
const MouseState& GetMouseState() { return mouse; }
|
||||
|
||||
struct Input
|
||||
struct Input
|
||||
{
|
||||
BUTTON button = BUTTON_NONE;
|
||||
int playerIndex = 0;
|
||||
@@ -155,7 +155,7 @@ namespace wi::input
|
||||
|
||||
#if defined(_WIN32) && !defined(PLATFORM_XBOX)
|
||||
wi::input::rawinput::GetMouseState(&mouse); // currently only the relative data can be used from this
|
||||
wi::input::rawinput::GetKeyboardState(&keyboard);
|
||||
wi::input::rawinput::GetKeyboardState(&keyboard);
|
||||
|
||||
// apparently checking the mouse here instead of Down() avoids missing the button presses (review!)
|
||||
mouse.left_button_press |= KEY_DOWN(VK_LBUTTON);
|
||||
@@ -474,15 +474,15 @@ namespace wi::input
|
||||
switch (button)
|
||||
{
|
||||
case wi::input::MOUSE_BUTTON_LEFT:
|
||||
if (mouse.left_button_press)
|
||||
if (mouse.left_button_press)
|
||||
return true;
|
||||
return false;
|
||||
case wi::input::MOUSE_BUTTON_RIGHT:
|
||||
if (mouse.right_button_press)
|
||||
if (mouse.right_button_press)
|
||||
return true;
|
||||
return false;
|
||||
case wi::input::MOUSE_BUTTON_MIDDLE:
|
||||
if (mouse.middle_button_press)
|
||||
if (mouse.middle_button_press)
|
||||
return true;
|
||||
return false;
|
||||
#ifdef _WIN32
|
||||
@@ -507,7 +507,7 @@ namespace wi::input
|
||||
case wi::input::KEYBOARD_BUTTON_LSHIFT:
|
||||
keycode = VK_LSHIFT;
|
||||
break;
|
||||
case wi::input::KEYBOARD_BUTTON_F1:
|
||||
case wi::input::KEYBOARD_BUTTON_F1:
|
||||
keycode = VK_F1;
|
||||
break;
|
||||
case wi::input::KEYBOARD_BUTTON_F2:
|
||||
@@ -718,22 +718,24 @@ namespace wi::input
|
||||
ClientToScreen(hWnd, &p);
|
||||
SetCursorPos(p.x, p.y);
|
||||
#elif defined(SDL2)
|
||||
// Keeping with the trend of 'Set Pointer' API on different platforms,
|
||||
// SDL_WarpMouseInWindow is used in the case of SDL2. This unfortunately
|
||||
// causes SDL2 to generate a mouse event for the delta between the old
|
||||
// and new positions leading to 'rubber banding'.
|
||||
// The current solution is to artifically generate a motion event of our own
|
||||
// which will 'undo' this unwanted motion event during the mouse motion
|
||||
// accumulation in wiSDLInput.cpp Update()
|
||||
XMFLOAT4 currentPointer = GetPointer();
|
||||
SDL_MouseMotionEvent motionEvent = {0};
|
||||
motionEvent.type = SDL_MOUSEMOTION;
|
||||
motionEvent.x = motionEvent.y = 0; // doesn't matter
|
||||
motionEvent.xrel = currentPointer.x - props.x;
|
||||
motionEvent.yrel = currentPointer.y - props.y;
|
||||
SDL_PushEvent((SDL_Event*)&motionEvent);
|
||||
SDL_WarpMouseInWindow(window, props.x, props.y);
|
||||
|
||||
if (window.type == platform::LinuxWindow::eSDLWindow)
|
||||
{
|
||||
// Keeping with the trend of 'Set Pointer' API on different platforms,
|
||||
// SDL_WarpMouseInWindow is used in the case of SDL2. This unfortunately
|
||||
// causes SDL2 to generate a mouse event for the delta between the old
|
||||
// and new positions leading to 'rubber banding'.
|
||||
// The current solution is to artifically generate a motion event of our own
|
||||
// which will 'undo' this unwanted motion event during the mouse motion
|
||||
// accumulation in wiSDLInput.cpp Update()
|
||||
XMFLOAT4 currentPointer = GetPointer();
|
||||
SDL_MouseMotionEvent motionEvent = {0};
|
||||
motionEvent.type = SDL_MOUSEMOTION;
|
||||
motionEvent.x = motionEvent.y = 0; // doesn't matter
|
||||
motionEvent.xrel = currentPointer.x - props.x;
|
||||
motionEvent.yrel = currentPointer.y - props.y;
|
||||
SDL_PushEvent((SDL_Event*)&motionEvent);
|
||||
SDL_WarpMouseInWindow(window.sdl_window, props.x, props.y);
|
||||
}
|
||||
#endif // SDL2
|
||||
}
|
||||
void HidePointer(bool value)
|
||||
|
||||
@@ -34,6 +34,7 @@ typedef void* HMODULE;
|
||||
#include <SDL2/SDL.h>
|
||||
#include <SDL_vulkan.h>
|
||||
#include "sdl2.h"
|
||||
#include "Wayland/wiWaylandWindow.h"
|
||||
#endif
|
||||
|
||||
|
||||
@@ -42,7 +43,25 @@ namespace wi::platform
|
||||
#ifdef _WIN32
|
||||
using window_type = HWND;
|
||||
#elif SDL2
|
||||
using window_type = SDL_Window*;
|
||||
struct LinuxWindow {
|
||||
enum ELinuxWindowType {
|
||||
eNoneWindow,
|
||||
eSDLWindow,
|
||||
eWaylandWindow,
|
||||
} type;
|
||||
union {
|
||||
void* null;
|
||||
SDL_Window* sdl_window;
|
||||
wi::wayland::Window* wl_window;
|
||||
};
|
||||
LinuxWindow(std::nullptr_t)
|
||||
: type(eNoneWindow), null(nullptr) {}
|
||||
LinuxWindow(SDL_Window* window)
|
||||
: type(eSDLWindow), sdl_window(window) {}
|
||||
LinuxWindow(wi::wayland::Window* window)
|
||||
: type(eWaylandWindow), wl_window(window) {}
|
||||
};
|
||||
using window_type = LinuxWindow;
|
||||
#else
|
||||
using window_type = void*;
|
||||
#endif // _WIN32
|
||||
@@ -83,10 +102,18 @@ namespace wi::platform
|
||||
#endif // PLATFORM_WINDOWS_DESKTOP || PLATFORM_XBOX
|
||||
|
||||
#ifdef PLATFORM_LINUX
|
||||
int window_width, window_height;
|
||||
SDL_GetWindowSize(window, &window_width, &window_height);
|
||||
SDL_Vulkan_GetDrawableSize(window, &dest->width, &dest->height);
|
||||
dest->dpi = ((float)dest->width / (float)window_width) * 96.f;
|
||||
if (window.type == window.eSDLWindow)
|
||||
{
|
||||
int window_width, window_height;
|
||||
SDL_GetWindowSize(window.sdl_window, &window_width, &window_height);
|
||||
SDL_Vulkan_GetDrawableSize(window.sdl_window, &dest->width, &dest->height);
|
||||
dest->dpi = ((float)dest->width / (float)window_width) * 96.f;
|
||||
}
|
||||
else if (window.type == window.eWaylandWindow)
|
||||
{
|
||||
window.wl_window->GetWindowCurrentSize(&dest->width, &dest->height);
|
||||
dest->dpi = 96.f;
|
||||
}
|
||||
#endif // PLATFORM_LINUX
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user