Compare commits
246 Commits
tmp-gpu-po
...
xr-control
Author | SHA1 | Date | |
---|---|---|---|
6fc81d6bca | |||
85e1f28fca | |||
c4f65fa5da | |||
dda9762a16 | |||
fa23369373 | |||
1ef02d8f4b | |||
6d7113c363 | |||
33306067da | |||
ff5733ef2f | |||
c996926c05 | |||
593621fdfb | |||
07a92c616f | |||
99ce2f3e4d | |||
c8c782fbf4 | |||
0f1ef110a4 | |||
5fd158bb87 | |||
21a24aa61e | |||
c9a4c29589 | |||
a063d58080 | |||
f58bebf688 | |||
ba79625f9e | |||
72381da800 | |||
9d68c34a75 | |||
e41cc8162a | |||
1990bb921f | |||
567c22f0d8 | |||
be0a272d91 | |||
5f5289512c | |||
05c3e5c433 | |||
9f6b8bc3a1 | |||
d870b85dab | |||
2f4712841a | |||
6dec69daa8 | |||
be7653fe52 | |||
c600251eae | |||
d2c4094425 | |||
14fc1c73e8 | |||
ef07af330a | |||
9561a0a0a3 | |||
9f5089b67a | |||
f34cb9f8bf | |||
5a640b94b4 | |||
9025f2adc6 | |||
d5989308fb | |||
8a103470c9 | |||
be59b7699e | |||
6b67760bd8 | |||
fb3154447b | |||
c56b73277e | |||
99beac7b3f | |||
c4c4b1a03d | |||
af90b8aaa3 | |||
2c5241ad01 | |||
6daab062b4 | |||
4b3aaa76bd | |||
707bc260d8 | |||
5b45070024 | |||
bd8b3f57df | |||
4040ebd1ff | |||
3feb3a4707 | |||
aa92c23430 | |||
7863f2fbe0 | |||
872484dfaa | |||
1185259db8 | |||
1f1589b4df | |||
6ee46d5e83 | |||
a177eb3dd2 | |||
f7d42065eb | |||
7a7ee11f13 | |||
5465112930 | |||
f89f63eefd | |||
714224ee1f | |||
1184da2974 | |||
e8926d40c8 | |||
004034f8c5 | |||
7b867dd00a | |||
e022f99e5c | |||
80c80f5e18 | |||
0d6c6a6787 | |||
e3cab5c206 | |||
8ace7897a8 | |||
e5089d3924 | |||
65804b203e | |||
2a768ffe43 | |||
2585d7f1b8 | |||
eed31613e5 | |||
6732d31f18 | |||
1bd403430d | |||
9926553255 | |||
0c92bf5e37 | |||
9ce38d17ed | |||
40741a8942 | |||
eeb948f428 | |||
9c3ac44c89 | |||
819a7e7900 | |||
5544ffabd5 | |||
2a3b8880e3 | |||
05f5d2791f | |||
29702c6d8b | |||
36463a16bb | |||
b57cc27ec9 | |||
8b53855371 | |||
af1c2869a6 | |||
9df2fae994 | |||
daf5570c42 | |||
795ae6433d | |||
1e8b3692b9 | |||
544c6fd1b6 | |||
963a6c3c12 | |||
f799fc3033 | |||
5a786038cb | |||
7343845d7b | |||
ce5fc090a8 | |||
2fa8e2686e | |||
f89460a872 | |||
8c8bc114b8 | |||
11a63417ea | |||
ed869a2609 | |||
79ed8f21f7 | |||
a5d1f3e4c5 | |||
7c05339597 | |||
cd3030bb8d | |||
5677c02954 | |||
3e7524b52b | |||
c34d0fbee2 | |||
63f0dcf6b7 | |||
517a3cdad1 | |||
585f98784c | |||
c9c052aae0 | |||
9cfc8ebcc9 | |||
dfc8860502 | |||
97c8878753 | |||
49707f5d83 | |||
334114d287 | |||
034dd0d702 | |||
d8cf5e7f4d | |||
854d115d68 | |||
886cba7fe8 | |||
f21eb52ecc | |||
81944920a7 | |||
cf12206311 | |||
247267dee4 | |||
2370781389 | |||
1aecb31acc | |||
2092d39dfd | |||
412ea63063 | |||
0f236af817 | |||
798c33ab3b | |||
a87b142e51 | |||
2ddf55f358 | |||
84f821f271 | |||
29ed6a6872 | |||
78563e9bf1 | |||
8916a04df8 | |||
c9f0da5b20 | |||
f7a72a238b | |||
c8db91fc93 | |||
e089ad2b4b | |||
6c67d808b7 | |||
d3e352a7ec | |||
4423ab787b | |||
57f7e1ff97 | |||
f8ad9c696e | |||
79733505bf | |||
b4a21355d7 | |||
d685b9ca57 | |||
d3b07d5ad5 | |||
86faaaa934 | |||
4d5f104faf | |||
6fdf493028 | |||
43dd6ba330 | |||
423619fd3d | |||
6489002982 | |||
634812e579 | |||
8ccdd43fc1 | |||
78d7dbbad9 | |||
4ec85983af | |||
dc0b81bc99 | |||
f6e71179fe | |||
36bdbe6ce3 | |||
5f7285d4af | |||
1625bb3e71 | |||
a399445b3c | |||
f32d320e90 | |||
78cd4e8cee | |||
848c87c6d9 | |||
f5ff515085 | |||
07a7c88918 | |||
48ec546911 | |||
8335da48f9 | |||
8fae3debf3 | |||
2ed0965e97 | |||
2b338373d7 | |||
c565bb8985 | |||
03bb02337f | |||
618df6b0b7 | |||
0c246b2b52 | |||
ff2dcdb447 | |||
73daf1f721 | |||
9c28e6e62f | |||
9c288d3e20 | |||
86f76f46f9 | |||
498804edc8 | |||
3d24ef827c | |||
c8be04b7f8 | |||
58ecc0d1bf | |||
1a6d76c5c7 | |||
a1333cf2c3 | |||
9be27de831 | |||
a90bfa17a9 | |||
d72fafd62a | |||
62c5f71da1 | |||
09377b4c9c | |||
b596d70a1f | |||
1d86e1ff46 | |||
3e0acdfe94 | |||
a6c5a1a2dc | |||
ceab20d5e5 | |||
cb75a83df0 | |||
db1cdcdafe | |||
297decbe1f | |||
8af91a18e0 | |||
9ec8ca2d55 | |||
5561fbf1f8 | |||
de026d1395 | |||
07e5488c61 | |||
2eb44677dd | |||
3e33c89828 | |||
f2385a3f05 | |||
f6a7d5336b | |||
336c8a628a | |||
66e22a2ed7 | |||
6920906f75 | |||
ae1d8f4c35 | |||
e0eafd2757 | |||
5e8d3f6d28 | |||
090c1b7dda | |||
f126ce2d5b | |||
3b3955d9e2 | |||
9c9081bf83 | |||
cfc5c1b46d | |||
45194962c1 | |||
921510f34f | |||
d7083de46d | |||
b44173754f | |||
e0da725075 |
@@ -5,7 +5,7 @@
|
||||
update-code:
|
||||
git:
|
||||
submodules:
|
||||
- branch: master
|
||||
- branch: xr-controller-support
|
||||
commit_id: HEAD
|
||||
path: release/scripts/addons
|
||||
- branch: master
|
||||
|
@@ -178,7 +178,7 @@ def submodules_update(args, release_version, branch):
|
||||
branch = branch_fallback
|
||||
|
||||
submodules = [
|
||||
("release/scripts/addons", branch, branch_fallback),
|
||||
("release/scripts/addons", "xr-controller-support", branch_fallback),
|
||||
("release/scripts/addons_contrib", branch, branch_fallback),
|
||||
("release/datafiles/locale", branch, branch_fallback),
|
||||
("source/tools", branch, branch_fallback),
|
||||
|
@@ -473,6 +473,7 @@ if(WITH_XR_OPENXR)
|
||||
intern/GHOST_Xr.cpp
|
||||
intern/GHOST_XrAction.cpp
|
||||
intern/GHOST_XrContext.cpp
|
||||
intern/GHOST_XrControllerModel.cpp
|
||||
intern/GHOST_XrEvent.cpp
|
||||
intern/GHOST_XrGraphicsBinding.cpp
|
||||
intern/GHOST_XrSession.cpp
|
||||
@@ -482,13 +483,19 @@ if(WITH_XR_OPENXR)
|
||||
intern/GHOST_IXrGraphicsBinding.h
|
||||
intern/GHOST_XrAction.h
|
||||
intern/GHOST_XrContext.h
|
||||
intern/GHOST_XrControllerModel.h
|
||||
intern/GHOST_XrException.h
|
||||
intern/GHOST_XrSession.h
|
||||
intern/GHOST_XrSwapchain.h
|
||||
intern/GHOST_Xr_intern.h
|
||||
intern/GHOST_Xr_openxr_includes.h
|
||||
)
|
||||
list(APPEND INC
|
||||
../../extern/json/include
|
||||
../../extern/tinygltf
|
||||
)
|
||||
list(APPEND INC_SYS
|
||||
${EIGEN3_INCLUDE_DIRS}
|
||||
${XR_OPENXR_SDK_INCLUDE_DIR}
|
||||
)
|
||||
list(APPEND LIB
|
||||
|
@@ -1140,6 +1140,30 @@ void GHOST_XrGetActionCustomdataArray(GHOST_XrContextHandle xr_context,
|
||||
const char *action_set_name,
|
||||
void **r_customdata_array);
|
||||
|
||||
/* controller model */
|
||||
/**
|
||||
* Load the OpenXR controller model.
|
||||
*/
|
||||
int GHOST_XrLoadControllerModel(GHOST_XrContextHandle xr_context, const char *subaction_path);
|
||||
|
||||
/**
|
||||
* Unload the OpenXR controller model.
|
||||
*/
|
||||
void GHOST_XrUnloadControllerModel(GHOST_XrContextHandle xr_context, const char *subaction_path);
|
||||
|
||||
/**
|
||||
* Update component transforms for the OpenXR controller model.
|
||||
*/
|
||||
int GHOST_XrUpdateControllerModelComponents(GHOST_XrContextHandle xr_context,
|
||||
const char *subaction_path);
|
||||
|
||||
/**
|
||||
* Get vertex data for the OpenXR controller model.
|
||||
*/
|
||||
int GHOST_XrGetControllerModelData(GHOST_XrContextHandle xr_context,
|
||||
const char *subaction_path,
|
||||
GHOST_XrControllerModelData *r_data);
|
||||
|
||||
#endif /* WITH_XR_OPENXR */
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@@ -643,7 +643,7 @@ typedef void (*GHOST_XrDrawViewFn)(const struct GHOST_XrDrawViewInfo *draw_view,
|
||||
*/
|
||||
typedef const GHOST_TXrGraphicsBinding *GHOST_XrGraphicsBindingCandidates;
|
||||
|
||||
typedef struct {
|
||||
typedef struct GHOST_XrPose {
|
||||
float position[3];
|
||||
/* Blender convention (w, x, y, z) */
|
||||
float orientation_quat[4];
|
||||
@@ -753,8 +753,31 @@ typedef struct GHOST_XrActionProfileInfo {
|
||||
const char *profile_path;
|
||||
uint32_t count_subaction_paths;
|
||||
const char **subaction_paths;
|
||||
/* Bindings for each subaction path. */
|
||||
/** Bindings for each subaction path. */
|
||||
const GHOST_XrActionBindingInfo *bindings;
|
||||
} GHOST_XrActionProfileInfo;
|
||||
|
||||
typedef struct GHOST_XrControllerModelVertex {
|
||||
float position[3];
|
||||
float normal[3];
|
||||
} GHOST_XrControllerModelVertex;
|
||||
|
||||
typedef struct GHOST_XrControllerModelComponent {
|
||||
/** World space transform. */
|
||||
float transform[4][4];
|
||||
uint32_t vertex_offset;
|
||||
uint32_t vertex_count;
|
||||
uint32_t index_offset;
|
||||
uint32_t index_count;
|
||||
} GHOST_XrControllerModelComponent;
|
||||
|
||||
typedef struct GHOST_XrControllerModelData {
|
||||
uint32_t count_vertices;
|
||||
const GHOST_XrControllerModelVertex *vertices;
|
||||
uint32_t count_indices;
|
||||
const uint32_t *indices;
|
||||
uint32_t count_components;
|
||||
const GHOST_XrControllerModelComponent *components;
|
||||
} GHOST_XrControllerModelData;
|
||||
|
||||
#endif /* WITH_XR_OPENXR */
|
||||
|
@@ -1069,4 +1069,39 @@ void GHOST_XrGetActionCustomdataArray(GHOST_XrContextHandle xr_contexthandle,
|
||||
xr_context);
|
||||
}
|
||||
|
||||
int GHOST_XrLoadControllerModel(GHOST_XrContextHandle xr_contexthandle, const char *subaction_path)
|
||||
{
|
||||
GHOST_IXrContext *xr_context = (GHOST_IXrContext *)xr_contexthandle;
|
||||
GHOST_XrSession *xr_session = xr_context->getSession();
|
||||
GHOST_XR_CAPI_CALL_RET(xr_session->loadControllerModel(subaction_path), xr_context);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void GHOST_XrUnloadControllerModel(GHOST_XrContextHandle xr_contexthandle,
|
||||
const char *subaction_path)
|
||||
{
|
||||
GHOST_IXrContext *xr_context = (GHOST_IXrContext *)xr_contexthandle;
|
||||
GHOST_XrSession *xr_session = xr_context->getSession();
|
||||
GHOST_XR_CAPI_CALL(xr_session->unloadControllerModel(subaction_path), xr_context);
|
||||
}
|
||||
|
||||
int GHOST_XrUpdateControllerModelComponents(GHOST_XrContextHandle xr_contexthandle,
|
||||
const char *subaction_path)
|
||||
{
|
||||
GHOST_IXrContext *xr_context = (GHOST_IXrContext *)xr_contexthandle;
|
||||
GHOST_XrSession *xr_session = xr_context->getSession();
|
||||
GHOST_XR_CAPI_CALL_RET(xr_session->updateControllerModelComponents(subaction_path), xr_context);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int GHOST_XrGetControllerModelData(GHOST_XrContextHandle xr_contexthandle,
|
||||
const char *subaction_path,
|
||||
GHOST_XrControllerModelData *r_data)
|
||||
{
|
||||
GHOST_IXrContext *xr_context = (GHOST_IXrContext *)xr_contexthandle;
|
||||
GHOST_XrSession *xr_session = xr_context->getSession();
|
||||
GHOST_XR_CAPI_CALL_RET(xr_session->getControllerModelData(subaction_path, *r_data), xr_context);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* WITH_XR_OPENXR */
|
||||
|
@@ -22,7 +22,6 @@
|
||||
#include <cstring>
|
||||
|
||||
#include "GHOST_Types.h"
|
||||
|
||||
#include "GHOST_XrException.h"
|
||||
#include "GHOST_Xr_intern.h"
|
||||
|
||||
|
@@ -26,6 +26,7 @@
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "GHOST_Util.h"
|
||||
|
||||
|
@@ -412,11 +412,14 @@ void GHOST_XrContext::getExtensionsToEnable(
|
||||
try_ext.push_back(XR_EXT_DEBUG_UTILS_EXTENSION_NAME);
|
||||
}
|
||||
|
||||
/* Try enabling interaction profile extensions. */
|
||||
/* Interaction profile extensions. */
|
||||
try_ext.push_back(XR_EXT_HP_MIXED_REALITY_CONTROLLER_EXTENSION_NAME);
|
||||
try_ext.push_back(XR_HTC_VIVE_COSMOS_CONTROLLER_INTERACTION_EXTENSION_NAME);
|
||||
try_ext.push_back(XR_HUAWEI_CONTROLLER_INTERACTION_EXTENSION_NAME);
|
||||
|
||||
/* Controller model extension. */
|
||||
try_ext.push_back(XR_MSFT_CONTROLLER_MODEL_EXTENSION_NAME);
|
||||
|
||||
/* Varjo quad view extension. */
|
||||
try_ext.push_back(XR_VARJO_QUAD_VIEWS_EXTENSION_NAME);
|
||||
|
||||
|
629
intern/ghost/intern/GHOST_XrControllerModel.cpp
Normal file
629
intern/ghost/intern/GHOST_XrControllerModel.cpp
Normal file
@@ -0,0 +1,629 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* \ingroup GHOST
|
||||
*/
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#include <Eigen/Core>
|
||||
#include <Eigen/Geometry>
|
||||
|
||||
#include "GHOST_Types.h"
|
||||
#include "GHOST_XrException.h"
|
||||
#include "GHOST_Xr_intern.h"
|
||||
|
||||
#include "GHOST_XrControllerModel.h"
|
||||
|
||||
#define TINYGLTF_IMPLEMENTATION
|
||||
#define TINYGLTF_NO_STB_IMAGE
|
||||
#define TINYGLTF_NO_STB_IMAGE_WRITE
|
||||
#define STBIWDEF static inline
|
||||
#include "tiny_gltf.h"
|
||||
|
||||
struct GHOST_XrControllerModelNode {
|
||||
int32_t parent_idx = -1;
|
||||
int32_t component_idx = -1;
|
||||
float local_transform[4][4];
|
||||
};
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name glTF Utilities
|
||||
*
|
||||
* Adapted from Microsoft OpenXR-Mixed Reality Samples (MIT License):
|
||||
* https://github.com/microsoft/OpenXR-MixedReality
|
||||
* \{ */
|
||||
|
||||
struct GHOST_XrPrimitive {
|
||||
std::vector<GHOST_XrControllerModelVertex> vertices;
|
||||
std::vector<uint32_t> indices;
|
||||
};
|
||||
|
||||
/**
|
||||
* Validate that an accessor does not go out of bounds of the buffer view that it references and
|
||||
* that the buffer view does not exceed the bounds of the buffer that it references
|
||||
*/
|
||||
static void validate_accessor(const tinygltf::Accessor &accessor,
|
||||
const tinygltf::BufferView &buffer_view,
|
||||
const tinygltf::Buffer &buffer,
|
||||
size_t byte_stride,
|
||||
size_t element_size)
|
||||
{
|
||||
/* Make sure the accessor does not go out of range of the buffer view. */
|
||||
if (accessor.byteOffset + (accessor.count - 1) * byte_stride + element_size >
|
||||
buffer_view.byteLength) {
|
||||
throw GHOST_XrException("glTF: Accessor goes out of range of bufferview.");
|
||||
}
|
||||
|
||||
/* Make sure the buffer view does not go out of range of the buffer. */
|
||||
if (buffer_view.byteOffset + buffer_view.byteLength > buffer.data.size()) {
|
||||
throw GHOST_XrException("glTF: BufferView goes out of range of buffer.");
|
||||
}
|
||||
}
|
||||
|
||||
template<float (GHOST_XrControllerModelVertex::*field)[3]>
|
||||
static void read_vertices(const tinygltf::Accessor &accessor,
|
||||
const tinygltf::BufferView &buffer_view,
|
||||
const tinygltf::Buffer &buffer,
|
||||
GHOST_XrPrimitive &primitive)
|
||||
{
|
||||
if (accessor.type != TINYGLTF_TYPE_VEC3) {
|
||||
throw GHOST_XrException(
|
||||
"glTF: Accessor for primitive attribute has incorrect type (VEC3 expected).");
|
||||
}
|
||||
|
||||
if (accessor.componentType != TINYGLTF_COMPONENT_TYPE_FLOAT) {
|
||||
throw GHOST_XrException(
|
||||
"glTF: Accessor for primitive attribute has incorrect component type (FLOAT expected).");
|
||||
}
|
||||
|
||||
/* If stride is not specified, it is tightly packed. */
|
||||
constexpr size_t packed_size = sizeof(float) * 3;
|
||||
const size_t stride = buffer_view.byteStride == 0 ? packed_size : buffer_view.byteStride;
|
||||
validate_accessor(accessor, buffer_view, buffer, stride, packed_size);
|
||||
|
||||
/* Resize the vertices vector, if necessary, to include room for the attribute data.
|
||||
If there are multiple attributes for a primitive, the first one will resize, and the
|
||||
subsequent will not need to. */
|
||||
primitive.vertices.resize(accessor.count);
|
||||
|
||||
/* Copy the attribute value over from the glTF buffer into the appropriate vertex field. */
|
||||
const uint8_t *buffer_ptr = buffer.data.data() + buffer_view.byteOffset + accessor.byteOffset;
|
||||
for (size_t i = 0; i < accessor.count; i++, buffer_ptr += stride) {
|
||||
memcpy(primitive.vertices[i].*field, buffer_ptr, stride);
|
||||
}
|
||||
}
|
||||
|
||||
static void load_attribute_accessor(const tinygltf::Model &gltf_model,
|
||||
const std::string &attribute_name,
|
||||
int accessor_id,
|
||||
GHOST_XrPrimitive &primitive)
|
||||
{
|
||||
const auto &accessor = gltf_model.accessors.at(accessor_id);
|
||||
|
||||
if (accessor.bufferView == -1) {
|
||||
throw GHOST_XrException("glTF: Accessor for primitive attribute specifies no bufferview.");
|
||||
}
|
||||
|
||||
const tinygltf::BufferView &buffer_view = gltf_model.bufferViews.at(accessor.bufferView);
|
||||
if (buffer_view.target != TINYGLTF_TARGET_ARRAY_BUFFER && buffer_view.target != 0) {
|
||||
throw GHOST_XrException(
|
||||
"glTF: Accessor for primitive attribute uses bufferview with invalid 'target' type.");
|
||||
}
|
||||
|
||||
const tinygltf::Buffer &buffer = gltf_model.buffers.at(buffer_view.buffer);
|
||||
|
||||
if (attribute_name.compare("POSITION") == 0) {
|
||||
read_vertices<&GHOST_XrControllerModelVertex::position>(
|
||||
accessor, buffer_view, buffer, primitive);
|
||||
}
|
||||
else if (attribute_name.compare("NORMAL") == 0) {
|
||||
read_vertices<&GHOST_XrControllerModelVertex::normal>(
|
||||
accessor, buffer_view, buffer, primitive);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads index data from a glTF primitive into a GHOST_XrPrimitive. glTF indices may be 8bit, 16bit
|
||||
* or 32bit integers. This will coalesce indices from the source type(s) into a 32bit integer.
|
||||
*/
|
||||
template<typename TSrcIndex>
|
||||
static void read_indices(const tinygltf::Accessor &accessor,
|
||||
const tinygltf::BufferView &buffer_view,
|
||||
const tinygltf::Buffer &buffer,
|
||||
GHOST_XrPrimitive &primitive)
|
||||
{
|
||||
if (buffer_view.target != TINYGLTF_TARGET_ELEMENT_ARRAY_BUFFER &&
|
||||
buffer_view.target != 0) { /* Allow 0 (not specified) even though spec doesn't seem to allow
|
||||
this (BoomBox GLB fails). */
|
||||
throw GHOST_XrException(
|
||||
"glTF: Accessor for indices uses bufferview with invalid 'target' type.");
|
||||
}
|
||||
|
||||
constexpr size_t component_size_bytes = sizeof(TSrcIndex);
|
||||
if (buffer_view.byteStride != 0 &&
|
||||
buffer_view.byteStride !=
|
||||
component_size_bytes) { /* Index buffer must be packed per glTF spec. */
|
||||
throw GHOST_XrException(
|
||||
"glTF: Accessor for indices uses bufferview with invalid 'byteStride'.");
|
||||
}
|
||||
|
||||
validate_accessor(accessor, buffer_view, buffer, component_size_bytes, component_size_bytes);
|
||||
|
||||
if ((accessor.count % 3) != 0) { /* Since only triangles are supported, enforce that the number
|
||||
of indices is divisible by 3. */
|
||||
throw GHOST_XrException("glTF: Unexpected number of indices for triangle primitive");
|
||||
}
|
||||
|
||||
const TSrcIndex *index_buffer = reinterpret_cast<const TSrcIndex *>(
|
||||
buffer.data.data() + buffer_view.byteOffset + accessor.byteOffset);
|
||||
for (uint32_t i = 0; i < accessor.count; i++) {
|
||||
primitive.indices.push_back(*(index_buffer + i));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads index data from a glTF primitive into a GHOST_XrPrimitive.
|
||||
*/
|
||||
static void load_index_accessor(const tinygltf::Model &gltf_model,
|
||||
const tinygltf::Accessor &accessor,
|
||||
GHOST_XrPrimitive &primitive)
|
||||
{
|
||||
if (accessor.type != TINYGLTF_TYPE_SCALAR) {
|
||||
throw GHOST_XrException("glTF: Accessor for indices specifies invalid 'type'.");
|
||||
}
|
||||
|
||||
if (accessor.bufferView == -1) {
|
||||
throw GHOST_XrException("glTF: Index accessor without bufferView is currently not supported.");
|
||||
}
|
||||
|
||||
const tinygltf::BufferView &buffer_view = gltf_model.bufferViews.at(accessor.bufferView);
|
||||
const tinygltf::Buffer &buffer = gltf_model.buffers.at(buffer_view.buffer);
|
||||
|
||||
if (accessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE) {
|
||||
read_indices<uint8_t>(accessor, buffer_view, buffer, primitive);
|
||||
}
|
||||
else if (accessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT) {
|
||||
read_indices<uint16_t>(accessor, buffer_view, buffer, primitive);
|
||||
}
|
||||
else if (accessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT) {
|
||||
read_indices<uint32_t>(accessor, buffer_view, buffer, primitive);
|
||||
}
|
||||
else {
|
||||
throw GHOST_XrException("glTF: Accessor for indices specifies invalid 'componentType'.");
|
||||
}
|
||||
}
|
||||
|
||||
static GHOST_XrPrimitive read_primitive(const tinygltf::Model &gltf_model,
|
||||
const tinygltf::Primitive &gltf_primitive)
|
||||
{
|
||||
if (gltf_primitive.mode != TINYGLTF_MODE_TRIANGLES) {
|
||||
throw GHOST_XrException(
|
||||
"glTF: Unsupported primitive mode. Only TINYGLTF_MODE_TRIANGLES is supported.");
|
||||
}
|
||||
|
||||
GHOST_XrPrimitive primitive;
|
||||
|
||||
/* glTF vertex data is stored in an attribute dictionary.Loop through each attribute and insert
|
||||
* it into the GHOST_XrPrimitive. */
|
||||
for (const auto &[attr_name, accessor_idx] : gltf_primitive.attributes) {
|
||||
load_attribute_accessor(gltf_model, attr_name, accessor_idx, primitive);
|
||||
}
|
||||
|
||||
if (gltf_primitive.indices != -1) {
|
||||
/* If indices are specified for the glTF primitive, read them into the GHOST_XrPrimitive. */
|
||||
load_index_accessor(gltf_model, gltf_model.accessors.at(gltf_primitive.indices), primitive);
|
||||
}
|
||||
|
||||
return primitive;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate node local and world transforms.
|
||||
*/
|
||||
static void calc_node_transforms(const tinygltf::Node &gltf_node,
|
||||
const float parent_transform[4][4],
|
||||
float r_local_transform[4][4],
|
||||
float r_world_transform[4][4])
|
||||
{
|
||||
/* A node may specify either a 4x4 matrix or TRS (Translation - Rotation - Scale) values, but not
|
||||
* both. */
|
||||
if (gltf_node.matrix.size() == 16) {
|
||||
const std::vector<double> &dm = gltf_node.matrix;
|
||||
float m[4][4] = {(float)dm[0],
|
||||
(float)dm[1],
|
||||
(float)dm[2],
|
||||
(float)dm[3],
|
||||
(float)dm[4],
|
||||
(float)dm[5],
|
||||
(float)dm[6],
|
||||
(float)dm[7],
|
||||
(float)dm[8],
|
||||
(float)dm[9],
|
||||
(float)dm[10],
|
||||
(float)dm[11],
|
||||
(float)dm[12],
|
||||
(float)dm[13],
|
||||
(float)dm[14],
|
||||
(float)dm[15]};
|
||||
memcpy(r_local_transform, m, sizeof(float) * 16);
|
||||
}
|
||||
else {
|
||||
/* No matrix is present, so construct a matrix from the TRS values (each one is optional). */
|
||||
std::vector<double> translation = gltf_node.translation;
|
||||
std::vector<double> rotation = gltf_node.rotation;
|
||||
std::vector<double> scale = gltf_node.scale;
|
||||
Eigen::Matrix4f &m = *(Eigen::Matrix4f *)r_local_transform;
|
||||
Eigen::Quaternionf q;
|
||||
Eigen::Matrix3f scalemat;
|
||||
|
||||
if (translation.size() != 3) {
|
||||
translation.resize(3);
|
||||
translation[0] = translation[1] = translation[2] = 0.0;
|
||||
}
|
||||
if (rotation.size() != 4) {
|
||||
rotation.resize(4);
|
||||
rotation[0] = rotation[1] = rotation[2] = 0.0;
|
||||
rotation[3] = 1.0;
|
||||
}
|
||||
if (scale.size() != 3) {
|
||||
scale.resize(3);
|
||||
scale[0] = scale[1] = scale[2] = 1.0;
|
||||
}
|
||||
|
||||
q.w() = (float)rotation[3];
|
||||
q.x() = (float)rotation[0];
|
||||
q.y() = (float)rotation[1];
|
||||
q.z() = (float)rotation[2];
|
||||
q.normalize();
|
||||
|
||||
scalemat.setIdentity();
|
||||
scalemat(0, 0) = (float)scale[0];
|
||||
scalemat(1, 1) = (float)scale[1];
|
||||
scalemat(2, 2) = (float)scale[2];
|
||||
|
||||
m.setIdentity();
|
||||
m.block<3, 3>(0, 0) = q.toRotationMatrix() * scalemat;
|
||||
m.block<3, 1>(0, 3) = Eigen::Vector3f(
|
||||
(float)translation[0], (float)translation[1], (float)translation[2]);
|
||||
}
|
||||
|
||||
*(Eigen::Matrix4f *)r_world_transform = *(Eigen::Matrix4f *)parent_transform *
|
||||
*(Eigen::Matrix4f *)r_local_transform;
|
||||
}
|
||||
|
||||
static void load_node(const tinygltf::Model &gltf_model,
|
||||
int gltf_node_id,
|
||||
int32_t parent_idx,
|
||||
const float parent_transform[4][4],
|
||||
const std::string &parent_name,
|
||||
const std::vector<XrControllerModelNodePropertiesMSFT> &node_properties,
|
||||
std::vector<GHOST_XrControllerModelVertex> &vertices,
|
||||
std::vector<uint32_t> &indices,
|
||||
std::vector<GHOST_XrControllerModelComponent> &components,
|
||||
std::vector<GHOST_XrControllerModelNode> &nodes,
|
||||
std::vector<int32_t> &node_state_indices)
|
||||
{
|
||||
const tinygltf::Node &gltf_node = gltf_model.nodes.at(gltf_node_id);
|
||||
float world_transform[4][4];
|
||||
|
||||
GHOST_XrControllerModelNode &node = nodes.emplace_back();
|
||||
const int32_t node_idx = (int32_t)(nodes.size() - 1);
|
||||
node.parent_idx = parent_idx;
|
||||
calc_node_transforms(gltf_node, parent_transform, node.local_transform, world_transform);
|
||||
|
||||
for (size_t i = 0; i < node_properties.size(); ++i) {
|
||||
if ((node_state_indices[i] < 0) && (parent_name == node_properties[i].parentNodeName) &&
|
||||
(gltf_node.name == node_properties[i].nodeName)) {
|
||||
node_state_indices[i] = node_idx;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (gltf_node.mesh != -1) {
|
||||
const tinygltf::Mesh &gltf_mesh = gltf_model.meshes.at(gltf_node.mesh);
|
||||
|
||||
GHOST_XrControllerModelComponent &component = components.emplace_back();
|
||||
node.component_idx = components.size() - 1;
|
||||
memcpy(component.transform, world_transform, sizeof(component.transform));
|
||||
component.vertex_offset = vertices.size();
|
||||
component.index_offset = indices.size();
|
||||
|
||||
for (const tinygltf::Primitive &gltf_primitive : gltf_mesh.primitives) {
|
||||
/* Read the primitive data from the glTF buffers. */
|
||||
const GHOST_XrPrimitive primitive = read_primitive(gltf_model, gltf_primitive);
|
||||
|
||||
const size_t start_vertex = vertices.size();
|
||||
size_t offset = start_vertex;
|
||||
size_t count = primitive.vertices.size();
|
||||
vertices.resize(offset + count);
|
||||
memcpy(vertices.data() + offset,
|
||||
primitive.vertices.data(),
|
||||
count * sizeof(decltype(primitive.vertices)::value_type));
|
||||
|
||||
offset = indices.size();
|
||||
count = primitive.indices.size();
|
||||
indices.resize(offset + count);
|
||||
for (size_t i = 0; i < count; i += 3) {
|
||||
indices[offset + i + 0] = start_vertex + primitive.indices[i + 0];
|
||||
indices[offset + i + 1] = start_vertex + primitive.indices[i + 2];
|
||||
indices[offset + i + 2] = start_vertex + primitive.indices[i + 1];
|
||||
}
|
||||
}
|
||||
|
||||
component.vertex_count = vertices.size() - component.vertex_offset;
|
||||
component.index_count = indices.size() - component.index_offset;
|
||||
}
|
||||
|
||||
/* Recursively load all children. */
|
||||
for (const int child_node_id : gltf_node.children) {
|
||||
load_node(gltf_model,
|
||||
child_node_id,
|
||||
node_idx,
|
||||
world_transform,
|
||||
gltf_node.name,
|
||||
node_properties,
|
||||
vertices,
|
||||
indices,
|
||||
components,
|
||||
nodes,
|
||||
node_state_indices);
|
||||
}
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name OpenXR Extension Functions
|
||||
*
|
||||
* \{ */
|
||||
|
||||
static PFN_xrGetControllerModelKeyMSFT g_xrGetControllerModelKeyMSFT = nullptr;
|
||||
static PFN_xrLoadControllerModelMSFT g_xrLoadControllerModelMSFT = nullptr;
|
||||
static PFN_xrGetControllerModelPropertiesMSFT g_xrGetControllerModelPropertiesMSFT = nullptr;
|
||||
static PFN_xrGetControllerModelStateMSFT g_xrGetControllerModelStateMSFT = nullptr;
|
||||
static XrInstance g_instance = XR_NULL_HANDLE;
|
||||
|
||||
#define INIT_EXTENSION_FUNCTION(name) \
|
||||
CHECK_XR( \
|
||||
xrGetInstanceProcAddr(instance, #name, reinterpret_cast<PFN_xrVoidFunction *>(&g_##name)), \
|
||||
"Failed to get pointer to extension function: " #name);
|
||||
|
||||
static void init_controller_model_extension_functions(XrInstance instance)
|
||||
{
|
||||
if (instance != g_instance) {
|
||||
g_instance = instance;
|
||||
g_xrGetControllerModelKeyMSFT = nullptr;
|
||||
g_xrLoadControllerModelMSFT = nullptr;
|
||||
g_xrGetControllerModelPropertiesMSFT = nullptr;
|
||||
g_xrGetControllerModelStateMSFT = nullptr;
|
||||
}
|
||||
|
||||
if (g_xrGetControllerModelKeyMSFT == nullptr) {
|
||||
INIT_EXTENSION_FUNCTION(xrGetControllerModelKeyMSFT);
|
||||
}
|
||||
if (g_xrLoadControllerModelMSFT == nullptr) {
|
||||
INIT_EXTENSION_FUNCTION(xrLoadControllerModelMSFT);
|
||||
}
|
||||
if (g_xrGetControllerModelPropertiesMSFT == nullptr) {
|
||||
INIT_EXTENSION_FUNCTION(xrGetControllerModelPropertiesMSFT);
|
||||
}
|
||||
if (g_xrGetControllerModelStateMSFT == nullptr) {
|
||||
INIT_EXTENSION_FUNCTION(xrGetControllerModelStateMSFT);
|
||||
}
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name GHOST_XrControllerModel
|
||||
*
|
||||
* \{ */
|
||||
|
||||
GHOST_XrControllerModel::GHOST_XrControllerModel(XrInstance instance,
|
||||
const char *subaction_path_str)
|
||||
{
|
||||
init_controller_model_extension_functions(instance);
|
||||
|
||||
CHECK_XR(xrStringToPath(instance, subaction_path_str, &m_subaction_path),
|
||||
(std::string("Failed to get user path \"") + subaction_path_str + "\".").data());
|
||||
}
|
||||
|
||||
GHOST_XrControllerModel::~GHOST_XrControllerModel()
|
||||
{
|
||||
if (m_load_task.valid()) {
|
||||
m_load_task.wait();
|
||||
}
|
||||
}
|
||||
|
||||
void GHOST_XrControllerModel::load(XrSession session)
|
||||
{
|
||||
if (m_data_loaded || m_load_task.valid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Get model key. */
|
||||
XrControllerModelKeyStateMSFT key_state{XR_TYPE_CONTROLLER_MODEL_KEY_STATE_MSFT};
|
||||
CHECK_XR(g_xrGetControllerModelKeyMSFT(session, m_subaction_path, &key_state),
|
||||
"Failed to get controller model key state.");
|
||||
|
||||
if (key_state.modelKey != XR_NULL_CONTROLLER_MODEL_KEY_MSFT) {
|
||||
m_model_key = key_state.modelKey;
|
||||
/* Load asynchronously. */
|
||||
m_load_task = std::async(std::launch::async,
|
||||
[&, session = session]() { return loadControllerModel(session); });
|
||||
}
|
||||
}
|
||||
|
||||
void GHOST_XrControllerModel::loadControllerModel(XrSession session)
|
||||
{
|
||||
/* Load binary buffers. */
|
||||
uint32_t buf_size = 0;
|
||||
CHECK_XR(g_xrLoadControllerModelMSFT(session, m_model_key, 0, &buf_size, nullptr),
|
||||
"Failed to get controller model buffer size.");
|
||||
|
||||
std::vector<uint8_t> buf((size_t)buf_size);
|
||||
CHECK_XR(g_xrLoadControllerModelMSFT(session, m_model_key, buf_size, &buf_size, buf.data()),
|
||||
"Failed to load controller model binary buffers.");
|
||||
|
||||
/* Convert to glTF model. */
|
||||
tinygltf::TinyGLTF gltf_loader;
|
||||
tinygltf::Model gltf_model;
|
||||
std::string err_msg;
|
||||
{
|
||||
/* Workaround for TINYGLTF_NO_STB_IMAGE define. Set custom image loader to prevent failure when
|
||||
* parsing image data. */
|
||||
auto load_img_func = [](tinygltf::Image *img,
|
||||
const int p0,
|
||||
std::string *p1,
|
||||
std::string *p2,
|
||||
int p3,
|
||||
int p4,
|
||||
const unsigned char *p5,
|
||||
int p6,
|
||||
void *user_pointer) -> bool {
|
||||
(void)img;
|
||||
(void)p0;
|
||||
(void)p1;
|
||||
(void)p2;
|
||||
(void)p3;
|
||||
(void)p4;
|
||||
(void)p5;
|
||||
(void)p6;
|
||||
(void)user_pointer;
|
||||
return true;
|
||||
};
|
||||
gltf_loader.SetImageLoader(load_img_func, nullptr);
|
||||
}
|
||||
|
||||
if (!gltf_loader.LoadBinaryFromMemory(&gltf_model, &err_msg, nullptr, buf.data(), buf_size)) {
|
||||
throw GHOST_XrException(("Failed to load glTF controller model: " + err_msg).c_str());
|
||||
}
|
||||
|
||||
/* Get node properties. */
|
||||
XrControllerModelPropertiesMSFT model_properties{XR_TYPE_CONTROLLER_MODEL_PROPERTIES_MSFT};
|
||||
model_properties.nodeCapacityInput = 0;
|
||||
CHECK_XR(g_xrGetControllerModelPropertiesMSFT(session, m_model_key, &model_properties),
|
||||
"Failed to get controller model node properties count.");
|
||||
|
||||
std::vector<XrControllerModelNodePropertiesMSFT> node_properties(
|
||||
model_properties.nodeCountOutput, {XR_TYPE_CONTROLLER_MODEL_NODE_PROPERTIES_MSFT});
|
||||
model_properties.nodeCapacityInput = (uint32_t)node_properties.size();
|
||||
model_properties.nodeProperties = node_properties.data();
|
||||
CHECK_XR(g_xrGetControllerModelPropertiesMSFT(session, m_model_key, &model_properties),
|
||||
"Failed to get controller model node properties.");
|
||||
|
||||
m_node_state_indices.resize(node_properties.size(), -1);
|
||||
|
||||
/* Get mesh vertex data. */
|
||||
const tinygltf::Scene &default_scene = gltf_model.scenes.at(
|
||||
(gltf_model.defaultScene == -1) ? 0 : gltf_model.defaultScene);
|
||||
const int32_t root_idx = -1;
|
||||
const std::string root_name = "";
|
||||
float root_transform[4][4] = {0};
|
||||
root_transform[0][0] = root_transform[1][1] = root_transform[2][2] = root_transform[3][3] = 1.0f;
|
||||
|
||||
for (const int node_id : default_scene.nodes) {
|
||||
load_node(gltf_model,
|
||||
node_id,
|
||||
root_idx,
|
||||
root_transform,
|
||||
root_name,
|
||||
node_properties,
|
||||
m_vertices,
|
||||
m_indices,
|
||||
m_components,
|
||||
m_nodes,
|
||||
m_node_state_indices);
|
||||
}
|
||||
|
||||
m_data_loaded = true;
|
||||
}
|
||||
|
||||
void GHOST_XrControllerModel::updateComponents(XrSession session)
|
||||
{
|
||||
if (!m_data_loaded) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Get node states. */
|
||||
XrControllerModelStateMSFT model_state{XR_TYPE_CONTROLLER_MODEL_STATE_MSFT};
|
||||
model_state.nodeCapacityInput = 0;
|
||||
CHECK_XR(g_xrGetControllerModelStateMSFT(session, m_model_key, &model_state),
|
||||
"Failed to get controller model node state count.");
|
||||
|
||||
const uint32_t count = model_state.nodeCountOutput;
|
||||
std::vector<XrControllerModelNodeStateMSFT> node_states(
|
||||
count, {XR_TYPE_CONTROLLER_MODEL_NODE_STATE_MSFT});
|
||||
model_state.nodeCapacityInput = count;
|
||||
model_state.nodeStates = node_states.data();
|
||||
CHECK_XR(g_xrGetControllerModelStateMSFT(session, m_model_key, &model_state),
|
||||
"Failed to get controller model node states.");
|
||||
|
||||
/* Update node local transforms. */
|
||||
assert(m_node_state_indices.size() == count);
|
||||
|
||||
for (uint32_t state_idx = 0; state_idx < count; ++state_idx) {
|
||||
const int32_t &node_idx = m_node_state_indices[state_idx];
|
||||
if (node_idx >= 0) {
|
||||
const XrPosef &pose = node_states[state_idx].nodePose;
|
||||
Eigen::Matrix4f &m = *(Eigen::Matrix4f *)m_nodes[node_idx].local_transform;
|
||||
Eigen::Quaternionf q(
|
||||
pose.orientation.w, pose.orientation.x, pose.orientation.y, pose.orientation.z);
|
||||
m.setIdentity();
|
||||
m.block<3, 3>(0, 0) = q.toRotationMatrix();
|
||||
m.block<3, 1>(0, 3) = Eigen::Vector3f(pose.position.x, pose.position.y, pose.position.z);
|
||||
}
|
||||
}
|
||||
|
||||
/* Calculate component transforms (in world space). */
|
||||
std::vector<Eigen::Matrix4f> world_transforms(m_nodes.size());
|
||||
uint32_t i = 0;
|
||||
for (const GHOST_XrControllerModelNode &node : m_nodes) {
|
||||
world_transforms[i] = (node.parent_idx >= 0) ? world_transforms[node.parent_idx] *
|
||||
*(Eigen::Matrix4f *)node.local_transform :
|
||||
*(Eigen::Matrix4f *)node.local_transform;
|
||||
if (node.component_idx >= 0) {
|
||||
memcpy(m_components[node.component_idx].transform,
|
||||
world_transforms[i].data(),
|
||||
sizeof(m_components[node.component_idx].transform));
|
||||
}
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
void GHOST_XrControllerModel::getData(GHOST_XrControllerModelData &r_data)
|
||||
{
|
||||
if (m_data_loaded) {
|
||||
r_data.count_vertices = (uint32_t)m_vertices.size();
|
||||
r_data.vertices = m_vertices.data();
|
||||
r_data.count_indices = (uint32_t)m_indices.size();
|
||||
r_data.indices = m_indices.data();
|
||||
r_data.count_components = (uint32_t)m_components.size();
|
||||
r_data.components = m_components.data();
|
||||
}
|
||||
else {
|
||||
r_data.count_vertices = 0;
|
||||
r_data.vertices = nullptr;
|
||||
r_data.count_indices = 0;
|
||||
r_data.indices = nullptr;
|
||||
r_data.count_components = 0;
|
||||
r_data.components = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
/** \} */
|
59
intern/ghost/intern/GHOST_XrControllerModel.h
Normal file
59
intern/ghost/intern/GHOST_XrControllerModel.h
Normal file
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* \ingroup GHOST
|
||||
*/
|
||||
|
||||
/* Note: Requires OpenXR headers to be included before this one for OpenXR types (XrInstance,
|
||||
* XrSession, etc.). */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
#include <future>
|
||||
#include <vector>
|
||||
|
||||
struct GHOST_XrControllerModelNode;
|
||||
|
||||
/**
|
||||
* OpenXR glTF controller model.
|
||||
*/
|
||||
class GHOST_XrControllerModel {
|
||||
public:
|
||||
GHOST_XrControllerModel(XrInstance instance, const char *subaction_path);
|
||||
~GHOST_XrControllerModel();
|
||||
|
||||
void load(XrSession session);
|
||||
void updateComponents(XrSession session);
|
||||
void getData(GHOST_XrControllerModelData &r_data);
|
||||
|
||||
private:
|
||||
XrPath m_subaction_path = XR_NULL_PATH;
|
||||
XrControllerModelKeyMSFT m_model_key = XR_NULL_CONTROLLER_MODEL_KEY_MSFT;
|
||||
|
||||
std::future<void> m_load_task;
|
||||
std::atomic<bool> m_data_loaded = false;
|
||||
|
||||
std::vector<GHOST_XrControllerModelVertex> m_vertices;
|
||||
std::vector<uint32_t> m_indices;
|
||||
std::vector<GHOST_XrControllerModelComponent> m_components;
|
||||
std::vector<GHOST_XrControllerModelNode> m_nodes;
|
||||
/** Maps node states to nodes. */
|
||||
std::vector<int32_t> m_node_state_indices;
|
||||
|
||||
void loadControllerModel(XrSession session);
|
||||
};
|
@@ -30,6 +30,7 @@
|
||||
#include "GHOST_IXrGraphicsBinding.h"
|
||||
#include "GHOST_XrAction.h"
|
||||
#include "GHOST_XrContext.h"
|
||||
#include "GHOST_XrControllerModel.h"
|
||||
#include "GHOST_XrException.h"
|
||||
#include "GHOST_XrSwapchain.h"
|
||||
#include "GHOST_Xr_intern.h"
|
||||
@@ -52,6 +53,8 @@ struct OpenXRSessionData {
|
||||
std::vector<GHOST_XrSwapchain> swapchains;
|
||||
|
||||
std::map<std::string, GHOST_XrActionSet> action_sets;
|
||||
/* Controller models identified by subaction path. */
|
||||
std::map<std::string, GHOST_XrControllerModel> controller_models;
|
||||
};
|
||||
|
||||
struct GHOST_XrDrawInfo {
|
||||
@@ -916,3 +919,71 @@ void GHOST_XrSession::getActionCustomdataArray(const char *action_set_name,
|
||||
}
|
||||
|
||||
/** \} */ /* Actions */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Controller Model
|
||||
*
|
||||
* \{ */
|
||||
|
||||
bool GHOST_XrSession::loadControllerModel(const char *subaction_path)
|
||||
{
|
||||
if (!m_context->isExtensionEnabled(XR_MSFT_CONTROLLER_MODEL_EXTENSION_NAME)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
XrSession session = m_oxr->session;
|
||||
std::map<std::string, GHOST_XrControllerModel> &controller_models = m_oxr->controller_models;
|
||||
std::map<std::string, GHOST_XrControllerModel>::iterator it = controller_models.find(
|
||||
subaction_path);
|
||||
|
||||
if (it == controller_models.end()) {
|
||||
XrInstance instance = m_context->getInstance();
|
||||
it = controller_models
|
||||
.emplace(std::piecewise_construct,
|
||||
std::make_tuple(subaction_path),
|
||||
std::make_tuple(instance, subaction_path))
|
||||
.first;
|
||||
}
|
||||
|
||||
it->second.load(session);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void GHOST_XrSession::unloadControllerModel(const char *subaction_path)
|
||||
{
|
||||
std::map<std::string, GHOST_XrControllerModel> &controller_models = m_oxr->controller_models;
|
||||
if (controller_models.find(subaction_path) != controller_models.end()) {
|
||||
controller_models.erase(subaction_path);
|
||||
}
|
||||
}
|
||||
|
||||
bool GHOST_XrSession::updateControllerModelComponents(const char *subaction_path)
|
||||
{
|
||||
XrSession session = m_oxr->session;
|
||||
std::map<std::string, GHOST_XrControllerModel>::iterator it = m_oxr->controller_models.find(
|
||||
subaction_path);
|
||||
if (it == m_oxr->controller_models.end()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
it->second.updateComponents(session);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GHOST_XrSession::getControllerModelData(const char *subaction_path,
|
||||
GHOST_XrControllerModelData &r_data)
|
||||
{
|
||||
std::map<std::string, GHOST_XrControllerModel>::iterator it = m_oxr->controller_models.find(
|
||||
subaction_path);
|
||||
if (it == m_oxr->controller_models.end()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
it->second.getData(r_data);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/** \} */ /* Controller Model */
|
@@ -69,10 +69,8 @@ class GHOST_XrSession {
|
||||
const char *const *profile_paths);
|
||||
bool attachActionSets();
|
||||
|
||||
/**
|
||||
* Action functions to be called post-session start.
|
||||
* \param action_set_name: When `nullptr`, all attached action sets will be synced.
|
||||
*/
|
||||
/** Action functions to be called post-session start. */
|
||||
/** param action_set_name : When `nullptr`, all attached action sets will be synced. */
|
||||
bool syncActions(const char *action_set_name = nullptr);
|
||||
bool applyHapticAction(const char *action_set_name,
|
||||
const char *action_name,
|
||||
@@ -84,12 +82,18 @@ class GHOST_XrSession {
|
||||
const char *action_name,
|
||||
const char *subaction_path);
|
||||
|
||||
/* Custom data (owned by Blender, not GHOST) accessors. */
|
||||
/** Custom data (owned by Blender, not GHOST) accessors. */
|
||||
void *getActionSetCustomdata(const char *action_set_name);
|
||||
void *getActionCustomdata(const char *action_set_name, const char *action_name);
|
||||
uint32_t getActionCount(const char *action_set_name);
|
||||
void getActionCustomdataArray(const char *action_set_name, void **r_customdata_array);
|
||||
|
||||
/** Controller model functions. */
|
||||
bool loadControllerModel(const char *subaction_path);
|
||||
void unloadControllerModel(const char *subaction_path);
|
||||
bool updateControllerModelComponents(const char *subaction_path);
|
||||
bool getControllerModelData(const char *subaction_path, GHOST_XrControllerModelData &r_data);
|
||||
|
||||
private:
|
||||
/** Pointer back to context managing this session. Would be nice to avoid, but needed to access
|
||||
* custom callbacks set before session start. */
|
||||
|
@@ -21,6 +21,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <string.h>
|
||||
#include <vector>
|
||||
|
||||
#include "GHOST_Xr_openxr_includes.h"
|
||||
|
Submodule release/scripts/addons updated: f86f25e622...c64726810b
@@ -717,6 +717,12 @@ void map_to_plane_axis_angle_v2_v3v3fl(float r_co[2],
|
||||
const float co[3],
|
||||
const float axis[3],
|
||||
const float angle);
|
||||
void map_to_pixel(int r_co[2],
|
||||
const float co[3],
|
||||
const float viewmat[4][4],
|
||||
const float winmat[4][4],
|
||||
int winx,
|
||||
int winy);
|
||||
|
||||
/********************************** Normals **********************************/
|
||||
|
||||
|
@@ -5277,6 +5277,23 @@ void map_to_plane_axis_angle_v2_v3v3fl(float r_co[2],
|
||||
copy_v2_v2(r_co, tmp);
|
||||
}
|
||||
|
||||
void map_to_pixel(int r_co[2],
|
||||
const float co[3],
|
||||
const float viewmat[4][4],
|
||||
const float winmat[4][4],
|
||||
int winx,
|
||||
int winy)
|
||||
{
|
||||
float persmat[4][4];
|
||||
float vec[3];
|
||||
|
||||
mul_m4_m4m4(persmat, winmat, viewmat);
|
||||
mul_v3_project_m4_v3(vec, persmat, co);
|
||||
|
||||
r_co[0] = (int)(((float)winx / 2.0f) * (1.0f + vec[0]));
|
||||
r_co[1] = (int)(((float)winy / 2.0f) * (1.0f + vec[1]));
|
||||
}
|
||||
|
||||
/********************************* Normals **********************************/
|
||||
|
||||
void accumulate_vertex_normals_tri_v3(float n1[3],
|
||||
|
@@ -2489,6 +2489,10 @@ static void lib_link_wm_xr_data_restore(struct IDNameLib_Map *id_map, wmXrData *
|
||||
{
|
||||
xr_data->session_settings.base_pose_object = restore_pointer_by_name(
|
||||
id_map, (ID *)xr_data->session_settings.base_pose_object, USER_REAL);
|
||||
|
||||
LISTBASE_FOREACH (XrMotionCaptureObject *, mocap_ob, &xr_data->session_settings.mocap_objects) {
|
||||
mocap_ob->ob = restore_pointer_by_name(id_map, (ID *)mocap_ob->ob, USER_REAL);
|
||||
}
|
||||
}
|
||||
|
||||
static void lib_link_window_scene_data_restore(wmWindow *win, Scene *scene, ViewLayer *view_layer)
|
||||
|
@@ -1189,6 +1189,14 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
|
||||
}
|
||||
}
|
||||
|
||||
if (!MAIN_VERSION_ATLEAST(bmain, 300, 7)) {
|
||||
LISTBASE_FOREACH (wmWindowManager *, wm, &bmain->wm) {
|
||||
wm->xr.session_settings.draw_flags |= (V3D_OFSDRAW_SHOW_SELECTION |
|
||||
V3D_OFSDRAW_XR_SHOW_CONTROLLERS |
|
||||
V3D_OFSDRAW_XR_SHOW_CUSTOM_OVERLAYS);
|
||||
}
|
||||
}
|
||||
|
||||
if (!MAIN_VERSION_ATLEAST(bmain, 300, 8)) {
|
||||
LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
|
||||
if (scene->master_collection != NULL) {
|
||||
|
@@ -200,6 +200,15 @@ void OVERLAY_grid_init(OVERLAY_Data *vedata)
|
||||
shd->grid_distance = dist / 2.0f;
|
||||
|
||||
ED_view3d_grid_steps(scene, v3d, rv3d, shd->grid_steps);
|
||||
|
||||
if (((v3d->flag & V3D_XR_SESSION_SURFACE) != 0) || ((v3d->flag & V3D_XR_SESSION_MIRROR) != 0)) {
|
||||
/* The calculations for the grid parameters assume that the view matrix has no scale component,
|
||||
* which may not be correct if the user is "shrunk" or "enlarged" by zooming in or out.
|
||||
* Therefore, we need to compensate the values here. */
|
||||
float viewinvscale = len_v3(
|
||||
viewinv[0]); /* Assumption is uniform scaling (all column vectors are of same length). */
|
||||
shd->grid_distance *= viewinvscale;
|
||||
}
|
||||
}
|
||||
|
||||
void OVERLAY_grid_cache_init(OVERLAY_Data *vedata)
|
||||
|
@@ -51,6 +51,7 @@
|
||||
#include "BKE_pbvh.h"
|
||||
#include "BKE_pointcache.h"
|
||||
#include "BKE_pointcloud.h"
|
||||
#include "BKE_screen.h"
|
||||
#include "BKE_volume.h"
|
||||
|
||||
#include "DNA_camera_types.h"
|
||||
@@ -1402,6 +1403,27 @@ void DRW_draw_callbacks_post_scene(void)
|
||||
|
||||
ED_region_draw_cb_draw(DST.draw_ctx.evil_C, DST.draw_ctx.region, REGION_DRAW_POST_VIEW);
|
||||
|
||||
#ifdef WITH_XR_OPENXR
|
||||
/* XR callbacks (controllers, custom draw functions). */
|
||||
if ((v3d->flag & V3D_XR_SESSION_MIRROR) != 0) {
|
||||
if ((v3d->flag2 & V3D_XR_SHOW_CONTROLLERS) != 0) {
|
||||
ARegionType *art = WM_xr_surface_controller_region_type_get();
|
||||
if (art) {
|
||||
ED_region_surface_draw_cb_draw(art, REGION_DRAW_POST_VIEW);
|
||||
}
|
||||
}
|
||||
if ((v3d->flag2 & V3D_XR_SHOW_CUSTOM_OVERLAYS) != 0) {
|
||||
SpaceType *st = BKE_spacetype_from_id(SPACE_VIEW3D);
|
||||
if (st) {
|
||||
ARegionType *art = BKE_regiontype_from_id(st, RGN_TYPE_XR);
|
||||
if (art) {
|
||||
ED_region_surface_draw_cb_draw(art, REGION_DRAW_POST_VIEW);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Callback can be nasty and do whatever they want with the state.
|
||||
* Don't trust them! */
|
||||
DRW_state_reset();
|
||||
@@ -1448,6 +1470,46 @@ void DRW_draw_callbacks_post_scene(void)
|
||||
ED_annotation_draw_view3d(DEG_get_input_scene(depsgraph), depsgraph, v3d, region, true);
|
||||
GPU_depth_test(GPU_DEPTH_LESS_EQUAL);
|
||||
}
|
||||
|
||||
#ifdef WITH_XR_OPENXR
|
||||
if ((v3d->flag & V3D_XR_SESSION_SURFACE) != 0) {
|
||||
DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
|
||||
|
||||
DRW_state_reset();
|
||||
|
||||
GPU_framebuffer_bind(dfbl->overlay_fb);
|
||||
|
||||
GPU_matrix_projection_set(rv3d->winmat);
|
||||
GPU_matrix_set(rv3d->viewmat);
|
||||
|
||||
/* Callbacks (controllers, custom draw functions). */
|
||||
if (((v3d->flag2 & V3D_XR_SHOW_CONTROLLERS) != 0) ||
|
||||
((v3d->flag2 & V3D_XR_SHOW_CUSTOM_OVERLAYS) != 0)) {
|
||||
GPU_depth_test(GPU_DEPTH_NONE);
|
||||
GPU_apply_state();
|
||||
|
||||
if ((v3d->flag2 & V3D_XR_SHOW_CONTROLLERS) != 0) {
|
||||
ARegionType *art = WM_xr_surface_controller_region_type_get();
|
||||
if (art) {
|
||||
ED_region_surface_draw_cb_draw(art, REGION_DRAW_POST_VIEW);
|
||||
}
|
||||
}
|
||||
if ((v3d->flag2 & V3D_XR_SHOW_CUSTOM_OVERLAYS) != 0) {
|
||||
SpaceType *st = BKE_spacetype_from_id(SPACE_VIEW3D);
|
||||
if (st) {
|
||||
ARegionType *art = BKE_regiontype_from_id(st, RGN_TYPE_XR);
|
||||
if (art) {
|
||||
ED_region_surface_draw_cb_draw(art, REGION_DRAW_POST_VIEW);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DRW_state_reset();
|
||||
}
|
||||
|
||||
GPU_depth_test(GPU_DEPTH_LESS_EQUAL);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -1682,10 +1682,12 @@ static void draw_frustum_bound_sphere_calc(const BoundBox *bbox,
|
||||
bsphere->center[0] = farcenter[0] * z / e;
|
||||
bsphere->center[1] = farcenter[1] * z / e;
|
||||
bsphere->center[2] = z;
|
||||
bsphere->radius = len_v3v3(bsphere->center, farpoint);
|
||||
|
||||
/* Transform to world space. */
|
||||
mul_m4_v3(viewinv, bsphere->center);
|
||||
/* For XR, the view matrix may contain a scale factor. Then, transforming only the center
|
||||
* into world space after calculating the radius will result in incorrect behavior. */
|
||||
mul_m4_v3(viewinv, bsphere->center); /* Transform to world space. */
|
||||
mul_m4_v3(viewinv, farpoint);
|
||||
bsphere->radius = len_v3v3(bsphere->center, farpoint);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -72,7 +72,8 @@ void *ED_region_draw_cb_activate(struct ARegionType *art,
|
||||
void (*draw)(const struct bContext *, struct ARegion *, void *),
|
||||
void *customdata,
|
||||
int type);
|
||||
void ED_region_draw_cb_draw(const struct bContext *, struct ARegion *, int);
|
||||
void ED_region_draw_cb_draw(const struct bContext *C, struct ARegion *region, int type);
|
||||
void ED_region_surface_draw_cb_draw(struct ARegionType *art, int type);
|
||||
void ED_region_draw_cb_exit(struct ARegionType *, void *);
|
||||
void ED_region_draw_cb_remove_by_type(struct ARegionType *art,
|
||||
void *draw_fn,
|
||||
|
@@ -31,8 +31,10 @@ extern "C" {
|
||||
|
||||
struct Object;
|
||||
struct bContext;
|
||||
struct ViewLayer;
|
||||
struct wmKeyConfig;
|
||||
struct wmOperatorType;
|
||||
struct wmTimer;
|
||||
|
||||
void ED_keymap_transform(struct wmKeyConfig *keyconf);
|
||||
void transform_operatortypes(void);
|
||||
@@ -193,6 +195,19 @@ int ED_transform_calc_gizmo_stats(const struct bContext *C,
|
||||
const struct TransformCalcParams *params,
|
||||
struct TransformBounds *tbounds);
|
||||
|
||||
/* transform_convert.c */
|
||||
void ED_transform_animrecord_check_state(struct Scene *scene,
|
||||
struct wmTimer *animtimer,
|
||||
struct Object *ob);
|
||||
|
||||
/* transform_convert_object.c */
|
||||
void ED_transform_autokeyframe_object(struct bContext *C,
|
||||
struct Scene *scene,
|
||||
struct ViewLayer *view_layer,
|
||||
struct Object *ob,
|
||||
int tmode);
|
||||
bool ED_transform_motionpath_need_update_object(struct Scene *scene, struct Object *ob);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@@ -44,6 +44,8 @@ typedef enum {
|
||||
SNAP_NOT_SELECTED = 1,
|
||||
SNAP_NOT_ACTIVE = 2,
|
||||
SNAP_ONLY_ACTIVE = 3,
|
||||
SNAP_SELECTED = 4,
|
||||
SNAP_SELECTABLE = 5,
|
||||
} eSnapSelect;
|
||||
|
||||
typedef enum {
|
||||
|
@@ -595,6 +595,7 @@ void ED_view3d_viewcontext_init(struct bContext *C,
|
||||
void ED_view3d_viewcontext_init_object(struct ViewContext *vc, struct Object *obact);
|
||||
void view3d_operator_needs_opengl(const struct bContext *C);
|
||||
void view3d_region_operator_needs_opengl(struct wmWindow *win, struct ARegion *region);
|
||||
bool object_deselect_all_except(struct ViewLayer *view_layer, struct Base *b);
|
||||
|
||||
/* XXX should move to BLI_math */
|
||||
bool edge_inside_circle(const float cent[2],
|
||||
@@ -776,12 +777,27 @@ void ED_view3d_buttons_region_layout_ex(const struct bContext *C,
|
||||
bool ED_view3d_local_collections_set(struct Main *bmain, struct View3D *v3d);
|
||||
void ED_view3d_local_collections_reset(struct bContext *C, const bool reset_all);
|
||||
|
||||
void ED_view3d_view_params_get(const struct View3D *v3d,
|
||||
const struct RegionView3D *rv3d,
|
||||
float *r_lens,
|
||||
float *r_clip_start,
|
||||
float *r_clip_end,
|
||||
float r_viewmat[4][4]);
|
||||
void ED_view3d_view_params_set(struct Depsgraph *depsgraph,
|
||||
struct Scene *scene,
|
||||
struct View3D *v3d,
|
||||
struct ARegion *region,
|
||||
const float lens,
|
||||
const float clip_start,
|
||||
const float clip_end,
|
||||
const float viewmat[4][4]);
|
||||
|
||||
#ifdef WITH_XR_OPENXR
|
||||
void ED_view3d_xr_mirror_update(const struct ScrArea *area,
|
||||
const struct View3D *v3d,
|
||||
const bool enable);
|
||||
void ED_view3d_xr_shading_update(struct wmWindowManager *wm,
|
||||
const View3D *v3d,
|
||||
const struct View3D *v3d,
|
||||
const struct Scene *scene);
|
||||
bool ED_view3d_is_region_xr_mirror_active(const struct wmWindowManager *wm,
|
||||
const struct View3D *v3d,
|
||||
|
@@ -60,7 +60,7 @@ void ED_view3d_draw_offscreen(struct Depsgraph *depsgraph,
|
||||
void ED_view3d_draw_offscreen_simple(struct Depsgraph *depsgraph,
|
||||
struct Scene *scene,
|
||||
struct View3DShading *shading_override,
|
||||
int drawtype,
|
||||
eDrawType drawtype,
|
||||
int winx,
|
||||
int winy,
|
||||
unsigned int draw_flags,
|
||||
@@ -68,6 +68,7 @@ void ED_view3d_draw_offscreen_simple(struct Depsgraph *depsgraph,
|
||||
const float winmat[4][4],
|
||||
float clip_start,
|
||||
float clip_end,
|
||||
bool is_xr_surface,
|
||||
bool is_image_render,
|
||||
bool draw_background,
|
||||
const char *viewname,
|
||||
|
@@ -2192,6 +2192,7 @@ void uiTemplateEditModeSelection(uiLayout *layout, struct bContext *C);
|
||||
void uiTemplateReportsBanner(uiLayout *layout, struct bContext *C);
|
||||
void uiTemplateInputStatus(uiLayout *layout, struct bContext *C);
|
||||
void uiTemplateKeymapItemProperties(uiLayout *layout, struct PointerRNA *ptr);
|
||||
void uiTemplateXrActionmapItemProperties(uiLayout *layout, struct PointerRNA *ptr);
|
||||
|
||||
bool uiTemplateEventFromKeymapItem(struct uiLayout *layout,
|
||||
const char *text,
|
||||
|
@@ -113,5 +113,8 @@ if(WIN32 OR APPLE)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(WITH_XR_OPENXR)
|
||||
add_definitions(-DWITH_XR_OPENXR)
|
||||
endif()
|
||||
|
||||
blender_add_lib(bf_editor_interface "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
|
||||
|
@@ -6235,6 +6235,44 @@ void uiTemplateKeymapItemProperties(uiLayout *layout, PointerRNA *ptr)
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name XR Actionmap Template
|
||||
* \{ */
|
||||
|
||||
#ifdef WITH_XR_OPENXR
|
||||
static void xr_actionmap_item_modified(bContext *UNUSED(C), void *ami_p, void *UNUSED(unused))
|
||||
{
|
||||
XrActionMapItem *ami = (XrActionMapItem *)ami_p;
|
||||
WM_xr_actionconfig_update_tag(NULL, ami);
|
||||
}
|
||||
#endif
|
||||
|
||||
void uiTemplateXrActionmapItemProperties(uiLayout *layout, PointerRNA *ptr)
|
||||
{
|
||||
#ifdef WITH_XR_OPENXR
|
||||
PointerRNA propptr = RNA_pointer_get(ptr, "op_properties");
|
||||
|
||||
if (propptr.data) {
|
||||
uiBut *but = uiLayoutGetBlock(layout)->buttons.last;
|
||||
|
||||
WM_operator_properties_sanitize(&propptr, false);
|
||||
/* Use same template as keymap item properties. */
|
||||
template_keymap_item_properties(layout, NULL, &propptr);
|
||||
|
||||
for (; but; but = but->next) {
|
||||
if (but->rnaprop) {
|
||||
UI_but_func_set(but, xr_actionmap_item_modified, ptr->data, NULL);
|
||||
UI_but_flag_enable(but, UI_BUT_UPDATE_DELAY);
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
UNUSED_VARS(layout, ptr);
|
||||
#endif
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Event Icon Template
|
||||
* \{ */
|
||||
|
@@ -264,9 +264,9 @@ void ED_region_draw_cb_exit(ARegionType *art, void *handle)
|
||||
}
|
||||
}
|
||||
|
||||
void ED_region_draw_cb_draw(const bContext *C, ARegion *region, int type)
|
||||
static void ed_region_draw_cb_draw(const bContext *C, ARegion *region, ARegionType *art, int type)
|
||||
{
|
||||
LISTBASE_FOREACH_MUTABLE (RegionDrawCB *, rdc, ®ion->type->drawcalls) {
|
||||
LISTBASE_FOREACH_MUTABLE (RegionDrawCB *, rdc, &art->drawcalls) {
|
||||
if (rdc->type == type) {
|
||||
rdc->draw(C, region, rdc->customdata);
|
||||
|
||||
@@ -276,6 +276,16 @@ void ED_region_draw_cb_draw(const bContext *C, ARegion *region, int type)
|
||||
}
|
||||
}
|
||||
|
||||
void ED_region_draw_cb_draw(const bContext *C, ARegion *region, int type)
|
||||
{
|
||||
ed_region_draw_cb_draw(C, region, region->type, type);
|
||||
}
|
||||
|
||||
void ED_region_surface_draw_cb_draw(ARegionType *art, int type)
|
||||
{
|
||||
ed_region_draw_cb_draw(NULL, NULL, art, type);
|
||||
}
|
||||
|
||||
void ED_region_draw_cb_remove_by_type(ARegionType *art, void *draw_fn, void (*free)(void *))
|
||||
{
|
||||
LISTBASE_FOREACH_MUTABLE (RegionDrawCB *, rdc, &art->drawcalls) {
|
||||
|
@@ -1798,5 +1798,10 @@ void ED_spacetype_view3d(void)
|
||||
art = ED_area_type_hud(st->spaceid);
|
||||
BLI_addhead(&st->regiontypes, art);
|
||||
|
||||
/* regions: xr */
|
||||
art = MEM_callocN(sizeof(ARegionType), "spacetype view3d xr region");
|
||||
art->regionid = RGN_TYPE_XR;
|
||||
BLI_addhead(&st->regiontypes, art);
|
||||
|
||||
BKE_spacetype_register(st);
|
||||
}
|
||||
|
@@ -328,19 +328,44 @@ static void view3d_xr_mirror_setup(const wmWindowManager *wm,
|
||||
ARegion *region,
|
||||
const rcti *rect)
|
||||
{
|
||||
RegionView3D *rv3d = region->regiondata;
|
||||
float viewmat[4][4];
|
||||
const float lens_old = v3d->lens;
|
||||
const float clip_start_old = v3d->clip_start;
|
||||
const float clip_end_old = v3d->clip_end;
|
||||
/* Here we need to use the viewmat from the selection eye instead of the eye centroid because
|
||||
* this function may be called from a GPU select operation. In that case we need to match the
|
||||
* selection eye's view, which was used to project 3D to 2D, for a correct result. */
|
||||
const bool from_selection_eye = true;
|
||||
|
||||
if (!WM_xr_session_state_viewer_pose_matrix_info_get(&wm->xr, viewmat, &v3d->lens)) {
|
||||
if (!WM_xr_session_state_viewer_pose_matrix_info_get(
|
||||
&wm->xr, from_selection_eye, viewmat, &v3d->lens, &v3d->clip_start, &v3d->clip_end)) {
|
||||
/* Can't get info from XR session, use fallback values. */
|
||||
copy_m4_m4(viewmat, rv3d->viewmat);
|
||||
copy_m4_m4(viewmat, ((RegionView3D *)region->regiondata)->viewmat);
|
||||
v3d->lens = lens_old;
|
||||
v3d->clip_start = clip_start_old;
|
||||
v3d->clip_end = clip_end_old;
|
||||
}
|
||||
view3d_main_region_setup_view(depsgraph, scene, v3d, region, viewmat, NULL, rect);
|
||||
|
||||
/* Reset overridden View3D data */
|
||||
if ((wm->xr.session_settings.draw_flags & V3D_OFSDRAW_XR_SHOW_CONTROLLERS) != 0) {
|
||||
v3d->flag2 |= V3D_XR_SHOW_CONTROLLERS;
|
||||
}
|
||||
else {
|
||||
v3d->flag2 &= ~V3D_XR_SHOW_CONTROLLERS;
|
||||
}
|
||||
if ((wm->xr.session_settings.draw_flags & V3D_OFSDRAW_XR_SHOW_CUSTOM_OVERLAYS) != 0) {
|
||||
v3d->flag2 |= V3D_XR_SHOW_CUSTOM_OVERLAYS;
|
||||
}
|
||||
else {
|
||||
v3d->flag2 &= ~V3D_XR_SHOW_CUSTOM_OVERLAYS;
|
||||
}
|
||||
/* Hide navigation gizmo. */
|
||||
v3d->gizmo_flag |= V3D_GIZMO_HIDE_NAVIGATE;
|
||||
|
||||
/* Reset overridden View3D data. */
|
||||
v3d->lens = lens_old;
|
||||
v3d->clip_start = clip_start_old;
|
||||
v3d->clip_end = clip_end_old;
|
||||
}
|
||||
#endif /* WITH_XR_OPENXR */
|
||||
|
||||
@@ -1750,7 +1775,7 @@ void ED_view3d_draw_offscreen(Depsgraph *depsgraph,
|
||||
void ED_view3d_draw_offscreen_simple(Depsgraph *depsgraph,
|
||||
Scene *scene,
|
||||
View3DShading *shading_override,
|
||||
int drawtype,
|
||||
eDrawType drawtype,
|
||||
int winx,
|
||||
int winy,
|
||||
uint draw_flags,
|
||||
@@ -1758,6 +1783,7 @@ void ED_view3d_draw_offscreen_simple(Depsgraph *depsgraph,
|
||||
const float winmat[4][4],
|
||||
float clip_start,
|
||||
float clip_end,
|
||||
bool is_xr_surface,
|
||||
bool is_image_render,
|
||||
bool draw_background,
|
||||
const char *viewname,
|
||||
@@ -1787,23 +1813,37 @@ void ED_view3d_draw_offscreen_simple(Depsgraph *depsgraph,
|
||||
v3d.shading.flag = V3D_SHADING_SCENE_WORLD | V3D_SHADING_SCENE_LIGHTS;
|
||||
}
|
||||
|
||||
if (draw_flags & V3D_OFSDRAW_SHOW_ANNOTATION) {
|
||||
v3d.flag2 |= V3D_SHOW_ANNOTATION;
|
||||
if ((draw_flags & ~V3D_OFSDRAW_OVERRIDE_SCENE_SETTINGS) == V3D_OFSDRAW_NONE) {
|
||||
v3d.flag2 = V3D_HIDE_OVERLAYS;
|
||||
}
|
||||
if (draw_flags & V3D_OFSDRAW_SHOW_GRIDFLOOR) {
|
||||
v3d.gridflag |= V3D_SHOW_FLOOR | V3D_SHOW_X | V3D_SHOW_Y;
|
||||
v3d.grid = 1.0f;
|
||||
v3d.gridlines = 16;
|
||||
v3d.gridsubdiv = 10;
|
||||
|
||||
/* Show grid, disable other overlays (set all available _HIDE_ flags). */
|
||||
else {
|
||||
if (draw_flags & V3D_OFSDRAW_SHOW_ANNOTATION) {
|
||||
v3d.flag2 |= V3D_SHOW_ANNOTATION;
|
||||
}
|
||||
if (draw_flags & V3D_OFSDRAW_SHOW_GRIDFLOOR) {
|
||||
v3d.gridflag |= V3D_SHOW_FLOOR | V3D_SHOW_X | V3D_SHOW_Y;
|
||||
v3d.grid = 1.0f;
|
||||
v3d.gridlines = 16;
|
||||
v3d.gridsubdiv = 10;
|
||||
}
|
||||
if (draw_flags & V3D_OFSDRAW_SHOW_SELECTION) {
|
||||
v3d.flag |= V3D_SELECT_OUTLINE;
|
||||
}
|
||||
if (draw_flags & V3D_OFSDRAW_XR_SHOW_CONTROLLERS) {
|
||||
v3d.flag2 |= V3D_XR_SHOW_CONTROLLERS;
|
||||
}
|
||||
if (draw_flags & V3D_OFSDRAW_XR_SHOW_CUSTOM_OVERLAYS) {
|
||||
v3d.flag2 |= V3D_XR_SHOW_CUSTOM_OVERLAYS;
|
||||
}
|
||||
/* Disable other overlays (set all available _HIDE_ flags). */
|
||||
v3d.overlay.flag |= V3D_OVERLAY_HIDE_CURSOR | V3D_OVERLAY_HIDE_TEXT |
|
||||
V3D_OVERLAY_HIDE_MOTION_PATHS | V3D_OVERLAY_HIDE_BONES |
|
||||
V3D_OVERLAY_HIDE_OBJECT_XTRAS | V3D_OVERLAY_HIDE_OBJECT_ORIGINS;
|
||||
v3d.flag |= V3D_HIDE_HELPLINES;
|
||||
}
|
||||
else {
|
||||
v3d.flag2 = V3D_HIDE_OVERLAYS;
|
||||
|
||||
if (is_xr_surface) {
|
||||
v3d.flag |= V3D_XR_SESSION_SURFACE;
|
||||
}
|
||||
|
||||
rv3d.persp = RV3D_PERSP;
|
||||
|
@@ -169,7 +169,7 @@ static bool object_deselect_all_visible(ViewLayer *view_layer, View3D *v3d)
|
||||
}
|
||||
|
||||
/* deselect all except b */
|
||||
static bool object_deselect_all_except(ViewLayer *view_layer, Base *b)
|
||||
bool object_deselect_all_except(ViewLayer *view_layer, Base *b)
|
||||
{
|
||||
bool changed = false;
|
||||
LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
|
||||
@@ -2818,6 +2818,57 @@ static int view3d_select_invoke(bContext *C, wmOperator *op, const wmEvent *even
|
||||
return WM_operator_flag_only_pass_through_on_press(retval, event);
|
||||
}
|
||||
|
||||
static int view3d_select_invoke_3d(bContext *C, wmOperator *op, const wmEvent *event)
|
||||
{
|
||||
BLI_assert(event->type == EVT_XR_ACTION);
|
||||
BLI_assert(event->custom == EVT_DATA_XR);
|
||||
BLI_assert(event->customdata);
|
||||
|
||||
const wmXrActionData *actiondata = event->customdata;
|
||||
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
View3D *v3d = CTX_wm_view3d(C);
|
||||
ARegion *region = CTX_wm_region(C);
|
||||
RegionView3D *rv3d = region->regiondata;
|
||||
wmWindowManager *wm = CTX_wm_manager(C);
|
||||
wmXrData *xr = &wm->xr;
|
||||
float lens_prev;
|
||||
float clip_start_prev, clip_end_prev;
|
||||
float viewmat_prev[4][4];
|
||||
int mval[2];
|
||||
int retval;
|
||||
|
||||
/* Since this function is called in a window context, we need to replace the
|
||||
* window view parameters with the XR surface counterparts to get a correct
|
||||
* result for GPU select. */
|
||||
ED_view3d_view_params_get(v3d, rv3d, &lens_prev, &clip_start_prev, &clip_end_prev, viewmat_prev);
|
||||
ED_view3d_view_params_set(depsgraph,
|
||||
scene,
|
||||
v3d,
|
||||
region,
|
||||
actiondata->eye_lens,
|
||||
xr->session_settings.clip_start,
|
||||
xr->session_settings.clip_end,
|
||||
actiondata->eye_viewmat);
|
||||
|
||||
map_to_pixel(mval,
|
||||
actiondata->controller_loc,
|
||||
actiondata->eye_viewmat,
|
||||
rv3d->winmat,
|
||||
region->winx,
|
||||
region->winy);
|
||||
|
||||
RNA_int_set_array(op->ptr, "location", mval);
|
||||
|
||||
retval = view3d_select_exec(C, op);
|
||||
|
||||
/* Restore window view. */
|
||||
ED_view3d_view_params_set(
|
||||
depsgraph, scene, v3d, region, lens_prev, clip_start_prev, clip_end_prev, viewmat_prev);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
void VIEW3D_OT_select(wmOperatorType *ot)
|
||||
{
|
||||
PropertyRNA *prop;
|
||||
@@ -2829,6 +2880,7 @@ void VIEW3D_OT_select(wmOperatorType *ot)
|
||||
|
||||
/* api callbacks */
|
||||
ot->invoke = view3d_select_invoke;
|
||||
ot->invoke_3d = view3d_select_invoke_3d;
|
||||
ot->exec = view3d_select_exec;
|
||||
ot->poll = ED_operator_view3d_active;
|
||||
|
||||
@@ -3698,8 +3750,10 @@ void VIEW3D_OT_select_box(wmOperatorType *ot)
|
||||
|
||||
/* api callbacks */
|
||||
ot->invoke = WM_gesture_box_invoke;
|
||||
ot->invoke_3d = WM_gesture_box_invoke_3d;
|
||||
ot->exec = view3d_box_select_exec;
|
||||
ot->modal = WM_gesture_box_modal;
|
||||
ot->modal_3d = WM_gesture_box_modal_3d;
|
||||
ot->poll = view3d_selectable_data;
|
||||
ot->cancel = WM_gesture_box_cancel;
|
||||
|
||||
|
@@ -1692,6 +1692,44 @@ void ED_view3d_local_collections_reset(struct bContext *C, const bool reset_all)
|
||||
/** \name XR Functionality
|
||||
* \{ */
|
||||
|
||||
/* Used for invoke_3d/modal_3d (XR) operators. */
|
||||
void ED_view3d_view_params_get(const struct View3D *v3d,
|
||||
const struct RegionView3D *rv3d,
|
||||
float *r_lens,
|
||||
float *r_clip_start,
|
||||
float *r_clip_end,
|
||||
float r_viewmat[4][4])
|
||||
{
|
||||
*r_lens = v3d->lens;
|
||||
*r_clip_start = v3d->clip_start;
|
||||
*r_clip_end = v3d->clip_end;
|
||||
|
||||
if (r_viewmat) {
|
||||
copy_m4_m4(r_viewmat, rv3d->viewmat);
|
||||
}
|
||||
}
|
||||
|
||||
void ED_view3d_view_params_set(struct Depsgraph *depsgraph,
|
||||
struct Scene *scene,
|
||||
struct View3D *v3d,
|
||||
struct ARegion *region,
|
||||
const float lens,
|
||||
const float clip_start,
|
||||
const float clip_end,
|
||||
const float viewmat[4][4])
|
||||
{
|
||||
v3d->lens = lens;
|
||||
v3d->clip_start = clip_start;
|
||||
v3d->clip_end = clip_end;
|
||||
|
||||
if (viewmat) {
|
||||
ED_view3d_update_viewmat(depsgraph, scene, v3d, region, viewmat, NULL, NULL, false);
|
||||
}
|
||||
else {
|
||||
view3d_winmatrix_set(depsgraph, region, v3d, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef WITH_XR_OPENXR
|
||||
|
||||
static void view3d_xr_mirror_begin(RegionView3D *rv3d)
|
||||
@@ -1729,8 +1767,6 @@ void ED_view3d_xr_shading_update(wmWindowManager *wm, const View3D *v3d, const S
|
||||
{
|
||||
if (v3d->runtime.flag & V3D_RUNTIME_XR_SESSION_ROOT) {
|
||||
View3DShading *xr_shading = &wm->xr.session_settings.shading;
|
||||
/* Flags that shouldn't be overridden by the 3D View shading. */
|
||||
const int flag_copy = V3D_SHADING_WORLD_ORIENTATION;
|
||||
|
||||
BLI_assert(WM_xr_session_exists(&wm->xr));
|
||||
|
||||
@@ -1748,9 +1784,7 @@ void ED_view3d_xr_shading_update(wmWindowManager *wm, const View3D *v3d, const S
|
||||
}
|
||||
|
||||
/* Copy shading from View3D to VR view. */
|
||||
const int old_xr_shading_flag = xr_shading->flag;
|
||||
*xr_shading = v3d->shading;
|
||||
xr_shading->flag = (xr_shading->flag & ~flag_copy) | (old_xr_shading_flag & flag_copy);
|
||||
if (v3d->shading.prop) {
|
||||
xr_shading->prop = IDP_CopyProperty(xr_shading->prop);
|
||||
}
|
||||
|
@@ -129,5 +129,8 @@ if(WITH_INTERNATIONAL)
|
||||
add_definitions(-DWITH_INTERNATIONAL)
|
||||
endif()
|
||||
|
||||
if(WITH_XR_OPENXR)
|
||||
add_definitions(-DWITH_XR_OPENXR)
|
||||
endif()
|
||||
|
||||
blender_add_lib(bf_editor_transform "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
|
||||
|
@@ -1597,11 +1597,9 @@ void transform_convert_clip_mirror_modifier_apply(TransDataContainer *tc)
|
||||
}
|
||||
|
||||
/* for the realtime animation recording feature, handle overlapping data */
|
||||
void animrecord_check_state(TransInfo *t, struct Object *ob)
|
||||
void ED_transform_animrecord_check_state(Scene *scene, wmTimer *animtimer, struct Object *ob)
|
||||
{
|
||||
Scene *scene = t->scene;
|
||||
ID *id = &ob->id;
|
||||
wmTimer *animtimer = t->animtimer;
|
||||
ScreenAnimData *sad = (animtimer) ? animtimer->customdata : NULL;
|
||||
|
||||
/* sanity checks */
|
||||
|
@@ -65,7 +65,6 @@ struct TransDataCurveHandleFlags *initTransDataCurveHandles(TransData *td, struc
|
||||
char transform_convert_frame_side_dir_get(TransInfo *t, float cframe);
|
||||
bool FrameOnMouseSide(char side, float frame, float cframe);
|
||||
void transform_convert_clip_mirror_modifier_apply(TransDataContainer *tc);
|
||||
void animrecord_check_state(TransInfo *t, struct Object *ob);
|
||||
|
||||
/* transform_convert_action.c */
|
||||
void createTransActionData(bContext *C, TransInfo *t);
|
||||
|
@@ -1449,7 +1449,7 @@ void recalcData_pose(TransInfo *t)
|
||||
/* XXX: this currently doesn't work, since flags aren't set yet! */
|
||||
int targetless_ik = (t->flag & T_AUTOIK);
|
||||
|
||||
animrecord_check_state(t, ob);
|
||||
ED_transform_animrecord_check_state(t->scene, t->animtimer, ob);
|
||||
autokeyframe_pose(t->context, t->scene, ob, t->mode, targetless_ik);
|
||||
}
|
||||
|
||||
|
@@ -728,7 +728,7 @@ void createTransObject(bContext *C, TransInfo *t)
|
||||
* \note Context may not always be available,
|
||||
* so must check before using it as it's a luxury for a few cases.
|
||||
*/
|
||||
static void autokeyframe_object(
|
||||
void ED_transform_autokeyframe_object(
|
||||
bContext *C, Scene *scene, ViewLayer *view_layer, Object *ob, int tmode)
|
||||
{
|
||||
Main *bmain = CTX_data_main(C);
|
||||
@@ -850,7 +850,7 @@ static void autokeyframe_object(
|
||||
|
||||
/* Return if we need to update motion paths, only if they already exist,
|
||||
* and we will insert a keyframe at the end of transform. */
|
||||
static bool motionpath_need_update_object(Scene *scene, Object *ob)
|
||||
bool ED_transform_motionpath_need_update_object(Scene *scene, Object *ob)
|
||||
{
|
||||
/* XXX: there's potential here for problems with unkeyed rotations/scale,
|
||||
* but for now (until proper data-locality for baking operations),
|
||||
@@ -895,11 +895,11 @@ void recalcData_objects(TransInfo *t)
|
||||
/* TODO: autokeyframe calls need some setting to specify to add samples
|
||||
* (FPoints) instead of keyframes? */
|
||||
if ((t->animtimer) && IS_AUTOKEY_ON(t->scene)) {
|
||||
animrecord_check_state(t, ob);
|
||||
autokeyframe_object(t->context, t->scene, t->view_layer, ob, t->mode);
|
||||
ED_transform_animrecord_check_state(t->scene, t->animtimer, ob);
|
||||
ED_transform_autokeyframe_object(t->context, t->scene, t->view_layer, ob, t->mode);
|
||||
}
|
||||
|
||||
motionpath_update |= motionpath_need_update_object(t->scene, ob);
|
||||
motionpath_update |= ED_transform_motionpath_need_update_object(t->scene, ob);
|
||||
|
||||
/* sets recalc flags fully, instead of flushing existing ones
|
||||
* otherwise proxies don't function correctly
|
||||
@@ -971,10 +971,10 @@ void special_aftertrans_update__object(bContext *C, TransInfo *t)
|
||||
|
||||
/* Set auto-key if necessary. */
|
||||
if (!canceled) {
|
||||
autokeyframe_object(C, t->scene, t->view_layer, ob, t->mode);
|
||||
ED_transform_autokeyframe_object(C, t->scene, t->view_layer, ob, t->mode);
|
||||
}
|
||||
|
||||
motionpath_update |= motionpath_need_update_object(t->scene, ob);
|
||||
motionpath_update |= ED_transform_motionpath_need_update_object(t->scene, ob);
|
||||
|
||||
/* Restore rigid body transform. */
|
||||
if (ob->rigidbody_object && canceled) {
|
||||
|
@@ -470,6 +470,68 @@ static int transform_modal(bContext *C, wmOperator *op, const wmEvent *event)
|
||||
return exit_code;
|
||||
}
|
||||
|
||||
static int transform_modal_3d(bContext *C, wmOperator *op, const wmEvent *event)
|
||||
{
|
||||
BLI_assert(event->type == EVT_XR_ACTION);
|
||||
BLI_assert(event->custom == EVT_DATA_XR);
|
||||
BLI_assert(event->customdata);
|
||||
|
||||
const wmXrActionData *actiondata = event->customdata;
|
||||
TransInfo *t = op->customdata;
|
||||
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
View3D *v3d = CTX_wm_view3d(C);
|
||||
ARegion *region = CTX_wm_region(C);
|
||||
RegionView3D *rv3d = region->regiondata;
|
||||
wmWindowManager *wm = CTX_wm_manager(C);
|
||||
wmXrData *xr = &wm->xr;
|
||||
float lens_prev;
|
||||
float clip_start_prev, clip_end_prev;
|
||||
float viewmat_prev[4][4];
|
||||
int retval;
|
||||
|
||||
wmEvent event_mut;
|
||||
memcpy(&event_mut, event, sizeof(wmEvent));
|
||||
|
||||
/* Replace window view parameters with XR surface counterparts. */
|
||||
ED_view3d_view_params_get(v3d, rv3d, &lens_prev, &clip_start_prev, &clip_end_prev, viewmat_prev);
|
||||
ED_view3d_view_params_set(
|
||||
depsgraph,
|
||||
scene,
|
||||
v3d,
|
||||
region,
|
||||
actiondata->eye_lens,
|
||||
xr->session_settings.clip_start,
|
||||
xr->session_settings.clip_end,
|
||||
t->viewmat); /* Use viewmat from when transform was invoked instead of latest XR viewmat. */
|
||||
|
||||
map_to_pixel(event_mut.mval,
|
||||
actiondata->controller_loc,
|
||||
t->viewmat,
|
||||
rv3d->winmat,
|
||||
region->winx,
|
||||
region->winy);
|
||||
|
||||
if (event->val == KM_PRESS) {
|
||||
event_mut.type = MOUSEMOVE;
|
||||
}
|
||||
else if (event->val == KM_RELEASE) {
|
||||
event_mut.type = LEFTMOUSE;
|
||||
}
|
||||
else {
|
||||
/* XR events currently only support press and release. */
|
||||
BLI_assert(false);
|
||||
}
|
||||
|
||||
retval = transform_modal(C, op, &event_mut);
|
||||
|
||||
/* Restore window view. */
|
||||
ED_view3d_view_params_set(
|
||||
depsgraph, scene, v3d, region, lens_prev, clip_start_prev, clip_end_prev, viewmat_prev);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void transform_cancel(bContext *C, wmOperator *op)
|
||||
{
|
||||
TransInfo *t = op->customdata;
|
||||
@@ -530,6 +592,56 @@ static int transform_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
||||
return OPERATOR_RUNNING_MODAL;
|
||||
}
|
||||
|
||||
static int transform_invoke_3d(bContext *C, wmOperator *op, const wmEvent *event)
|
||||
{
|
||||
BLI_assert(event->type == EVT_XR_ACTION);
|
||||
BLI_assert(event->custom == EVT_DATA_XR);
|
||||
BLI_assert(event->customdata);
|
||||
|
||||
const wmXrActionData *actiondata = event->customdata;
|
||||
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
View3D *v3d = CTX_wm_view3d(C);
|
||||
ARegion *region = CTX_wm_region(C);
|
||||
RegionView3D *rv3d = region->regiondata;
|
||||
wmWindowManager *wm = CTX_wm_manager(C);
|
||||
wmXrData *xr = &wm->xr;
|
||||
float lens_prev;
|
||||
float clip_start_prev, clip_end_prev;
|
||||
float viewmat_prev[4][4];
|
||||
int retval;
|
||||
|
||||
wmEvent event_mut;
|
||||
memcpy(&event_mut, event, sizeof(wmEvent));
|
||||
event_mut.type = LEFTMOUSE;
|
||||
|
||||
/* Replace window view parameters with XR surface counterparts. */
|
||||
ED_view3d_view_params_get(v3d, rv3d, &lens_prev, &clip_start_prev, &clip_end_prev, viewmat_prev);
|
||||
ED_view3d_view_params_set(depsgraph,
|
||||
scene,
|
||||
v3d,
|
||||
region,
|
||||
actiondata->eye_lens,
|
||||
xr->session_settings.clip_start,
|
||||
xr->session_settings.clip_end,
|
||||
actiondata->eye_viewmat);
|
||||
|
||||
map_to_pixel(event_mut.mval,
|
||||
actiondata->controller_loc,
|
||||
actiondata->eye_viewmat,
|
||||
rv3d->winmat,
|
||||
region->winx,
|
||||
region->winy);
|
||||
|
||||
retval = transform_invoke(C, op, &event_mut);
|
||||
|
||||
/* Restore window view. */
|
||||
ED_view3d_view_params_set(
|
||||
depsgraph, scene, v3d, region, lens_prev, clip_start_prev, clip_end_prev, viewmat_prev);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static bool transform_poll_property(const bContext *UNUSED(C),
|
||||
wmOperator *op,
|
||||
const PropertyRNA *prop)
|
||||
@@ -747,8 +859,10 @@ static void TRANSFORM_OT_translate(struct wmOperatorType *ot)
|
||||
|
||||
/* api callbacks */
|
||||
ot->invoke = transform_invoke;
|
||||
ot->invoke_3d = transform_invoke_3d;
|
||||
ot->exec = transform_exec;
|
||||
ot->modal = transform_modal;
|
||||
ot->modal_3d = transform_modal_3d;
|
||||
ot->cancel = transform_cancel;
|
||||
ot->poll = ED_operator_screenactive;
|
||||
ot->poll_property = transform_poll_property;
|
||||
@@ -774,8 +888,10 @@ static void TRANSFORM_OT_resize(struct wmOperatorType *ot)
|
||||
|
||||
/* api callbacks */
|
||||
ot->invoke = transform_invoke;
|
||||
ot->invoke_3d = transform_invoke_3d;
|
||||
ot->exec = transform_exec;
|
||||
ot->modal = transform_modal;
|
||||
ot->modal_3d = transform_modal_3d;
|
||||
ot->cancel = transform_cancel;
|
||||
ot->poll = ED_operator_screenactive;
|
||||
ot->poll_property = transform_poll_property;
|
||||
@@ -862,8 +978,10 @@ static void TRANSFORM_OT_rotate(struct wmOperatorType *ot)
|
||||
|
||||
/* api callbacks */
|
||||
ot->invoke = transform_invoke;
|
||||
ot->invoke_3d = transform_invoke_3d;
|
||||
ot->exec = transform_exec;
|
||||
ot->modal = transform_modal;
|
||||
ot->modal_3d = transform_modal_3d;
|
||||
ot->cancel = transform_cancel;
|
||||
ot->poll = transform_rotate_poll;
|
||||
ot->poll_property = transform_poll_property;
|
||||
@@ -1264,8 +1382,10 @@ static void TRANSFORM_OT_transform(struct wmOperatorType *ot)
|
||||
|
||||
/* api callbacks */
|
||||
ot->invoke = transform_invoke;
|
||||
ot->invoke_3d = transform_invoke_3d;
|
||||
ot->exec = transform_exec;
|
||||
ot->modal = transform_modal;
|
||||
ot->modal_3d = transform_modal_3d;
|
||||
ot->cancel = transform_cancel;
|
||||
ot->poll = ED_operator_screenactive;
|
||||
ot->poll_property = transform_poll_property;
|
||||
|
@@ -499,6 +499,16 @@ static void iter_snap_objects(SnapObjectContext *sctx,
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (snap_select == SNAP_SELECTED) {
|
||||
if (!(base->flag & BASE_SELECTED) && !(base->flag_legacy & BA_WAS_SEL)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (snap_select == SNAP_SELECTABLE) {
|
||||
if (!(base->flag & BASE_SELECTABLE)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
Object *obj_eval = DEG_get_evaluated_object(depsgraph, base->object);
|
||||
if (obj_eval->transflag & OB_DUPLI || BKE_object_has_geometry_set_instances(obj_eval)) {
|
||||
|
@@ -666,8 +666,11 @@ typedef enum eRegionType {
|
||||
RGN_TYPE_EXECUTE = 10,
|
||||
RGN_TYPE_FOOTER = 11,
|
||||
RGN_TYPE_TOOL_HEADER = 12,
|
||||
/* Region type used exclusively by internal code and add-ons to register draw callbacks to the XR
|
||||
context (surface, mirror view). Does not represent any real region. */
|
||||
RGN_TYPE_XR = 13,
|
||||
|
||||
#define RGN_TYPE_LEN (RGN_TYPE_TOOL_HEADER + 1)
|
||||
#define RGN_TYPE_LEN (RGN_TYPE_XR + 1)
|
||||
} eRegionType;
|
||||
|
||||
/* use for function args */
|
||||
|
@@ -30,6 +30,9 @@ typedef enum eV3DOffscreenDrawFlag {
|
||||
V3D_OFSDRAW_SHOW_ANNOTATION = (1 << 0),
|
||||
V3D_OFSDRAW_OVERRIDE_SCENE_SETTINGS = (1 << 1),
|
||||
V3D_OFSDRAW_SHOW_GRIDFLOOR = (1 << 2),
|
||||
V3D_OFSDRAW_SHOW_SELECTION = (1 << 3),
|
||||
V3D_OFSDRAW_XR_SHOW_CONTROLLERS = (1 << 4),
|
||||
V3D_OFSDRAW_XR_SHOW_CUSTOM_OVERLAYS = (1 << 5),
|
||||
} eV3DOffscreenDrawFlag;
|
||||
|
||||
/** #View3DShading.light */
|
||||
|
@@ -373,6 +373,7 @@ typedef struct View3D {
|
||||
#define V3D_HIDE_HELPLINES (1 << 2)
|
||||
#define V3D_FLAG_UNUSED_2 (1 << 3) /* cleared */
|
||||
#define V3D_XR_SESSION_MIRROR (1 << 4)
|
||||
#define V3D_XR_SESSION_SURFACE (1 << 5)
|
||||
|
||||
#define V3D_FLAG_UNUSED_10 (1 << 10) /* cleared */
|
||||
#define V3D_SELECT_OUTLINE (1 << 11)
|
||||
@@ -465,6 +466,8 @@ enum {
|
||||
#define V3D_FLAG2_UNUSED_13 (1 << 13) /* cleared */
|
||||
#define V3D_FLAG2_UNUSED_14 (1 << 14) /* cleared */
|
||||
#define V3D_FLAG2_UNUSED_15 (1 << 15) /* cleared */
|
||||
#define V3D_XR_SHOW_CONTROLLERS (1 << 16)
|
||||
#define V3D_XR_SHOW_CUSTOM_OVERLAYS (1 << 17)
|
||||
|
||||
/** #View3D.gp_flag (short) */
|
||||
#define V3D_GP_FADE_OBJECTS (1 << 0) /* Fade all non GP objects */
|
||||
|
@@ -26,15 +26,17 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct XrActionConfig;
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
||||
typedef struct XrSessionSettings {
|
||||
/** Shading settings, struct shared with 3D-View so settings are the same. */
|
||||
struct View3DShading shading;
|
||||
|
||||
char _pad[7];
|
||||
|
||||
char base_pose_type; /* #eXRSessionBasePoseType */
|
||||
float base_scale;
|
||||
char _pad[3];
|
||||
char base_pose_type; /* eXrSessionBasePoseType */
|
||||
/** Object to take the location and rotation as base position from. */
|
||||
Object *base_pose_object;
|
||||
float base_pose_location[3];
|
||||
@@ -42,12 +44,30 @@ typedef struct XrSessionSettings {
|
||||
|
||||
/** View3D draw flags (V3D_OFSDRAW_NONE, V3D_OFSDRAW_SHOW_ANNOTATION, ...). */
|
||||
char draw_flags;
|
||||
char _pad2[3];
|
||||
/** Draw style for controller visualization. */
|
||||
char controller_draw_style;
|
||||
/** The eye (view) used when projecting 3D to 2D (e.g. when performing GPU select). */
|
||||
char selection_eye;
|
||||
char _pad2;
|
||||
|
||||
/** Clipping distance. */
|
||||
float clip_start, clip_end;
|
||||
|
||||
int flag;
|
||||
int flag; /* eXrSessionFlag */
|
||||
|
||||
/** Known action configurations. */
|
||||
ListBase actionconfigs; /* XrActionConfig */
|
||||
/** Default configuration. */
|
||||
struct XrActionConfig *defaultconf;
|
||||
/** Addon configuration. */
|
||||
struct XrActionConfig *addonconf;
|
||||
/** User configuration. */
|
||||
struct XrActionConfig *userconf;
|
||||
|
||||
/** Objects to bind to headset/controller poses. */
|
||||
ListBase mocap_objects; /* XrMotionCaptureObject */
|
||||
short sel_mocap_object;
|
||||
char _pad3[6];
|
||||
} XrSessionSettings;
|
||||
|
||||
typedef enum eXrSessionFlag {
|
||||
@@ -55,11 +75,23 @@ typedef enum eXrSessionFlag {
|
||||
XR_SESSION_USE_ABSOLUTE_TRACKING = (1 << 1),
|
||||
} eXrSessionFlag;
|
||||
|
||||
typedef enum eXRSessionBasePoseType {
|
||||
typedef enum eXrSessionBasePoseType {
|
||||
XR_BASE_POSE_SCENE_CAMERA = 0,
|
||||
XR_BASE_POSE_OBJECT = 1,
|
||||
XR_BASE_POSE_CUSTOM = 2,
|
||||
} eXRSessionBasePoseType;
|
||||
} eXrSessionBasePoseType;
|
||||
|
||||
typedef enum eXrSessionControllerDrawStyle {
|
||||
XR_CONTROLLER_DRAW_DARK = 0,
|
||||
XR_CONTROLLER_DRAW_LIGHT = 1,
|
||||
XR_CONTROLLER_DRAW_DARK_RAY = 2,
|
||||
XR_CONTROLLER_DRAW_LIGHT_RAY = 3,
|
||||
} eXrSessionControllerDrawStyle;
|
||||
|
||||
typedef enum eXrSessionEye {
|
||||
XR_EYE_LEFT = 0,
|
||||
XR_EYE_RIGHT = 1,
|
||||
} eXrSessionEye;
|
||||
|
||||
/** XR action type. Enum values match those in GHOST_XrActionType enum for consistency. */
|
||||
typedef enum eXrActionType {
|
||||
@@ -94,11 +126,11 @@ typedef enum eXrHapticFlag {
|
||||
XR_HAPTIC_REPEAT = (1 << 3),
|
||||
} eXrHapticFlag;
|
||||
|
||||
/**
|
||||
* For axis-based inputs (thumb-stick/track-pad/etc).
|
||||
* Determines the region for action execution (mutually exclusive per axis).
|
||||
*/
|
||||
typedef enum eXrAxisFlag {
|
||||
/**
|
||||
* For axis-based inputs (thumb-stick/track-pad/etc).
|
||||
* Determines the region for action execution (mutually exclusive per axis).
|
||||
*/
|
||||
XR_AXIS0_POS = (1 << 0),
|
||||
XR_AXIS0_NEG = (1 << 1),
|
||||
XR_AXIS1_POS = (1 << 2),
|
||||
@@ -111,6 +143,11 @@ typedef enum eXrPoseFlag {
|
||||
XR_POSE_AIM = (1 << 1),
|
||||
} eXrPoseFlag;
|
||||
|
||||
typedef enum eXrMotionCaptureFlag {
|
||||
XR_MOCAP_OBJECT_ENABLE = (1 << 0),
|
||||
XR_MOCAP_OBJECT_AUTOKEY = (1 << 1),
|
||||
} eXrMotionCaptureFlag;
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
||||
typedef struct XrActionMapBinding {
|
||||
@@ -151,7 +188,7 @@ typedef struct XrActionMapItem {
|
||||
char user_path1[64];
|
||||
|
||||
/** Operator to be called on XR events. */
|
||||
char op[64]; /* OP_MAX_TYPENAME */
|
||||
char op[64];
|
||||
/** Operator properties, assigned to ptr->data and can be written to a file. */
|
||||
IDProperty *op_properties;
|
||||
/** RNA pointer to access properties. */
|
||||
@@ -171,10 +208,15 @@ typedef struct XrActionMapItem {
|
||||
float haptic_amplitude;
|
||||
|
||||
short selbinding;
|
||||
char _pad3[2];
|
||||
short flag;
|
||||
ListBase bindings; /* XrActionMapBinding */
|
||||
} XrActionMapItem;
|
||||
|
||||
/** #XrActionMapItem.flag */
|
||||
enum {
|
||||
XR_ACTIONMAP_ITEM_UPDATE = (1 << 0),
|
||||
};
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
||||
typedef struct XrActionMap {
|
||||
@@ -185,9 +227,53 @@ typedef struct XrActionMap {
|
||||
|
||||
ListBase items; /* XrActionMapItem */
|
||||
short selitem;
|
||||
char _pad[6];
|
||||
short flag;
|
||||
char _pad[4];
|
||||
} XrActionMap;
|
||||
|
||||
/** #XrActionMap.flag */
|
||||
enum {
|
||||
XR_ACTIONMAP_UPDATE = (1 << 0),
|
||||
};
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
||||
typedef struct XrActionConfig {
|
||||
struct XrActionConfig *next, *prev;
|
||||
|
||||
/** Unique name. */
|
||||
char name[64]; /* MAX_NAME */
|
||||
|
||||
ListBase actionmaps; /* XrActionMap */
|
||||
short actactionmap;
|
||||
short selactionmap;
|
||||
short flag;
|
||||
char _pad[2];
|
||||
} XrActionConfig;
|
||||
|
||||
/** #XrActionConfig.flag */
|
||||
enum {
|
||||
XR_ACTIONCONF_USER = (1 << 0), /* User action config. */
|
||||
};
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
||||
typedef struct XrMotionCaptureObject {
|
||||
struct XrMotionCaptureObject *next, *prev;
|
||||
|
||||
/** Object to bind to a VR device. Used as struct identifier. */
|
||||
Object *ob;
|
||||
/** OpenXR user path, identifies the target headset/controller. */
|
||||
char user_path[64];
|
||||
|
||||
/** Location/rotation offsets. */
|
||||
float location_offset[3];
|
||||
float rotation_offset[3];
|
||||
|
||||
short flag; /* eXrMotionCaptureFlag */
|
||||
char _pad[6];
|
||||
} XrMotionCaptureObject;
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@@ -46,6 +46,7 @@ const EnumPropertyItem rna_enum_region_type_items[] = {
|
||||
{RGN_TYPE_EXECUTE, "EXECUTE", 0, "Execute Buttons", ""},
|
||||
{RGN_TYPE_FOOTER, "FOOTER", 0, "Footer", ""},
|
||||
{RGN_TYPE_TOOL_HEADER, "TOOL_HEADER", 0, "Tool Header", ""},
|
||||
{RGN_TYPE_XR, "XR", 0, "XR", ""},
|
||||
{0, NULL, 0, NULL, NULL},
|
||||
};
|
||||
|
||||
|
@@ -1755,6 +1755,11 @@ void RNA_api_ui_layout(StructRNA *srna)
|
||||
parm = RNA_def_pointer(func, "item", "KeyMapItem", "", "");
|
||||
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
|
||||
|
||||
func = RNA_def_function(
|
||||
srna, "template_xr_actionmap_item_properties", "uiTemplateXrActionmapItemProperties");
|
||||
parm = RNA_def_pointer(func, "item", "XrActionMapItem", "", "");
|
||||
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
|
||||
|
||||
func = RNA_def_function(srna, "template_component_menu", "uiTemplateComponentMenu");
|
||||
RNA_def_function_ui_description(func, "Item. Display expanded property in a popup menu");
|
||||
parm = RNA_def_pointer(func, "data", "AnyType", "", "Data from which to take property");
|
||||
|
@@ -362,6 +362,8 @@ const EnumPropertyItem rna_enum_event_type_items[] = {
|
||||
0,
|
||||
"ActionZone Fullscreen",
|
||||
"AZone FullScr"},
|
||||
/* xr */
|
||||
{EVT_XR_ACTION, "XR_ACTION", 0, "XR Action", ""},
|
||||
{0, NULL, 0, NULL, NULL},
|
||||
};
|
||||
|
||||
@@ -700,6 +702,238 @@ static void rna_Event_tilt_get(PointerRNA *ptr, float *values)
|
||||
WM_event_tablet_data(event, NULL, values);
|
||||
}
|
||||
|
||||
static bool rna_Event_is_xr_get(PointerRNA *ptr)
|
||||
{
|
||||
const wmEvent *event = ptr->data;
|
||||
return WM_event_is_xr(event);
|
||||
}
|
||||
|
||||
static void rna_Event_xr_action_set_get(PointerRNA *ptr, char *value)
|
||||
{
|
||||
const wmEvent *event = ptr->data;
|
||||
if (WM_event_is_xr(event)) {
|
||||
WM_event_xr_data(
|
||||
event, &value, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
|
||||
}
|
||||
else {
|
||||
value[0] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
static int rna_Event_xr_action_set_length(PointerRNA *ptr)
|
||||
{
|
||||
const wmEvent *event = ptr->data;
|
||||
if (WM_event_is_xr(event)) {
|
||||
wmXrActionData *data = event->customdata;
|
||||
return strlen(data->action_set) + 1;
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void rna_Event_xr_action_get(PointerRNA *ptr, char *value)
|
||||
{
|
||||
const wmEvent *event = ptr->data;
|
||||
if (WM_event_is_xr(event)) {
|
||||
WM_event_xr_data(
|
||||
event, NULL, &value, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
|
||||
}
|
||||
else {
|
||||
value[0] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
static int rna_Event_xr_action_length(PointerRNA *ptr)
|
||||
{
|
||||
const wmEvent *event = ptr->data;
|
||||
if (WM_event_is_xr(event)) {
|
||||
wmXrActionData *data = event->customdata;
|
||||
return strlen(data->action) + 1;
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int rna_Event_xr_type_get(PointerRNA *ptr)
|
||||
{
|
||||
const wmEvent *event = ptr->data;
|
||||
if (WM_event_is_xr(event)) {
|
||||
int type;
|
||||
WM_event_xr_data(event,
|
||||
NULL,
|
||||
NULL,
|
||||
(char *)&type,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL);
|
||||
return type;
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void rna_Event_xr_state_get(PointerRNA *ptr, float *value)
|
||||
{
|
||||
const wmEvent *event = ptr->data;
|
||||
if (WM_event_is_xr(event)) {
|
||||
WM_event_xr_data(
|
||||
event, NULL, NULL, NULL, value, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
|
||||
}
|
||||
else {
|
||||
memset(value, 0, sizeof(float[2]));
|
||||
}
|
||||
}
|
||||
|
||||
static void rna_Event_xr_state_other_get(PointerRNA *ptr, float *value)
|
||||
{
|
||||
const wmEvent *event = ptr->data;
|
||||
if (WM_event_is_xr(event)) {
|
||||
WM_event_xr_data(
|
||||
event, NULL, NULL, NULL, NULL, value, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
|
||||
}
|
||||
else {
|
||||
memset(value, 0, sizeof(float[2]));
|
||||
}
|
||||
}
|
||||
|
||||
static float rna_Event_xr_float_threshold_get(PointerRNA *ptr)
|
||||
{
|
||||
const wmEvent *event = ptr->data;
|
||||
if (WM_event_is_xr(event)) {
|
||||
float float_threshold;
|
||||
WM_event_xr_data(event,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
&float_threshold,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL);
|
||||
return float_threshold;
|
||||
}
|
||||
else {
|
||||
return 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
static void rna_Event_xr_controller_location_get(PointerRNA *ptr, float *value)
|
||||
{
|
||||
const wmEvent *event = ptr->data;
|
||||
if (WM_event_is_xr(event)) {
|
||||
WM_event_xr_data(
|
||||
event, NULL, NULL, NULL, NULL, NULL, NULL, value, NULL, NULL, NULL, NULL, NULL, NULL);
|
||||
}
|
||||
else {
|
||||
memset(value, 0, sizeof(float[3]));
|
||||
}
|
||||
}
|
||||
|
||||
static void rna_Event_xr_controller_rotation_get(PointerRNA *ptr, float *value)
|
||||
{
|
||||
const wmEvent *event = ptr->data;
|
||||
if (WM_event_is_xr(event)) {
|
||||
WM_event_xr_data(
|
||||
event, NULL, NULL, NULL, NULL, NULL, NULL, NULL, value, NULL, NULL, NULL, NULL, NULL);
|
||||
}
|
||||
else {
|
||||
value[0] = 1.0f;
|
||||
value[1] = value[2] = value[3] = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
static void rna_Event_xr_controller_location_other_get(PointerRNA *ptr, float *value)
|
||||
{
|
||||
const wmEvent *event = ptr->data;
|
||||
if (WM_event_is_xr(event)) {
|
||||
WM_event_xr_data(
|
||||
event, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, value, NULL, NULL, NULL, NULL);
|
||||
}
|
||||
else {
|
||||
memset(value, 0, sizeof(float[3]));
|
||||
}
|
||||
}
|
||||
|
||||
static void rna_Event_xr_controller_rotation_other_get(PointerRNA *ptr, float *value)
|
||||
{
|
||||
const wmEvent *event = ptr->data;
|
||||
if (WM_event_is_xr(event)) {
|
||||
WM_event_xr_data(
|
||||
event, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, value, NULL, NULL, NULL);
|
||||
}
|
||||
else {
|
||||
value[0] = 1.0f;
|
||||
value[1] = value[2] = value[3] = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
static float rna_Event_xr_focal_length_get(PointerRNA *ptr)
|
||||
{
|
||||
const wmEvent *event = ptr->data;
|
||||
if (WM_event_is_xr(event)) {
|
||||
float focal_len;
|
||||
WM_event_xr_data(
|
||||
event, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &focal_len, NULL, NULL);
|
||||
return focal_len;
|
||||
}
|
||||
else {
|
||||
return 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
static void rna_Event_xr_view_matrix_get(PointerRNA *ptr, float values[16])
|
||||
{
|
||||
const wmEvent *event = ptr->data;
|
||||
if (WM_event_is_xr(event)) {
|
||||
WM_event_xr_data(event,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
(float(*)[4])values,
|
||||
NULL);
|
||||
}
|
||||
else {
|
||||
memset(values, 0, sizeof(float[16]));
|
||||
}
|
||||
}
|
||||
|
||||
static bool rna_Event_xr_bimanual_get(PointerRNA *ptr)
|
||||
{
|
||||
const wmEvent *event = ptr->data;
|
||||
if (WM_event_is_xr(event)) {
|
||||
bool bimanual;
|
||||
WM_event_xr_data(
|
||||
event, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &bimanual);
|
||||
return bimanual;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static PointerRNA rna_PopupMenu_layout_get(PointerRNA *ptr)
|
||||
{
|
||||
struct uiPopupMenu *pup = ptr->data;
|
||||
@@ -2130,6 +2364,13 @@ static void rna_def_event(BlenderRNA *brna)
|
||||
StructRNA *srna;
|
||||
PropertyRNA *prop;
|
||||
|
||||
static const EnumPropertyItem xr_action_types[] = {
|
||||
{XR_BOOLEAN_INPUT, "BOOLEAN", 0, "Boolean", "Boolean value"},
|
||||
{XR_FLOAT_INPUT, "FLOAT", 0, "Float", "Float value"},
|
||||
{XR_VECTOR2F_INPUT, "VECTOR2F", 0, "Vector2f", "2D float vector value"},
|
||||
{0, NULL, 0, NULL, NULL},
|
||||
};
|
||||
|
||||
srna = RNA_def_struct(brna, "Event", NULL);
|
||||
RNA_def_struct_ui_text(srna, "Event", "Window Manager Event");
|
||||
RNA_def_struct_sdna(srna, "wmEvent");
|
||||
@@ -2250,6 +2491,97 @@ static void rna_def_event(BlenderRNA *brna)
|
||||
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
|
||||
RNA_def_property_ui_text(prop, "OS Key", "True when the Cmd key is held");
|
||||
|
||||
/* xr */
|
||||
prop = RNA_def_property(srna, "is_xr", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
|
||||
RNA_def_property_boolean_funcs(prop, "rna_Event_is_xr_get", NULL);
|
||||
RNA_def_property_ui_text(prop, "Is XR", "The event has XR data");
|
||||
|
||||
prop = RNA_def_property(srna, "xr_action_set", PROP_STRING, PROP_NONE);
|
||||
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
|
||||
RNA_def_property_string_funcs(
|
||||
prop, "rna_Event_xr_action_set_get", "rna_Event_xr_action_set_length", NULL);
|
||||
RNA_def_property_ui_text(prop, "XR Action Set", "XR action set name");
|
||||
|
||||
prop = RNA_def_property(srna, "xr_action", PROP_STRING, PROP_NONE);
|
||||
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
|
||||
RNA_def_property_string_funcs(
|
||||
prop, "rna_Event_xr_action_get", "rna_Event_xr_action_length", NULL);
|
||||
RNA_def_property_ui_text(prop, "XR Action", "XR action name");
|
||||
|
||||
prop = RNA_def_property(srna, "xr_type", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
|
||||
RNA_def_property_enum_items(prop, xr_action_types);
|
||||
RNA_def_property_enum_funcs(prop, "rna_Event_xr_type_get", NULL, NULL);
|
||||
RNA_def_property_ui_text(prop, "XR Type", "XR action type");
|
||||
|
||||
prop = RNA_def_property(srna, "xr_state", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_array(prop, 2);
|
||||
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
|
||||
RNA_def_property_float_funcs(prop, "rna_Event_xr_state_get", NULL, NULL);
|
||||
RNA_def_property_ui_text(prop, "XR State", "XR action values corresponding to type");
|
||||
|
||||
prop = RNA_def_property(srna, "xr_state_other", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_array(prop, 2);
|
||||
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
|
||||
RNA_def_property_float_funcs(prop, "rna_Event_xr_state_other_get", NULL, NULL);
|
||||
RNA_def_property_ui_text(
|
||||
prop, "XR State Other", "State of the other user path for bimanual actions");
|
||||
|
||||
prop = RNA_def_property(srna, "xr_float_threshold", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
|
||||
RNA_def_property_float_funcs(prop, "rna_Event_xr_float_threshold_get", NULL, NULL);
|
||||
RNA_def_property_ui_text(
|
||||
prop, "XR Float Threshold", "Input threshold for Float/Vector2f actions");
|
||||
|
||||
prop = RNA_def_property(srna, "xr_controller_location", PROP_FLOAT, PROP_TRANSLATION);
|
||||
RNA_def_property_array(prop, 3);
|
||||
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
|
||||
RNA_def_property_float_funcs(prop, "rna_Event_xr_controller_location_get", NULL, NULL);
|
||||
RNA_def_property_ui_text(prop,
|
||||
"XR Controller Location",
|
||||
"Location of the action's corresponding controller aim in world space");
|
||||
|
||||
prop = RNA_def_property(srna, "xr_controller_rotation", PROP_FLOAT, PROP_QUATERNION);
|
||||
RNA_def_property_array(prop, 4);
|
||||
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
|
||||
RNA_def_property_float_funcs(prop, "rna_Event_xr_controller_rotation_get", NULL, NULL);
|
||||
RNA_def_property_ui_text(prop,
|
||||
"XR Controller Rotation",
|
||||
"Rotation of the action's corresponding controller aim in world space");
|
||||
|
||||
prop = RNA_def_property(srna, "xr_controller_location_other", PROP_FLOAT, PROP_TRANSLATION);
|
||||
RNA_def_property_array(prop, 3);
|
||||
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
|
||||
RNA_def_property_float_funcs(prop, "rna_Event_xr_controller_location_other_get", NULL, NULL);
|
||||
RNA_def_property_ui_text(prop,
|
||||
"XR Controller Location Other",
|
||||
"Controller aim location of the other user path for bimanual actions");
|
||||
|
||||
prop = RNA_def_property(srna, "xr_controller_rotation_other", PROP_FLOAT, PROP_QUATERNION);
|
||||
RNA_def_property_array(prop, 4);
|
||||
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
|
||||
RNA_def_property_float_funcs(prop, "rna_Event_xr_controller_rotation_other_get", NULL, NULL);
|
||||
RNA_def_property_ui_text(prop,
|
||||
"XR Controller Rotation Other",
|
||||
"Controller aim rotation of the other user path for bimanual actions");
|
||||
|
||||
prop = RNA_def_property(srna, "xr_focal_length", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
|
||||
RNA_def_property_float_funcs(prop, "rna_Event_xr_focal_length_get", NULL, NULL);
|
||||
RNA_def_property_ui_text(prop, "XR Focal Length", "Focal length of the XR selection eye");
|
||||
|
||||
prop = RNA_def_property(srna, "xr_view_matrix", PROP_FLOAT, PROP_MATRIX);
|
||||
RNA_def_property_array(prop, 16);
|
||||
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
|
||||
RNA_def_property_float_funcs(prop, "rna_Event_xr_view_matrix_get", NULL, NULL);
|
||||
RNA_def_property_ui_text(prop, "XR View Matrix", "View matrix of the XR selection eye");
|
||||
|
||||
prop = RNA_def_property(srna, "xr_bimanual", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
|
||||
RNA_def_property_boolean_funcs(prop, "rna_Event_xr_bimanual_get", NULL);
|
||||
RNA_def_property_ui_text(prop, "XR Bimanual", "Bimanual interaction is occurring");
|
||||
|
||||
RNA_define_verify_sdna(1); /* not in sdna */
|
||||
}
|
||||
|
||||
|
@@ -40,24 +40,7 @@
|
||||
# include "WM_api.h"
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
||||
# ifdef WITH_XR_OPENXR
|
||||
static wmXrData *rna_XrSession_wm_xr_data_get(PointerRNA *ptr)
|
||||
{
|
||||
/* Callers could also get XrSessionState pointer through ptr->data, but prefer if we just
|
||||
* consistently pass wmXrData pointers to the WM_xr_xxx() API. */
|
||||
|
||||
BLI_assert((ptr->type == &RNA_XrSessionSettings) || (ptr->type == &RNA_XrSessionState));
|
||||
|
||||
wmWindowManager *wm = (wmWindowManager *)ptr->owner_id;
|
||||
BLI_assert(wm && (GS(wm->id.name) == ID_WM));
|
||||
|
||||
return &wm->xr;
|
||||
}
|
||||
# endif
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name XR Action Map
|
||||
/** \name XR Action Configuration
|
||||
* \{ */
|
||||
|
||||
static XrActionMapBinding *rna_XrActionMapBinding_new(XrActionMapItem *ami,
|
||||
@@ -171,15 +154,17 @@ static void rna_XrActionMapBinding_name_update(Main *bmain, Scene *UNUSED(scene)
|
||||
{
|
||||
# ifdef WITH_XR_OPENXR
|
||||
wmWindowManager *wm = bmain->wm.first;
|
||||
if (wm && wm->xr.runtime) {
|
||||
ListBase *actionmaps = WM_xr_actionmaps_get(wm->xr.runtime);
|
||||
short idx = WM_xr_actionmap_selected_index_get(wm->xr.runtime);
|
||||
XrActionMap *actionmap = BLI_findlink(actionmaps, idx);
|
||||
if (actionmap) {
|
||||
XrActionMapItem *ami = BLI_findlink(&actionmap->items, actionmap->selitem);
|
||||
if (ami) {
|
||||
XrActionMapBinding *amb = ptr->data;
|
||||
WM_xr_actionmap_binding_ensure_unique(ami, amb);
|
||||
if (wm) {
|
||||
XrSessionSettings *settings = &wm->xr.session_settings;
|
||||
XrActionConfig *actionconf = WM_xr_actionconfig_active_get(settings);
|
||||
if (actionconf) {
|
||||
XrActionMap *actionmap = BLI_findlink(&actionconf->actionmaps, actionconf->selactionmap);
|
||||
if (actionmap) {
|
||||
XrActionMapItem *ami = BLI_findlink(&actionmap->items, actionmap->selitem);
|
||||
if (ami) {
|
||||
XrActionMapBinding *amb = ptr->data;
|
||||
WM_xr_actionmap_binding_ensure_unique(ami, amb);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -413,13 +398,15 @@ static void rna_XrActionMapItem_name_update(Main *bmain, Scene *UNUSED(scene), P
|
||||
{
|
||||
# ifdef WITH_XR_OPENXR
|
||||
wmWindowManager *wm = bmain->wm.first;
|
||||
if (wm && wm->xr.runtime) {
|
||||
ListBase *actionmaps = WM_xr_actionmaps_get(wm->xr.runtime);
|
||||
short idx = WM_xr_actionmap_selected_index_get(wm->xr.runtime);
|
||||
XrActionMap *actionmap = BLI_findlink(actionmaps, idx);
|
||||
if (actionmap) {
|
||||
XrActionMapItem *ami = ptr->data;
|
||||
WM_xr_actionmap_item_ensure_unique(actionmap, ami);
|
||||
if (wm) {
|
||||
XrSessionSettings *settings = &wm->xr.session_settings;
|
||||
XrActionConfig *actionconf = WM_xr_actionconfig_active_get(settings);
|
||||
if (actionconf) {
|
||||
XrActionMap *actionmap = BLI_findlink(&actionconf->actionmaps, actionconf->selactionmap);
|
||||
if (actionmap) {
|
||||
XrActionMapItem *ami = ptr->data;
|
||||
WM_xr_actionmap_item_ensure_unique(actionmap, ami);
|
||||
}
|
||||
}
|
||||
}
|
||||
# else
|
||||
@@ -437,50 +424,51 @@ static void rna_XrActionMapItem_update(Main *UNUSED(bmain), Scene *UNUSED(scene)
|
||||
# endif
|
||||
}
|
||||
|
||||
static XrActionMap *rna_XrActionMap_new(PointerRNA *ptr, const char *name, bool replace_existing)
|
||||
static XrActionMap *rna_XrActionMap_new(XrActionConfig *actionconf,
|
||||
const char *name,
|
||||
bool replace_existing)
|
||||
{
|
||||
# ifdef WITH_XR_OPENXR
|
||||
wmXrData *xr = rna_XrSession_wm_xr_data_get(ptr);
|
||||
return WM_xr_actionmap_new(xr->runtime, name, replace_existing);
|
||||
return WM_xr_actionmap_new(actionconf, name, replace_existing);
|
||||
# else
|
||||
UNUSED_VARS(ptr, name, replace_existing);
|
||||
UNUSED_VARS(actionconf, name, replace_existing);
|
||||
return NULL;
|
||||
# endif
|
||||
}
|
||||
|
||||
static XrActionMap *rna_XrActionMap_new_from_actionmap(PointerRNA *ptr, XrActionMap *am_src)
|
||||
static XrActionMap *rna_XrActionMap_new_from_actionmap(XrActionConfig *actionconf,
|
||||
XrActionMap *am_src)
|
||||
{
|
||||
# ifdef WITH_XR_OPENXR
|
||||
wmXrData *xr = rna_XrSession_wm_xr_data_get(ptr);
|
||||
return WM_xr_actionmap_add_copy(xr->runtime, am_src);
|
||||
return WM_xr_actionmap_add_copy(actionconf, am_src);
|
||||
# else
|
||||
UNUSED_VARS(ptr, am_src);
|
||||
UNUSED_VARS(actionconf, am_src);
|
||||
return NULL;
|
||||
# endif
|
||||
}
|
||||
|
||||
static void rna_XrActionMap_remove(ReportList *reports, PointerRNA *ptr, PointerRNA *actionmap_ptr)
|
||||
static void rna_XrActionMap_remove(XrActionConfig *actionconf,
|
||||
ReportList *reports,
|
||||
PointerRNA *actionmap_ptr)
|
||||
{
|
||||
# ifdef WITH_XR_OPENXR
|
||||
wmXrData *xr = rna_XrSession_wm_xr_data_get(ptr);
|
||||
XrActionMap *actionmap = actionmap_ptr->data;
|
||||
if (WM_xr_actionmap_remove(xr->runtime, actionmap) == false) {
|
||||
if (WM_xr_actionmap_remove(actionconf, actionmap) == false) {
|
||||
BKE_reportf(reports, RPT_ERROR, "ActionMap '%s' cannot be removed", actionmap->name);
|
||||
return;
|
||||
}
|
||||
RNA_POINTER_INVALIDATE(actionmap_ptr);
|
||||
# else
|
||||
UNUSED_VARS(ptr, reports, actionmap_ptr);
|
||||
UNUSED_VARS(actionconf, reports, actionmap_ptr);
|
||||
# endif
|
||||
}
|
||||
|
||||
static XrActionMap *rna_XrActionMap_find(PointerRNA *ptr, const char *name)
|
||||
static XrActionMap *rna_XrActionMap_find(XrActionConfig *actionconf, const char *name)
|
||||
{
|
||||
# ifdef WITH_XR_OPENXR
|
||||
wmXrData *xr = rna_XrSession_wm_xr_data_get(ptr);
|
||||
return WM_xr_actionmap_find(xr->runtime, name);
|
||||
return WM_xr_actionmap_find(actionconf, name);
|
||||
# else
|
||||
UNUSED_VARS(ptr, name);
|
||||
UNUSED_VARS(actionconf, name);
|
||||
return NULL;
|
||||
# endif
|
||||
}
|
||||
@@ -489,17 +477,223 @@ static void rna_XrActionMap_name_update(Main *bmain, Scene *UNUSED(scene), Point
|
||||
{
|
||||
# ifdef WITH_XR_OPENXR
|
||||
wmWindowManager *wm = bmain->wm.first;
|
||||
if (wm && wm->xr.runtime) {
|
||||
XrActionMap *actionmap = ptr->data;
|
||||
WM_xr_actionmap_ensure_unique(wm->xr.runtime, actionmap);
|
||||
if (wm) {
|
||||
XrSessionSettings *settings = &wm->xr.session_settings;
|
||||
XrActionConfig *actionconf = WM_xr_actionconfig_active_get(settings);
|
||||
if (actionconf) {
|
||||
XrActionMap *actionmap = ptr->data;
|
||||
WM_xr_actionmap_ensure_unique(actionconf, actionmap);
|
||||
}
|
||||
}
|
||||
# else
|
||||
UNUSED_VARS(bmain, ptr);
|
||||
# endif
|
||||
}
|
||||
|
||||
static XrActionConfig *rna_XrActionConfig_new(XrSessionSettings *settings, const char *name)
|
||||
{
|
||||
# ifdef WITH_XR_OPENXR
|
||||
return WM_xr_actionconfig_new(settings, name, true);
|
||||
# else
|
||||
UNUSED_VARS(settings, name);
|
||||
return NULL;
|
||||
# endif
|
||||
}
|
||||
|
||||
static void rna_XrActionConfig_remove(XrSessionSettings *settings,
|
||||
ReportList *reports,
|
||||
PointerRNA *actionconf_ptr)
|
||||
{
|
||||
# ifdef WITH_XR_OPENXR
|
||||
XrActionConfig *actionconf = actionconf_ptr->data;
|
||||
if (WM_xr_actionconfig_remove(settings, actionconf) == false) {
|
||||
BKE_reportf(reports, RPT_ERROR, "ActionConfig '%s' cannot be removed", actionconf->name);
|
||||
return;
|
||||
}
|
||||
RNA_POINTER_INVALIDATE(actionconf_ptr);
|
||||
# else
|
||||
UNUSED_VARS(settings, reports, actionconf_ptr);
|
||||
# endif
|
||||
}
|
||||
|
||||
static void rna_XrActionConfig_update(XrSessionSettings *settings)
|
||||
{
|
||||
# ifdef WITH_XR_OPENXR
|
||||
WM_xr_actionconfig_update(settings);
|
||||
# else
|
||||
UNUSED_VARS(settings);
|
||||
# endif
|
||||
}
|
||||
|
||||
static PointerRNA rna_XrSessionSettings_actionconfig_active_get(PointerRNA *ptr)
|
||||
{
|
||||
# ifdef WITH_XR_OPENXR
|
||||
XrSessionSettings *settings = ptr->data;
|
||||
XrActionConfig *ac = WM_xr_actionconfig_active_get(settings);
|
||||
if (!ac) {
|
||||
ac = settings->defaultconf;
|
||||
}
|
||||
return rna_pointer_inherit_refine(ptr, &RNA_XrActionConfig, ac);
|
||||
# else
|
||||
UNUSED_VARS(ptr);
|
||||
return PointerRNA_NULL;
|
||||
# endif
|
||||
}
|
||||
|
||||
static void rna_XrSessionSettings_actionconfig_active_set(PointerRNA *ptr,
|
||||
PointerRNA value,
|
||||
struct ReportList *UNUSED(reports))
|
||||
{
|
||||
# ifdef WITH_XR_OPENXR
|
||||
XrSessionSettings *settings = ptr->data;
|
||||
XrActionConfig *ac = value.data;
|
||||
if (ac) {
|
||||
WM_xr_actionconfig_active_set(settings, ac->name);
|
||||
}
|
||||
# else
|
||||
UNUSED_VARS(ptr, value);
|
||||
# endif
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name XR Motion Capture
|
||||
* \{ */
|
||||
|
||||
static XrMotionCaptureObject *rna_XrMotionCaptureObject_new(XrSessionSettings *settings,
|
||||
PointerRNA *ob_ptr)
|
||||
{
|
||||
# ifdef WITH_XR_OPENXR
|
||||
Object *ob = ob_ptr->data;
|
||||
return WM_xr_mocap_object_new(settings, ob);
|
||||
# else
|
||||
UNUSED_VARS(settings, ob_ptr);
|
||||
return NULL;
|
||||
# endif
|
||||
}
|
||||
|
||||
static void rna_XrMotionCaptureObject_remove(XrSessionSettings *settings, PointerRNA *mocap_ob_ptr)
|
||||
{
|
||||
# ifdef WITH_XR_OPENXR
|
||||
XrMotionCaptureObject *mocap_ob = mocap_ob_ptr->data;
|
||||
WM_xr_mocap_object_remove(settings, mocap_ob);
|
||||
RNA_POINTER_INVALIDATE(mocap_ob_ptr);
|
||||
# else
|
||||
UNUSED_VARS(settings, mocap_ob_ptr);
|
||||
# endif
|
||||
}
|
||||
|
||||
static XrMotionCaptureObject *rna_XrMotionCaptureObject_find(XrSessionSettings *settings,
|
||||
PointerRNA *ob_ptr)
|
||||
{
|
||||
# ifdef WITH_XR_OPENXR
|
||||
Object *ob = ob_ptr->data;
|
||||
return WM_xr_mocap_object_find(settings, ob);
|
||||
# else
|
||||
UNUSED_VARS(settings, ob_ptr);
|
||||
return NULL;
|
||||
# endif
|
||||
}
|
||||
|
||||
static void rna_XrMotionCaptureObject_object_update(Main *bmain,
|
||||
Scene *UNUSED(scene),
|
||||
PointerRNA *ptr)
|
||||
{
|
||||
# ifdef WITH_XR_OPENXR
|
||||
wmWindowManager *wm = bmain->wm.first;
|
||||
if (wm) {
|
||||
XrMotionCaptureObject *mocap_ob = ptr->data;
|
||||
WM_xr_mocap_object_ensure_unique(&wm->xr.session_settings, mocap_ob);
|
||||
}
|
||||
# else
|
||||
UNUSED_VARS(bmain, ptr);
|
||||
# endif
|
||||
}
|
||||
|
||||
static bool rna_XrMotionCaptureObject_enable_get(PointerRNA *ptr)
|
||||
{
|
||||
# ifdef WITH_XR_OPENXR
|
||||
const XrMotionCaptureObject *mocap_ob = ptr->data;
|
||||
return (mocap_ob->flag & XR_MOCAP_OBJECT_ENABLE) != 0;
|
||||
# else
|
||||
UNUSED_VARS(ptr);
|
||||
return false;
|
||||
# endif
|
||||
}
|
||||
|
||||
static void rna_XrMotionCaptureObject_enable_set(PointerRNA *ptr, bool value)
|
||||
{
|
||||
# ifdef WITH_XR_OPENXR
|
||||
XrMotionCaptureObject *mocap_ob = ptr->data;
|
||||
SET_FLAG_FROM_TEST(mocap_ob->flag, value, XR_MOCAP_OBJECT_ENABLE);
|
||||
# else
|
||||
UNUSED_VARS(ptr, value);
|
||||
# endif
|
||||
}
|
||||
|
||||
static void rna_XrMotionCaptureObject_enable_update(Main *bmain,
|
||||
Scene *UNUSED(scene),
|
||||
PointerRNA *ptr)
|
||||
{
|
||||
# ifdef WITH_XR_OPENXR
|
||||
wmWindowManager *wm = bmain->wm.first;
|
||||
if (wm) {
|
||||
XrMotionCaptureObject *mocap_ob = ptr->data;
|
||||
if ((mocap_ob->flag & XR_MOCAP_OBJECT_ENABLE) != 0) {
|
||||
/* Store object's original pose. */
|
||||
WM_xr_session_state_mocap_pose_set(&wm->xr, mocap_ob);
|
||||
}
|
||||
else {
|
||||
/* Restore object's original pose. */
|
||||
WM_xr_session_state_mocap_pose_get(&wm->xr, mocap_ob);
|
||||
}
|
||||
}
|
||||
# else
|
||||
UNUSED_VARS(bmain, ptr);
|
||||
# endif
|
||||
}
|
||||
|
||||
static bool rna_XrMotionCaptureObject_autokey_get(PointerRNA *ptr)
|
||||
{
|
||||
# ifdef WITH_XR_OPENXR
|
||||
const XrMotionCaptureObject *mocap_ob = ptr->data;
|
||||
return (mocap_ob->flag & XR_MOCAP_OBJECT_AUTOKEY) != 0;
|
||||
# else
|
||||
UNUSED_VARS(ptr);
|
||||
return false;
|
||||
# endif
|
||||
}
|
||||
|
||||
static void rna_XrMotionCaptureObject_autokey_set(PointerRNA *ptr, bool value)
|
||||
{
|
||||
# ifdef WITH_XR_OPENXR
|
||||
XrMotionCaptureObject *mocap_ob = ptr->data;
|
||||
SET_FLAG_FROM_TEST(mocap_ob->flag, value, XR_MOCAP_OBJECT_AUTOKEY);
|
||||
# else
|
||||
UNUSED_VARS(ptr, value);
|
||||
# endif
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
||||
# ifdef WITH_XR_OPENXR
|
||||
static wmXrData *rna_XrSession_wm_xr_data_get(PointerRNA *ptr)
|
||||
{
|
||||
/* Callers could also get XrSessionState pointer through ptr->data, but prefer if we just
|
||||
* consistently pass wmXrData pointers to the WM_xr_xxx() API. */
|
||||
|
||||
BLI_assert((ptr->type == &RNA_XrSessionSettings) || (ptr->type == &RNA_XrSessionState));
|
||||
|
||||
wmWindowManager *wm = (wmWindowManager *)ptr->owner_id;
|
||||
BLI_assert(wm && (GS(wm->id.name) == ID_WM));
|
||||
|
||||
return &wm->xr;
|
||||
}
|
||||
# endif
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name XR Session Settings
|
||||
* \{ */
|
||||
@@ -892,54 +1086,66 @@ static void rna_XrSessionState_viewer_pose_rotation_get(PointerRNA *ptr, float *
|
||||
# endif
|
||||
}
|
||||
|
||||
static void rna_XrSessionState_actionmaps_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
|
||||
{
|
||||
# ifdef WITH_XR_OPENXR
|
||||
wmXrData *xr = rna_XrSession_wm_xr_data_get(ptr);
|
||||
ListBase *lb = WM_xr_actionmaps_get(xr->runtime);
|
||||
rna_iterator_listbase_begin(iter, lb, NULL);
|
||||
# else
|
||||
UNUSED_VARS(iter, ptr);
|
||||
# endif
|
||||
}
|
||||
|
||||
static int rna_XrSessionState_active_actionmap_get(PointerRNA *ptr)
|
||||
static void rna_XrSessionState_nav_location_get(PointerRNA *ptr, float *r_values)
|
||||
{
|
||||
# ifdef WITH_XR_OPENXR
|
||||
const wmXrData *xr = rna_XrSession_wm_xr_data_get(ptr);
|
||||
return WM_xr_actionmap_active_index_get(xr->runtime);
|
||||
WM_xr_session_state_nav_location_get(xr, r_values);
|
||||
# else
|
||||
UNUSED_VARS(ptr);
|
||||
return -1;
|
||||
zero_v3(r_values);
|
||||
# endif
|
||||
}
|
||||
|
||||
static void rna_XrSessionState_active_actionmap_set(PointerRNA *ptr, int value)
|
||||
static void rna_XrSessionState_nav_location_set(PointerRNA *ptr, const float *values)
|
||||
{
|
||||
# ifdef WITH_XR_OPENXR
|
||||
wmXrData *xr = rna_XrSession_wm_xr_data_get(ptr);
|
||||
WM_xr_actionmap_active_index_set(xr->runtime, (short)value);
|
||||
WM_xr_session_state_nav_location_set(xr, values);
|
||||
# else
|
||||
UNUSED_VARS(ptr, value);
|
||||
UNUSED_VARS(ptr, values);
|
||||
# endif
|
||||
}
|
||||
|
||||
static int rna_XrSessionState_selected_actionmap_get(PointerRNA *ptr)
|
||||
static void rna_XrSessionState_nav_rotation_get(PointerRNA *ptr, float *r_values)
|
||||
{
|
||||
# ifdef WITH_XR_OPENXR
|
||||
const wmXrData *xr = rna_XrSession_wm_xr_data_get(ptr);
|
||||
return WM_xr_actionmap_selected_index_get(xr->runtime);
|
||||
WM_xr_session_state_nav_rotation_get(xr, r_values);
|
||||
# else
|
||||
UNUSED_VARS(ptr);
|
||||
return -1;
|
||||
unit_qt(r_values);
|
||||
# endif
|
||||
}
|
||||
|
||||
static void rna_XrSessionState_selected_actionmap_set(PointerRNA *ptr, int value)
|
||||
static void rna_XrSessionState_nav_rotation_set(PointerRNA *ptr, const float *values)
|
||||
{
|
||||
# ifdef WITH_XR_OPENXR
|
||||
wmXrData *xr = rna_XrSession_wm_xr_data_get(ptr);
|
||||
WM_xr_actionmap_selected_index_set(xr->runtime, (short)value);
|
||||
WM_xr_session_state_nav_rotation_set(xr, values);
|
||||
# else
|
||||
UNUSED_VARS(ptr, values);
|
||||
# endif
|
||||
}
|
||||
|
||||
static float rna_XrSessionState_nav_scale_get(PointerRNA *ptr)
|
||||
{
|
||||
float value;
|
||||
# ifdef WITH_XR_OPENXR
|
||||
const wmXrData *xr = rna_XrSession_wm_xr_data_get(ptr);
|
||||
WM_xr_session_state_nav_scale_get(xr, &value);
|
||||
# else
|
||||
UNUSED_VARS(ptr);
|
||||
value = 1.0f;
|
||||
# endif
|
||||
return value;
|
||||
}
|
||||
|
||||
static void rna_XrSessionState_nav_scale_set(PointerRNA *ptr, float value)
|
||||
{
|
||||
# ifdef WITH_XR_OPENXR
|
||||
wmXrData *xr = rna_XrSession_wm_xr_data_get(ptr);
|
||||
WM_xr_session_state_nav_scale_set(xr, value);
|
||||
# else
|
||||
UNUSED_VARS(ptr, value);
|
||||
# endif
|
||||
@@ -1037,7 +1243,7 @@ static const EnumPropertyItem rna_enum_xr_axis1_flags[] = {
|
||||
};
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name XR Action Map
|
||||
/** \name XR Action Configuration
|
||||
* \{ */
|
||||
|
||||
static void rna_def_xr_actionmap_bindings(BlenderRNA *brna, PropertyRNA *cprop)
|
||||
@@ -1058,7 +1264,7 @@ static void rna_def_xr_actionmap_bindings(BlenderRNA *brna, PropertyRNA *cprop)
|
||||
"replace_existing",
|
||||
true,
|
||||
"Replace Existing",
|
||||
"Replace any existing binding with the same name");
|
||||
"Replace any existing binding with same name");
|
||||
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
|
||||
parm = RNA_def_pointer(
|
||||
func, "binding", "XrActionMapBinding", "Binding", "Added action map binding");
|
||||
@@ -1107,7 +1313,7 @@ static void rna_def_xr_actionmap_items(BlenderRNA *brna, PropertyRNA *cprop)
|
||||
"replace_existing",
|
||||
true,
|
||||
"Replace Existing",
|
||||
"Replace any existing item with the same name");
|
||||
"Replace any existing item with same name");
|
||||
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
|
||||
parm = RNA_def_pointer(func, "item", "XrActionMapItem", "Item", "Added action map item");
|
||||
RNA_def_function_return(func, parm);
|
||||
@@ -1140,27 +1346,22 @@ static void rna_def_xr_actionmaps(BlenderRNA *brna, PropertyRNA *cprop)
|
||||
|
||||
RNA_def_property_srna(cprop, "XrActionMaps");
|
||||
srna = RNA_def_struct(brna, "XrActionMaps", NULL);
|
||||
RNA_def_struct_sdna(srna, "XrActionConfig");
|
||||
RNA_def_struct_ui_text(srna, "XR Action Maps", "Collection of XR action maps");
|
||||
|
||||
func = RNA_def_function(srna, "new", "rna_XrActionMap_new");
|
||||
RNA_def_function_flag(func, FUNC_NO_SELF);
|
||||
parm = RNA_def_pointer(func, "xr_session_state", "XrSessionState", "XR Session State", "");
|
||||
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
|
||||
parm = RNA_def_string(func, "name", NULL, MAX_NAME, "Name", "");
|
||||
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
|
||||
parm = RNA_def_boolean(func,
|
||||
"replace_existing",
|
||||
true,
|
||||
"Replace Existing",
|
||||
"Replace any existing actionmap with the same name");
|
||||
"Replace any existing actionmap with same name");
|
||||
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
|
||||
parm = RNA_def_pointer(func, "actionmap", "XrActionMap", "Action Map", "Added action map");
|
||||
RNA_def_function_return(func, parm);
|
||||
|
||||
func = RNA_def_function(srna, "new_from_actionmap", "rna_XrActionMap_new_from_actionmap");
|
||||
RNA_def_function_flag(func, FUNC_NO_SELF);
|
||||
parm = RNA_def_pointer(func, "xr_session_state", "XrSessionState", "XR Session State", "");
|
||||
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
|
||||
parm = RNA_def_pointer(
|
||||
func, "actionmap", "XrActionMap", "Action Map", "Action map to use as a reference");
|
||||
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
|
||||
@@ -1168,17 +1369,12 @@ static void rna_def_xr_actionmaps(BlenderRNA *brna, PropertyRNA *cprop)
|
||||
RNA_def_function_return(func, parm);
|
||||
|
||||
func = RNA_def_function(srna, "remove", "rna_XrActionMap_remove");
|
||||
RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_USE_REPORTS);
|
||||
parm = RNA_def_pointer(func, "xr_session_state", "XrSessionState", "XR Session State", "");
|
||||
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
|
||||
RNA_def_function_flag(func, FUNC_USE_REPORTS);
|
||||
parm = RNA_def_pointer(func, "actionmap", "XrActionMap", "Action Map", "Removed action map");
|
||||
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
|
||||
RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
|
||||
|
||||
func = RNA_def_function(srna, "find", "rna_XrActionMap_find");
|
||||
RNA_def_function_flag(func, FUNC_NO_SELF);
|
||||
parm = RNA_def_pointer(func, "xr_session_state", "XrSessionState", "XR Session State", "");
|
||||
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
|
||||
parm = RNA_def_string(func, "name", NULL, MAX_NAME, "Name", "");
|
||||
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
|
||||
parm = RNA_def_pointer(
|
||||
@@ -1186,11 +1382,106 @@ static void rna_def_xr_actionmaps(BlenderRNA *brna, PropertyRNA *cprop)
|
||||
RNA_def_function_return(func, parm);
|
||||
}
|
||||
|
||||
static void rna_def_xr_actionmap(BlenderRNA *brna)
|
||||
static void rna_def_xr_actionconfigs(BlenderRNA *brna, PropertyRNA *cprop)
|
||||
{
|
||||
StructRNA *srna;
|
||||
FunctionRNA *func;
|
||||
PropertyRNA *prop, *parm;
|
||||
|
||||
RNA_def_property_srna(cprop, "XrActionConfigurations");
|
||||
srna = RNA_def_struct(brna, "XrActionConfigurations", NULL);
|
||||
RNA_def_struct_sdna(srna, "XrSessionSettings");
|
||||
RNA_def_struct_ui_text(
|
||||
srna, "XR Action Configurations", "Collection of XR action configurations");
|
||||
|
||||
prop = RNA_def_property(srna, "active", PROP_POINTER, PROP_NONE);
|
||||
RNA_def_property_struct_type(prop, "XrActionConfig");
|
||||
RNA_def_property_pointer_funcs(prop,
|
||||
"rna_XrSessionSettings_actionconfig_active_get",
|
||||
"rna_XrSessionSettings_actionconfig_active_set",
|
||||
NULL,
|
||||
NULL);
|
||||
RNA_def_property_flag(prop, PROP_EDITABLE);
|
||||
RNA_def_property_ui_text(
|
||||
prop, "Active XR Action Configuration", "Active XR action configuration (preset)");
|
||||
|
||||
prop = RNA_def_property(srna, "default", PROP_POINTER, PROP_NEVER_NULL);
|
||||
RNA_def_property_pointer_sdna(prop, NULL, "defaultconf");
|
||||
RNA_def_property_struct_type(prop, "XrActionConfig");
|
||||
RNA_def_property_ui_text(
|
||||
prop, "Default XR Action Configuration", "Default builtin XR action configuration");
|
||||
|
||||
prop = RNA_def_property(srna, "addon", PROP_POINTER, PROP_NEVER_NULL);
|
||||
RNA_def_property_pointer_sdna(prop, NULL, "addonconf");
|
||||
RNA_def_property_struct_type(prop, "XrActionConfig");
|
||||
RNA_def_property_ui_text(prop,
|
||||
"Add-on XR Action Configuration",
|
||||
"XR action configuration that can be extended by add-ons");
|
||||
|
||||
prop = RNA_def_property(srna, "user", PROP_POINTER, PROP_NEVER_NULL);
|
||||
RNA_def_property_pointer_sdna(prop, NULL, "userconf");
|
||||
RNA_def_property_struct_type(prop, "XrActionConfig");
|
||||
RNA_def_property_ui_text(prop,
|
||||
"User XR Action Configuration",
|
||||
"XR action configuration that can be extended by users");
|
||||
|
||||
func = RNA_def_function(srna, "new", "rna_XrActionConfig_new");
|
||||
parm = RNA_def_string(func, "name", NULL, MAX_NAME, "Name", "");
|
||||
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
|
||||
parm = RNA_def_pointer(func,
|
||||
"actionconfig",
|
||||
"XrActionConfig",
|
||||
"Action Configuration",
|
||||
"Added action configuration");
|
||||
RNA_def_function_return(func, parm);
|
||||
|
||||
func = RNA_def_function(srna, "remove", "rna_XrActionConfig_remove");
|
||||
RNA_def_function_flag(func, FUNC_USE_REPORTS);
|
||||
parm = RNA_def_pointer(func,
|
||||
"actionconfig",
|
||||
"XrActionConfig",
|
||||
"Action Configuration",
|
||||
"Removed action configuration");
|
||||
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
|
||||
RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
|
||||
|
||||
RNA_def_function(srna, "update", "rna_XrActionConfig_update");
|
||||
}
|
||||
|
||||
static void rna_def_xr_actionconfig(BlenderRNA *brna)
|
||||
{
|
||||
StructRNA *srna;
|
||||
PropertyRNA *prop;
|
||||
|
||||
/* XrActionConfig */
|
||||
srna = RNA_def_struct(brna, "XrActionConfig", NULL);
|
||||
RNA_def_struct_sdna(srna, "XrActionConfig");
|
||||
RNA_def_struct_ui_text(srna, "XR Action Configuration", "");
|
||||
|
||||
prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
|
||||
RNA_def_property_ui_text(prop, "Name", "Name of the action configuration");
|
||||
RNA_def_struct_name_property(srna, prop);
|
||||
|
||||
prop = RNA_def_property(srna, "actionmaps", PROP_COLLECTION, PROP_NONE);
|
||||
RNA_def_property_struct_type(prop, "XrActionMap");
|
||||
RNA_def_property_ui_text(
|
||||
prop, "Action Maps", "Action maps configured as part of this configuration");
|
||||
rna_def_xr_actionmaps(brna, prop);
|
||||
|
||||
prop = RNA_def_property(srna, "active_actionmap", PROP_INT, PROP_NONE);
|
||||
RNA_def_property_int_sdna(prop, NULL, "actactionmap");
|
||||
RNA_def_property_ui_text(prop, "Active Action Map", "");
|
||||
|
||||
prop = RNA_def_property(srna, "selected_actionmap", PROP_INT, PROP_NONE);
|
||||
RNA_def_property_int_sdna(prop, NULL, "selactionmap");
|
||||
RNA_def_property_ui_text(prop, "Selected Action Map", "");
|
||||
|
||||
prop = RNA_def_property(srna, "is_user_defined", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "flag", KEYCONF_USER);
|
||||
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
|
||||
RNA_def_property_ui_text(
|
||||
prop, "User Defined", "Indicates that an action configuration was defined by the user");
|
||||
|
||||
/* XrActionMap */
|
||||
srna = RNA_def_struct(brna, "XrActionMap", NULL);
|
||||
RNA_def_struct_sdna(srna, "XrActionMap");
|
||||
@@ -1321,7 +1612,7 @@ static void rna_def_xr_actionmap(BlenderRNA *brna)
|
||||
prop = RNA_def_property(srna, "bindings", PROP_COLLECTION, PROP_NONE);
|
||||
RNA_def_property_struct_type(prop, "XrActionMapBinding");
|
||||
RNA_def_property_ui_text(
|
||||
prop, "Bindings", "Bindings for the action map item, mapping the action to an XR input");
|
||||
prop, "Bindings", "Bindings in the actionmap, linking an action to an XR input");
|
||||
rna_def_xr_actionmap_bindings(brna, prop);
|
||||
|
||||
prop = RNA_def_property(srna, "selected_binding", PROP_INT, PROP_NONE);
|
||||
@@ -1331,7 +1622,9 @@ static void rna_def_xr_actionmap(BlenderRNA *brna)
|
||||
/* XrActionMapBinding */
|
||||
srna = RNA_def_struct(brna, "XrActionMapBinding", NULL);
|
||||
RNA_def_struct_sdna(srna, "XrActionMapBinding");
|
||||
RNA_def_struct_ui_text(srna, "XR Action Map Binding", "Binding in an XR action map item");
|
||||
RNA_def_struct_ui_text(srna,
|
||||
"XR Action Map Binding",
|
||||
"Bindings for the action map item, mapping the action to an XR input");
|
||||
|
||||
prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
|
||||
RNA_def_property_ui_text(prop, "Name", "Name of the action map binding");
|
||||
@@ -1353,7 +1646,7 @@ static void rna_def_xr_actionmap(BlenderRNA *brna)
|
||||
prop = RNA_def_property(srna, "threshold", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_float_sdna(prop, NULL, "float_threshold");
|
||||
RNA_def_property_range(prop, 0.0, 1.0);
|
||||
RNA_def_property_ui_text(prop, "Threshold", "Input threshold for button/axis actions");
|
||||
RNA_def_property_ui_text(prop, "Input Threshold", "Input threshold for button/axis actions");
|
||||
|
||||
prop = RNA_def_property(srna, "axis0_region", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_items(prop, rna_enum_xr_axis0_flags);
|
||||
@@ -1374,10 +1667,101 @@ static void rna_def_xr_actionmap(BlenderRNA *brna)
|
||||
prop, "Axis 1 Region", "Action execution region for the second input axis");
|
||||
|
||||
prop = RNA_def_property(srna, "pose_location", PROP_FLOAT, PROP_TRANSLATION);
|
||||
RNA_def_property_ui_text(prop, "Pose Location Offset", "");
|
||||
RNA_def_property_ui_text(prop, "Pose Location Offset", "Pose location offset");
|
||||
|
||||
prop = RNA_def_property(srna, "pose_rotation", PROP_FLOAT, PROP_EULER);
|
||||
RNA_def_property_ui_text(prop, "Pose Rotation Offset", "");
|
||||
RNA_def_property_ui_text(prop, "Pose Rotation Offset", "Pose rotation offset");
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name XR Motion Capture
|
||||
* \{ */
|
||||
|
||||
static void rna_def_xr_motioncapture_objects(BlenderRNA *brna, PropertyRNA *cprop)
|
||||
{
|
||||
StructRNA *srna;
|
||||
FunctionRNA *func;
|
||||
PropertyRNA *parm;
|
||||
|
||||
RNA_def_property_srna(cprop, "XrMotionCaptureObjects");
|
||||
srna = RNA_def_struct(brna, "XrMotionCaptureObjects", NULL);
|
||||
RNA_def_struct_sdna(srna, "XrSessionSettings");
|
||||
RNA_def_struct_ui_text(
|
||||
srna, "XR Motion Capture Objects", "Collection of XR motion capture objects");
|
||||
|
||||
func = RNA_def_function(srna, "new", "rna_XrMotionCaptureObject_new");
|
||||
parm = RNA_def_pointer(func,
|
||||
"object",
|
||||
"Object",
|
||||
"Object",
|
||||
"Blender object used to identify the motion capture object");
|
||||
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED | PARM_RNAPTR);
|
||||
parm = RNA_def_pointer(func,
|
||||
"mocap_object",
|
||||
"XrMotionCaptureObject",
|
||||
"Motion Capture Object",
|
||||
"Added motion capture object");
|
||||
RNA_def_function_return(func, parm);
|
||||
|
||||
func = RNA_def_function(srna, "remove", "rna_XrMotionCaptureObject_remove");
|
||||
parm = RNA_def_pointer(func,
|
||||
"mocap_object",
|
||||
"XrMotionCaptureObject",
|
||||
"Motion Capture Object",
|
||||
"Removed motion capture object");
|
||||
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
|
||||
RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
|
||||
|
||||
func = RNA_def_function(srna, "find", "rna_XrMotionCaptureObject_find");
|
||||
parm = RNA_def_pointer(
|
||||
func, "object", "Object", "Object", "Blender object identifying the motion capture object");
|
||||
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED | PARM_RNAPTR);
|
||||
parm = RNA_def_pointer(func,
|
||||
"mocap_object",
|
||||
"XrMotionCaptureObject",
|
||||
"Motion Capture Object",
|
||||
"The motion capture object with the given name");
|
||||
RNA_def_function_return(func, parm);
|
||||
}
|
||||
|
||||
static void rna_def_xr_motioncapture_object(BlenderRNA *brna)
|
||||
{
|
||||
StructRNA *srna;
|
||||
PropertyRNA *prop;
|
||||
|
||||
srna = RNA_def_struct(brna, "XrMotionCaptureObject", NULL);
|
||||
RNA_def_struct_sdna(srna, "XrMotionCaptureObject");
|
||||
RNA_def_struct_ui_text(srna, "XR Motion Capture Object", "");
|
||||
|
||||
prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE);
|
||||
RNA_def_property_pointer_sdna(prop, NULL, "ob");
|
||||
RNA_def_property_flag(prop, PROP_EDITABLE);
|
||||
RNA_def_property_ui_text(prop, "Object", "Object to bind to a VR device");
|
||||
RNA_def_property_update(prop, 0, "rna_XrMotionCaptureObject_object_update");
|
||||
|
||||
prop = RNA_def_property(srna, "user_path", PROP_STRING, PROP_NONE);
|
||||
RNA_def_property_string_maxlength(prop, 64);
|
||||
RNA_def_property_ui_text(prop, "User Path", "OpenXR user path identifying the target VR device");
|
||||
|
||||
prop = RNA_def_property(srna, "location_offset", PROP_FLOAT, PROP_TRANSLATION);
|
||||
RNA_def_property_ui_text(prop, "Location Offset", "Location offset in device space");
|
||||
|
||||
prop = RNA_def_property(srna, "rotation_offset", PROP_FLOAT, PROP_EULER);
|
||||
RNA_def_property_ui_text(prop, "Rotation Offset", "Rotation offset in device space");
|
||||
|
||||
prop = RNA_def_property(srna, "enable", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_flag(prop, PROP_EDITABLE);
|
||||
RNA_def_property_boolean_funcs(
|
||||
prop, "rna_XrMotionCaptureObject_enable_get", "rna_XrMotionCaptureObject_enable_set");
|
||||
RNA_def_property_ui_text(prop, "Enable", "Bind object to target VR device");
|
||||
RNA_def_property_update(prop, 0, "rna_XrMotionCaptureObject_enable_update");
|
||||
|
||||
prop = RNA_def_property(srna, "autokey", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_funcs(
|
||||
prop, "rna_XrMotionCaptureObject_autokey_get", "rna_XrMotionCaptureObject_autokey_set");
|
||||
RNA_def_property_ui_text(prop, "Auto Key", "Auto-insert keyframes on animation playback");
|
||||
}
|
||||
|
||||
/** \} */
|
||||
@@ -1410,6 +1794,32 @@ static void rna_def_xr_session_settings(BlenderRNA *brna)
|
||||
{0, NULL, 0, NULL, NULL},
|
||||
};
|
||||
|
||||
static const EnumPropertyItem controller_draw_styles[] = {
|
||||
{XR_CONTROLLER_DRAW_DARK, "DARK", 0, "Dark", "Draw dark controller"},
|
||||
{XR_CONTROLLER_DRAW_LIGHT, "LIGHT", 0, "Light", "Draw light controller"},
|
||||
{XR_CONTROLLER_DRAW_DARK_RAY,
|
||||
"DARK_RAY",
|
||||
0,
|
||||
"Dark + Ray",
|
||||
"Draw dark controller with aiming axis ray"},
|
||||
{XR_CONTROLLER_DRAW_LIGHT_RAY,
|
||||
"LIGHT_RAY",
|
||||
0,
|
||||
"Light + Ray",
|
||||
"Draw light controller with aiming axis ray"},
|
||||
{0, NULL, 0, NULL, NULL},
|
||||
};
|
||||
|
||||
static const EnumPropertyItem selection_eyes[] = {
|
||||
{XR_EYE_LEFT, "EYE_LEFT", 0, "Left Eye", "Use the left eye's perspective for VR selection"},
|
||||
{XR_EYE_RIGHT,
|
||||
"EYE_RIGHT",
|
||||
0,
|
||||
"Right Eye",
|
||||
"Use the right eye's perspective for VR selection"},
|
||||
{0, NULL, 0, NULL, NULL},
|
||||
};
|
||||
|
||||
srna = RNA_def_struct(brna, "XrSessionSettings", NULL);
|
||||
RNA_def_struct_ui_text(srna, "XR Session Settings", "");
|
||||
|
||||
@@ -1450,6 +1860,13 @@ static void rna_def_xr_session_settings(BlenderRNA *brna)
|
||||
"Rotation angle around the Z-Axis to apply the rotation deltas from the VR headset to");
|
||||
RNA_def_property_update(prop, NC_WM | ND_XR_DATA_CHANGED, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "base_scale", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_ui_text(prop, "Base Scale", "Uniform scale to apply to VR view");
|
||||
RNA_def_property_range(prop, 0.001f, 1000.0f);
|
||||
RNA_def_property_ui_range(prop, 0.001f, 1000.0f, 1, 3);
|
||||
RNA_def_property_float_default(prop, 1.0f);
|
||||
RNA_def_property_update(prop, NC_WM | ND_XR_DATA_CHANGED, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "show_floor", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "draw_flags", V3D_OFSDRAW_SHOW_GRIDFLOOR);
|
||||
RNA_def_property_ui_text(prop, "Display Grid Floor", "Show the ground plane grid");
|
||||
@@ -1460,6 +1877,36 @@ static void rna_def_xr_session_settings(BlenderRNA *brna)
|
||||
RNA_def_property_ui_text(prop, "Show Annotation", "Show annotations for this view");
|
||||
RNA_def_property_update(prop, NC_WM | ND_XR_DATA_CHANGED, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "show_selection", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "draw_flags", V3D_OFSDRAW_SHOW_SELECTION);
|
||||
RNA_def_property_ui_text(prop, "Show Selection", "Show selection outlines");
|
||||
RNA_def_property_update(prop, NC_WM | ND_XR_DATA_CHANGED, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "show_controllers", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "draw_flags", V3D_OFSDRAW_XR_SHOW_CONTROLLERS);
|
||||
RNA_def_property_ui_text(
|
||||
prop, "Show Controllers", "Show VR controllers (requires VR actions for controller poses)");
|
||||
RNA_def_property_update(prop, NC_WM | ND_XR_DATA_CHANGED, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "show_custom_overlays", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "draw_flags", V3D_OFSDRAW_XR_SHOW_CUSTOM_OVERLAYS);
|
||||
RNA_def_property_ui_text(prop, "Show Custom Overlays", "Show custom VR overlays");
|
||||
RNA_def_property_update(prop, NC_WM | ND_XR_DATA_CHANGED, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "controller_draw_style", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
RNA_def_property_enum_items(prop, controller_draw_styles);
|
||||
RNA_def_property_ui_text(
|
||||
prop, "Controller Draw Style", "Style to use when drawing VR controllers");
|
||||
RNA_def_property_update(prop, NC_WM | ND_XR_DATA_CHANGED, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "selection_eye", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
RNA_def_property_enum_items(prop, selection_eyes);
|
||||
RNA_def_property_ui_text(
|
||||
prop, "Selection Eye", "Which eye's perspective to use when selecting in VR (GPU select)");
|
||||
RNA_def_property_update(prop, NC_WM | ND_XR_DATA_CHANGED, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "clip_start", PROP_FLOAT, PROP_DISTANCE);
|
||||
RNA_def_property_range(prop, 1e-6f, FLT_MAX);
|
||||
RNA_def_property_ui_range(prop, 0.001f, FLT_MAX, 10, 3);
|
||||
@@ -1489,6 +1936,23 @@ static void rna_def_xr_session_settings(BlenderRNA *brna)
|
||||
RNA_def_property_ui_text(
|
||||
prop, "Absolute Tracking", "Use unadjusted location/rotation as defined by the XR runtime");
|
||||
RNA_def_property_update(prop, NC_WM | ND_XR_DATA_CHANGED, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "actionconfigs", PROP_COLLECTION, PROP_NONE);
|
||||
RNA_def_property_struct_type(prop, "XrActionConfig");
|
||||
RNA_def_property_ui_text(
|
||||
prop, "XR Action Configurations", "Registered XR action configurations");
|
||||
rna_def_xr_actionconfigs(brna, prop);
|
||||
|
||||
prop = RNA_def_property(srna, "mocap_objects", PROP_COLLECTION, PROP_NONE);
|
||||
RNA_def_property_struct_type(prop, "XrMotionCaptureObject");
|
||||
RNA_def_property_ui_text(
|
||||
prop, "XR Motion Capture Objects", "Objects to bind to headset/controller poses");
|
||||
rna_def_xr_motioncapture_objects(brna, prop);
|
||||
|
||||
prop = RNA_def_property(srna, "selected_mocap_object", PROP_INT, PROP_NONE);
|
||||
RNA_def_property_int_sdna(prop, NULL, "sel_mocap_object");
|
||||
RNA_def_property_ui_text(
|
||||
prop, "Selected Motion Capture Object", "Currently selected motion capture object");
|
||||
}
|
||||
|
||||
/** \} */
|
||||
@@ -1793,33 +2257,30 @@ static void rna_def_xr_session_state(BlenderRNA *brna)
|
||||
"Viewer Pose Rotation",
|
||||
"Last known rotation of the viewer pose (center between the eyes) in world space");
|
||||
|
||||
prop = RNA_def_property(srna, "actionmaps", PROP_COLLECTION, PROP_NONE);
|
||||
RNA_def_property_collection_funcs(prop,
|
||||
"rna_XrSessionState_actionmaps_begin",
|
||||
"rna_iterator_listbase_next",
|
||||
"rna_iterator_listbase_end",
|
||||
"rna_iterator_listbase_get",
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL);
|
||||
RNA_def_property_struct_type(prop, "XrActionMap");
|
||||
RNA_def_property_ui_text(prop, "XR Action Maps", "");
|
||||
rna_def_xr_actionmaps(brna, prop);
|
||||
prop = RNA_def_property(srna, "navigation_location", PROP_FLOAT, PROP_TRANSLATION);
|
||||
RNA_def_property_array(prop, 3);
|
||||
RNA_def_property_float_funcs(
|
||||
prop, "rna_XrSessionState_nav_location_get", "rna_XrSessionState_nav_location_set", NULL);
|
||||
RNA_def_property_ui_text(
|
||||
prop,
|
||||
"Navigation Location",
|
||||
"Location offset to apply to base pose when determining viewer location");
|
||||
|
||||
prop = RNA_def_property(srna, "active_actionmap", PROP_INT, PROP_NONE);
|
||||
RNA_def_property_int_funcs(prop,
|
||||
"rna_XrSessionState_active_actionmap_get",
|
||||
"rna_XrSessionState_active_actionmap_set",
|
||||
NULL);
|
||||
RNA_def_property_ui_text(prop, "Active Action Map", "");
|
||||
prop = RNA_def_property(srna, "navigation_rotation", PROP_FLOAT, PROP_QUATERNION);
|
||||
RNA_def_property_array(prop, 4);
|
||||
RNA_def_property_float_funcs(
|
||||
prop, "rna_XrSessionState_nav_rotation_get", "rna_XrSessionState_nav_rotation_set", NULL);
|
||||
RNA_def_property_ui_text(
|
||||
prop,
|
||||
"Navigation Rotation",
|
||||
"Rotation offset to apply to base pose when determining viewer rotation");
|
||||
|
||||
prop = RNA_def_property(srna, "selected_actionmap", PROP_INT, PROP_NONE);
|
||||
RNA_def_property_int_funcs(prop,
|
||||
"rna_XrSessionState_selected_actionmap_get",
|
||||
"rna_XrSessionState_selected_actionmap_set",
|
||||
NULL);
|
||||
RNA_def_property_ui_text(prop, "Selected Action Map", "");
|
||||
prop = RNA_def_property(srna, "navigation_scale", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_float_funcs(
|
||||
prop, "rna_XrSessionState_nav_scale_get", "rna_XrSessionState_nav_scale_set", NULL);
|
||||
RNA_def_property_ui_text(prop,
|
||||
"Navigation Scale",
|
||||
"Scale multiplier to apply to base pose when determining viewer scale");
|
||||
}
|
||||
|
||||
/** \} */
|
||||
@@ -1828,7 +2289,8 @@ void RNA_def_xr(BlenderRNA *brna)
|
||||
{
|
||||
RNA_define_animate_sdna(false);
|
||||
|
||||
rna_def_xr_actionmap(brna);
|
||||
rna_def_xr_actionconfig(brna);
|
||||
rna_def_xr_motioncapture_object(brna);
|
||||
rna_def_xr_session_settings(brna);
|
||||
rna_def_xr_session_state(brna);
|
||||
|
||||
|
@@ -195,6 +195,8 @@ if(WITH_XR_OPENXR)
|
||||
|
||||
list(APPEND INC
|
||||
xr
|
||||
# for wm_xr_operators.c: BKE_editmesh.h
|
||||
../bmesh
|
||||
)
|
||||
|
||||
list(APPEND SRC
|
||||
@@ -202,6 +204,8 @@ if(WITH_XR_OPENXR)
|
||||
xr/intern/wm_xr_action.c
|
||||
xr/intern/wm_xr_actionmap.c
|
||||
xr/intern/wm_xr_draw.c
|
||||
xr/intern/wm_xr_mocap.c
|
||||
xr/intern/wm_xr_operators.c
|
||||
xr/intern/wm_xr_session.c
|
||||
|
||||
xr/wm_xr.h
|
||||
|
@@ -73,10 +73,6 @@ struct wmTabletData;
|
||||
struct wmNDOFMotionData;
|
||||
#endif
|
||||
|
||||
#ifdef WITH_XR_OPENXR
|
||||
struct wmXrRuntimeData;
|
||||
#endif
|
||||
|
||||
typedef struct wmGizmo wmGizmo;
|
||||
typedef struct wmGizmoMap wmGizmoMap;
|
||||
typedef struct wmGizmoMapType wmGizmoMapType;
|
||||
@@ -664,7 +660,13 @@ void WM_paneltype_remove(struct PanelType *pt);
|
||||
|
||||
/* wm_gesture_ops.c */
|
||||
int WM_gesture_box_invoke(struct bContext *C, struct wmOperator *op, const struct wmEvent *event);
|
||||
int WM_gesture_box_invoke_3d(struct bContext *C,
|
||||
struct wmOperator *op,
|
||||
const struct wmEvent *event);
|
||||
int WM_gesture_box_modal(struct bContext *C, struct wmOperator *op, const struct wmEvent *event);
|
||||
int WM_gesture_box_modal_3d(struct bContext *C,
|
||||
struct wmOperator *op,
|
||||
const struct wmEvent *event);
|
||||
void WM_gesture_box_cancel(struct bContext *C, struct wmOperator *op);
|
||||
int WM_gesture_circle_invoke(struct bContext *C,
|
||||
struct wmOperator *op,
|
||||
@@ -932,6 +934,22 @@ bool WM_event_is_tablet(const struct wmEvent *event);
|
||||
int WM_event_absolute_delta_x(const struct wmEvent *event);
|
||||
int WM_event_absolute_delta_y(const struct wmEvent *event);
|
||||
|
||||
void WM_event_xr_data(const struct wmEvent *event,
|
||||
char **action_set,
|
||||
char **action,
|
||||
char *type,
|
||||
float state[2],
|
||||
float state_other[2],
|
||||
float *float_threshold,
|
||||
float controller_loc[3],
|
||||
float controller_rot[4],
|
||||
float controller_loc_other[3],
|
||||
float controller_rot_other[4],
|
||||
float *eye_lens,
|
||||
float eye_viewmat[4][4],
|
||||
bool *bimanual);
|
||||
bool WM_event_is_xr(const struct wmEvent *event);
|
||||
|
||||
#ifdef WITH_INPUT_IME
|
||||
bool WM_event_is_ime_switch(const struct wmEvent *event);
|
||||
#endif
|
||||
@@ -982,8 +1000,11 @@ void WM_xr_session_base_pose_reset(wmXrData *xr);
|
||||
bool WM_xr_session_state_viewer_pose_location_get(const wmXrData *xr, float r_location[3]);
|
||||
bool WM_xr_session_state_viewer_pose_rotation_get(const wmXrData *xr, float r_rotation[4]);
|
||||
bool WM_xr_session_state_viewer_pose_matrix_info_get(const wmXrData *xr,
|
||||
bool from_selection_eye,
|
||||
float r_viewmat[4][4],
|
||||
float *r_focal_len);
|
||||
float *r_focal_len,
|
||||
float *r_clip_start,
|
||||
float *r_clip_end);
|
||||
bool WM_xr_session_state_controller_grip_location_get(const wmXrData *xr,
|
||||
unsigned int subaction_idx,
|
||||
float r_location[3]);
|
||||
@@ -996,6 +1017,15 @@ bool WM_xr_session_state_controller_aim_location_get(const wmXrData *xr,
|
||||
bool WM_xr_session_state_controller_aim_rotation_get(const wmXrData *xr,
|
||||
unsigned int subaction_idx,
|
||||
float r_rotation[4]);
|
||||
bool WM_xr_session_state_nav_location_get(const wmXrData *xr, float r_location[3]);
|
||||
void WM_xr_session_state_nav_location_set(wmXrData *xr, const float location[3]);
|
||||
bool WM_xr_session_state_nav_rotation_get(const wmXrData *xr, float r_rotation[4]);
|
||||
void WM_xr_session_state_nav_rotation_set(wmXrData *xr, const float rotation[4]);
|
||||
bool WM_xr_session_state_nav_scale_get(const wmXrData *xr, float *r_scale);
|
||||
void WM_xr_session_state_nav_scale_set(wmXrData *xr, float scale);
|
||||
void WM_xr_session_state_navigation_reset(struct wmXrSessionState *state);
|
||||
|
||||
struct ARegionType *WM_xr_surface_controller_region_type_get(void);
|
||||
|
||||
/* wm_xr_actions.c */
|
||||
/* XR action functions to be called pre-XR session start.
|
||||
@@ -1060,20 +1090,24 @@ void WM_xr_haptic_action_stop(wmXrData *xr,
|
||||
const char *subaction_path);
|
||||
|
||||
/* wm_xr_actionmap.c */
|
||||
XrActionMap *WM_xr_actionmap_new(struct wmXrRuntimeData *runtime,
|
||||
void WM_xr_actionconfig_init(struct bContext *C);
|
||||
void WM_xr_actionconfig_update_tag(XrActionMap *actionmap, XrActionMapItem *ami);
|
||||
void WM_xr_actionconfig_update(XrSessionSettings *settings);
|
||||
|
||||
XrActionConfig *WM_xr_actionconfig_new(XrSessionSettings *settings,
|
||||
const char *name,
|
||||
bool user_defined);
|
||||
bool WM_xr_actionconfig_remove(XrSessionSettings *settings, XrActionConfig *actionconf);
|
||||
XrActionConfig *WM_xr_actionconfig_active_get(XrSessionSettings *settings);
|
||||
void WM_xr_actionconfig_active_set(XrSessionSettings *settings, const char *name);
|
||||
|
||||
XrActionMap *WM_xr_actionmap_new(XrActionConfig *actionconf,
|
||||
const char *name,
|
||||
bool replace_existing);
|
||||
void WM_xr_actionmap_ensure_unique(struct wmXrRuntimeData *runtime, XrActionMap *actionmap);
|
||||
XrActionMap *WM_xr_actionmap_add_copy(struct wmXrRuntimeData *runtime, XrActionMap *am_src);
|
||||
bool WM_xr_actionmap_remove(struct wmXrRuntimeData *runtime, XrActionMap *actionmap);
|
||||
XrActionMap *WM_xr_actionmap_find(struct wmXrRuntimeData *runtime, const char *name);
|
||||
void WM_xr_actionmap_clear(XrActionMap *actionmap);
|
||||
void WM_xr_actionmaps_clear(struct wmXrRuntimeData *runtime);
|
||||
ListBase *WM_xr_actionmaps_get(struct wmXrRuntimeData *runtime);
|
||||
short WM_xr_actionmap_active_index_get(const struct wmXrRuntimeData *runtime);
|
||||
void WM_xr_actionmap_active_index_set(struct wmXrRuntimeData *runtime, short idx);
|
||||
short WM_xr_actionmap_selected_index_get(const struct wmXrRuntimeData *runtime);
|
||||
void WM_xr_actionmap_selected_index_set(struct wmXrRuntimeData *runtime, short idx);
|
||||
void WM_xr_actionmap_ensure_unique(XrActionConfig *actionconf, XrActionMap *actionmap);
|
||||
XrActionMap *WM_xr_actionmap_add_copy(XrActionConfig *actionconf, XrActionMap *am_src);
|
||||
bool WM_xr_actionmap_remove(XrActionConfig *actionconf, XrActionMap *actionmap);
|
||||
XrActionMap *WM_xr_actionmap_find(XrActionConfig *actionconf, const char *name);
|
||||
|
||||
XrActionMapItem *WM_xr_actionmap_item_new(XrActionMap *actionmap,
|
||||
const char *name,
|
||||
@@ -1094,6 +1128,25 @@ bool WM_xr_actionmap_binding_remove(XrActionMapItem *ami, XrActionMapBinding *am
|
||||
XrActionMapBinding *WM_xr_actionmap_binding_find(XrActionMapItem *ami, const char *name);
|
||||
#endif /* WITH_XR_OPENXR */
|
||||
|
||||
/* wm.c */
|
||||
/* These need to be accessible even when WITH_XR_OPENXR is not defined since actionmaps can be
|
||||
* stored in files. */
|
||||
void WM_xr_actionconfig_free(XrActionConfig *actionconf);
|
||||
void WM_xr_actionconfig_clear(XrActionConfig *actionconf);
|
||||
void WM_xr_actionmap_clear(XrActionMap *actionmap);
|
||||
void WM_xr_actionmap_item_properties_free(XrActionMapItem *ami);
|
||||
void WM_xr_actionmap_item_bindings_clear(XrActionMapItem *ami);
|
||||
|
||||
/* wm_xr_mocap.c */
|
||||
XrMotionCaptureObject *WM_xr_mocap_object_new(XrSessionSettings *settings, Object *ob);
|
||||
void WM_xr_mocap_object_ensure_unique(XrSessionSettings *settings,
|
||||
XrMotionCaptureObject *mocap_ob);
|
||||
void WM_xr_mocap_object_remove(XrSessionSettings *settings, XrMotionCaptureObject *mocap_ob);
|
||||
XrMotionCaptureObject *WM_xr_mocap_object_find(const XrSessionSettings *settings,
|
||||
const Object *ob);
|
||||
|
||||
bool WM_xr_session_state_mocap_pose_get(const wmXrData *xr, XrMotionCaptureObject *mocap_ob);
|
||||
void WM_xr_session_state_mocap_pose_set(wmXrData *xr, const XrMotionCaptureObject *mocap_ob);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@@ -109,17 +109,20 @@
|
||||
#pragma once
|
||||
|
||||
struct ID;
|
||||
struct IDProperty;
|
||||
struct ImBuf;
|
||||
struct bContext;
|
||||
struct wmDrag;
|
||||
struct wmDropBox;
|
||||
struct wmEvent;
|
||||
struct wmOperator;
|
||||
struct wmOperatorType;
|
||||
struct wmWindowManager;
|
||||
|
||||
#include "BLI_compiler_attrs.h"
|
||||
#include "DNA_listBase.h"
|
||||
#include "DNA_vec_types.h"
|
||||
#include "DNA_xr_types.h"
|
||||
#include "RNA_types.h"
|
||||
|
||||
/* exported types for WM */
|
||||
@@ -723,6 +726,41 @@ typedef struct wmXrActionState {
|
||||
} wmXrActionState;
|
||||
#endif
|
||||
|
||||
typedef struct wmXrActionData {
|
||||
/** Action set name. */
|
||||
char action_set[64];
|
||||
/** Action name. */
|
||||
char action[64];
|
||||
/** Type. */
|
||||
eXrActionType type;
|
||||
/** State. Set appropriately based on type. */
|
||||
float state[2];
|
||||
/** State of the other subaction path for bimanual actions. */
|
||||
float state_other[2];
|
||||
|
||||
/** Input threshold for float/vector2f actions. */
|
||||
float float_threshold;
|
||||
|
||||
/** Controller aim pose corresponding to the action's subaction path. */
|
||||
float controller_loc[3];
|
||||
float controller_rot[4];
|
||||
/** Controller aim pose of the other subaction path for bimanual actions. */
|
||||
float controller_loc_other[3];
|
||||
float controller_rot_other[4];
|
||||
|
||||
/** Lens (focal length) of the selection eye. */
|
||||
float eye_lens;
|
||||
/** Viewmat of the selection eye. */
|
||||
float eye_viewmat[4][4];
|
||||
|
||||
/** Operator. */
|
||||
struct wmOperatorType *ot;
|
||||
struct IDProperty *op_properties;
|
||||
|
||||
/** Whether bimanual interaction is occuring. */
|
||||
bool bimanual;
|
||||
} wmXrActionData;
|
||||
|
||||
/** Timer flags. */
|
||||
typedef enum {
|
||||
/** Do not attempt to free customdata pointer even if non-NULL. */
|
||||
@@ -796,6 +834,14 @@ typedef struct wmOperatorType {
|
||||
struct wmOperator *,
|
||||
const struct wmEvent *) ATTR_WARN_UNUSED_RESULT;
|
||||
|
||||
/**
|
||||
* Same as invoke() but intended to be called from an XR session.
|
||||
* The event type should be EVT_XR_ACTION and custom data type EVT_DATA_XR.
|
||||
*/
|
||||
int (*invoke_3d)(struct bContext *,
|
||||
struct wmOperator *,
|
||||
const struct wmEvent *) ATTR_WARN_UNUSED_RESULT;
|
||||
|
||||
/**
|
||||
* Called when a modal operator is canceled (not used often).
|
||||
* Internal cleanup can be done here if needed.
|
||||
@@ -812,6 +858,14 @@ typedef struct wmOperatorType {
|
||||
struct wmOperator *,
|
||||
const struct wmEvent *) ATTR_WARN_UNUSED_RESULT;
|
||||
|
||||
/**
|
||||
* Same as modal() but intended to be called from an XR session.
|
||||
* The event type should be EVT_XR_ACTION and custom data type EVT_DATA_XR.
|
||||
*/
|
||||
int (*modal_3d)(struct bContext *,
|
||||
struct wmOperator *,
|
||||
const struct wmEvent *) ATTR_WARN_UNUSED_RESULT;
|
||||
|
||||
/**
|
||||
* Verify if the operator can be executed in the current context, note
|
||||
* that the operator might still fail to execute even if this return true.
|
||||
|
@@ -106,6 +106,32 @@ static void window_manager_foreach_id(ID *id, LibraryForeachIDData *data)
|
||||
static void write_wm_xr_data(BlendWriter *writer, wmXrData *xr_data)
|
||||
{
|
||||
BKE_screen_view3d_shading_blend_write(writer, &xr_data->session_settings.shading);
|
||||
|
||||
LISTBASE_FOREACH (XrActionConfig *, ac, &xr_data->session_settings.actionconfigs) {
|
||||
BLO_write_struct(writer, XrActionConfig, ac);
|
||||
|
||||
/* Only write actionmaps for user configs. */
|
||||
if ((ac->flag & XR_ACTIONCONF_USER) != 0) {
|
||||
LISTBASE_FOREACH (XrActionMap *, am, &ac->actionmaps) {
|
||||
BLO_write_struct(writer, XrActionMap, am);
|
||||
|
||||
LISTBASE_FOREACH (XrActionMapItem *, ami, &am->items) {
|
||||
BLO_write_struct(writer, XrActionMapItem, ami);
|
||||
if (ami->op[0] && ami->op_properties) {
|
||||
IDP_BlendWrite(writer, ami->op_properties);
|
||||
}
|
||||
|
||||
LISTBASE_FOREACH (XrActionMapBinding *, amb, &ami->bindings) {
|
||||
BLO_write_struct(writer, XrActionMapBinding, amb);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LISTBASE_FOREACH (XrMotionCaptureObject *, mocap_ob, &xr_data->session_settings.mocap_objects) {
|
||||
BLO_write_struct(writer, XrMotionCaptureObject, mocap_ob);
|
||||
}
|
||||
}
|
||||
|
||||
static void window_manager_blend_write(BlendWriter *writer, ID *id, const void *id_address)
|
||||
@@ -134,6 +160,39 @@ static void window_manager_blend_write(BlendWriter *writer, ID *id, const void *
|
||||
static void direct_link_wm_xr_data(BlendDataReader *reader, wmXrData *xr_data)
|
||||
{
|
||||
BKE_screen_view3d_shading_blend_read_data(reader, &xr_data->session_settings.shading);
|
||||
|
||||
BLO_read_list(reader, &xr_data->session_settings.actionconfigs);
|
||||
|
||||
LISTBASE_FOREACH (XrActionConfig *, ac, &xr_data->session_settings.actionconfigs) {
|
||||
BLO_read_list(reader, &ac->actionmaps);
|
||||
|
||||
LISTBASE_FOREACH (XrActionMap *, am, &ac->actionmaps) {
|
||||
BLO_read_list(reader, &am->items);
|
||||
|
||||
LISTBASE_FOREACH (XrActionMapItem *, ami, &am->items) {
|
||||
if (ami->op[0] && ami->op_properties) {
|
||||
BLO_read_data_address(reader, &ami->op_properties);
|
||||
IDP_BlendDataRead(reader, &ami->op_properties);
|
||||
|
||||
ami->op_properties_ptr = MEM_callocN(sizeof(PointerRNA), "wmOpItemPtr");
|
||||
WM_operator_properties_create(ami->op_properties_ptr, ami->op);
|
||||
ami->op_properties_ptr->data = ami->op_properties;
|
||||
}
|
||||
else {
|
||||
ami->op_properties = NULL;
|
||||
ami->op_properties_ptr = NULL;
|
||||
}
|
||||
|
||||
BLO_read_list(reader, &ami->bindings);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BLO_read_data_address(reader, &xr_data->session_settings.defaultconf);
|
||||
BLO_read_data_address(reader, &xr_data->session_settings.addonconf);
|
||||
BLO_read_data_address(reader, &xr_data->session_settings.userconf);
|
||||
|
||||
BLO_read_list(reader, &xr_data->session_settings.mocap_objects);
|
||||
}
|
||||
|
||||
static void window_manager_blend_read_data(BlendDataReader *reader, ID *id)
|
||||
@@ -227,6 +286,10 @@ static void window_manager_blend_read_data(BlendDataReader *reader, ID *id)
|
||||
static void lib_link_wm_xr_data(BlendLibReader *reader, ID *parent_id, wmXrData *xr_data)
|
||||
{
|
||||
BLO_read_id_address(reader, parent_id->lib, &xr_data->session_settings.base_pose_object);
|
||||
|
||||
LISTBASE_FOREACH (XrMotionCaptureObject *, mocap_ob, &xr_data->session_settings.mocap_objects) {
|
||||
BLO_read_id_address(reader, parent_id->lib, &mocap_ob->ob);
|
||||
}
|
||||
}
|
||||
|
||||
static void lib_link_workspace_instance_hook(BlendLibReader *reader,
|
||||
@@ -433,6 +496,55 @@ void WM_operator_handlers_clear(wmWindowManager *wm, wmOperatorType *ot)
|
||||
}
|
||||
}
|
||||
|
||||
void WM_xr_actionmap_item_bindings_clear(XrActionMapItem *ami)
|
||||
{
|
||||
BLI_freelistN(&ami->bindings);
|
||||
|
||||
ami->selbinding = 0;
|
||||
}
|
||||
|
||||
void WM_xr_actionmap_item_properties_free(XrActionMapItem *ami)
|
||||
{
|
||||
if (ami->op_properties_ptr) {
|
||||
WM_operator_properties_free(ami->op_properties_ptr);
|
||||
MEM_freeN(ami->op_properties_ptr);
|
||||
ami->op_properties_ptr = NULL;
|
||||
ami->op_properties = NULL;
|
||||
}
|
||||
else {
|
||||
BLI_assert(ami->op_properties == NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void WM_xr_actionmap_clear(XrActionMap *actionmap)
|
||||
{
|
||||
LISTBASE_FOREACH (XrActionMapItem *, ami, &actionmap->items) {
|
||||
WM_xr_actionmap_item_bindings_clear(ami);
|
||||
WM_xr_actionmap_item_properties_free(ami);
|
||||
}
|
||||
|
||||
BLI_freelistN(&actionmap->items);
|
||||
|
||||
actionmap->selitem = 0;
|
||||
}
|
||||
|
||||
void WM_xr_actionconfig_clear(XrActionConfig *actionconf)
|
||||
{
|
||||
LISTBASE_FOREACH (XrActionMap *, am, &actionconf->actionmaps) {
|
||||
WM_xr_actionmap_clear(am);
|
||||
}
|
||||
|
||||
BLI_freelistN(&actionconf->actionmaps);
|
||||
|
||||
actionconf->selactionmap = actionconf->actactionmap = 0;
|
||||
}
|
||||
|
||||
void WM_xr_actionconfig_free(XrActionConfig *actionconf)
|
||||
{
|
||||
WM_xr_actionconfig_clear(actionconf);
|
||||
MEM_freeN(actionconf);
|
||||
}
|
||||
|
||||
/* ****************************************** */
|
||||
|
||||
void WM_keyconfig_reload(bContext *C)
|
||||
@@ -507,6 +619,9 @@ void WM_check(bContext *C)
|
||||
/* Case: fileread. */
|
||||
if ((wm->initialized & WM_WINDOW_IS_INIT) == 0) {
|
||||
WM_keyconfig_init(C);
|
||||
#ifdef WITH_XR_OPENXR
|
||||
WM_xr_actionconfig_init(C);
|
||||
#endif
|
||||
WM_autosave_init(wm);
|
||||
}
|
||||
|
||||
@@ -595,6 +710,13 @@ void wm_close_and_free(bContext *C, wmWindowManager *wm)
|
||||
WM_keyconfig_free(keyconf);
|
||||
}
|
||||
|
||||
XrActionConfig *actionconf;
|
||||
while ((actionconf = BLI_pophead(&wm->xr.session_settings.actionconfigs))) {
|
||||
WM_xr_actionconfig_free(actionconf);
|
||||
}
|
||||
|
||||
BLI_freelistN(&wm->xr.session_settings.mocap_objects);
|
||||
|
||||
BLI_freelistN(&wm->notifier_queue);
|
||||
|
||||
if (wm->message_bus != NULL) {
|
||||
|
@@ -485,6 +485,75 @@ int WM_event_absolute_delta_y(const struct wmEvent *event)
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name XR Input Access
|
||||
* \{ */
|
||||
|
||||
void WM_event_xr_data(const wmEvent *event,
|
||||
char **action_set,
|
||||
char **action,
|
||||
char *type,
|
||||
float state[2],
|
||||
float state_other[2],
|
||||
float *float_threshold,
|
||||
float controller_loc[3],
|
||||
float controller_rot[4],
|
||||
float controller_loc_other[3],
|
||||
float controller_rot_other[4],
|
||||
float *eye_lens,
|
||||
float eye_viewmat[4][4],
|
||||
bool *bimanual)
|
||||
{
|
||||
const wmXrActionData *data = event->customdata;
|
||||
|
||||
if (action_set) {
|
||||
strcpy(*action_set, data->action_set);
|
||||
}
|
||||
if (action) {
|
||||
strcpy(*action, data->action);
|
||||
}
|
||||
if (type) {
|
||||
*type = data->type;
|
||||
}
|
||||
if (state) {
|
||||
copy_v2_v2(state, data->state);
|
||||
}
|
||||
if (state_other) {
|
||||
copy_v2_v2(state_other, data->state_other);
|
||||
}
|
||||
if (float_threshold) {
|
||||
*float_threshold = data->float_threshold;
|
||||
}
|
||||
if (controller_loc) {
|
||||
copy_v3_v3(controller_loc, data->controller_loc);
|
||||
}
|
||||
if (controller_rot) {
|
||||
copy_v4_v4(controller_rot, data->controller_rot);
|
||||
}
|
||||
if (controller_loc_other) {
|
||||
copy_v3_v3(controller_loc_other, data->controller_loc_other);
|
||||
}
|
||||
if (controller_rot_other) {
|
||||
copy_v4_v4(controller_rot_other, data->controller_rot_other);
|
||||
}
|
||||
if (eye_lens) {
|
||||
*eye_lens = data->eye_lens;
|
||||
}
|
||||
if (eye_viewmat) {
|
||||
copy_m4_m4(eye_viewmat, data->eye_viewmat);
|
||||
}
|
||||
if (bimanual) {
|
||||
*bimanual = data->bimanual;
|
||||
}
|
||||
}
|
||||
|
||||
bool WM_event_is_xr(const struct wmEvent *event)
|
||||
{
|
||||
return (event->custom == EVT_DATA_XR);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Event IME Input Access
|
||||
* \{ */
|
||||
|
@@ -83,6 +83,7 @@
|
||||
#include "wm.h"
|
||||
#include "wm_event_system.h"
|
||||
#include "wm_event_types.h"
|
||||
#include "wm_surface.h"
|
||||
#include "wm_window.h"
|
||||
|
||||
#include "DEG_depsgraph.h"
|
||||
@@ -1341,7 +1342,19 @@ static int wm_operator_invoke(bContext *C,
|
||||
ot->idname);
|
||||
}
|
||||
|
||||
if (op->type->invoke && event) {
|
||||
if (op->type->invoke_3d && event && (event->type == EVT_XR_ACTION)) {
|
||||
if (op->type->flag & OPTYPE_UNDO) {
|
||||
wm->op_undo_depth++;
|
||||
}
|
||||
|
||||
retval = op->type->invoke_3d(C, op, event);
|
||||
OPERATOR_RETVAL_CHECK(retval);
|
||||
|
||||
if (op->type->flag & OPTYPE_UNDO && CTX_wm_manager(C) == wm) {
|
||||
wm->op_undo_depth--;
|
||||
}
|
||||
}
|
||||
else if (op->type->invoke && event) {
|
||||
wm_region_mouse_co(C, event);
|
||||
|
||||
if (op->type->flag & OPTYPE_UNDO) {
|
||||
@@ -2227,7 +2240,7 @@ static int wm_handler_operator_call(bContext *C,
|
||||
* nothing to do in this case.
|
||||
*/
|
||||
}
|
||||
else if (ot->modal) {
|
||||
else if (ot->modal || ot->modal_3d) {
|
||||
/* We set context to where modal handler came from. */
|
||||
wmWindowManager *wm = CTX_wm_manager(C);
|
||||
wmWindow *win = CTX_wm_window(C);
|
||||
@@ -2245,7 +2258,15 @@ static int wm_handler_operator_call(bContext *C,
|
||||
}
|
||||
|
||||
/* Warning, after this call all context data and 'event' may be freed. see check below. */
|
||||
retval = ot->modal(C, op, event);
|
||||
if (ot->modal_3d && event->type == EVT_XR_ACTION) {
|
||||
retval = ot->modal_3d(C, op, event);
|
||||
}
|
||||
else if (ot->modal) {
|
||||
retval = ot->modal(C, op, event);
|
||||
}
|
||||
else {
|
||||
/* Pass through. An "XR operator" (only modal_3d) received a non-XR event.*/
|
||||
}
|
||||
OPERATOR_RETVAL_CHECK(retval);
|
||||
|
||||
if (ot->flag & OPTYPE_UNDO && CTX_wm_manager(C) == wm) {
|
||||
@@ -3434,6 +3455,71 @@ static void wm_event_free_and_remove_from_queue_if_valid(wmEvent *event)
|
||||
* Handle events for all windows, run from the #WM_main event loop.
|
||||
* \{ */
|
||||
|
||||
#ifdef WITH_XR_OPENXR
|
||||
static void wm_event_handle_xrevent(
|
||||
bContext *C, wmWindowManager *wm, wmWindow *win, bScreen *screen, wmEvent *event)
|
||||
{
|
||||
int action = 0;
|
||||
|
||||
/* Find a valid region for XR operator execution and modal handling. */
|
||||
ED_screen_areas_iter (win, screen, area) {
|
||||
CTX_wm_area_set(C, area);
|
||||
if (!CTX_wm_view3d(C)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
|
||||
if (!WM_region_use_viewport(area, region)) {
|
||||
continue;
|
||||
}
|
||||
CTX_wm_region_set(C, region);
|
||||
|
||||
action |= wm_handlers_do(C, event, &win->modalhandlers);
|
||||
|
||||
if ((action & WM_HANDLER_BREAK) == 0) {
|
||||
wmXrActionData *actiondata = event->customdata;
|
||||
if ((actiondata->ot->modal || actiondata->ot->modal_3d) && event->val == KM_RELEASE) {
|
||||
/* Don't execute modal operators on release. */
|
||||
}
|
||||
else {
|
||||
PointerRNA properties = {.type = actiondata->ot->srna,
|
||||
.data = actiondata->op_properties};
|
||||
if (actiondata->ot->invoke || actiondata->ot->invoke_3d) {
|
||||
/* Invoke operator, either executing operator or transferring responsibility to window
|
||||
* modal handlers. */
|
||||
wm_operator_invoke(C,
|
||||
actiondata->ot,
|
||||
event,
|
||||
actiondata->op_properties ? &properties : NULL,
|
||||
NULL,
|
||||
false,
|
||||
false);
|
||||
}
|
||||
else {
|
||||
/* Execute operator. */
|
||||
wmOperator *op = wm_operator_create(
|
||||
wm, actiondata->ot, actiondata->op_properties ? &properties : NULL, NULL);
|
||||
if ((WM_operator_call(C, op) & OPERATOR_HANDLED) == 0) {
|
||||
WM_operator_free(op);
|
||||
}
|
||||
}
|
||||
}
|
||||
action |= WM_HANDLER_BREAK;
|
||||
}
|
||||
|
||||
CTX_wm_region_set(C, NULL);
|
||||
break;
|
||||
}
|
||||
|
||||
if (action & WM_HANDLER_BREAK) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
CTX_wm_area_set(C, NULL);
|
||||
}
|
||||
#endif /* WITH_XR_OPENXR */
|
||||
|
||||
/* Called in main loop. */
|
||||
/* Goes over entire hierarchy: events -> window -> screen -> area -> region. */
|
||||
void wm_event_do_handlers(bContext *C)
|
||||
@@ -3531,6 +3617,16 @@ void wm_event_do_handlers(bContext *C)
|
||||
|
||||
CTX_wm_window_set(C, win);
|
||||
|
||||
#ifdef WITH_XR_OPENXR
|
||||
if (event->type == EVT_XR_ACTION) {
|
||||
wm_event_handle_xrevent(C, wm, win, screen, event);
|
||||
BLI_remlink(&win->event_queue, event);
|
||||
wm_event_free(event);
|
||||
/* Skip mouse event handling below, which is unnecessary for XR events. */
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Clear tool-tip on mouse move. */
|
||||
if (screen->tool_tip && screen->tool_tip->exit_on_event) {
|
||||
if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) {
|
||||
@@ -5083,6 +5179,24 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef WITH_XR_OPENXR
|
||||
void wm_event_add_xrevent(wmWindow *win, wmXrActionData *actiondata, short val)
|
||||
{
|
||||
BLI_assert(val == KM_PRESS || val == KM_RELEASE);
|
||||
|
||||
wmEvent event = {
|
||||
.type = EVT_XR_ACTION,
|
||||
.val = val,
|
||||
.is_repeat = false,
|
||||
.custom = EVT_DATA_XR,
|
||||
.customdata = actiondata,
|
||||
.customdatafree = 1,
|
||||
};
|
||||
|
||||
wm_event_add(win, &event);
|
||||
}
|
||||
#endif /* WITH_XR_OPENXR */
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
@@ -204,6 +204,18 @@ static void wm_window_match_init(bContext *C, ListBase *wmlist)
|
||||
WM_event_remove_handlers(C, &win->modalhandlers);
|
||||
ED_screen_exit(C, win, WM_window_get_active_screen(win));
|
||||
}
|
||||
|
||||
/* Free XR actionconfigs and motion capture objects. */
|
||||
XrSessionSettings *xrsettings = &wm->xr.session_settings;
|
||||
XrActionConfig *actionconf;
|
||||
while ((actionconf = BLI_pophead(&xrsettings->actionconfigs))) {
|
||||
WM_xr_actionconfig_free(actionconf);
|
||||
}
|
||||
xrsettings->defaultconf = NULL;
|
||||
xrsettings->addonconf = NULL;
|
||||
xrsettings->userconf = NULL;
|
||||
|
||||
BLI_freelistN(&xrsettings->mocap_objects);
|
||||
}
|
||||
|
||||
/* reset active window */
|
||||
|
@@ -36,6 +36,8 @@
|
||||
|
||||
#include "BKE_context.h"
|
||||
|
||||
#include "DEG_depsgraph.h"
|
||||
|
||||
#include "WM_api.h"
|
||||
#include "WM_types.h"
|
||||
|
||||
@@ -45,6 +47,9 @@
|
||||
|
||||
#include "ED_screen.h"
|
||||
#include "ED_select_utils.h"
|
||||
#include "ED_view3d.h"
|
||||
|
||||
#include "../editors/space_view3d/view3d_intern.h"
|
||||
|
||||
#include "UI_interface.h"
|
||||
|
||||
@@ -202,6 +207,60 @@ int WM_gesture_box_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
||||
return OPERATOR_RUNNING_MODAL;
|
||||
}
|
||||
|
||||
int WM_gesture_box_invoke_3d(bContext *C, wmOperator *op, const wmEvent *event)
|
||||
{
|
||||
BLI_assert(event->type == EVT_XR_ACTION);
|
||||
BLI_assert(event->custom == EVT_DATA_XR);
|
||||
BLI_assert(event->customdata);
|
||||
|
||||
const wmXrActionData *actiondata = event->customdata;
|
||||
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
View3D *v3d = CTX_wm_view3d(C);
|
||||
ARegion *region = CTX_wm_region(C);
|
||||
RegionView3D *rv3d = region->regiondata;
|
||||
wmWindowManager *wm = CTX_wm_manager(C);
|
||||
wmXrData *xr = &wm->xr;
|
||||
float lens_prev;
|
||||
float clip_start_prev, clip_end_prev;
|
||||
int mval[2];
|
||||
int retval;
|
||||
|
||||
wmEvent event_mut;
|
||||
memcpy(&event_mut, event, sizeof(wmEvent));
|
||||
|
||||
/* Replace window view parameters with XR surface counterparts. */
|
||||
ED_view3d_view_params_get(v3d, rv3d, &lens_prev, &clip_start_prev, &clip_end_prev, NULL);
|
||||
ED_view3d_view_params_set(depsgraph,
|
||||
scene,
|
||||
v3d,
|
||||
region,
|
||||
actiondata->eye_lens,
|
||||
xr->session_settings.clip_start,
|
||||
xr->session_settings.clip_end,
|
||||
NULL);
|
||||
|
||||
map_to_pixel(mval,
|
||||
actiondata->controller_loc,
|
||||
actiondata->eye_viewmat,
|
||||
rv3d->winmat,
|
||||
region->winx,
|
||||
region->winy);
|
||||
|
||||
event_mut.x = region->winrct.xmin + mval[0];
|
||||
event_mut.y = region->winrct.ymin + mval[1];
|
||||
|
||||
RNA_boolean_set(op->ptr, "wait_for_input", false);
|
||||
|
||||
retval = WM_gesture_box_invoke(C, op, &event_mut);
|
||||
|
||||
/* Restore window view. */
|
||||
ED_view3d_view_params_set(
|
||||
depsgraph, scene, v3d, region, lens_prev, clip_start_prev, clip_end_prev, NULL);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
int WM_gesture_box_modal(bContext *C, wmOperator *op, const wmEvent *event)
|
||||
{
|
||||
wmWindow *win = CTX_wm_window(C);
|
||||
@@ -280,6 +339,85 @@ int WM_gesture_box_modal(bContext *C, wmOperator *op, const wmEvent *event)
|
||||
return OPERATOR_RUNNING_MODAL;
|
||||
}
|
||||
|
||||
int WM_gesture_box_modal_3d(bContext *C, wmOperator *op, const wmEvent *event)
|
||||
{
|
||||
BLI_assert(event->type == EVT_XR_ACTION);
|
||||
BLI_assert(event->custom == EVT_DATA_XR);
|
||||
BLI_assert(event->customdata);
|
||||
|
||||
const bool release = (event->val == KM_RELEASE);
|
||||
|
||||
const wmXrActionData *actiondata = event->customdata;
|
||||
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
View3D *v3d = CTX_wm_view3d(C);
|
||||
ARegion *region = CTX_wm_region(C);
|
||||
RegionView3D *rv3d = region->regiondata;
|
||||
wmWindowManager *wm = CTX_wm_manager(C);
|
||||
wmXrData *xr = &wm->xr;
|
||||
float lens_prev;
|
||||
float clip_start_prev, clip_end_prev;
|
||||
float viewmat_prev[4][4];
|
||||
int mval[2];
|
||||
int retval;
|
||||
|
||||
wmEvent event_mut;
|
||||
memcpy(&event_mut, event, sizeof(wmEvent));
|
||||
|
||||
/* Since this function is called in a window context, we need to replace the
|
||||
* window view parameters with the XR surface counterparts to get a correct
|
||||
* result for some operators (e.g. GPU select). */
|
||||
ED_view3d_view_params_get(
|
||||
v3d, rv3d, &lens_prev, &clip_start_prev, &clip_end_prev, release ? viewmat_prev : NULL);
|
||||
ED_view3d_view_params_set(depsgraph,
|
||||
scene,
|
||||
v3d,
|
||||
region,
|
||||
actiondata->eye_lens,
|
||||
xr->session_settings.clip_start,
|
||||
xr->session_settings.clip_end,
|
||||
release ? actiondata->eye_viewmat : NULL);
|
||||
|
||||
map_to_pixel(mval,
|
||||
actiondata->controller_loc,
|
||||
actiondata->eye_viewmat,
|
||||
rv3d->winmat,
|
||||
region->winx,
|
||||
region->winy);
|
||||
|
||||
if (event->val == KM_PRESS) {
|
||||
event_mut.type = MOUSEMOVE;
|
||||
{
|
||||
wmGesture *gesture = op->customdata;
|
||||
gesture->is_active = true;
|
||||
}
|
||||
event_mut.x = region->winrct.xmin + mval[0];
|
||||
event_mut.y = region->winrct.ymin + mval[1];
|
||||
}
|
||||
else if (event->val == KM_RELEASE) {
|
||||
event_mut.type = EVT_MODAL_MAP;
|
||||
event_mut.val = GESTURE_MODAL_SELECT;
|
||||
}
|
||||
else {
|
||||
/* XR events currently only support press and release. */
|
||||
BLI_assert(false);
|
||||
}
|
||||
|
||||
retval = WM_gesture_box_modal(C, op, &event_mut);
|
||||
|
||||
/* Restore window view. */
|
||||
ED_view3d_view_params_set(depsgraph,
|
||||
scene,
|
||||
v3d,
|
||||
region,
|
||||
lens_prev,
|
||||
clip_start_prev,
|
||||
clip_end_prev,
|
||||
release ? viewmat_prev : NULL);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
void WM_gesture_box_cancel(bContext *C, wmOperator *op)
|
||||
{
|
||||
gesture_modal_end(C, op);
|
||||
|
@@ -3760,87 +3760,6 @@ static void WM_OT_stereo3d_set(wmOperatorType *ot)
|
||||
|
||||
/** \} */
|
||||
|
||||
#ifdef WITH_XR_OPENXR
|
||||
|
||||
static void wm_xr_session_update_screen(Main *bmain, const wmXrData *xr_data)
|
||||
{
|
||||
const bool session_exists = WM_xr_session_exists(xr_data);
|
||||
|
||||
for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
|
||||
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
|
||||
LISTBASE_FOREACH (SpaceLink *, slink, &area->spacedata) {
|
||||
if (slink->spacetype == SPACE_VIEW3D) {
|
||||
View3D *v3d = (View3D *)slink;
|
||||
|
||||
if (v3d->flag & V3D_XR_SESSION_MIRROR) {
|
||||
ED_view3d_xr_mirror_update(area, v3d, session_exists);
|
||||
}
|
||||
|
||||
if (session_exists) {
|
||||
wmWindowManager *wm = bmain->wm.first;
|
||||
const Scene *scene = WM_windows_scene_get_from_screen(wm, screen);
|
||||
|
||||
ED_view3d_xr_shading_update(wm, v3d, scene);
|
||||
}
|
||||
/* Ensure no 3D View is tagged as session root. */
|
||||
else {
|
||||
v3d->runtime.flag &= ~V3D_RUNTIME_XR_SESSION_ROOT;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
WM_main_add_notifier(NC_WM | ND_XR_DATA_CHANGED, NULL);
|
||||
}
|
||||
|
||||
static void wm_xr_session_update_screen_on_exit_cb(const wmXrData *xr_data)
|
||||
{
|
||||
/* Just use G_MAIN here, storing main isn't reliable enough on file read or exit. */
|
||||
wm_xr_session_update_screen(G_MAIN, xr_data);
|
||||
}
|
||||
|
||||
static int wm_xr_session_toggle_exec(bContext *C, wmOperator *UNUSED(op))
|
||||
{
|
||||
Main *bmain = CTX_data_main(C);
|
||||
wmWindowManager *wm = CTX_wm_manager(C);
|
||||
wmWindow *win = CTX_wm_window(C);
|
||||
View3D *v3d = CTX_wm_view3d(C);
|
||||
|
||||
/* Lazy-create xr context - tries to dynlink to the runtime, reading active_runtime.json. */
|
||||
if (wm_xr_init(wm) == false) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
v3d->runtime.flag |= V3D_RUNTIME_XR_SESSION_ROOT;
|
||||
wm_xr_session_toggle(wm, win, wm_xr_session_update_screen_on_exit_cb);
|
||||
wm_xr_session_update_screen(bmain, &wm->xr);
|
||||
|
||||
WM_event_add_notifier(C, NC_WM | ND_XR_DATA_CHANGED, NULL);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
static void WM_OT_xr_session_toggle(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name = "Toggle VR Session";
|
||||
ot->idname = "WM_OT_xr_session_toggle";
|
||||
ot->description =
|
||||
"Open a view for use with virtual reality headsets, or close it if already "
|
||||
"opened";
|
||||
|
||||
/* callbacks */
|
||||
ot->exec = wm_xr_session_toggle_exec;
|
||||
ot->poll = ED_operator_view3d_active;
|
||||
|
||||
/* XXX INTERNAL just to hide it from the search menu by default, an Add-on will expose it in the
|
||||
* UI instead. Not meant as a permanent solution. */
|
||||
ot->flag = OPTYPE_INTERNAL;
|
||||
}
|
||||
|
||||
#endif /* WITH_XR_OPENXR */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Operator Registration & Keymaps
|
||||
* \{ */
|
||||
@@ -3882,9 +3801,6 @@ void wm_operatortypes_register(void)
|
||||
WM_operatortype_append(WM_OT_call_panel);
|
||||
WM_operatortype_append(WM_OT_radial_control);
|
||||
WM_operatortype_append(WM_OT_stereo3d_set);
|
||||
#ifdef WITH_XR_OPENXR
|
||||
WM_operatortype_append(WM_OT_xr_session_toggle);
|
||||
#endif
|
||||
#if defined(WIN32)
|
||||
WM_operatortype_append(WM_OT_console_toggle);
|
||||
#endif
|
||||
@@ -3895,6 +3811,10 @@ void wm_operatortypes_register(void)
|
||||
/* gizmos */
|
||||
WM_operatortype_append(GIZMOGROUP_OT_gizmo_select);
|
||||
WM_operatortype_append(GIZMOGROUP_OT_gizmo_tweak);
|
||||
|
||||
#ifdef WITH_XR_OPENXR
|
||||
wm_xr_operatortypes_register();
|
||||
#endif
|
||||
}
|
||||
|
||||
/* circleselect-like modal operators */
|
||||
|
@@ -1561,7 +1561,7 @@ void wm_window_process_events(const bContext *C)
|
||||
#ifdef WITH_XR_OPENXR
|
||||
/* XR events don't use the regular window queues. So here we don't only trigger
|
||||
* processing/dispatching but also handling. */
|
||||
has_event |= wm_xr_events_handle(CTX_wm_manager(C));
|
||||
has_event |= wm_xr_events_handle(C);
|
||||
#endif
|
||||
|
||||
/* When there is no event, sleep 5 milliseconds not to use too much CPU when idle.
|
||||
|
@@ -33,6 +33,10 @@ struct ARegion;
|
||||
struct GHOST_TabletData;
|
||||
struct ScrArea;
|
||||
|
||||
#ifdef WITH_XR_OPENXR
|
||||
struct wmXrActionData;
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
@@ -147,6 +151,9 @@ void wm_event_free_handler(wmEventHandler *handler);
|
||||
void wm_event_do_handlers(bContext *C);
|
||||
|
||||
void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void *customdata);
|
||||
#ifdef WITH_XR_OPENXR
|
||||
void wm_event_add_xrevent(wmWindow *win, wmXrActionData *actiondata, short val);
|
||||
#endif
|
||||
|
||||
void wm_event_do_depsgraph(bContext *C, bool is_after_open_file);
|
||||
void wm_event_do_refresh_wm_and_depsgraph(bContext *C);
|
||||
|
@@ -34,6 +34,7 @@ enum {
|
||||
EVT_DATA_TIMER = 2,
|
||||
EVT_DATA_DRAGDROP = 3,
|
||||
EVT_DATA_NDOF_MOTION = 4,
|
||||
EVT_DATA_XR = 5,
|
||||
};
|
||||
|
||||
/* tablet active, matches GHOST_TTabletMode */
|
||||
@@ -341,6 +342,10 @@ enum {
|
||||
|
||||
/* could become gizmo callback */
|
||||
EVT_GIZMO_UPDATE = 0x5025, /* 20517 */
|
||||
|
||||
/* XR events: 0x503x */
|
||||
EVT_XR_ACTION = 0x5030, /* 20528 */
|
||||
|
||||
/* ********** End of Blender internal events. ********** */
|
||||
};
|
||||
|
||||
|
@@ -22,6 +22,7 @@
|
||||
* representation of the OpenXR runtime connection within the application.
|
||||
*/
|
||||
|
||||
#include "BKE_context.h"
|
||||
#include "BKE_global.h"
|
||||
#include "BKE_idprop.h"
|
||||
#include "BKE_report.h"
|
||||
@@ -54,6 +55,7 @@ static void wm_xr_error_handler(const GHOST_XrError *error)
|
||||
wmWindowManager *wm = handler_data->wm;
|
||||
|
||||
BKE_reports_clear(&wm->reports);
|
||||
|
||||
WM_report(RPT_ERROR, error->user_message);
|
||||
WM_report_banner_show();
|
||||
|
||||
@@ -130,14 +132,16 @@ void wm_xr_exit(wmWindowManager *wm)
|
||||
}
|
||||
}
|
||||
|
||||
bool wm_xr_events_handle(wmWindowManager *wm)
|
||||
bool wm_xr_events_handle(const bContext *C)
|
||||
{
|
||||
wmWindowManager *wm = CTX_wm_manager(C);
|
||||
|
||||
if (wm->xr.runtime && wm->xr.runtime->context) {
|
||||
GHOST_XrEventsHandle(wm->xr.runtime->context);
|
||||
|
||||
/* Process OpenXR action events. */
|
||||
/* Process OpenXR action events and dispatch to XR surface / window queues. */
|
||||
if (WM_xr_session_is_ready(&wm->xr)) {
|
||||
wm_xr_session_actions_update(&wm->xr);
|
||||
wm_xr_session_actions_update(C);
|
||||
}
|
||||
|
||||
/* wm_window_process_events() uses the return value to determine if it can put the main thread
|
||||
@@ -173,7 +177,6 @@ void wm_xr_runtime_data_free(wmXrRuntimeData **runtime)
|
||||
(*runtime)->context = NULL;
|
||||
|
||||
wm_xr_session_data_free(&(*runtime)->session_state);
|
||||
WM_xr_actionmaps_clear(*runtime);
|
||||
|
||||
GHOST_XrContextDestroy(context);
|
||||
}
|
||||
|
@@ -26,24 +26,67 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "BKE_context.h"
|
||||
#include "BKE_global.h"
|
||||
#include "BKE_idprop.h"
|
||||
|
||||
#include "BLI_listbase.h"
|
||||
#include "BLI_string.h"
|
||||
|
||||
#include "GHOST_Types.h"
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "WM_api.h"
|
||||
#include "WM_types.h"
|
||||
|
||||
#include "wm_xr_intern.h"
|
||||
|
||||
#define WM_XR_ACTIONCONF_STR_DEFAULT "blender"
|
||||
#define WM_XR_ACTIONMAP_STR_DEFAULT "actionmap"
|
||||
#define WM_XR_ACTIONMAP_ITEM_STR_DEFAULT "action"
|
||||
#define WM_XR_ACTIONMAP_BINDING_STR_DEFAULT "binding"
|
||||
|
||||
/* Replacement for U.keyconfigstr for actionconfigs. */
|
||||
static char g_xr_actionconfigstr[64];
|
||||
|
||||
/* Actionconfig update flag. */
|
||||
enum {
|
||||
WM_XR_ACTIONCONF_UPDATE_ACTIVE = (1 << 0), /* Update active actionconfig. */
|
||||
WM_XR_ACTIONCONF_UPDATE_ALL = (1 << 1), /* Update all actionconfigs. */
|
||||
WM_XR_ACTIONCONF_UPDATE_ENSURE =
|
||||
(1 << 2), /* Skip actionmap/item flag checks when updating actionconfigs. */
|
||||
};
|
||||
|
||||
static char g_xr_actionconfig_update_flag = 0;
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
||||
void WM_xr_actionconfig_update_tag(XrActionMap *actionmap, XrActionMapItem *ami)
|
||||
{
|
||||
g_xr_actionconfig_update_flag |= WM_XR_ACTIONCONF_UPDATE_ACTIVE;
|
||||
|
||||
if (actionmap) {
|
||||
actionmap->flag |= XR_ACTIONMAP_UPDATE;
|
||||
}
|
||||
if (ami) {
|
||||
ami->flag |= XR_ACTIONMAP_ITEM_UPDATE;
|
||||
}
|
||||
}
|
||||
|
||||
#if 0 /* Currently unused. */
|
||||
static void wm_xr_actionconfig_update_active(XrActionMap *actionmap, XrActionMapItem *ami, bool ensure)
|
||||
{
|
||||
WM_xr_actionconfig_update_tag(actionmap, ami);
|
||||
if (ensure) {
|
||||
g_xr_actionconfig_update_flag |= WM_XR_ACTIONCONF_UPDATE_ENSURE;
|
||||
}
|
||||
}
|
||||
|
||||
static void wm_xr_actionconfig_update_all(bool ensure)
|
||||
{
|
||||
g_xr_actionconfig_update_flag |= WM_XR_ACTIONCONF_UPDATE_ALL;
|
||||
if (ensure) {
|
||||
g_xr_actionconfig_update_flag |= WM_XR_ACTIONCONF_UPDATE_ENSURE;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Action Map Binding
|
||||
*
|
||||
@@ -51,16 +94,16 @@
|
||||
* \{ */
|
||||
|
||||
XrActionMapBinding *WM_xr_actionmap_binding_new(XrActionMapItem *ami,
|
||||
const char *name,
|
||||
const char *idname,
|
||||
bool replace_existing)
|
||||
{
|
||||
XrActionMapBinding *amb_prev = WM_xr_actionmap_binding_find(ami, name);
|
||||
XrActionMapBinding *amb_prev = WM_xr_actionmap_binding_find(ami, idname);
|
||||
if (amb_prev && replace_existing) {
|
||||
return amb_prev;
|
||||
}
|
||||
|
||||
XrActionMapBinding *amb = MEM_callocN(sizeof(XrActionMapBinding), __func__);
|
||||
BLI_strncpy(amb->name, name, MAX_NAME);
|
||||
BLI_strncpy(amb->name, idname, MAX_NAME);
|
||||
if (amb_prev) {
|
||||
WM_xr_actionmap_binding_ensure_unique(ami, amb);
|
||||
}
|
||||
@@ -173,31 +216,12 @@ XrActionMapBinding *WM_xr_actionmap_binding_find(XrActionMapItem *ami, const cha
|
||||
* Item in an XR action map, that maps an XR event to an operator, pose, or haptic output.
|
||||
* \{ */
|
||||
|
||||
static void wm_xr_actionmap_item_bindings_clear(XrActionMapItem *ami)
|
||||
{
|
||||
BLI_freelistN(&ami->bindings);
|
||||
ami->selbinding = 0;
|
||||
}
|
||||
|
||||
static void wm_xr_actionmap_item_properties_set(XrActionMapItem *ami)
|
||||
{
|
||||
WM_operator_properties_alloc(&(ami->op_properties_ptr), &(ami->op_properties), ami->op);
|
||||
WM_operator_properties_sanitize(ami->op_properties_ptr, 1);
|
||||
}
|
||||
|
||||
static void wm_xr_actionmap_item_properties_free(XrActionMapItem *ami)
|
||||
{
|
||||
if (ami->op_properties_ptr) {
|
||||
WM_operator_properties_free(ami->op_properties_ptr);
|
||||
MEM_freeN(ami->op_properties_ptr);
|
||||
ami->op_properties_ptr = NULL;
|
||||
ami->op_properties = NULL;
|
||||
}
|
||||
else {
|
||||
BLI_assert(ami->op_properties == NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Similar to #wm_xr_actionmap_item_properties_set()
|
||||
* but checks for the #eXrActionType and #wmOperatorType having changed.
|
||||
@@ -211,13 +235,13 @@ void WM_xr_actionmap_item_properties_update_ot(XrActionMapItem *ami)
|
||||
break;
|
||||
case XR_POSE_INPUT:
|
||||
case XR_VIBRATION_OUTPUT:
|
||||
wm_xr_actionmap_item_properties_free(ami);
|
||||
WM_xr_actionmap_item_properties_free(ami);
|
||||
memset(ami->op, 0, sizeof(ami->op));
|
||||
return;
|
||||
}
|
||||
|
||||
if (ami->op[0] == 0) {
|
||||
wm_xr_actionmap_item_properties_free(ami);
|
||||
WM_xr_actionmap_item_properties_free(ami);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -237,7 +261,33 @@ void WM_xr_actionmap_item_properties_update_ot(XrActionMapItem *ami)
|
||||
}
|
||||
}
|
||||
else {
|
||||
wm_xr_actionmap_item_properties_free(ami);
|
||||
WM_xr_actionmap_item_properties_free(ami);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void wm_xr_actionmap_item_properties_update_ot_from_list(ListBase *am_lb, bool ensure)
|
||||
{
|
||||
if (ensure) {
|
||||
LISTBASE_FOREACH (XrActionMap *, am, am_lb) {
|
||||
LISTBASE_FOREACH (XrActionMapItem *, ami, &am->items) {
|
||||
WM_xr_actionmap_item_properties_update_ot(ami);
|
||||
ami->flag &= ~XR_ACTIONMAP_ITEM_UPDATE;
|
||||
}
|
||||
am->flag &= ~XR_ACTIONMAP_UPDATE;
|
||||
}
|
||||
}
|
||||
else {
|
||||
LISTBASE_FOREACH (XrActionMap *, am, am_lb) {
|
||||
if ((am->flag & XR_ACTIONMAP_UPDATE) != 0) {
|
||||
LISTBASE_FOREACH (XrActionMapItem *, ami, &am->items) {
|
||||
if ((ami->flag & XR_ACTIONMAP_ITEM_UPDATE) != 0) {
|
||||
WM_xr_actionmap_item_properties_update_ot(ami);
|
||||
ami->flag &= ~XR_ACTIONMAP_ITEM_UPDATE;
|
||||
}
|
||||
}
|
||||
am->flag &= ~XR_ACTIONMAP_UPDATE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -248,7 +298,7 @@ XrActionMapItem *WM_xr_actionmap_item_new(XrActionMap *actionmap,
|
||||
{
|
||||
XrActionMapItem *ami_prev = WM_xr_actionmap_item_find(actionmap, name);
|
||||
if (ami_prev && replace_existing) {
|
||||
wm_xr_actionmap_item_properties_free(ami_prev);
|
||||
WM_xr_actionmap_item_properties_free(ami_prev);
|
||||
return ami_prev;
|
||||
}
|
||||
|
||||
@@ -263,12 +313,14 @@ XrActionMapItem *WM_xr_actionmap_item_new(XrActionMap *actionmap,
|
||||
/* Set type to float (button) input by default. */
|
||||
ami->type = XR_FLOAT_INPUT;
|
||||
|
||||
WM_xr_actionconfig_update_tag(actionmap, ami);
|
||||
|
||||
return ami;
|
||||
}
|
||||
|
||||
static XrActionMapItem *wm_xr_actionmap_item_find_except(XrActionMap *actionmap,
|
||||
const char *name,
|
||||
const XrActionMapItem *amiexcept)
|
||||
XrActionMapItem *amiexcept)
|
||||
{
|
||||
LISTBASE_FOREACH (XrActionMapItem *, ami, &actionmap->items) {
|
||||
if (STREQLEN(name, ami->name, MAX_NAME) && (ami != amiexcept)) {
|
||||
@@ -308,25 +360,32 @@ void WM_xr_actionmap_item_ensure_unique(XrActionMap *actionmap, XrActionMapItem
|
||||
BLI_strncpy(ami->name, name, MAX_NAME);
|
||||
}
|
||||
|
||||
static XrActionMapItem *wm_xr_actionmap_item_copy(XrActionMapItem *ami)
|
||||
static XrActionMapItem *wm_xr_actionmap_item_copy(XrActionMapItem *ami_src)
|
||||
{
|
||||
XrActionMapItem *amin = MEM_dupallocN(ami);
|
||||
XrActionMapItem *ami_dst = MEM_dupallocN(ami_src);
|
||||
|
||||
amin->prev = amin->next = NULL;
|
||||
ami_dst->prev = ami_dst->next = NULL;
|
||||
BLI_listbase_clear(&ami_dst->bindings);
|
||||
ami_dst->flag &= ~XR_ACTIONMAP_ITEM_UPDATE;
|
||||
|
||||
if (amin->op_properties) {
|
||||
amin->op_properties_ptr = MEM_callocN(sizeof(PointerRNA), "wmOpItemPtr");
|
||||
WM_operator_properties_create(amin->op_properties_ptr, amin->op);
|
||||
LISTBASE_FOREACH (XrActionMapBinding *, amb, &ami_src->bindings) {
|
||||
XrActionMapBinding *amb_new = wm_xr_actionmap_binding_copy(amb);
|
||||
BLI_addtail(&ami_dst->bindings, amb_new);
|
||||
}
|
||||
|
||||
amin->op_properties = IDP_CopyProperty(amin->op_properties);
|
||||
amin->op_properties_ptr->data = amin->op_properties;
|
||||
if (ami_dst->op_properties) {
|
||||
ami_dst->op_properties_ptr = MEM_callocN(sizeof(PointerRNA), "wmOpItemPtr");
|
||||
WM_operator_properties_create(ami_dst->op_properties_ptr, ami_dst->op);
|
||||
|
||||
ami_dst->op_properties = IDP_CopyProperty(ami_dst->op_properties);
|
||||
ami_dst->op_properties_ptr->data = ami_dst->op_properties;
|
||||
}
|
||||
else {
|
||||
amin->op_properties = NULL;
|
||||
amin->op_properties_ptr = NULL;
|
||||
ami_dst->op_properties = NULL;
|
||||
ami_dst->op_properties_ptr = NULL;
|
||||
}
|
||||
|
||||
return amin;
|
||||
return ami_dst;
|
||||
}
|
||||
|
||||
XrActionMapItem *WM_xr_actionmap_item_add_copy(XrActionMap *actionmap, XrActionMapItem *ami_src)
|
||||
@@ -337,6 +396,8 @@ XrActionMapItem *WM_xr_actionmap_item_add_copy(XrActionMap *actionmap, XrActionM
|
||||
|
||||
BLI_addtail(&actionmap->items, ami_dst);
|
||||
|
||||
WM_xr_actionconfig_update_tag(actionmap, ami_dst);
|
||||
|
||||
return ami_dst;
|
||||
}
|
||||
|
||||
@@ -345,8 +406,8 @@ bool WM_xr_actionmap_item_remove(XrActionMap *actionmap, XrActionMapItem *ami)
|
||||
int idx = BLI_findindex(&actionmap->items, ami);
|
||||
|
||||
if (idx != -1) {
|
||||
wm_xr_actionmap_item_bindings_clear(ami);
|
||||
wm_xr_actionmap_item_properties_free(ami);
|
||||
WM_xr_actionmap_item_bindings_clear(ami);
|
||||
WM_xr_actionmap_item_properties_free(ami);
|
||||
BLI_freelinkN(&actionmap->items, ami);
|
||||
|
||||
if (idx <= actionmap->selitem) {
|
||||
@@ -355,6 +416,8 @@ bool WM_xr_actionmap_item_remove(XrActionMap *actionmap, XrActionMapItem *ami)
|
||||
}
|
||||
}
|
||||
|
||||
WM_xr_actionconfig_update_tag(actionmap, NULL);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -379,9 +442,11 @@ XrActionMapItem *WM_xr_actionmap_item_find(XrActionMap *actionmap, const char *n
|
||||
* List of XR action map items.
|
||||
* \{ */
|
||||
|
||||
XrActionMap *WM_xr_actionmap_new(wmXrRuntimeData *runtime, const char *name, bool replace_existing)
|
||||
XrActionMap *WM_xr_actionmap_new(XrActionConfig *actionconf,
|
||||
const char *name,
|
||||
bool replace_existing)
|
||||
{
|
||||
XrActionMap *am_prev = WM_xr_actionmap_find(runtime, name);
|
||||
XrActionMap *am_prev = WM_xr_actionmap_find(actionconf, name);
|
||||
if (am_prev && replace_existing) {
|
||||
WM_xr_actionmap_clear(am_prev);
|
||||
return am_prev;
|
||||
@@ -390,31 +455,32 @@ XrActionMap *WM_xr_actionmap_new(wmXrRuntimeData *runtime, const char *name, boo
|
||||
XrActionMap *am = MEM_callocN(sizeof(struct XrActionMap), __func__);
|
||||
BLI_strncpy(am->name, name, MAX_NAME);
|
||||
if (am_prev) {
|
||||
WM_xr_actionmap_ensure_unique(runtime, am);
|
||||
WM_xr_actionmap_ensure_unique(actionconf, am);
|
||||
}
|
||||
|
||||
BLI_addtail(&runtime->actionmaps, am);
|
||||
BLI_addtail(&actionconf->actionmaps, am);
|
||||
|
||||
WM_xr_actionconfig_update_tag(am, NULL);
|
||||
|
||||
return am;
|
||||
}
|
||||
|
||||
static XrActionMap *wm_xr_actionmap_find_except(wmXrRuntimeData *runtime,
|
||||
static XrActionMap *wm_xr_actionmap_find_except(XrActionConfig *actionconf,
|
||||
const char *name,
|
||||
const XrActionMap *am_except)
|
||||
XrActionMap *am_except)
|
||||
{
|
||||
LISTBASE_FOREACH (XrActionMap *, am, &runtime->actionmaps) {
|
||||
LISTBASE_FOREACH (XrActionMap *, am, &actionconf->actionmaps) {
|
||||
if (STREQLEN(name, am->name, MAX_NAME) && (am != am_except)) {
|
||||
return am;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure unique name among all action maps.
|
||||
*/
|
||||
void WM_xr_actionmap_ensure_unique(wmXrRuntimeData *runtime, XrActionMap *actionmap)
|
||||
void WM_xr_actionmap_ensure_unique(XrActionConfig *actionconf, XrActionMap *actionmap)
|
||||
{
|
||||
char name[MAX_NAME];
|
||||
char *suffix;
|
||||
@@ -425,7 +491,7 @@ void WM_xr_actionmap_ensure_unique(wmXrRuntimeData *runtime, XrActionMap *action
|
||||
baselen = BLI_strnlen(name, MAX_NAME);
|
||||
suffix = &name[baselen];
|
||||
|
||||
while (wm_xr_actionmap_find_except(runtime, name, actionmap)) {
|
||||
while (wm_xr_actionmap_find_except(actionconf, name, actionmap)) {
|
||||
if ((baselen + 1) + (log10(++idx) + 1) > MAX_NAME) {
|
||||
/* Use default base name. */
|
||||
BLI_strncpy(name, WM_XR_ACTIONMAP_STR_DEFAULT, MAX_NAME);
|
||||
@@ -447,6 +513,7 @@ static XrActionMap *wm_xr_actionmap_copy(XrActionMap *am_src)
|
||||
|
||||
am_dst->prev = am_dst->next = NULL;
|
||||
BLI_listbase_clear(&am_dst->items);
|
||||
am_dst->flag &= ~(XR_ACTIONMAP_UPDATE);
|
||||
|
||||
LISTBASE_FOREACH (XrActionMapItem *, ami, &am_src->items) {
|
||||
XrActionMapItem *ami_new = wm_xr_actionmap_item_copy(ami);
|
||||
@@ -456,33 +523,35 @@ static XrActionMap *wm_xr_actionmap_copy(XrActionMap *am_src)
|
||||
return am_dst;
|
||||
}
|
||||
|
||||
XrActionMap *WM_xr_actionmap_add_copy(wmXrRuntimeData *runtime, XrActionMap *am_src)
|
||||
XrActionMap *WM_xr_actionmap_add_copy(XrActionConfig *actionconf, XrActionMap *am_src)
|
||||
{
|
||||
XrActionMap *am_dst = wm_xr_actionmap_copy(am_src);
|
||||
|
||||
WM_xr_actionmap_ensure_unique(runtime, am_dst);
|
||||
WM_xr_actionmap_ensure_unique(actionconf, am_dst);
|
||||
|
||||
BLI_addtail(&runtime->actionmaps, am_dst);
|
||||
BLI_addtail(&actionconf->actionmaps, am_dst);
|
||||
|
||||
WM_xr_actionconfig_update_tag(am_dst, NULL);
|
||||
|
||||
return am_dst;
|
||||
}
|
||||
|
||||
bool WM_xr_actionmap_remove(wmXrRuntimeData *runtime, XrActionMap *actionmap)
|
||||
bool WM_xr_actionmap_remove(XrActionConfig *actionconf, XrActionMap *actionmap)
|
||||
{
|
||||
int idx = BLI_findindex(&runtime->actionmaps, actionmap);
|
||||
int idx = BLI_findindex(&actionconf->actionmaps, actionmap);
|
||||
|
||||
if (idx != -1) {
|
||||
WM_xr_actionmap_clear(actionmap);
|
||||
BLI_freelinkN(&runtime->actionmaps, actionmap);
|
||||
BLI_freelinkN(&actionconf->actionmaps, actionmap);
|
||||
|
||||
if (idx <= runtime->actactionmap) {
|
||||
if (--runtime->actactionmap < 0) {
|
||||
runtime->actactionmap = 0;
|
||||
if (idx <= actionconf->actactionmap) {
|
||||
if (--actionconf->actactionmap < 0) {
|
||||
actionconf->actactionmap = 0;
|
||||
}
|
||||
}
|
||||
if (idx <= runtime->selactionmap) {
|
||||
if (--runtime->selactionmap < 0) {
|
||||
runtime->selactionmap = 0;
|
||||
if (idx <= actionconf->selactionmap) {
|
||||
if (--actionconf->selactionmap < 0) {
|
||||
actionconf->selactionmap = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -492,9 +561,9 @@ bool WM_xr_actionmap_remove(wmXrRuntimeData *runtime, XrActionMap *actionmap)
|
||||
return false;
|
||||
}
|
||||
|
||||
XrActionMap *WM_xr_actionmap_find(wmXrRuntimeData *runtime, const char *name)
|
||||
XrActionMap *WM_xr_actionmap_find(XrActionConfig *actionconf, const char *name)
|
||||
{
|
||||
LISTBASE_FOREACH (XrActionMap *, am, &runtime->actionmaps) {
|
||||
LISTBASE_FOREACH (XrActionMap *, am, &actionconf->actionmaps) {
|
||||
if (STREQLEN(name, am->name, MAX_NAME)) {
|
||||
return am;
|
||||
}
|
||||
@@ -502,52 +571,147 @@ XrActionMap *WM_xr_actionmap_find(wmXrRuntimeData *runtime, const char *name)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void WM_xr_actionmap_clear(XrActionMap *actionmap)
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Action Configuration
|
||||
*
|
||||
* List of XR action maps.
|
||||
* \{ */
|
||||
|
||||
XrActionConfig *WM_xr_actionconfig_new(XrSessionSettings *settings,
|
||||
const char *name,
|
||||
bool user_defined)
|
||||
{
|
||||
LISTBASE_FOREACH (XrActionMapItem *, ami, &actionmap->items) {
|
||||
wm_xr_actionmap_item_bindings_clear(ami);
|
||||
wm_xr_actionmap_item_properties_free(ami);
|
||||
XrActionConfig *actionconf = BLI_findstring(
|
||||
&settings->actionconfigs, name, offsetof(XrActionConfig, name));
|
||||
if (actionconf) {
|
||||
WM_xr_actionconfig_clear(actionconf);
|
||||
return actionconf;
|
||||
}
|
||||
|
||||
BLI_freelistN(&actionmap->items);
|
||||
actionconf = MEM_callocN(sizeof(XrActionConfig), __func__);
|
||||
BLI_strncpy(actionconf->name, name, sizeof(actionconf->name));
|
||||
BLI_addtail(&settings->actionconfigs, actionconf);
|
||||
|
||||
actionmap->selitem = 0;
|
||||
}
|
||||
|
||||
void WM_xr_actionmaps_clear(wmXrRuntimeData *runtime)
|
||||
{
|
||||
LISTBASE_FOREACH (XrActionMap *, am, &runtime->actionmaps) {
|
||||
WM_xr_actionmap_clear(am);
|
||||
if (user_defined) {
|
||||
actionconf->flag |= XR_ACTIONCONF_USER;
|
||||
}
|
||||
|
||||
BLI_freelistN(&runtime->actionmaps);
|
||||
|
||||
runtime->actactionmap = runtime->selactionmap = 0;
|
||||
return actionconf;
|
||||
}
|
||||
|
||||
ListBase *WM_xr_actionmaps_get(wmXrRuntimeData *runtime)
|
||||
bool WM_xr_actionconfig_remove(XrSessionSettings *settings, XrActionConfig *actionconf)
|
||||
{
|
||||
return &runtime->actionmaps;
|
||||
if (BLI_findindex(&settings->actionconfigs, actionconf) != -1) {
|
||||
if (STREQLEN(g_xr_actionconfigstr, actionconf->name, sizeof(g_xr_actionconfigstr))) {
|
||||
BLI_strncpy(g_xr_actionconfigstr, settings->defaultconf->name, sizeof(g_xr_actionconfigstr));
|
||||
WM_xr_actionconfig_update_tag(NULL, NULL);
|
||||
}
|
||||
|
||||
BLI_remlink(&settings->actionconfigs, actionconf);
|
||||
WM_xr_actionconfig_free(actionconf);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
short WM_xr_actionmap_active_index_get(const wmXrRuntimeData *runtime)
|
||||
XrActionConfig *WM_xr_actionconfig_active_get(XrSessionSettings *settings)
|
||||
{
|
||||
return runtime->actactionmap;
|
||||
XrActionConfig *actionconf;
|
||||
|
||||
/* First try from preset. */
|
||||
actionconf = BLI_findstring(
|
||||
&settings->actionconfigs, g_xr_actionconfigstr, offsetof(XrActionConfig, name));
|
||||
if (actionconf) {
|
||||
return actionconf;
|
||||
}
|
||||
|
||||
/* Otherwise use default. */
|
||||
return settings->defaultconf;
|
||||
}
|
||||
|
||||
void WM_xr_actionmap_active_index_set(wmXrRuntimeData *runtime, short idx)
|
||||
void WM_xr_actionconfig_active_set(XrSessionSettings *settings, const char *idname)
|
||||
{
|
||||
runtime->actactionmap = idx;
|
||||
}
|
||||
/* Setting a different action configuration as active: we ensure all is
|
||||
* updated properly before and after making the change. */
|
||||
|
||||
short WM_xr_actionmap_selected_index_get(const wmXrRuntimeData *runtime)
|
||||
{
|
||||
return runtime->selactionmap;
|
||||
}
|
||||
WM_xr_actionconfig_update(settings);
|
||||
|
||||
void WM_xr_actionmap_selected_index_set(wmXrRuntimeData *runtime, short idx)
|
||||
{
|
||||
runtime->selactionmap = idx;
|
||||
BLI_strncpy(g_xr_actionconfigstr, idname, sizeof(g_xr_actionconfigstr));
|
||||
|
||||
WM_xr_actionconfig_update_tag(NULL, NULL);
|
||||
WM_xr_actionconfig_update(settings);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name XR Action Configuration API
|
||||
*
|
||||
* API functions for managing XR action configurations.
|
||||
*
|
||||
* \{ */
|
||||
|
||||
void WM_xr_actionconfig_init(bContext *C)
|
||||
{
|
||||
wmWindowManager *wm = CTX_wm_manager(C);
|
||||
XrSessionSettings *settings = &wm->xr.session_settings;
|
||||
|
||||
/* Create standard action configs. */
|
||||
if (settings->defaultconf == NULL) {
|
||||
settings->defaultconf = WM_xr_actionconfig_new(settings, WM_XR_ACTIONCONF_STR_DEFAULT, false);
|
||||
}
|
||||
if (settings->addonconf == NULL) {
|
||||
settings->addonconf = WM_xr_actionconfig_new(
|
||||
settings, WM_XR_ACTIONCONF_STR_DEFAULT " addon", false);
|
||||
}
|
||||
if (settings->userconf == NULL) {
|
||||
/* Treat user config as user-defined so its actionmaps can be saved to files. */
|
||||
settings->userconf = WM_xr_actionconfig_new(
|
||||
settings, WM_XR_ACTIONCONF_STR_DEFAULT " user", true);
|
||||
}
|
||||
}
|
||||
|
||||
void WM_xr_actionconfig_update(XrSessionSettings *settings)
|
||||
{
|
||||
if (G.background) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (g_xr_actionconfig_update_flag == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const bool ensure = ((g_xr_actionconfig_update_flag & WM_XR_ACTIONCONF_UPDATE_ENSURE) != 0);
|
||||
|
||||
if ((g_xr_actionconfig_update_flag & WM_XR_ACTIONCONF_UPDATE_ALL) != 0) {
|
||||
/* Update properties for all actionconfigs. */
|
||||
LISTBASE_FOREACH (XrActionConfig *, ac, &settings->actionconfigs) {
|
||||
wm_xr_actionmap_item_properties_update_ot_from_list(&ac->actionmaps, ensure);
|
||||
}
|
||||
|
||||
g_xr_actionconfig_update_flag &= ~(WM_XR_ACTIONCONF_UPDATE_ALL |
|
||||
WM_XR_ACTIONCONF_UPDATE_ACTIVE);
|
||||
}
|
||||
|
||||
if ((g_xr_actionconfig_update_flag & WM_XR_ACTIONCONF_UPDATE_ACTIVE) != 0) {
|
||||
/* Update properties for active actionconfig. */
|
||||
XrActionConfig *ac = WM_xr_actionconfig_active_get(settings);
|
||||
if (ac) {
|
||||
wm_xr_actionmap_item_properties_update_ot_from_list(&ac->actionmaps, ensure);
|
||||
}
|
||||
|
||||
g_xr_actionconfig_update_flag &= ~WM_XR_ACTIONCONF_UPDATE_ACTIVE;
|
||||
}
|
||||
|
||||
if (ensure) {
|
||||
g_xr_actionconfig_update_flag &= ~WM_XR_ACTIONCONF_UPDATE_ENSURE;
|
||||
}
|
||||
|
||||
BLI_assert(g_xr_actionconfig_update_flag == 0);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
@@ -24,6 +24,8 @@
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "BKE_context.h"
|
||||
|
||||
#include "BLI_listbase.h"
|
||||
#include "BLI_math.h"
|
||||
|
||||
@@ -31,6 +33,9 @@
|
||||
|
||||
#include "GHOST_C-api.h"
|
||||
|
||||
#include "GPU_batch_presets.h"
|
||||
#include "GPU_immediate.h"
|
||||
#include "GPU_matrix.h"
|
||||
#include "GPU_viewport.h"
|
||||
|
||||
#include "WM_api.h"
|
||||
@@ -44,6 +49,16 @@ void wm_xr_pose_to_mat(const GHOST_XrPose *pose, float r_mat[4][4])
|
||||
copy_v3_v3(r_mat[3], pose->position);
|
||||
}
|
||||
|
||||
void wm_xr_pose_scale_to_mat(const GHOST_XrPose *pose, float scale, float r_mat[4][4])
|
||||
{
|
||||
wm_xr_pose_to_mat(pose, r_mat);
|
||||
|
||||
BLI_assert(scale > 0.0f);
|
||||
mul_v3_fl(r_mat[0], scale);
|
||||
mul_v3_fl(r_mat[1], scale);
|
||||
mul_v3_fl(r_mat[2], scale);
|
||||
}
|
||||
|
||||
void wm_xr_pose_to_imat(const GHOST_XrPose *pose, float r_imat[4][4])
|
||||
{
|
||||
float iquat[4];
|
||||
@@ -52,15 +67,33 @@ void wm_xr_pose_to_imat(const GHOST_XrPose *pose, float r_imat[4][4])
|
||||
translate_m4(r_imat, -pose->position[0], -pose->position[1], -pose->position[2]);
|
||||
}
|
||||
|
||||
void wm_xr_pose_scale_to_imat(const GHOST_XrPose *pose, float scale, float r_imat[4][4])
|
||||
{
|
||||
float iquat[4];
|
||||
invert_qt_qt_normalized(iquat, pose->orientation_quat);
|
||||
quat_to_mat4(r_imat, iquat);
|
||||
|
||||
BLI_assert(scale > 0.0f);
|
||||
scale = 1.0f / scale;
|
||||
mul_v3_fl(r_imat[0], scale);
|
||||
mul_v3_fl(r_imat[1], scale);
|
||||
mul_v3_fl(r_imat[2], scale);
|
||||
|
||||
translate_m4(r_imat, -pose->position[0], -pose->position[1], -pose->position[2]);
|
||||
}
|
||||
|
||||
static void wm_xr_draw_matrices_create(const wmXrDrawData *draw_data,
|
||||
const GHOST_XrDrawViewInfo *draw_view,
|
||||
const XrSessionSettings *session_settings,
|
||||
float r_view_mat[4][4],
|
||||
float r_proj_mat[4][4])
|
||||
const wmXrSessionState *session_state,
|
||||
float r_viewmat[4][4],
|
||||
float r_viewmat_base[4][4],
|
||||
float r_projmat[4][4])
|
||||
{
|
||||
GHOST_XrPose eye_pose;
|
||||
float eye_inv[4][4], base_inv[4][4];
|
||||
float eye_inv[4][4], base_inv[4][4], nav_inv[4][4];
|
||||
|
||||
/* Calculate inverse eye matrix. */
|
||||
copy_qt_qt(eye_pose.orientation_quat, draw_view->eye_pose.orientation_quat);
|
||||
copy_v3_v3(eye_pose.position, draw_view->eye_pose.position);
|
||||
if ((session_settings->flag & XR_SESSION_USE_POSITION_TRACKING) == 0) {
|
||||
@@ -69,14 +102,15 @@ static void wm_xr_draw_matrices_create(const wmXrDrawData *draw_data,
|
||||
if ((session_settings->flag & XR_SESSION_USE_ABSOLUTE_TRACKING) == 0) {
|
||||
sub_v3_v3(eye_pose.position, draw_data->eye_position_ofs);
|
||||
}
|
||||
|
||||
wm_xr_pose_to_imat(&eye_pose, eye_inv);
|
||||
/* Calculate the base pose matrix (in world space!). */
|
||||
wm_xr_pose_to_imat(&draw_data->base_pose, base_inv);
|
||||
|
||||
mul_m4_m4m4(r_view_mat, eye_inv, base_inv);
|
||||
/* Apply base pose and navigation. */
|
||||
wm_xr_pose_scale_to_imat(&draw_data->base_pose, draw_data->base_scale, base_inv);
|
||||
wm_xr_pose_scale_to_imat(&session_state->nav_pose_prev, session_state->nav_scale_prev, nav_inv);
|
||||
mul_m4_m4m4(r_viewmat_base, eye_inv, base_inv);
|
||||
mul_m4_m4m4(r_viewmat, r_viewmat_base, nav_inv);
|
||||
|
||||
perspective_m4_fov(r_proj_mat,
|
||||
perspective_m4_fov(r_projmat,
|
||||
draw_view->fov.angle_left,
|
||||
draw_view->fov.angle_right,
|
||||
draw_view->fov.angle_up,
|
||||
@@ -121,13 +155,14 @@ void wm_xr_draw_view(const GHOST_XrDrawViewInfo *draw_view, void *customdata)
|
||||
|
||||
const int display_flags = V3D_OFSDRAW_OVERRIDE_SCENE_SETTINGS | settings->draw_flags;
|
||||
|
||||
float viewmat[4][4], winmat[4][4];
|
||||
float viewmat[4][4], viewmat_base[4][4], winmat[4][4];
|
||||
|
||||
BLI_assert(WM_xr_session_is_ready(xr_data));
|
||||
|
||||
wm_xr_session_draw_data_update(session_state, settings, draw_view, draw_data);
|
||||
wm_xr_draw_matrices_create(draw_data, draw_view, settings, viewmat, winmat);
|
||||
wm_xr_session_state_update(settings, draw_data, draw_view, session_state);
|
||||
wm_xr_draw_matrices_create(
|
||||
draw_data, draw_view, settings, session_state, viewmat, viewmat_base, winmat);
|
||||
wm_xr_session_state_update(settings, draw_data, draw_view, viewmat, viewmat_base, session_state);
|
||||
|
||||
if (!wm_xr_session_surface_offscreen_ensure(surface_data, draw_view)) {
|
||||
return;
|
||||
@@ -153,6 +188,7 @@ void wm_xr_draw_view(const GHOST_XrDrawViewInfo *draw_view, void *customdata)
|
||||
winmat,
|
||||
settings->clip_start,
|
||||
settings->clip_end,
|
||||
true,
|
||||
false,
|
||||
true,
|
||||
NULL,
|
||||
@@ -172,3 +208,200 @@ void wm_xr_draw_view(const GHOST_XrDrawViewInfo *draw_view, void *customdata)
|
||||
|
||||
wm_xr_draw_viewport_buffers_to_active_framebuffer(xr_data->runtime, surface_data, draw_view);
|
||||
}
|
||||
|
||||
static GPUBatch *wm_xr_controller_model_batch_create(GHOST_XrContextHandle xr_context,
|
||||
const char *subaction_path)
|
||||
{
|
||||
GHOST_XrControllerModelData model_data;
|
||||
|
||||
if (!GHOST_XrGetControllerModelData(xr_context, subaction_path, &model_data) ||
|
||||
model_data.count_vertices < 1) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
GPUVertFormat format = {0};
|
||||
GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
|
||||
GPU_vertformat_attr_add(&format, "nor", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
|
||||
|
||||
GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
|
||||
GPU_vertbuf_data_alloc(vbo, model_data.count_vertices);
|
||||
void *vbo_data = GPU_vertbuf_get_data(vbo);
|
||||
memcpy(
|
||||
vbo_data, model_data.vertices, model_data.count_vertices * sizeof(model_data.vertices[0]));
|
||||
|
||||
GPUIndexBuf *ibo = NULL;
|
||||
if (model_data.count_indices > 0 && ((model_data.count_indices % 3) == 0)) {
|
||||
GPUIndexBufBuilder ibo_builder;
|
||||
const unsigned int prim_len = model_data.count_indices / 3;
|
||||
GPU_indexbuf_init(&ibo_builder, GPU_PRIM_TRIS, prim_len, model_data.count_vertices);
|
||||
for (unsigned int i = 0; i < prim_len; ++i) {
|
||||
const uint32_t *idx = &model_data.indices[i * 3];
|
||||
GPU_indexbuf_add_tri_verts(&ibo_builder, idx[0], idx[1], idx[2]);
|
||||
}
|
||||
ibo = GPU_indexbuf_build(&ibo_builder);
|
||||
}
|
||||
|
||||
return GPU_batch_create_ex(GPU_PRIM_TRIS, vbo, ibo, GPU_BATCH_OWNS_VBO | GPU_BATCH_OWNS_INDEX);
|
||||
}
|
||||
|
||||
static void wm_xr_controller_model_draw(const XrSessionSettings *settings,
|
||||
GHOST_XrContextHandle xr_context,
|
||||
wmXrSessionState *state)
|
||||
{
|
||||
GHOST_XrControllerModelData model_data;
|
||||
|
||||
float color[4];
|
||||
switch (settings->controller_draw_style) {
|
||||
case XR_CONTROLLER_DRAW_DARK:
|
||||
case XR_CONTROLLER_DRAW_DARK_RAY:
|
||||
color[0] = color[1] = color[2] = 0.0f, color[3] = 0.4f;
|
||||
break;
|
||||
case XR_CONTROLLER_DRAW_LIGHT:
|
||||
case XR_CONTROLLER_DRAW_LIGHT_RAY:
|
||||
color[0] = 0.422f, color[1] = 0.438f, color[2] = 0.446f, color[3] = 0.4f;
|
||||
break;
|
||||
}
|
||||
|
||||
GPU_depth_test(GPU_DEPTH_NONE);
|
||||
GPU_blend(GPU_BLEND_ALPHA);
|
||||
|
||||
LISTBASE_FOREACH (wmXrController *, controller, &state->controllers) {
|
||||
GPUBatch *model = controller->model;
|
||||
if (!model) {
|
||||
model = controller->model = wm_xr_controller_model_batch_create(xr_context,
|
||||
controller->subaction_path);
|
||||
}
|
||||
|
||||
if (model &&
|
||||
GHOST_XrGetControllerModelData(xr_context, controller->subaction_path, &model_data) &&
|
||||
model_data.count_components > 0) {
|
||||
GPU_batch_program_set_builtin(model, GPU_SHADER_3D_UNIFORM_COLOR);
|
||||
GPU_batch_uniform_4fv(model, "color", color);
|
||||
|
||||
GPU_matrix_push();
|
||||
GPU_matrix_mul(controller->grip_mat);
|
||||
for (unsigned int component_idx = 0; component_idx < model_data.count_components;
|
||||
++component_idx) {
|
||||
const GHOST_XrControllerModelComponent *component = &model_data.components[component_idx];
|
||||
GPU_matrix_push();
|
||||
GPU_matrix_mul(component->transform);
|
||||
GPU_batch_draw_range(model,
|
||||
model->elem ? component->index_offset : component->vertex_offset,
|
||||
model->elem ? component->index_count : component->vertex_count);
|
||||
GPU_matrix_pop();
|
||||
}
|
||||
GPU_matrix_pop();
|
||||
}
|
||||
else {
|
||||
/* Fallback. */
|
||||
const float scale = 0.05f;
|
||||
GPUBatch *sphere = GPU_batch_preset_sphere(2);
|
||||
GPU_batch_program_set_builtin(sphere, GPU_SHADER_3D_UNIFORM_COLOR);
|
||||
GPU_batch_uniform_4fv(sphere, "color", color);
|
||||
|
||||
GPU_matrix_push();
|
||||
GPU_matrix_mul(controller->grip_mat);
|
||||
GPU_matrix_scale_1f(scale);
|
||||
GPU_batch_draw(sphere);
|
||||
GPU_matrix_pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void wm_xr_controller_aim_draw(const XrSessionSettings *settings, wmXrSessionState *state)
|
||||
{
|
||||
bool draw_ray;
|
||||
switch (settings->controller_draw_style) {
|
||||
case XR_CONTROLLER_DRAW_DARK:
|
||||
case XR_CONTROLLER_DRAW_LIGHT:
|
||||
draw_ray = false;
|
||||
break;
|
||||
case XR_CONTROLLER_DRAW_DARK_RAY:
|
||||
case XR_CONTROLLER_DRAW_LIGHT_RAY:
|
||||
draw_ray = true;
|
||||
break;
|
||||
}
|
||||
|
||||
GPUVertFormat *format = immVertexFormat();
|
||||
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
|
||||
uint col = GPU_vertformat_attr_add(format, "color", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
|
||||
immBindBuiltinProgram(GPU_SHADER_3D_POLYLINE_FLAT_COLOR);
|
||||
|
||||
float viewport[4];
|
||||
GPU_viewport_size_get_f(viewport);
|
||||
immUniform2fv("viewportSize", &viewport[2]);
|
||||
|
||||
immUniform1f("lineWidth", 3.0f * U.pixelsize);
|
||||
|
||||
if (draw_ray) {
|
||||
const uchar color[4] = {89, 89, 255, 127};
|
||||
const float scale = settings->clip_end;
|
||||
float ray[3];
|
||||
|
||||
GPU_depth_test(GPU_DEPTH_LESS_EQUAL);
|
||||
GPU_blend(GPU_BLEND_ALPHA);
|
||||
|
||||
immBegin(GPU_PRIM_LINES, (uint)BLI_listbase_count(&state->controllers) * 2);
|
||||
|
||||
LISTBASE_FOREACH (wmXrController *, controller, &state->controllers) {
|
||||
const float(*mat)[4] = controller->aim_mat;
|
||||
madd_v3_v3v3fl(ray, mat[3], mat[2], -scale);
|
||||
|
||||
immAttrSkip(col);
|
||||
immVertex3fv(pos, mat[3]);
|
||||
immAttr4ubv(col, color);
|
||||
immVertex3fv(pos, ray);
|
||||
}
|
||||
|
||||
immEnd();
|
||||
}
|
||||
else {
|
||||
const uchar r[4] = {255, 51, 82, 255};
|
||||
const uchar g[4] = {139, 220, 0, 255};
|
||||
const uchar b[4] = {40, 144, 255, 255};
|
||||
const float scale = 0.01f;
|
||||
float x_axis[3], y_axis[3], z_axis[3];
|
||||
|
||||
GPU_depth_test(GPU_DEPTH_NONE);
|
||||
GPU_blend(GPU_BLEND_NONE);
|
||||
|
||||
immBegin(GPU_PRIM_LINES, (uint)BLI_listbase_count(&state->controllers) * 6);
|
||||
|
||||
LISTBASE_FOREACH (wmXrController *, controller, &state->controllers) {
|
||||
const float(*mat)[4] = controller->aim_mat;
|
||||
madd_v3_v3v3fl(x_axis, mat[3], mat[0], scale);
|
||||
madd_v3_v3v3fl(y_axis, mat[3], mat[1], scale);
|
||||
madd_v3_v3v3fl(z_axis, mat[3], mat[2], scale);
|
||||
|
||||
immAttrSkip(col);
|
||||
immVertex3fv(pos, mat[3]);
|
||||
immAttr4ubv(col, r);
|
||||
immVertex3fv(pos, x_axis);
|
||||
|
||||
immAttrSkip(col);
|
||||
immVertex3fv(pos, mat[3]);
|
||||
immAttr4ubv(col, g);
|
||||
immVertex3fv(pos, y_axis);
|
||||
|
||||
immAttrSkip(col);
|
||||
immVertex3fv(pos, mat[3]);
|
||||
immAttr4ubv(col, b);
|
||||
immVertex3fv(pos, z_axis);
|
||||
}
|
||||
|
||||
immEnd();
|
||||
}
|
||||
|
||||
immUnbindProgram();
|
||||
}
|
||||
|
||||
void wm_xr_draw_controllers(const bContext *UNUSED(C), ARegion *UNUSED(region), void *customdata)
|
||||
{
|
||||
wmXrData *xr = customdata;
|
||||
const XrSessionSettings *settings = &xr->session_settings;
|
||||
GHOST_XrContextHandle xr_context = xr->runtime->context;
|
||||
wmXrSessionState *state = &xr->runtime->session_state;
|
||||
|
||||
wm_xr_controller_model_draw(settings, xr_context, state);
|
||||
wm_xr_controller_aim_draw(settings, state);
|
||||
}
|
||||
|
@@ -20,10 +20,23 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "BLI_sys_types.h"
|
||||
|
||||
#include "CLG_log.h"
|
||||
|
||||
#include "wm_xr.h"
|
||||
|
||||
struct ARegion;
|
||||
struct ARegionType;
|
||||
struct bContext;
|
||||
struct bScreen;
|
||||
struct Depsgraph;
|
||||
struct GPUBatch;
|
||||
struct GPUOffScreen;
|
||||
struct GPUViewport;
|
||||
struct Scene;
|
||||
struct ViewLayer;
|
||||
struct wmOperatorType;
|
||||
struct wmXrActionSet;
|
||||
|
||||
typedef struct wmXrSessionState {
|
||||
@@ -31,18 +44,25 @@ typedef struct wmXrSessionState {
|
||||
|
||||
/** Last known viewer pose (centroid of eyes, in world space) stored for queries. */
|
||||
GHOST_XrPose viewer_pose;
|
||||
/** The last known view matrix, calculated from above's viewer pose. */
|
||||
/** The last known view matrix (inverse viewer matrix), calculated from above's viewer pose. */
|
||||
float viewer_viewmat[4][4];
|
||||
float focal_len;
|
||||
/** The last known viewer matrix, without navigation applied. */
|
||||
float viewer_mat_base[4][4];
|
||||
/** Last known eye data. */
|
||||
ListBase eyes; /* wmXrEye */
|
||||
/** Last known controller data. */
|
||||
ListBase controllers; /* wmXrController */
|
||||
|
||||
/** Copy of XrSessionSettings.base_pose_ data to detect changes that need
|
||||
* resetting to base pose. */
|
||||
char prev_base_pose_type; /* eXRSessionBasePoseType */
|
||||
char prev_base_pose_type; /* eXrSessionBasePoseType */
|
||||
Object *prev_base_pose_object;
|
||||
/** Copy of XrSessionSettings.flag created on the last draw call, stored to detect changes. */
|
||||
int prev_settings_flag;
|
||||
/** Copy of wmXrDrawData.base_pose. */
|
||||
GHOST_XrPose prev_base_pose;
|
||||
/** Copy of wmXrDrawData.base_scale. */
|
||||
float prev_base_scale;
|
||||
/** Copy of GHOST_XrDrawViewInfo.local_pose. */
|
||||
GHOST_XrPose prev_local_pose;
|
||||
/** Copy of wmXrDrawData.eye_position_ofs. */
|
||||
@@ -51,13 +71,23 @@ typedef struct wmXrSessionState {
|
||||
bool force_reset_to_base_pose;
|
||||
bool is_view_data_set;
|
||||
|
||||
/** Last known controller data. */
|
||||
ListBase controllers; /* wmXrController */
|
||||
/** Current navigation transforms. */
|
||||
GHOST_XrPose nav_pose;
|
||||
float nav_scale;
|
||||
/** Navigation transforms from the last actions sync, used to calculate the viewer/controller
|
||||
* poses. */
|
||||
GHOST_XrPose nav_pose_prev;
|
||||
float nav_scale_prev;
|
||||
bool is_navigation_dirty;
|
||||
|
||||
/** The currently active action set that will be updated on calls to
|
||||
* wm_xr_session_actions_update(). If NULL, all action sets will be treated as active and
|
||||
* updated. */
|
||||
struct wmXrActionSet *active_action_set;
|
||||
|
||||
/* Original poses for motion capture objects. Used to properly restore object transforms on
|
||||
* session end. */
|
||||
ListBase mocap_orig_poses; /* wmXrMotionCapturePose */
|
||||
} wmXrSessionState;
|
||||
|
||||
typedef struct wmXrRuntimeData {
|
||||
@@ -70,10 +100,6 @@ typedef struct wmXrRuntimeData {
|
||||
/** Although this struct is internal, RNA gets a handle to this for state information queries. */
|
||||
wmXrSessionState session_state;
|
||||
wmXrSessionExitFn exit_fn;
|
||||
|
||||
ListBase actionmaps; /* XrActionMap */
|
||||
short actactionmap;
|
||||
short selactionmap;
|
||||
} wmXrRuntimeData;
|
||||
|
||||
typedef struct wmXrViewportPair {
|
||||
@@ -85,6 +111,11 @@ typedef struct wmXrViewportPair {
|
||||
typedef struct {
|
||||
/** Off-screen buffers/viewports for each view. */
|
||||
ListBase viewports; /* wmXrViewportPair */
|
||||
|
||||
/** Dummy region type for controller draw callback. */
|
||||
struct ARegionType *controller_art;
|
||||
/** Controller draw callback handle. */
|
||||
void *controller_draw_handle;
|
||||
} wmXrSurfaceData;
|
||||
|
||||
typedef struct wmXrDrawData {
|
||||
@@ -98,11 +129,21 @@ typedef struct wmXrDrawData {
|
||||
* space). With positional tracking enabled, it should be the same as the base pose, when
|
||||
* disabled it also contains a location delta from the moment the option was toggled. */
|
||||
GHOST_XrPose base_pose;
|
||||
/** Base scale (uniform, world space). */
|
||||
float base_scale;
|
||||
/** Offset to _substract_ from the OpenXR eye and viewer pose to get the wanted effective pose
|
||||
* (e.g. a pose exactly at the landmark position). */
|
||||
float eye_position_ofs[3]; /* Local/view space. */
|
||||
} wmXrDrawData;
|
||||
|
||||
typedef struct wmXrEye {
|
||||
struct wmXrEye *next, *prev;
|
||||
float focal_len;
|
||||
float viewmat[4][4];
|
||||
/** Viewmat without navigation applied. */
|
||||
float viewmat_base[4][4];
|
||||
} wmXrEye;
|
||||
|
||||
typedef struct wmXrController {
|
||||
struct wmXrController *next, *prev;
|
||||
/** OpenXR path identifier. Length is dependent on OpenXR's XR_MAX_PATH_LENGTH (256).
|
||||
@@ -111,12 +152,18 @@ typedef struct wmXrController {
|
||||
/input/trigger/value, interaction_path = /user/hand/left/input/trigger/value).
|
||||
*/
|
||||
char subaction_path[64];
|
||||
|
||||
/* Pose (in world space) that represents the user's hand when holding the controller.*/
|
||||
GHOST_XrPose grip_pose;
|
||||
float grip_mat[4][4];
|
||||
float grip_mat_base[4][4];
|
||||
/* Pose (in world space) that represents the controller's aiming source. */
|
||||
GHOST_XrPose aim_pose;
|
||||
float aim_mat[4][4];
|
||||
float aim_mat_base[4][4];
|
||||
|
||||
/** Controller model. */
|
||||
struct GPUBatch *model;
|
||||
} wmXrController;
|
||||
|
||||
typedef struct wmXrAction {
|
||||
@@ -167,22 +214,32 @@ typedef struct wmXrActionSet {
|
||||
wmXrAction *controller_aim_action;
|
||||
|
||||
/** Currently active modal actions. */
|
||||
ListBase active_modal_actions;
|
||||
ListBase active_modal_actions; /* wmXrAction */
|
||||
/** Currently active haptic actions. */
|
||||
ListBase active_haptic_actions;
|
||||
ListBase active_haptic_actions; /* wmXrHapticAction */
|
||||
} wmXrActionSet;
|
||||
|
||||
typedef struct wmXrMotionCapturePose {
|
||||
struct wmXrMotionCapturePose *next, *prev;
|
||||
const Object *ob;
|
||||
GHOST_XrPose pose;
|
||||
} wmXrMotionCapturePose;
|
||||
|
||||
/* wm_xr.c */
|
||||
wmXrRuntimeData *wm_xr_runtime_data_create(void);
|
||||
void wm_xr_runtime_data_free(wmXrRuntimeData **runtime);
|
||||
void wm_xr_session_data_free(wmXrSessionState *state);
|
||||
|
||||
void wm_xr_session_draw_data_update(const wmXrSessionState *state,
|
||||
/* wm_xr_session.c */
|
||||
void wm_xr_session_data_free(wmXrSessionState *state);
|
||||
void wm_xr_session_draw_data_update(wmXrSessionState *state,
|
||||
const XrSessionSettings *settings,
|
||||
const GHOST_XrDrawViewInfo *draw_view,
|
||||
wmXrDrawData *draw_data);
|
||||
void wm_xr_session_state_update(const XrSessionSettings *settings,
|
||||
const wmXrDrawData *draw_data,
|
||||
const GHOST_XrDrawViewInfo *draw_view,
|
||||
const float viewmat[4][4],
|
||||
const float viewmat_base[4][4],
|
||||
wmXrSessionState *state);
|
||||
bool wm_xr_session_surface_offscreen_ensure(wmXrSurfaceData *surface_data,
|
||||
const GHOST_XrDrawViewInfo *draw_view);
|
||||
@@ -190,12 +247,36 @@ void *wm_xr_session_gpu_binding_context_create(void);
|
||||
void wm_xr_session_gpu_binding_context_destroy(GHOST_ContextHandle context);
|
||||
|
||||
void wm_xr_session_actions_init(wmXrData *xr);
|
||||
void wm_xr_session_actions_update(wmXrData *xr);
|
||||
void wm_xr_session_actions_update(const struct bContext *C);
|
||||
void wm_xr_session_controller_data_populate(const wmXrAction *grip_action,
|
||||
const wmXrAction *aim_action,
|
||||
wmXrData *xr);
|
||||
void wm_xr_session_controller_data_clear(wmXrSessionState *state);
|
||||
|
||||
/* wm_xr_draw.c */
|
||||
void wm_xr_pose_to_mat(const GHOST_XrPose *pose, float r_mat[4][4]);
|
||||
void wm_xr_pose_scale_to_mat(const GHOST_XrPose *pose, float scale, float r_mat[4][4]);
|
||||
void wm_xr_pose_to_imat(const GHOST_XrPose *pose, float r_imat[4][4]);
|
||||
void wm_xr_pose_scale_to_imat(const GHOST_XrPose *pose, float scale, float r_imat[4][4]);
|
||||
|
||||
void wm_xr_draw_view(const GHOST_XrDrawViewInfo *draw_view, void *customdata);
|
||||
void wm_xr_draw_controllers(const struct bContext *C, struct ARegion *region, void *customdata);
|
||||
|
||||
/* wm_xr_mocap.c */
|
||||
void wm_xr_mocap_orig_poses_store(const XrSessionSettings *settings, wmXrSessionState *state);
|
||||
void wm_xr_mocap_orig_poses_restore(const wmXrSessionState *state, XrSessionSettings *settings);
|
||||
void wm_xr_mocap_object_autokey(struct bContext *C,
|
||||
struct Scene *scene,
|
||||
struct ViewLayer *view_layer,
|
||||
wmWindow *win,
|
||||
Object *ob,
|
||||
bool notify);
|
||||
void wm_xr_mocap_objects_update(const char *user_path,
|
||||
const GHOST_XrPose *pose,
|
||||
struct bContext *C,
|
||||
XrSessionSettings *settings,
|
||||
struct Scene *scene,
|
||||
struct ViewLayer *view_layer,
|
||||
wmWindow *win,
|
||||
struct bScreen *screen_anim,
|
||||
bool notify);
|
||||
|
267
source/blender/windowmanager/xr/intern/wm_xr_mocap.c
Normal file
267
source/blender/windowmanager/xr/intern/wm_xr_mocap.c
Normal file
@@ -0,0 +1,267 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* \ingroup wm
|
||||
*
|
||||
* \name Window-Manager XR Motion Capture
|
||||
*
|
||||
* API for XR motion capture objects.
|
||||
*/
|
||||
|
||||
#include "BKE_context.h"
|
||||
#include "BKE_layer.h"
|
||||
|
||||
#include "BLI_listbase.h"
|
||||
#include "BLI_math.h"
|
||||
|
||||
#include "DEG_depsgraph.h"
|
||||
|
||||
#include "DNA_object_types.h"
|
||||
|
||||
#include "ED_keyframing.h"
|
||||
#include "ED_object.h"
|
||||
#include "ED_screen.h"
|
||||
#include "ED_transform.h"
|
||||
|
||||
#include "GHOST_C-api.h"
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "WM_api.h"
|
||||
|
||||
#include "wm_xr_intern.h"
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name XR Motion Capture Objects
|
||||
*
|
||||
* List of XR motion capture objects. Stored in session settings and can be written to files.
|
||||
* \{ */
|
||||
|
||||
XrMotionCaptureObject *WM_xr_mocap_object_new(XrSessionSettings *settings, Object *ob)
|
||||
{
|
||||
XrMotionCaptureObject *mocap_ob = WM_xr_mocap_object_find(settings, ob);
|
||||
|
||||
if (!mocap_ob) {
|
||||
mocap_ob = MEM_callocN(sizeof(XrMotionCaptureObject), __func__);
|
||||
mocap_ob->ob = ob;
|
||||
BLI_addtail(&settings->mocap_objects, mocap_ob);
|
||||
}
|
||||
|
||||
return mocap_ob;
|
||||
}
|
||||
|
||||
void WM_xr_mocap_object_ensure_unique(XrSessionSettings *settings, XrMotionCaptureObject *mocap_ob)
|
||||
{
|
||||
LISTBASE_FOREACH (XrMotionCaptureObject *, mocap_ob_other, &settings->mocap_objects) {
|
||||
if ((mocap_ob_other != mocap_ob) && (mocap_ob_other->ob == mocap_ob->ob)) {
|
||||
mocap_ob->ob = NULL;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WM_xr_mocap_object_remove(XrSessionSettings *settings, XrMotionCaptureObject *mocap_ob)
|
||||
{
|
||||
int idx = BLI_findindex(&settings->mocap_objects, mocap_ob);
|
||||
|
||||
if (idx != -1) {
|
||||
BLI_freelinkN(&settings->mocap_objects, mocap_ob);
|
||||
|
||||
if (idx <= settings->sel_mocap_object) {
|
||||
if (--settings->sel_mocap_object < 0) {
|
||||
settings->sel_mocap_object = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
XrMotionCaptureObject *WM_xr_mocap_object_find(const XrSessionSettings *settings, const Object *ob)
|
||||
{
|
||||
return ob ? BLI_findptr(&settings->mocap_objects, ob, offsetof(XrMotionCaptureObject, ob)) :
|
||||
NULL;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Motion Capture Runtime
|
||||
*
|
||||
* Runtime functions for motion capture object poses and autokeying.
|
||||
* \{ */
|
||||
|
||||
static void wm_xr_mocap_object_pose_get(const XrMotionCaptureObject *mocap_ob, GHOST_XrPose *pose)
|
||||
{
|
||||
BLI_assert(mocap_ob->ob);
|
||||
copy_v3_v3(pose->position, mocap_ob->ob->loc);
|
||||
eul_to_quat(pose->orientation_quat, mocap_ob->ob->rot);
|
||||
}
|
||||
|
||||
static void wm_xr_mocap_object_pose_set(const GHOST_XrPose *pose,
|
||||
XrMotionCaptureObject *mocap_ob,
|
||||
bool apply_offset)
|
||||
{
|
||||
BLI_assert(mocap_ob->ob);
|
||||
|
||||
if (apply_offset) {
|
||||
/* Convert offsets to pose (device) space. */
|
||||
float loc_ofs[3], rot_ofs[4];
|
||||
copy_v3_v3(loc_ofs, mocap_ob->location_offset);
|
||||
mul_qt_v3(pose->orientation_quat, loc_ofs);
|
||||
|
||||
eul_to_quat(rot_ofs, mocap_ob->rotation_offset);
|
||||
normalize_qt(rot_ofs);
|
||||
invert_qt_normalized(rot_ofs);
|
||||
mul_qt_qtqt(rot_ofs, pose->orientation_quat, rot_ofs);
|
||||
normalize_qt(rot_ofs);
|
||||
|
||||
add_v3_v3v3(mocap_ob->ob->loc, pose->position, loc_ofs);
|
||||
quat_to_eul(mocap_ob->ob->rot, rot_ofs);
|
||||
}
|
||||
else {
|
||||
copy_v3_v3(mocap_ob->ob->loc, pose->position);
|
||||
quat_to_eul(mocap_ob->ob->rot, pose->orientation_quat);
|
||||
}
|
||||
|
||||
DEG_id_tag_update(&mocap_ob->ob->id, ID_RECALC_TRANSFORM);
|
||||
}
|
||||
|
||||
void wm_xr_mocap_orig_poses_store(const XrSessionSettings *settings, wmXrSessionState *state)
|
||||
{
|
||||
ListBase *mocap_orig_poses = &state->mocap_orig_poses;
|
||||
|
||||
LISTBASE_FOREACH (XrMotionCaptureObject *, mocap_ob, &settings->mocap_objects) {
|
||||
wmXrMotionCapturePose *mocap_pose = MEM_callocN(sizeof(wmXrMotionCapturePose), __func__);
|
||||
mocap_pose->ob = mocap_ob->ob;
|
||||
if (mocap_ob->ob) {
|
||||
wm_xr_mocap_object_pose_get(mocap_ob, &mocap_pose->pose);
|
||||
}
|
||||
BLI_addtail(mocap_orig_poses, mocap_pose);
|
||||
}
|
||||
}
|
||||
|
||||
void wm_xr_mocap_orig_poses_restore(const wmXrSessionState *state, XrSessionSettings *settings)
|
||||
{
|
||||
ListBase *mocap_objects = &settings->mocap_objects;
|
||||
|
||||
LISTBASE_FOREACH (wmXrMotionCapturePose *, mocap_pose, &state->mocap_orig_poses) {
|
||||
XrMotionCaptureObject *mocap_ob = BLI_findptr(
|
||||
mocap_objects, mocap_pose->ob, offsetof(XrMotionCaptureObject, ob));
|
||||
if (mocap_ob && mocap_ob->ob) {
|
||||
wm_xr_mocap_object_pose_set(&mocap_pose->pose, mocap_ob, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void wm_xr_mocap_object_autokey(
|
||||
bContext *C, Scene *scene, ViewLayer *view_layer, wmWindow *win, Object *ob, bool notify)
|
||||
{
|
||||
/* Poll functions in keyingsets_utils.py require an active window and object. */
|
||||
wmWindow *win_prev = win ? CTX_wm_window(C) : NULL;
|
||||
if (win) {
|
||||
CTX_wm_window_set(C, win);
|
||||
}
|
||||
|
||||
Object *obact = CTX_data_active_object(C);
|
||||
if (!obact) {
|
||||
Base *base = BKE_view_layer_base_find(view_layer, ob);
|
||||
if (base) {
|
||||
ED_object_base_select(base, BA_SELECT);
|
||||
ED_object_base_activate(C, base);
|
||||
}
|
||||
}
|
||||
|
||||
bScreen *screen = CTX_wm_screen(C);
|
||||
if (screen && screen->animtimer && (IS_AUTOKEY_FLAG(scene, INSERTAVAIL) == 0) &&
|
||||
((scene->toolsettings->autokey_flag & ANIMRECORD_FLAG_WITHNLA) != 0)) {
|
||||
ED_transform_animrecord_check_state(scene, screen->animtimer, ob);
|
||||
}
|
||||
|
||||
ED_transform_autokeyframe_object(C, scene, view_layer, ob, TFM_TRANSLATION);
|
||||
if (IS_AUTOKEY_FLAG(scene, INSERTNEEDED)) {
|
||||
ED_transform_autokeyframe_object(C, scene, view_layer, ob, TFM_ROTATION);
|
||||
}
|
||||
|
||||
if (ED_transform_motionpath_need_update_object(scene, ob)) {
|
||||
ED_objects_recalculate_paths(C, scene, OBJECT_PATH_CALC_RANGE_CURRENT_FRAME);
|
||||
}
|
||||
|
||||
if (notify) {
|
||||
WM_event_add_notifier(C, NC_OBJECT | ND_KEYS, NULL);
|
||||
WM_main_add_notifier(NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
|
||||
}
|
||||
|
||||
if (win) {
|
||||
CTX_wm_window_set(C, win_prev);
|
||||
}
|
||||
}
|
||||
|
||||
void wm_xr_mocap_objects_update(const char *user_path,
|
||||
const GHOST_XrPose *pose,
|
||||
bContext *C,
|
||||
XrSessionSettings *settings,
|
||||
Scene *scene,
|
||||
ViewLayer *view_layer,
|
||||
wmWindow *win,
|
||||
bScreen *screen_anim,
|
||||
bool notify)
|
||||
{
|
||||
LISTBASE_FOREACH (XrMotionCaptureObject *, mocap_ob, &settings->mocap_objects) {
|
||||
if (mocap_ob->ob && ((mocap_ob->flag & XR_MOCAP_OBJECT_ENABLE) != 0) &&
|
||||
STREQ(mocap_ob->user_path, user_path)) {
|
||||
wm_xr_mocap_object_pose_set(pose, mocap_ob, true);
|
||||
|
||||
if (((mocap_ob->flag & XR_MOCAP_OBJECT_AUTOKEY) != 0) && screen_anim &&
|
||||
autokeyframe_cfra_can_key(scene, &mocap_ob->ob->id)) {
|
||||
wm_xr_mocap_object_autokey(C, scene, view_layer, win, mocap_ob->ob, notify);
|
||||
notify = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool WM_xr_session_state_mocap_pose_get(const wmXrData *xr, XrMotionCaptureObject *mocap_ob)
|
||||
{
|
||||
if (!WM_xr_session_exists(xr)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mocap_ob->ob) {
|
||||
wmXrMotionCapturePose *mocap_pose = BLI_findptr(&xr->runtime->session_state.mocap_orig_poses,
|
||||
mocap_ob->ob,
|
||||
offsetof(wmXrMotionCapturePose, ob));
|
||||
if (!mocap_pose) {
|
||||
return false;
|
||||
}
|
||||
wm_xr_mocap_object_pose_set(&mocap_pose->pose, mocap_ob, false);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void WM_xr_session_state_mocap_pose_set(wmXrData *xr, const XrMotionCaptureObject *mocap_ob)
|
||||
{
|
||||
if (WM_xr_session_exists(xr) && mocap_ob->ob) {
|
||||
wmXrMotionCapturePose *mocap_pose = BLI_findptr(&xr->runtime->session_state.mocap_orig_poses,
|
||||
mocap_ob->ob,
|
||||
offsetof(wmXrMotionCapturePose, ob));
|
||||
if (mocap_pose) {
|
||||
wm_xr_mocap_object_pose_get(mocap_ob, &mocap_pose->pose);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** \} */
|
2492
source/blender/windowmanager/xr/intern/wm_xr_operators.c
Normal file
2492
source/blender/windowmanager/xr/intern/wm_xr_operators.c
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -22,6 +22,7 @@
|
||||
|
||||
struct wmWindowManager;
|
||||
struct wmXrData;
|
||||
struct bContext;
|
||||
|
||||
typedef void (*wmXrSessionExitFn)(const wmXrData *xr_data);
|
||||
|
||||
@@ -29,4 +30,7 @@ typedef void (*wmXrSessionExitFn)(const wmXrData *xr_data);
|
||||
bool wm_xr_init(wmWindowManager *wm);
|
||||
void wm_xr_exit(wmWindowManager *wm);
|
||||
void wm_xr_session_toggle(wmWindowManager *wm, wmWindow *win, wmXrSessionExitFn session_exit_fn);
|
||||
bool wm_xr_events_handle(wmWindowManager *wm);
|
||||
bool wm_xr_events_handle(const struct bContext *C);
|
||||
|
||||
/* wm_xr_operators.c */
|
||||
void wm_xr_operatortypes_register(void);
|
||||
|
@@ -513,6 +513,10 @@ int main(int argc,
|
||||
CTX_py_init_set(C, true);
|
||||
WM_keyconfig_init(C);
|
||||
|
||||
#ifdef WITH_XR_OPENXR
|
||||
WM_xr_actionconfig_init(C);
|
||||
#endif
|
||||
|
||||
#ifdef WITH_FREESTYLE
|
||||
/* Initialize Freestyle. */
|
||||
FRS_init();
|
||||
|
Reference in New Issue
Block a user