diff options
author | Antonio Vazquez <blendergit@gmail.com> | 2021-06-04 20:15:23 +0300 |
---|---|---|
committer | Antonio Vazquez <blendergit@gmail.com> | 2021-06-04 20:15:23 +0300 |
commit | 82cc3b5cc2515d7e4e25214bf7bb4828ed7ca18f (patch) | |
tree | bef740c3b00bb051bb043490ebf693800afab268 /intern | |
parent | 786aa4b5181e53151180df5158e722dd4a45e901 (diff) | |
parent | eb030204f198fe1b933380c63bd40f3dba58c105 (diff) |
Merge branch 'master' into eevee-gpencil
Diffstat (limited to 'intern')
22 files changed, 786 insertions, 460 deletions
diff --git a/intern/cycles/blender/blender_camera.cpp b/intern/cycles/blender/blender_camera.cpp index b31841801d8..6954c5c2f26 100644 --- a/intern/cycles/blender/blender_camera.cpp +++ b/intern/cycles/blender/blender_camera.cpp @@ -83,6 +83,8 @@ struct BlenderCamera { BoundBox2D pano_viewplane; BoundBox2D viewport_camera_border; + float passepartout_alpha; + Transform matrix; float offscreen_dicing_scale; @@ -125,6 +127,7 @@ static void blender_camera_init(BlenderCamera *bcam, BL::RenderSettings &b_rende bcam->pano_viewplane.top = 1.0f; bcam->viewport_camera_border.right = 1.0f; bcam->viewport_camera_border.top = 1.0f; + bcam->passepartout_alpha = 0.5f; bcam->offscreen_dicing_scale = 1.0f; bcam->matrix = transform_identity(); @@ -212,6 +215,8 @@ static void blender_camera_from_object(BlenderCamera *bcam, bcam->lens = b_camera.lens(); + bcam->passepartout_alpha = b_camera.show_passepartout() ? b_camera.passepartout_alpha() : 0.0f; + if (b_camera.dof().use_dof()) { /* allow f/stop number to change aperture_size but still * give manual control over aperture radius */ @@ -834,15 +839,19 @@ static void blender_camera_border(BlenderCamera *bcam, full_border, &bcam->viewport_camera_border); - if (!b_render.use_border()) { + if (b_render.use_border()) { + bcam->border.left = b_render.border_min_x(); + bcam->border.right = b_render.border_max_x(); + bcam->border.bottom = b_render.border_min_y(); + bcam->border.top = b_render.border_max_y(); + } + else if (bcam->passepartout_alpha == 1.0f) { + bcam->border = full_border; + } + else { return; } - bcam->border.left = b_render.border_min_x(); - bcam->border.right = b_render.border_max_x(); - bcam->border.bottom = b_render.border_min_y(); - bcam->border.top = b_render.border_max_y(); - /* Determine viewport subset matching camera border. */ blender_camera_border_subset(b_engine, b_render, @@ -885,8 +894,7 @@ void BlenderSync::sync_view(BL::SpaceView3D &b_v3d, } } -BufferParams BlenderSync::get_buffer_params(BL::RenderSettings &b_render, - BL::SpaceView3D &b_v3d, +BufferParams BlenderSync::get_buffer_params(BL::SpaceView3D &b_v3d, BL::RegionView3D &b_rv3d, Camera *cam, int width, @@ -902,7 +910,8 @@ BufferParams BlenderSync::get_buffer_params(BL::RenderSettings &b_render, if (b_v3d && b_rv3d && b_rv3d.view_perspective() != BL::RegionView3D::view_perspective_CAMERA) use_border = b_v3d.use_render_border(); else - use_border = b_render.use_border(); + /* the camera can always have a passepartout */ + use_border = true; if (use_border) { /* border render */ diff --git a/intern/cycles/blender/blender_session.cpp b/intern/cycles/blender/blender_session.cpp index 89854f6a0e5..29de886e4ff 100644 --- a/intern/cycles/blender/blender_session.cpp +++ b/intern/cycles/blender/blender_session.cpp @@ -155,7 +155,7 @@ void BlenderSession::create_session() /* set buffer parameters */ BufferParams buffer_params = BlenderSync::get_buffer_params( - b_render, b_v3d, b_rv3d, scene->camera, width, height, session_params.denoising.use); + b_v3d, b_rv3d, scene->camera, width, height, session_params.denoising.use); session->reset(buffer_params, session_params.samples); b_engine.use_highlight_tiles(session_params.progressive_refine == false); @@ -242,8 +242,7 @@ void BlenderSession::reset_session(BL::BlendData &b_data, BL::Depsgraph &b_depsg BL::SpaceView3D b_null_space_view3d(PointerRNA_NULL); BL::RegionView3D b_null_region_view3d(PointerRNA_NULL); - BufferParams buffer_params = BlenderSync::get_buffer_params(b_render, - b_null_space_view3d, + BufferParams buffer_params = BlenderSync::get_buffer_params(b_null_space_view3d, b_null_region_view3d, scene->camera, width, @@ -486,7 +485,7 @@ void BlenderSession::render(BL::Depsgraph &b_depsgraph_) SessionParams session_params = BlenderSync::get_session_params( b_engine, b_userpref, b_scene, background, b_view_layer); BufferParams buffer_params = BlenderSync::get_buffer_params( - b_render, b_v3d, b_rv3d, scene->camera, width, height, session_params.denoising.use); + b_v3d, b_rv3d, scene->camera, width, height, session_params.denoising.use); /* temporary render result to find needed passes and views */ BL::RenderResult b_rr = begin_render_result( @@ -810,7 +809,7 @@ void BlenderSession::synchronize(BL::Depsgraph &b_depsgraph_) /* get buffer parameters */ BufferParams buffer_params = BlenderSync::get_buffer_params( - b_render, b_v3d, b_rv3d, scene->camera, width, height, session_params.denoising.use); + b_v3d, b_rv3d, scene->camera, width, height, session_params.denoising.use); if (!buffer_params.denoising_data_pass) { session_params.denoising.use = false; @@ -889,7 +888,7 @@ bool BlenderSession::draw(int w, int h) SessionParams session_params = BlenderSync::get_session_params( b_engine, b_userpref, b_scene, background); BufferParams buffer_params = BlenderSync::get_buffer_params( - b_render, b_v3d, b_rv3d, scene->camera, width, height, session_params.denoising.use); + b_v3d, b_rv3d, scene->camera, width, height, session_params.denoising.use); bool session_pause = BlenderSync::get_session_pause(b_scene, background); if (session_pause == false) { @@ -907,7 +906,7 @@ bool BlenderSession::draw(int w, int h) /* draw */ BufferParams buffer_params = BlenderSync::get_buffer_params( - b_render, b_v3d, b_rv3d, scene->camera, width, height, session->params.denoising.use); + b_v3d, b_rv3d, scene->camera, width, height, session->params.denoising.use); DeviceDrawParams draw_params; if (session->params.display_buffer_linear) { diff --git a/intern/cycles/blender/blender_shader.cpp b/intern/cycles/blender/blender_shader.cpp index 736c10e8881..7f129310736 100644 --- a/intern/cycles/blender/blender_shader.cpp +++ b/intern/cycles/blender/blender_shader.cpp @@ -1373,7 +1373,7 @@ void BlenderSync::sync_world(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d, BlenderViewportParameters new_viewport_parameters(b_v3d); if (world_recalc || update_all || b_world.ptr.data != world_map || - viewport_parameters.modified(new_viewport_parameters)) { + viewport_parameters.shader_modified(new_viewport_parameters)) { Shader *shader = scene->default_background; ShaderGraph *graph = new ShaderGraph(); @@ -1501,8 +1501,8 @@ void BlenderSync::sync_world(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d, background->set_transparent_roughness_threshold(0.0f); } - background->set_use_shader(view_layer.use_background_shader | - viewport_parameters.custom_viewport_parameters()); + background->set_use_shader(view_layer.use_background_shader || + viewport_parameters.use_custom_shader()); background->set_use_ao(background->get_use_ao() && view_layer.use_background_ao); background->tag_update(scene); diff --git a/intern/cycles/blender/blender_sync.cpp b/intern/cycles/blender/blender_sync.cpp index bacf57df48e..82b3abd4432 100644 --- a/intern/cycles/blender/blender_sync.cpp +++ b/intern/cycles/blender/blender_sync.cpp @@ -225,18 +225,12 @@ void BlenderSync::sync_recalc(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d if (b_v3d) { BlenderViewportParameters new_viewport_parameters(b_v3d); - if (viewport_parameters.modified(new_viewport_parameters)) { + if (viewport_parameters.shader_modified(new_viewport_parameters)) { world_recalc = true; has_updates_ = true; } - if (!has_updates_) { - Film *film = scene->film; - - const PassType new_display_pass = new_viewport_parameters.get_viewport_display_render_pass( - b_v3d); - has_updates_ |= film->get_display_pass() != new_display_pass; - } + has_updates_ |= viewport_parameters.modified(new_viewport_parameters); } } diff --git a/intern/cycles/blender/blender_sync.h b/intern/cycles/blender/blender_sync.h index 8cd65f13f70..1c98e529190 100644 --- a/intern/cycles/blender/blender_sync.h +++ b/intern/cycles/blender/blender_sync.h @@ -104,8 +104,7 @@ class BlenderSync { bool background, BL::ViewLayer b_view_layer = BL::ViewLayer(PointerRNA_NULL)); static bool get_session_pause(BL::Scene &b_scene, bool background); - static BufferParams get_buffer_params(BL::RenderSettings &b_render, - BL::SpaceView3D &b_v3d, + static BufferParams get_buffer_params(BL::SpaceView3D &b_v3d, BL::RegionView3D &b_rv3d, Camera *cam, int width, diff --git a/intern/cycles/blender/blender_viewport.cpp b/intern/cycles/blender/blender_viewport.cpp index aac3d41314a..07408fee218 100644 --- a/intern/cycles/blender/blender_viewport.cpp +++ b/intern/cycles/blender/blender_viewport.cpp @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + #include "blender_viewport.h" #include "blender_util.h" @@ -25,7 +26,7 @@ BlenderViewportParameters::BlenderViewportParameters() studiolight_rotate_z(0.0f), studiolight_intensity(1.0f), studiolight_background_alpha(1.0f), - studiolight_path(ustring()) + display_pass(PASS_COMBINED) { } @@ -37,26 +38,27 @@ BlenderViewportParameters::BlenderViewportParameters(BL::SpaceView3D &b_v3d) } BL::View3DShading shading = b_v3d.shading(); + PointerRNA cshading = RNA_pointer_get(&shading.ptr, "cycles"); - /* We only copy the parameters if we are in look dev mode. otherwise + /* We only copy the shading parameters if we are in look dev mode. otherwise * defaults are being used. These defaults mimic normal render settings */ - if (shading.type() != BL::View3DShading::type_RENDERED) { - return; - } + if (shading.type() == BL::View3DShading::type_RENDERED) { + use_scene_world = shading.use_scene_world_render(); + use_scene_lights = shading.use_scene_lights_render(); - use_scene_world = shading.use_scene_world_render(); - use_scene_lights = shading.use_scene_lights_render(); - - if (!use_scene_world) { - studiolight_rotate_z = shading.studiolight_rotate_z(); - studiolight_intensity = shading.studiolight_intensity(); - studiolight_background_alpha = shading.studiolight_background_alpha(); - studiolight_path = shading.selected_studio_light().path(); + if (!use_scene_world) { + studiolight_rotate_z = shading.studiolight_rotate_z(); + studiolight_intensity = shading.studiolight_intensity(); + studiolight_background_alpha = shading.studiolight_background_alpha(); + studiolight_path = shading.selected_studio_light().path(); + } } + + /* Film. */ + display_pass = (PassType)get_enum(cshading, "render_pass", -1, -1); } -/* Check if two instances are different. */ -const bool BlenderViewportParameters::modified(const BlenderViewportParameters &other) const +bool BlenderViewportParameters::shader_modified(const BlenderViewportParameters &other) const { return use_scene_world != other.use_scene_world || use_scene_lights != other.use_scene_lights || studiolight_rotate_z != other.studiolight_rotate_z || @@ -65,26 +67,26 @@ const bool BlenderViewportParameters::modified(const BlenderViewportParameters & studiolight_path != other.studiolight_path; } -const bool BlenderViewportParameters::custom_viewport_parameters() const +bool BlenderViewportParameters::film_modified(const BlenderViewportParameters &other) const { - return !(use_scene_world && use_scene_lights); + return display_pass != other.display_pass; } -PassType BlenderViewportParameters::get_viewport_display_render_pass(BL::SpaceView3D &b_v3d) +bool BlenderViewportParameters::modified(const BlenderViewportParameters &other) const { - PassType display_pass = PASS_NONE; - if (b_v3d) { - BL::View3DShading b_view3dshading = b_v3d.shading(); - PointerRNA cshading = RNA_pointer_get(&b_view3dshading.ptr, "cycles"); - display_pass = (PassType)get_enum(cshading, "render_pass", -1, -1); - } - return display_pass; + return shader_modified(other) || film_modified(other); +} + +bool BlenderViewportParameters::use_custom_shader() const +{ + return !(use_scene_world && use_scene_lights); } PassType update_viewport_display_passes(BL::SpaceView3D &b_v3d, vector<Pass> &passes) { if (b_v3d) { - PassType display_pass = BlenderViewportParameters::get_viewport_display_render_pass(b_v3d); + const BlenderViewportParameters viewport_parameters(b_v3d); + const PassType display_pass = viewport_parameters.display_pass; passes.clear(); Pass::add(display_pass, passes); diff --git a/intern/cycles/blender/blender_viewport.h b/intern/cycles/blender/blender_viewport.h index 7c6c9c4d274..d6518597053 100644 --- a/intern/cycles/blender/blender_viewport.h +++ b/intern/cycles/blender/blender_viewport.h @@ -18,17 +18,18 @@ #define __BLENDER_VIEWPORT_H__ #include "MEM_guardedalloc.h" + #include "RNA_access.h" #include "RNA_blender_cpp.h" #include "RNA_types.h" #include "render/film.h" -#include "util/util_param.h" CCL_NAMESPACE_BEGIN class BlenderViewportParameters { - private: + public: + /* Shader. */ bool use_scene_world; bool use_scene_lights; float studiolight_rotate_z; @@ -36,17 +37,24 @@ class BlenderViewportParameters { float studiolight_background_alpha; ustring studiolight_path; + /* Film. */ + PassType display_pass; + BlenderViewportParameters(); - BlenderViewportParameters(BL::SpaceView3D &b_v3d); + explicit BlenderViewportParameters(BL::SpaceView3D &b_v3d); - const bool modified(const BlenderViewportParameters &other) const; - const bool custom_viewport_parameters() const; - friend class BlenderSync; + /* Check whether any of shading related settings are different from the given parameters. */ + bool shader_modified(const BlenderViewportParameters &other) const; - public: - /* Retrieve the render pass that needs to be displayed on the given `SpaceView3D` - * When the `b_v3d` parameter is not given `PASS_NONE` will be returned. */ - static PassType get_viewport_display_render_pass(BL::SpaceView3D &b_v3d); + /* Check whether any of film related settings are different from the given parameters. */ + bool film_modified(const BlenderViewportParameters &other) const; + + /* Check whether any of settings are different from the given parameters. */ + bool modified(const BlenderViewportParameters &other) const; + + /* Returns truth when a custom shader defined by the viewport is to be used instead of the + * regular background shader or scene light. */ + bool use_custom_shader() const; }; PassType update_viewport_display_passes(BL::SpaceView3D &b_v3d, vector<Pass> &passes); diff --git a/intern/cycles/kernel/kernel_montecarlo.h b/intern/cycles/kernel/kernel_montecarlo.h index ba25c0e24e4..ce37bd0b15e 100644 --- a/intern/cycles/kernel/kernel_montecarlo.h +++ b/intern/cycles/kernel/kernel_montecarlo.h @@ -195,31 +195,108 @@ ccl_device float2 regular_polygon_sample(float corners, float rotation, float u, ccl_device float3 ensure_valid_reflection(float3 Ng, float3 I, float3 N) { - float3 R; - float NI = dot(N, I); - float NgR, threshold; - - /* Check if the incident ray is coming from behind normal N. */ - if (NI > 0) { - /* Normal reflection */ - R = (2 * NI) * N - I; - NgR = dot(Ng, R); - - /* Reflection rays may always be at least as shallow as the incoming ray. */ - threshold = min(0.9f * dot(Ng, I), 0.01f); - if (NgR >= threshold) { - return N; + float3 R = 2 * dot(N, I) * N - I; + + /* Reflection rays may always be at least as shallow as the incoming ray. */ + float threshold = min(0.9f * dot(Ng, I), 0.01f); + if (dot(Ng, R) >= threshold) { + return N; + } + + /* Form coordinate system with Ng as the Z axis and N inside the X-Z-plane. + * The X axis is found by normalizing the component of N that's orthogonal to Ng. + * The Y axis isn't actually needed. + */ + float NdotNg = dot(N, Ng); + float3 X = normalize(N - NdotNg * Ng); + + /* Keep math expressions. */ + /* clang-format off */ + /* Calculate N.z and N.x in the local coordinate system. + * + * The goal of this computation is to find a N' that is rotated towards Ng just enough + * to lift R' above the threshold (here called t), therefore dot(R', Ng) = t. + * + * According to the standard reflection equation, + * this means that we want dot(2*dot(N', I)*N' - I, Ng) = t. + * + * Since the Z axis of our local coordinate system is Ng, dot(x, Ng) is just x.z, so we get + * 2*dot(N', I)*N'.z - I.z = t. + * + * The rotation is simple to express in the coordinate system we formed - + * since N lies in the X-Z-plane, we know that N' will also lie in the X-Z-plane, + * so N'.y = 0 and therefore dot(N', I) = N'.x*I.x + N'.z*I.z . + * + * Furthermore, we want N' to be normalized, so N'.x = sqrt(1 - N'.z^2). + * + * With these simplifications, + * we get the final equation 2*(sqrt(1 - N'.z^2)*I.x + N'.z*I.z)*N'.z - I.z = t. + * + * The only unknown here is N'.z, so we can solve for that. + * + * The equation has four solutions in general: + * + * N'.z = +-sqrt(0.5*(+-sqrt(I.x^2*(I.x^2 + I.z^2 - t^2)) + t*I.z + I.x^2 + I.z^2)/(I.x^2 + I.z^2)) + * We can simplify this expression a bit by grouping terms: + * + * a = I.x^2 + I.z^2 + * b = sqrt(I.x^2 * (a - t^2)) + * c = I.z*t + a + * N'.z = +-sqrt(0.5*(+-b + c)/a) + * + * Two solutions can immediately be discarded because they're negative so N' would lie in the + * lower hemisphere. + */ + /* clang-format on */ + + float Ix = dot(I, X), Iz = dot(I, Ng); + float Ix2 = sqr(Ix), Iz2 = sqr(Iz); + float a = Ix2 + Iz2; + + float b = safe_sqrtf(Ix2 * (a - sqr(threshold))); + float c = Iz * threshold + a; + + /* Evaluate both solutions. + * In many cases one can be immediately discarded (if N'.z would be imaginary or larger than + * one), so check for that first. If no option is viable (might happen in extreme cases like N + * being in the wrong hemisphere), give up and return Ng. */ + float fac = 0.5f / a; + float N1_z2 = fac * (b + c), N2_z2 = fac * (-b + c); + bool valid1 = (N1_z2 > 1e-5f) && (N1_z2 <= (1.0f + 1e-5f)); + bool valid2 = (N2_z2 > 1e-5f) && (N2_z2 <= (1.0f + 1e-5f)); + + float2 N_new; + if (valid1 && valid2) { + /* If both are possible, do the expensive reflection-based check. */ + float2 N1 = make_float2(safe_sqrtf(1.0f - N1_z2), safe_sqrtf(N1_z2)); + float2 N2 = make_float2(safe_sqrtf(1.0f - N2_z2), safe_sqrtf(N2_z2)); + + float R1 = 2 * (N1.x * Ix + N1.y * Iz) * N1.y - Iz; + float R2 = 2 * (N2.x * Ix + N2.y * Iz) * N2.y - Iz; + + valid1 = (R1 >= 1e-5f); + valid2 = (R2 >= 1e-5f); + if (valid1 && valid2) { + /* If both solutions are valid, return the one with the shallower reflection since it will be + * closer to the input (if the original reflection wasn't shallow, we would not be in this + * part of the function). */ + N_new = (R1 < R2) ? N1 : N2; } + else { + /* If only one reflection is valid (= positive), pick that one. */ + N_new = (R1 > R2) ? N1 : N2; + } + } + else if (valid1 || valid2) { + /* Only one solution passes the N'.z criterium, so pick that one. */ + float Nz2 = valid1 ? N1_z2 : N2_z2; + N_new = make_float2(safe_sqrtf(1.0f - Nz2), safe_sqrtf(Nz2)); } else { - /* Bad incident */ - R = -I; - NgR = dot(Ng, R); - threshold = 0.01f; + return Ng; } - R = R + Ng * (threshold - NgR); /* Lift the reflection above the threshold. */ - return normalize(I * len(R) + R * len(I)); /* Find a bisector. */ + return N_new.x * X + N_new.y * Ng; } CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/shaders/stdcycles.h b/intern/cycles/kernel/shaders/stdcycles.h index af7b645d9a2..dd604da68ce 100644 --- a/intern/cycles/kernel/shaders/stdcycles.h +++ b/intern/cycles/kernel/shaders/stdcycles.h @@ -84,30 +84,67 @@ closure color principled_hair(normal N, closure color henyey_greenstein(float g) BUILTIN; closure color absorption() BUILTIN; -normal ensure_valid_reflection(normal Ng, normal I, normal N) +normal ensure_valid_reflection(normal Ng, vector I, normal N) { /* The implementation here mirrors the one in kernel_montecarlo.h, * check there for an explanation of the algorithm. */ - vector R; - float NI = dot(N, I); - float NgR, threshold; - - if (NI > 0) { - R = (2 * NI) * N - I; - NgR = dot(Ng, R); - threshold = min(0.9 * dot(Ng, I), 0.01); - if (NgR >= threshold) { - return N; + + float sqr(float x) + { + return x * x; + } + + vector R = 2 * dot(N, I) * N - I; + + float threshold = min(0.9 * dot(Ng, I), 0.01); + if (dot(Ng, R) >= threshold) { + return N; + } + + float NdotNg = dot(N, Ng); + vector X = normalize(N - NdotNg * Ng); + + float Ix = dot(I, X), Iz = dot(I, Ng); + float Ix2 = sqr(Ix), Iz2 = sqr(Iz); + float a = Ix2 + Iz2; + + float b = sqrt(Ix2 * (a - sqr(threshold))); + float c = Iz * threshold + a; + + float fac = 0.5 / a; + float N1_z2 = fac * (b + c), N2_z2 = fac * (-b + c); + int valid1 = (N1_z2 > 1e-5) && (N1_z2 <= (1.0 + 1e-5)); + int valid2 = (N2_z2 > 1e-5) && (N2_z2 <= (1.0 + 1e-5)); + + float N_new_x, N_new_z; + if (valid1 && valid2) { + float N1_x = sqrt(1.0 - N1_z2), N1_z = sqrt(N1_z2); + float N2_x = sqrt(1.0 - N2_z2), N2_z = sqrt(N2_z2); + + float R1 = 2 * (N1_x * Ix + N1_z * Iz) * N1_z - Iz; + float R2 = 2 * (N2_x * Ix + N2_z * Iz) * N2_z - Iz; + + valid1 = (R1 >= 1e-5); + valid2 = (R2 >= 1e-5); + if (valid1 && valid2) { + N_new_x = (R1 < R2) ? N1_x : N2_x; + N_new_z = (R1 < R2) ? N1_z : N2_z; + } + else { + N_new_x = (R1 > R2) ? N1_x : N2_x; + N_new_z = (R1 > R2) ? N1_z : N2_z; } } + else if (valid1 || valid2) { + float Nz2 = valid1 ? N1_z2 : N2_z2; + N_new_x = sqrt(1.0 - Nz2); + N_new_z = sqrt(Nz2); + } else { - R = -I; - NgR = dot(Ng, R); - threshold = 0.01; + return Ng; } - R = R + Ng * (threshold - NgR); - return normalize(I * length(R) + R * length(I)); + return N_new_x * X + N_new_z * Ng; } #endif /* CCL_STDOSL_H */ diff --git a/intern/cycles/render/alembic_read.cpp b/intern/cycles/render/alembic_read.cpp index 4d09c40b07b..33ce3502879 100644 --- a/intern/cycles/render/alembic_read.cpp +++ b/intern/cycles/render/alembic_read.cpp @@ -606,7 +606,8 @@ void read_geometry_data(AlembicProcedural *proc, template<typename T> struct value_type_converter { using cycles_type = float; - static constexpr TypeDesc type_desc = TypeFloat; + /* Use `TypeDesc::FLOAT` instead of `TypeFloat` to work around a compiler bug in gcc 11. */ + static constexpr TypeDesc type_desc = TypeDesc::FLOAT; static constexpr const char *type_name = "float (default)"; static cycles_type convert_value(T value) diff --git a/intern/cycles/render/geometry.cpp b/intern/cycles/render/geometry.cpp index 1c4b360750f..ce76658acb6 100644 --- a/intern/cycles/render/geometry.cpp +++ b/intern/cycles/render/geometry.cpp @@ -2063,7 +2063,7 @@ void GeometryManager::device_update(Device *device, * for meshes with correct bounding boxes. * * This wouldn't cause wrong results, just true - * displacement might be less optimal ot calculate. + * displacement might be less optimal to calculate. */ scene->object_manager->need_flags_update = old_need_object_flags_update; } diff --git a/intern/cycles/util/util_task.h b/intern/cycles/util/util_task.h index 7c39ed675b5..906bf420756 100644 --- a/intern/cycles/util/util_task.h +++ b/intern/cycles/util/util_task.h @@ -32,7 +32,7 @@ typedef function<void(void)> TaskRunFunction; /* Task Pool * - * Pool of tasks that will be executed by the central TaskScheduler.For each + * Pool of tasks that will be executed by the central TaskScheduler. For each * pool, we can wait for all tasks to be done, or cancel them before they are * done. * @@ -77,7 +77,7 @@ class TaskPool { /* Task Scheduler * - * Central scheduler that holds running threads ready to execute tasks. A singe + * Central scheduler that holds running threads ready to execute tasks. A single * queue holds the task from all pools. */ class TaskScheduler { diff --git a/intern/ffmpeg/ffmpeg_compat.h b/intern/ffmpeg/ffmpeg_compat.h index 54a004d53e2..0c22cf82688 100644 --- a/intern/ffmpeg/ffmpeg_compat.h +++ b/intern/ffmpeg/ffmpeg_compat.h @@ -43,6 +43,55 @@ # define FFMPEG_INLINE static inline #endif +#if (LIBAVFORMAT_VERSION_MAJOR < 58) || \ + ((LIBAVFORMAT_VERSION_MAJOR == 58) && (LIBAVFORMAT_VERSION_MINOR < 76)) +# define FFMPEG_USE_DURATION_WORKAROUND 1 + +/* Before ffmpeg 4.4, package duration calculation used depricated variables to calculate the + * packet duration. Use the function from commit + * github.com/FFmpeg/FFmpeg/commit/1c0885334dda9ee8652e60c586fa2e3674056586 + * to calculate the correct framerate for ffmpeg < 4.4. + */ + +FFMPEG_INLINE +void my_guess_pkt_duration(AVFormatContext *s, AVStream *st, AVPacket *pkt) +{ + if (pkt->duration < 0 && st->codecpar->codec_type != AVMEDIA_TYPE_SUBTITLE) { + av_log(s, + AV_LOG_WARNING, + "Packet with invalid duration %" PRId64 " in stream %d\n", + pkt->duration, + pkt->stream_index); + pkt->duration = 0; + } + + if (pkt->duration) { + return; + } + + switch (st->codecpar->codec_type) { + case AVMEDIA_TYPE_VIDEO: + if (st->avg_frame_rate.num > 0 && st->avg_frame_rate.den > 0) { + pkt->duration = av_rescale_q(1, av_inv_q(st->avg_frame_rate), st->time_base); + } + else if (st->time_base.num * 1000LL > st->time_base.den) { + pkt->duration = 1; + } + break; + case AVMEDIA_TYPE_AUDIO: { + int frame_size = av_get_audio_frame_duration2(st->codecpar, pkt->size); + if (frame_size && st->codecpar->sample_rate) { + pkt->duration = av_rescale_q( + frame_size, (AVRational){1, st->codecpar->sample_rate}, st->time_base); + } + break; + } + default: + break; + } +} +#endif + FFMPEG_INLINE void my_update_cur_dts(AVFormatContext *s, AVStream *ref_st, int64_t timestamp) { diff --git a/intern/ghost/CMakeLists.txt b/intern/ghost/CMakeLists.txt index f90e8a973bf..1b5cdb3cda0 100644 --- a/intern/ghost/CMakeLists.txt +++ b/intern/ghost/CMakeLists.txt @@ -282,6 +282,7 @@ elseif(WITH_GHOST_X11 OR WITH_GHOST_WAYLAND) ${wayland-egl_INCLUDE_DIRS} ${xkbcommon_INCLUDE_DIRS} ${wayland-cursor_INCLUDE_DIRS} + ${dbus_INCLUDE_DIRS} ) list(APPEND SRC @@ -321,6 +322,11 @@ elseif(WITH_GHOST_X11 OR WITH_GHOST_WAYLAND) xdg-shell "${WAYLAND_PROTOCOLS_DIR}/stable/xdg-shell/xdg-shell.xml" ) + # xdg-decoration. + generate_protocol_bindings( + xdg-decoration + "${WAYLAND_PROTOCOLS_DIR}/unstable/xdg-decoration/xdg-decoration-unstable-v1.xml" + ) # Pointer-constraints. generate_protocol_bindings( pointer-constraints diff --git a/intern/ghost/intern/GHOST_SystemWayland.cpp b/intern/ghost/intern/GHOST_SystemWayland.cpp index 81d9824ed26..1d2a349fdf1 100644 --- a/intern/ghost/intern/GHOST_SystemWayland.cpp +++ b/intern/ghost/intern/GHOST_SystemWayland.cpp @@ -40,6 +40,7 @@ #include <unordered_map> #include <unordered_set> +#include "GHOST_WaylandCursorSettings.h" #include <pointer-constraints-client-protocol.h> #include <relative-pointer-client-protocol.h> #include <wayland-cursor.h> @@ -52,15 +53,6 @@ #include <cstring> -struct output_t { - struct wl_output *output; - int32_t width, height; - int transform; - int scale; - std::string make; - std::string model; -}; - struct buffer_t { void *data; size_t size; @@ -72,6 +64,12 @@ struct cursor_t { struct wl_buffer *buffer; struct wl_cursor_image image; struct buffer_t *file_buffer = nullptr; + struct wl_cursor_theme *theme = nullptr; + int size; + std::string theme_name; + // outputs on which the cursor is visible + std::unordered_set<const output_t *> outputs; + int scale = 1; }; struct data_offer_t { @@ -142,10 +140,14 @@ struct display_t { struct wl_display *display; struct wl_compositor *compositor = nullptr; struct xdg_wm_base *xdg_shell = nullptr; + struct zxdg_decoration_manager_v1 *xdg_decoration_manager = nullptr; struct wl_shm *shm = nullptr; std::vector<output_t *> outputs; std::vector<input_t *> inputs; - struct wl_cursor_theme *cursor_theme = nullptr; + struct { + std::string theme; + int size; + } cursor; struct wl_data_device_manager *data_device_manager = nullptr; struct zwp_relative_pointer_manager_v1 *relative_pointer_manager = nullptr; struct zwp_pointer_constraints_v1 *pointer_constraints = nullptr; @@ -154,6 +156,8 @@ struct display_t { std::vector<struct wl_egl_window *> os_egl_windows; }; +static GHOST_WindowManager *window_manager = nullptr; + static void display_destroy(display_t *d) { if (d->data_device_manager) { @@ -188,6 +192,9 @@ static void display_destroy(display_t *d) if (input->cursor.surface) { wl_surface_destroy(input->cursor.surface); } + if (input->cursor.theme) { + wl_cursor_theme_destroy(input->cursor.theme); + } if (input->pointer) { wl_pointer_destroy(input->pointer); } @@ -210,10 +217,6 @@ static void display_destroy(display_t *d) delete input; } - if (d->cursor_theme) { - wl_cursor_theme_destroy(d->cursor_theme); - } - if (d->shm) { wl_shm_destroy(d->shm); } @@ -238,6 +241,10 @@ static void display_destroy(display_t *d) wl_compositor_destroy(d->compositor); } + if (d->xdg_decoration_manager) { + zxdg_decoration_manager_v1_destroy(d->xdg_decoration_manager); + } + if (d->xdg_shell) { xdg_wm_base_destroy(d->xdg_shell); } @@ -478,7 +485,9 @@ static void dnd_events(const input_t *const input, const GHOST_TEventType event) static std::string read_pipe(data_offer_t *data_offer, const std::string mime_receive) { int pipefd[2]; - pipe(pipefd); + if (pipe(pipefd) != 0) { + return {}; + } wl_data_offer_receive(data_offer->id, mime_receive.c_str(), pipefd[1]); close(pipefd[1]); @@ -513,7 +522,9 @@ static void data_source_send(void *data, int32_t fd) { const char *const buffer = static_cast<char *>(data); - write(fd, buffer, strlen(buffer) + 1); + if (write(fd, buffer, strlen(buffer) + 1) < 0) { + GHOST_PRINT("error writing to clipboard: " << std::strerror(errno) << std::endl); + } close(fd); } @@ -789,13 +800,80 @@ static void cursor_buffer_release(void *data, struct wl_buffer *wl_buffer) cursor_t *cursor = static_cast<cursor_t *>(data); wl_buffer_destroy(wl_buffer); - cursor->buffer = nullptr; + + if (wl_buffer == cursor->buffer) { + /* the mapped buffer was from a custom cursor */ + cursor->buffer = nullptr; + } } const struct wl_buffer_listener cursor_buffer_listener = { cursor_buffer_release, }; +static GHOST_IWindow *get_window(struct wl_surface *surface) +{ + if (!surface) { + return nullptr; + } + + for (GHOST_IWindow *win : window_manager->getWindows()) { + if (surface == static_cast<const GHOST_WindowWayland *>(win)->surface()) { + return win; + } + } + return nullptr; +} + +static bool update_cursor_scale(cursor_t &cursor, wl_shm *shm) +{ + int scale = 0; + for (const output_t *output : cursor.outputs) { + if (output->scale > scale) + scale = output->scale; + } + + if (scale > 0 && cursor.scale != scale) { + cursor.scale = scale; + wl_surface_set_buffer_scale(cursor.surface, scale); + wl_cursor_theme_destroy(cursor.theme); + cursor.theme = wl_cursor_theme_load(cursor.theme_name.c_str(), scale * cursor.size, shm); + return true; + } + return false; +} + +static void cursor_surface_enter(void *data, + struct wl_surface * /*wl_surface*/, + struct wl_output *output) +{ + input_t *input = static_cast<input_t *>(data); + for (const output_t *reg_output : input->system->outputs()) { + if (reg_output->output == output) { + input->cursor.outputs.insert(reg_output); + } + } + update_cursor_scale(input->cursor, input->system->shm()); +} + +static void cursor_surface_leave(void *data, + struct wl_surface * /*wl_surface*/, + struct wl_output *output) +{ + input_t *input = static_cast<input_t *>(data); + for (const output_t *reg_output : input->system->outputs()) { + if (reg_output->output == output) { + input->cursor.outputs.erase(reg_output); + } + } + update_cursor_scale(input->cursor, input->system->shm()); +} + +struct wl_surface_listener cursor_surface_listener = { + cursor_surface_enter, + cursor_surface_leave, +}; + static void pointer_enter(void *data, struct wl_pointer * /*wl_pointer*/, uint32_t serial, @@ -803,22 +881,28 @@ static void pointer_enter(void *data, wl_fixed_t surface_x, wl_fixed_t surface_y) { - if (!surface) { + GHOST_WindowWayland *win = static_cast<GHOST_WindowWayland *>(get_window(surface)); + + if (!win) { return; } + + win->activate(); + input_t *input = static_cast<input_t *>(data); input->pointer_serial = serial; - input->x = wl_fixed_to_int(surface_x); - input->y = wl_fixed_to_int(surface_y); + input->x = win->scale() * wl_fixed_to_int(surface_x); + input->y = win->scale() * wl_fixed_to_int(surface_y); input->focus_pointer = surface; - input->system->pushEvent( - new GHOST_EventCursor(input->system->getMilliSeconds(), - GHOST_kEventCursorMove, - static_cast<GHOST_WindowWayland *>(wl_surface_get_user_data(surface)), - input->x, - input->y, - GHOST_TABLET_DATA_NONE)); + win->setCursorShape(win->getCursorShape()); + + input->system->pushEvent(new GHOST_EventCursor(input->system->getMilliSeconds(), + GHOST_kEventCursorMove, + static_cast<GHOST_WindowWayland *>(win), + input->x, + input->y, + GHOST_TABLET_DATA_NONE)); } static void pointer_leave(void *data, @@ -826,9 +910,14 @@ static void pointer_leave(void *data, uint32_t /*serial*/, struct wl_surface *surface) { - if (surface != nullptr) { - static_cast<input_t *>(data)->focus_pointer = nullptr; + GHOST_IWindow *win = get_window(surface); + + if (!win) { + return; } + + static_cast<input_t *>(data)->focus_pointer = nullptr; + static_cast<GHOST_WindowWayland *>(win)->deactivate(); } static void pointer_motion(void *data, @@ -839,21 +928,20 @@ static void pointer_motion(void *data, { input_t *input = static_cast<input_t *>(data); - GHOST_IWindow *win = static_cast<GHOST_WindowWayland *>( - wl_surface_get_user_data(input->focus_pointer)); + GHOST_WindowWayland *win = static_cast<GHOST_WindowWayland *>(get_window(input->focus_pointer)); if (!win) { return; } - input->x = wl_fixed_to_int(surface_x); - input->y = wl_fixed_to_int(surface_y); + input->x = win->scale() * wl_fixed_to_int(surface_x); + input->y = win->scale() * wl_fixed_to_int(surface_y); input->system->pushEvent(new GHOST_EventCursor(input->system->getMilliSeconds(), GHOST_kEventCursorMove, win, - wl_fixed_to_int(surface_x), - wl_fixed_to_int(surface_y), + input->x, + input->y, GHOST_TABLET_DATA_NONE)); } @@ -864,6 +952,14 @@ static void pointer_button(void *data, uint32_t button, uint32_t state) { + input_t *input = static_cast<input_t *>(data); + + GHOST_IWindow *win = get_window(input->focus_pointer); + + if (!win) { + return; + } + GHOST_TEventType etype = GHOST_kEventUnknown; switch (state) { case WL_POINTER_BUTTON_STATE_RELEASED: @@ -887,9 +983,6 @@ static void pointer_button(void *data, break; } - input_t *input = static_cast<input_t *>(data); - GHOST_IWindow *win = static_cast<GHOST_WindowWayland *>( - wl_surface_get_user_data(input->focus_pointer)); input->data_source->source_serial = serial; input->buttons.set(ebutton, state == WL_POINTER_BUTTON_STATE_PRESSED); input->system->pushEvent(new GHOST_EventButton( @@ -902,12 +995,18 @@ static void pointer_axis(void *data, uint32_t axis, wl_fixed_t value) { + input_t *input = static_cast<input_t *>(data); + + GHOST_IWindow *win = get_window(input->focus_pointer); + + if (!win) { + return; + } + if (axis != WL_POINTER_AXIS_VERTICAL_SCROLL) { return; } - input_t *input = static_cast<input_t *>(data); - GHOST_IWindow *win = static_cast<GHOST_WindowWayland *>( - wl_surface_get_user_data(input->focus_pointer)); + input->system->pushEvent( new GHOST_EventWheel(input->system->getMilliSeconds(), win, std::signbit(value) ? +1 : -1)); } @@ -1137,7 +1236,12 @@ static void seat_capabilities(void *data, struct wl_seat *wl_seat, uint32_t capa input->cursor.visible = true; input->cursor.buffer = nullptr; input->cursor.file_buffer = new buffer_t; + if (!get_cursor_settings(input->cursor.theme_name, input->cursor.size)) { + input->cursor.theme_name = std::string(); + input->cursor.size = default_cursor_size; + } wl_pointer_add_listener(input->pointer, &pointer_listener, data); + wl_surface_add_listener(input->cursor.surface, &cursor_surface_listener, data); } if (capabilities & WL_SEAT_CAPABILITY_KEYBOARD) { @@ -1160,8 +1264,8 @@ static void output_geometry(void *data, struct wl_output * /*wl_output*/, int32_t /*x*/, int32_t /*y*/, - int32_t /*physical_width*/, - int32_t /*physical_height*/, + int32_t physical_width, + int32_t physical_height, int32_t /*subpixel*/, const char *make, const char *model, @@ -1171,6 +1275,8 @@ static void output_geometry(void *data, output->transform = transform; output->make = std::string(make); output->model = std::string(model); + output->width_mm = physical_width; + output->height_mm = physical_height; } static void output_mode(void *data, @@ -1181,8 +1287,8 @@ static void output_mode(void *data, int32_t /*refresh*/) { output_t *output = static_cast<output_t *>(data); - output->width = width; - output->height = height; + output->width_pxl = width; + output->height_pxl = height; } /** @@ -1227,13 +1333,17 @@ static void global_add(void *data, struct display_t *display = static_cast<struct display_t *>(data); if (!strcmp(interface, wl_compositor_interface.name)) { display->compositor = static_cast<wl_compositor *>( - wl_registry_bind(wl_registry, name, &wl_compositor_interface, 1)); + wl_registry_bind(wl_registry, name, &wl_compositor_interface, 3)); } else if (!strcmp(interface, xdg_wm_base_interface.name)) { display->xdg_shell = static_cast<xdg_wm_base *>( wl_registry_bind(wl_registry, name, &xdg_wm_base_interface, 1)); xdg_wm_base_add_listener(display->xdg_shell, &shell_listener, nullptr); } + else if (!strcmp(interface, zxdg_decoration_manager_v1_interface.name)) { + display->xdg_decoration_manager = static_cast<zxdg_decoration_manager_v1 *>( + wl_registry_bind(wl_registry, name, &zxdg_decoration_manager_v1_interface, 1)); + } else if (!strcmp(interface, wl_output_interface.name)) { output_t *output = new output_t; output->scale = 1; @@ -1335,16 +1445,6 @@ GHOST_SystemWayland::GHOST_SystemWayland() : GHOST_System(), d(new display_t) wl_data_device_add_listener(input->data_device, &data_device_listener, input); } } - - const char *theme = std::getenv("XCURSOR_THEME"); - const char *size = std::getenv("XCURSOR_SIZE"); - const int sizei = size ? std::stoi(size) : default_cursor_size; - - d->cursor_theme = wl_cursor_theme_load(theme, sizei, d->shm); - if (!d->cursor_theme) { - display_destroy(d); - throw std::runtime_error("Wayland: unable to access cursor themes!"); - } } GHOST_SystemWayland::~GHOST_SystemWayland() @@ -1471,8 +1571,8 @@ void GHOST_SystemWayland::getMainDisplayDimensions(GHOST_TUns32 &width, GHOST_TU { if (getNumDisplays() > 0) { /* We assume first output as main. */ - width = uint32_t(d->outputs[0]->width); - height = uint32_t(d->outputs[0]->height); + width = uint32_t(d->outputs[0]->width_pxl) / d->outputs[0]->scale; + height = uint32_t(d->outputs[0]->height_pxl) / d->outputs[0]->scale; } } @@ -1481,7 +1581,7 @@ void GHOST_SystemWayland::getAllDisplayDimensions(GHOST_TUns32 &width, GHOST_TUn getMainDisplayDimensions(width, height); } -GHOST_IContext *GHOST_SystemWayland::createOffscreenContext(GHOST_GLSettings glSettings) +GHOST_IContext *GHOST_SystemWayland::createOffscreenContext(GHOST_GLSettings /*glSettings*/) { /* Create new off-screen window. */ wl_surface *os_surface = wl_compositor_create_surface(compositor()); @@ -1530,6 +1630,11 @@ GHOST_IWindow *GHOST_SystemWayland::createWindow(const char *title, const bool is_dialog, const GHOST_IWindow *parentWindow) { + /* globally store pointer to window manager */ + if (!window_manager) { + window_manager = getWindowManager(); + } + GHOST_WindowWayland *window = new GHOST_WindowWayland( this, title, @@ -1574,6 +1679,21 @@ xdg_wm_base *GHOST_SystemWayland::shell() return d->xdg_shell; } +zxdg_decoration_manager_v1 *GHOST_SystemWayland::decoration_manager() +{ + return d->xdg_decoration_manager; +} + +const std::vector<output_t *> &GHOST_SystemWayland::outputs() const +{ + return d->outputs; +} + +wl_shm *GHOST_SystemWayland::shm() const +{ + return d->shm; +} + void GHOST_SystemWayland::setSelection(const std::string &selection) { this->selection = selection; @@ -1581,23 +1701,20 @@ void GHOST_SystemWayland::setSelection(const std::string &selection) static void set_cursor_buffer(input_t *input, wl_buffer *buffer) { - input->cursor.visible = (buffer != nullptr); + cursor_t *c = &input->cursor; - wl_surface_attach(input->cursor.surface, buffer, 0, 0); - wl_surface_commit(input->cursor.surface); + c->visible = (buffer != nullptr); - if (input->cursor.visible) { - wl_surface_damage(input->cursor.surface, - 0, - 0, - int32_t(input->cursor.image.width), - int32_t(input->cursor.image.height)); - wl_pointer_set_cursor(input->pointer, - input->pointer_serial, - input->cursor.surface, - int32_t(input->cursor.image.hotspot_x), - int32_t(input->cursor.image.hotspot_y)); - } + wl_surface_attach(c->surface, buffer, 0, 0); + + wl_surface_damage(c->surface, 0, 0, int32_t(c->image.width), int32_t(c->image.height)); + wl_pointer_set_cursor(input->pointer, + input->pointer_serial, + c->visible ? c->surface : nullptr, + int32_t(c->image.hotspot_x) / c->scale, + int32_t(c->image.hotspot_y) / c->scale); + + wl_surface_commit(c->surface); } GHOST_TSuccess GHOST_SystemWayland::setCursorShape(GHOST_TStandardCursor shape) @@ -1608,7 +1725,15 @@ GHOST_TSuccess GHOST_SystemWayland::setCursorShape(GHOST_TStandardCursor shape) const std::string cursor_name = cursors.count(shape) ? cursors.at(shape) : cursors.at(GHOST_kStandardCursorDefault); - wl_cursor *cursor = wl_cursor_theme_get_cursor(d->cursor_theme, cursor_name.c_str()); + input_t *input = d->inputs[0]; + cursor_t *c = &input->cursor; + + if (!c->theme) { + /* The cursor surface hasn't entered an output yet. Initialise theme with scale 1. */ + c->theme = wl_cursor_theme_load(c->theme_name.c_str(), c->size, d->inputs[0]->system->shm()); + } + + wl_cursor *cursor = wl_cursor_theme_get_cursor(c->theme, cursor_name.c_str()); if (!cursor) { GHOST_PRINT("cursor '" << cursor_name << "' does not exist" << std::endl); @@ -1620,11 +1745,11 @@ GHOST_TSuccess GHOST_SystemWayland::setCursorShape(GHOST_TStandardCursor shape) if (!buffer) { return GHOST_kFailure; } - cursor_t *c = &d->inputs[0]->cursor; + c->buffer = buffer; c->image = *image; - set_cursor_buffer(d->inputs[0], buffer); + set_cursor_buffer(input, buffer); return GHOST_kSuccess; } @@ -1735,6 +1860,11 @@ GHOST_TSuccess GHOST_SystemWayland::setCursorVisibility(bool visible) GHOST_TSuccess GHOST_SystemWayland::setCursorGrab(const GHOST_TGrabCursorMode mode, wl_surface *surface) { + /* ignore, if the required protocols are not supported */ + if (!d->relative_pointer_manager || !d->pointer_constraints) { + return GHOST_kFailure; + } + if (d->inputs.empty()) { return GHOST_kFailure; } @@ -1754,6 +1884,7 @@ GHOST_TSuccess GHOST_SystemWayland::setCursorGrab(const GHOST_TGrabCursorMode mo break; case GHOST_kGrabNormal: + break; case GHOST_kGrabWrap: input->relative_pointer = zwp_relative_pointer_manager_v1_get_relative_pointer( d->relative_pointer_manager, input->pointer); diff --git a/intern/ghost/intern/GHOST_SystemWayland.h b/intern/ghost/intern/GHOST_SystemWayland.h index 10b9ef6bd62..3a08a0d3b16 100644 --- a/intern/ghost/intern/GHOST_SystemWayland.h +++ b/intern/ghost/intern/GHOST_SystemWayland.h @@ -26,6 +26,7 @@ #include "GHOST_WindowWayland.h" #include <wayland-client.h> +#include <xdg-decoration-client-protocol.h> #include <xdg-shell-client-protocol.h> #include <string> @@ -34,6 +35,16 @@ class GHOST_WindowWayland; struct display_t; +struct output_t { + struct wl_output *output; + int32_t width_pxl, height_pxl; // dimensions in pixel + int32_t width_mm, height_mm; // dimensions in millimeter + int transform; + int scale; + std::string make; + std::string model; +}; + class GHOST_SystemWayland : public GHOST_System { public: GHOST_SystemWayland(); @@ -84,6 +95,12 @@ class GHOST_SystemWayland : public GHOST_System { xdg_wm_base *shell(); + zxdg_decoration_manager_v1 *decoration_manager(); + + const std::vector<output_t *> &outputs() const; + + wl_shm *shm() const; + void setSelection(const std::string &selection); GHOST_TSuccess setCursorShape(GHOST_TStandardCursor shape); diff --git a/intern/ghost/intern/GHOST_SystemWin32.cpp b/intern/ghost/intern/GHOST_SystemWin32.cpp index 38dea9c1142..fc3cb81e26a 100644 --- a/intern/ghost/intern/GHOST_SystemWin32.cpp +++ b/intern/ghost/intern/GHOST_SystemWin32.cpp @@ -32,6 +32,7 @@ #include <commctrl.h> #include <psapi.h> #include <shellapi.h> +#include <shellscalingapi.h> #include <shlobj.h> #include <tlhelp32.h> #include <windowsx.h> @@ -97,41 +98,6 @@ # define VK_GR_LESS 0xE2 #endif // VK_GR_LESS -#ifndef VK_MEDIA_NEXT_TRACK -# define VK_MEDIA_NEXT_TRACK 0xB0 -#endif // VK_MEDIA_NEXT_TRACK -#ifndef VK_MEDIA_PREV_TRACK -# define VK_MEDIA_PREV_TRACK 0xB1 -#endif // VK_MEDIA_PREV_TRACK -#ifndef VK_MEDIA_STOP -# define VK_MEDIA_STOP 0xB2 -#endif // VK_MEDIA_STOP -#ifndef VK_MEDIA_PLAY_PAUSE -# define VK_MEDIA_PLAY_PAUSE 0xB3 -#endif // VK_MEDIA_PLAY_PAUSE - -// Window message newer than Windows 7 -#ifndef WM_DPICHANGED -# define WM_DPICHANGED 0x02E0 -#endif // WM_DPICHANGED - -// WM_POINTER API messages minimum Windows 7 -#ifndef WM_POINTERENTER -# define WM_POINTERENTER 0x0249 -#endif // WM_POINTERENTER -#ifndef WM_POINTERDOWN -# define WM_POINTERDOWN 0x0246 -#endif // WM_POINTERDOWN -#ifndef WM_POINTERUPDATE -# define WM_POINTERUPDATE 0x0245 -#endif // WM_POINTERUPDATE -#ifndef WM_POINTERUP -# define WM_POINTERUP 0x0247 -#endif // WM_POINTERUP -#ifndef WM_POINTERLEAVE -# define WM_POINTERLEAVE 0x024A -#endif // WM_POINTERLEAVE - /* Workaround for some laptop touchpads, some of which seems to * have driver issues which makes it so window function receives * the message, but PeekMessage doesn't pick those messages for @@ -173,24 +139,6 @@ static void initRawInput() #undef DEVICE_COUNT } -#ifndef DPI_ENUMS_DECLARED -typedef enum PROCESS_DPI_AWARENESS { - PROCESS_DPI_UNAWARE = 0, - PROCESS_SYSTEM_DPI_AWARE = 1, - PROCESS_PER_MONITOR_DPI_AWARE = 2 -} PROCESS_DPI_AWARENESS; - -typedef enum MONITOR_DPI_TYPE { - MDT_EFFECTIVE_DPI = 0, - MDT_ANGULAR_DPI = 1, - MDT_RAW_DPI = 2, - MDT_DEFAULT = MDT_EFFECTIVE_DPI -} MONITOR_DPI_TYPE; - -# define USER_DEFAULT_SCREEN_DPI 96 - -# define DPI_ENUMS_DECLARED -#endif typedef HRESULT(API *GHOST_WIN32_SetProcessDpiAwareness)(PROCESS_DPI_AWARENESS); typedef BOOL(API *GHOST_WIN32_EnableNonClientDpiScaling)(HWND); @@ -205,15 +153,7 @@ GHOST_SystemWin32::GHOST_SystemWin32() // Tell Windows we are per monitor DPI aware. This disables the default // blurry scaling and enables WM_DPICHANGED to allow us to draw at proper DPI. - HMODULE m_shcore = ::LoadLibrary("Shcore.dll"); - if (m_shcore) { - GHOST_WIN32_SetProcessDpiAwareness fpSetProcessDpiAwareness = - (GHOST_WIN32_SetProcessDpiAwareness)::GetProcAddress(m_shcore, "SetProcessDpiAwareness"); - - if (fpSetProcessDpiAwareness) { - fpSetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE); - } - } + SetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE); // Check if current keyboard layout uses AltGr and save keylayout ID for // specialized handling if keys like VK_OEM_*. I.e. french keylayout @@ -581,14 +521,7 @@ GHOST_TSuccess GHOST_SystemWin32::init() InitCommonControls(); /* Disable scaling on high DPI displays on Vista */ - HMODULE - user32 = ::LoadLibraryA("user32.dll"); - typedef BOOL(WINAPI * LPFNSETPROCESSDPIAWARE)(); - LPFNSETPROCESSDPIAWARE SetProcessDPIAware = (LPFNSETPROCESSDPIAWARE)GetProcAddress( - user32, "SetProcessDPIAware"); - if (SetProcessDPIAware) - SetProcessDPIAware(); - FreeLibrary(user32); + SetProcessDPIAware(); initRawInput(); m_lfstart = ::GetTickCount(); diff --git a/intern/ghost/intern/GHOST_WaylandCursorSettings.h b/intern/ghost/intern/GHOST_WaylandCursorSettings.h new file mode 100644 index 00000000000..c7d2d82ff84 --- /dev/null +++ b/intern/ghost/intern/GHOST_WaylandCursorSettings.h @@ -0,0 +1,130 @@ +/* + * 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 + */ + +#pragma once +#include <dbus/dbus.h> +#include <string> + +static DBusMessage *get_setting_sync(DBusConnection *const connection, + const char *key, + const char *value) +{ + DBusError error; + dbus_bool_t success; + DBusMessage *message; + DBusMessage *reply; + + dbus_error_init(&error); + + message = dbus_message_new_method_call("org.freedesktop.portal.Desktop", + "/org/freedesktop/portal/desktop", + "org.freedesktop.portal.Settings", + "Read"); + + success = dbus_message_append_args( + message, DBUS_TYPE_STRING, &key, DBUS_TYPE_STRING, &value, DBUS_TYPE_INVALID); + + if (!success) { + return NULL; + } + + reply = dbus_connection_send_with_reply_and_block( + connection, message, DBUS_TIMEOUT_USE_DEFAULT, &error); + + dbus_message_unref(message); + + if (dbus_error_is_set(&error)) { + return NULL; + } + + return reply; +} + +static bool parse_type(DBusMessage *const reply, const int type, void *value) +{ + DBusMessageIter iter[3]; + + dbus_message_iter_init(reply, &iter[0]); + if (dbus_message_iter_get_arg_type(&iter[0]) != DBUS_TYPE_VARIANT) { + return false; + } + + dbus_message_iter_recurse(&iter[0], &iter[1]); + if (dbus_message_iter_get_arg_type(&iter[1]) != DBUS_TYPE_VARIANT) { + return false; + } + + dbus_message_iter_recurse(&iter[1], &iter[2]); + if (dbus_message_iter_get_arg_type(&iter[2]) != type) { + return false; + } + + dbus_message_iter_get_basic(&iter[2], value); + + return true; +} + +static bool get_cursor_settings(std::string &theme, int &size) +{ + static const char name[] = "org.gnome.desktop.interface"; + static const char key_theme[] = "cursor-theme"; + static const char key_size[] = "cursor-size"; + + DBusError error; + DBusConnection *connection; + DBusMessage *reply; + const char *value_theme = NULL; + + dbus_error_init(&error); + + connection = dbus_bus_get(DBUS_BUS_SESSION, &error); + + if (dbus_error_is_set(&error)) { + return false; + } + + reply = get_setting_sync(connection, name, key_theme); + if (!reply) { + return false; + } + + if (!parse_type(reply, DBUS_TYPE_STRING, &value_theme)) { + dbus_message_unref(reply); + return false; + } + + theme = std::string(value_theme); + + dbus_message_unref(reply); + + reply = get_setting_sync(connection, name, key_size); + if (!reply) { + return false; + } + + if (!parse_type(reply, DBUS_TYPE_INT32, &size)) { + dbus_message_unref(reply); + return false; + } + + dbus_message_unref(reply); + + return true; +} diff --git a/intern/ghost/intern/GHOST_WindowWayland.cpp b/intern/ghost/intern/GHOST_WindowWayland.cpp index 1e1d0814d3a..cbac2d6eaa1 100644 --- a/intern/ghost/intern/GHOST_WindowWayland.cpp +++ b/intern/ghost/intern/GHOST_WindowWayland.cpp @@ -29,11 +29,19 @@ #include <wayland-egl.h> +static constexpr size_t base_dpi = 96; + struct window_t { GHOST_WindowWayland *w; wl_surface *surface; + // outputs on which the window is currently shown on + std::unordered_set<const output_t *> outputs; + GHOST_TUns16 dpi = 0; + int scale = 1; struct xdg_surface *xdg_surface; struct xdg_toplevel *xdg_toplevel; + struct zxdg_toplevel_decoration_v1 *xdg_toplevel_decoration = nullptr; + enum zxdg_toplevel_decoration_v1_mode decoration_mode; wl_egl_window *egl_window; int32_t pending_width, pending_height; bool is_maximised; @@ -93,17 +101,30 @@ static const xdg_toplevel_listener toplevel_listener = { toplevel_close, }; +static void toplevel_decoration_configure( + void *data, + struct zxdg_toplevel_decoration_v1 * /*zxdg_toplevel_decoration_v1*/, + uint32_t mode) +{ + static_cast<window_t *>(data)->decoration_mode = zxdg_toplevel_decoration_v1_mode(mode); +} + +static const zxdg_toplevel_decoration_v1_listener toplevel_decoration_v1_listener = { + toplevel_decoration_configure, +}; + static void surface_configure(void *data, xdg_surface *xdg_surface, uint32_t serial) { window_t *win = static_cast<window_t *>(data); - int w, h; - wl_egl_window_get_attached_size(win->egl_window, &w, &h); - if (win->pending_width != 0 && win->pending_height != 0 && win->pending_width != w && - win->pending_height != h) { - win->width = win->pending_width; - win->height = win->pending_height; - wl_egl_window_resize(win->egl_window, win->pending_width, win->pending_height, 0, 0); + if (win->xdg_surface != xdg_surface) { + return; + } + + if (win->pending_width != 0 && win->pending_height != 0) { + win->width = win->scale * win->pending_width; + win->height = win->scale * win->pending_height; + wl_egl_window_resize(win->egl_window, win->width, win->height, 0, 0); win->pending_width = 0; win->pending_height = 0; win->w->notify_size(); @@ -123,6 +144,52 @@ static const xdg_surface_listener surface_listener = { surface_configure, }; +static bool update_scale(GHOST_WindowWayland *window) +{ + int scale = 0; + for (const output_t *output : window->outputs_active()) { + if (output->scale > scale) + scale = output->scale; + } + + if (scale > 0 && window->scale() != scale) { + window->scale() = scale; + // using the real DPI will cause wrong scaling of the UI + // use a multiplier for the default DPI as workaround + window->dpi() = scale * base_dpi; + wl_surface_set_buffer_scale(window->surface(), scale); + return true; + } + return false; +} + +static void surface_enter(void *data, struct wl_surface * /*wl_surface*/, struct wl_output *output) +{ + GHOST_WindowWayland *w = static_cast<GHOST_WindowWayland *>(data); + for (const output_t *reg_output : w->outputs()) { + if (reg_output->output == output) { + w->outputs_active().insert(reg_output); + } + } + update_scale(w); +} + +static void surface_leave(void *data, struct wl_surface * /*wl_surface*/, struct wl_output *output) +{ + GHOST_WindowWayland *w = static_cast<GHOST_WindowWayland *>(data); + for (const output_t *reg_output : w->outputs()) { + if (reg_output->output == output) { + w->outputs_active().erase(reg_output); + } + } + update_scale(w); +} + +struct wl_surface_listener wl_surface_listener = { + surface_enter, + surface_leave, +}; + /** \} */ /* -------------------------------------------------------------------- */ @@ -161,17 +228,28 @@ GHOST_WindowWayland::GHOST_WindowWayland(GHOST_SystemWayland *system, /* Window surfaces. */ w->surface = wl_compositor_create_surface(m_system->compositor()); + wl_surface_add_listener(w->surface, &wl_surface_listener, this); + w->egl_window = wl_egl_window_create(w->surface, int(width), int(height)); w->xdg_surface = xdg_wm_base_get_xdg_surface(m_system->shell(), w->surface); w->xdg_toplevel = xdg_surface_get_toplevel(w->xdg_surface); + if (m_system->decoration_manager()) { + w->xdg_toplevel_decoration = zxdg_decoration_manager_v1_get_toplevel_decoration( + m_system->decoration_manager(), w->xdg_toplevel); + zxdg_toplevel_decoration_v1_add_listener( + w->xdg_toplevel_decoration, &toplevel_decoration_v1_listener, w); + zxdg_toplevel_decoration_v1_set_mode(w->xdg_toplevel_decoration, + ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE); + } + wl_surface_set_user_data(w->surface, this); xdg_surface_add_listener(w->xdg_surface, &surface_listener, w); xdg_toplevel_add_listener(w->xdg_toplevel, &toplevel_listener, w); - if (parentWindow) { + if (parentWindow && is_dialog) { xdg_toplevel_set_parent( w->xdg_toplevel, dynamic_cast<const GHOST_WindowWayland *>(parentWindow)->w->xdg_toplevel); } @@ -192,6 +270,9 @@ GHOST_WindowWayland::GHOST_WindowWayland(GHOST_SystemWayland *system, if (setDrawingContextType(type) == GHOST_kFailure) { GHOST_PRINT("Failed to create EGL context" << std::endl); } + + /* set swap interval to 0 to prevent blocking */ + setSwapInterval(0); } GHOST_TSuccess GHOST_WindowWayland::close() @@ -226,6 +307,31 @@ GHOST_TSuccess GHOST_WindowWayland::notify_size() new GHOST_Event(m_system->getMilliSeconds(), GHOST_kEventWindowSize, this)); } +wl_surface *GHOST_WindowWayland::surface() const +{ + return w->surface; +} + +const std::vector<output_t *> &GHOST_WindowWayland::outputs() const +{ + return m_system->outputs(); +} + +std::unordered_set<const output_t *> &GHOST_WindowWayland::outputs_active() +{ + return w->outputs; +} + +uint16_t &GHOST_WindowWayland::dpi() +{ + return w->dpi; +} + +int &GHOST_WindowWayland::scale() +{ + return w->scale; +} + GHOST_TSuccess GHOST_WindowWayland::setWindowCursorGrab(GHOST_TGrabCursorMode mode) { return m_system->setCursorGrab(mode, w->surface); @@ -310,6 +416,9 @@ GHOST_WindowWayland::~GHOST_WindowWayland() releaseNativeHandles(); wl_egl_window_destroy(w->egl_window); + if (w->xdg_toplevel_decoration) { + zxdg_toplevel_decoration_v1_destroy(w->xdg_toplevel_decoration); + } xdg_toplevel_destroy(w->xdg_toplevel); xdg_surface_destroy(w->xdg_surface); wl_surface_destroy(w->surface); @@ -317,6 +426,11 @@ GHOST_WindowWayland::~GHOST_WindowWayland() delete w; } +GHOST_TUns16 GHOST_WindowWayland::getDPIHint() +{ + return w->dpi; +} + GHOST_TSuccess GHOST_WindowWayland::setWindowCursorVisibility(bool visible) { return m_system->setCursorVisibility(visible); diff --git a/intern/ghost/intern/GHOST_WindowWayland.h b/intern/ghost/intern/GHOST_WindowWayland.h index b62b5c24d60..dbddc7c469e 100644 --- a/intern/ghost/intern/GHOST_WindowWayland.h +++ b/intern/ghost/intern/GHOST_WindowWayland.h @@ -24,9 +24,14 @@ #include "GHOST_Window.h" +#include <unordered_set> +#include <vector> + class GHOST_SystemWayland; struct window_t; +struct wl_surface; +struct output_t; class GHOST_WindowWayland : public GHOST_Window { public: @@ -47,6 +52,8 @@ class GHOST_WindowWayland : public GHOST_Window { ~GHOST_WindowWayland() override; + GHOST_TUns16 getDPIHint() override; + GHOST_TSuccess close(); GHOST_TSuccess activate(); @@ -55,6 +62,16 @@ class GHOST_WindowWayland : public GHOST_Window { GHOST_TSuccess notify_size(); + wl_surface *surface() const; + + const std::vector<output_t *> &outputs() const; + + std::unordered_set<const output_t *> &outputs_active(); + + uint16_t &dpi(); + + int &scale(); + protected: GHOST_TSuccess setWindowCursorGrab(GHOST_TGrabCursorMode mode) override; diff --git a/intern/ghost/intern/GHOST_WindowWin32.cpp b/intern/ghost/intern/GHOST_WindowWin32.cpp index 3af92153e8b..eeafe333633 100644 --- a/intern/ghost/intern/GHOST_WindowWin32.cpp +++ b/intern/ghost/intern/GHOST_WindowWin32.cpp @@ -84,9 +84,6 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system, m_wantAlphaBackground(alphaBackground), m_normal_state(GHOST_kWindowStateNormal), m_user32(NULL), - m_fpGetPointerInfoHistory(NULL), - m_fpGetPointerPenInfoHistory(NULL), - m_fpGetPointerTouchInfoHistory(NULL), m_parentWindowHwnd(parentwindow ? parentwindow->m_hWnd : HWND_DESKTOP), m_debug_context(is_debug) { @@ -153,19 +150,7 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system, m_user32 = ::LoadLibrary("user32.dll"); if (m_hWnd) { - if (m_user32) { - // Touch enabled screens with pen support by default have gestures - // enabled, which results in a delay between the pointer down event - // and the first move when using the stylus. RegisterTouchWindow - // disables the new gesture architecture enabling the events to be - // sent immediately to the application rather than being absorbed by - // the gesture API. - GHOST_WIN32_RegisterTouchWindow pRegisterTouchWindow = (GHOST_WIN32_RegisterTouchWindow) - GetProcAddress(m_user32, "RegisterTouchWindow"); - if (pRegisterTouchWindow) { - pRegisterTouchWindow(m_hWnd, 0); - } - } + RegisterTouchWindow(m_hWnd, 0); // Register this window as a droptarget. Requires m_hWnd to be valid. // Note that OleInitialize(0) has to be called prior to this. Done in GHOST_SystemWin32. @@ -232,16 +217,6 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system, } } - // Initialize Windows Ink - if (m_user32) { - m_fpGetPointerInfoHistory = (GHOST_WIN32_GetPointerInfoHistory)::GetProcAddress( - m_user32, "GetPointerInfoHistory"); - m_fpGetPointerPenInfoHistory = (GHOST_WIN32_GetPointerPenInfoHistory)::GetProcAddress( - m_user32, "GetPointerPenInfoHistory"); - m_fpGetPointerTouchInfoHistory = (GHOST_WIN32_GetPointerTouchInfoHistory)::GetProcAddress( - m_user32, "GetPointerTouchInfoHistory"); - } - // Initialize Wintab m_wintab.handle = ::LoadLibrary("Wintab32.dll"); if (m_wintab.handle && m_system->getTabletAPI() != GHOST_kTabletNative) { @@ -326,9 +301,6 @@ GHOST_WindowWin32::~GHOST_WindowWin32() if (m_user32) { FreeLibrary(m_user32); m_user32 = NULL; - m_fpGetPointerInfoHistory = NULL; - m_fpGetPointerPenInfoHistory = NULL; - m_fpGetPointerTouchInfoHistory = NULL; } if (m_customCursor) { @@ -950,15 +922,14 @@ GHOST_TSuccess GHOST_WindowWin32::getPointerInfo( GHOST_SystemWin32 *system = (GHOST_SystemWin32 *)GHOST_System::getSystem(); GHOST_TUns32 outCount; - if (!(m_fpGetPointerInfoHistory && m_fpGetPointerInfoHistory(pointerId, &outCount, NULL))) { + if (!(GetPointerInfoHistory(pointerId, &outCount, NULL))) { return GHOST_kFailure; } auto pointerPenInfo = std::vector<POINTER_PEN_INFO>(outCount); outPointerInfo.resize(outCount); - if (!(m_fpGetPointerPenInfoHistory && - m_fpGetPointerPenInfoHistory(pointerId, &outCount, pointerPenInfo.data()))) { + if (!(GetPointerPenInfoHistory(pointerId, &outCount, pointerPenInfo.data()))) { return GHOST_kFailure; } diff --git a/intern/ghost/intern/GHOST_WindowWin32.h b/intern/ghost/intern/GHOST_WindowWin32.h index b004f7e7b19..a13bd876667 100644 --- a/intern/ghost/intern/GHOST_WindowWin32.h +++ b/intern/ghost/intern/GHOST_WindowWin32.h @@ -53,177 +53,12 @@ typedef BOOL(API *GHOST_WIN32_WTPacket)(HCTX, UINT, LPVOID); typedef BOOL(API *GHOST_WIN32_WTEnable)(HCTX, BOOL); typedef BOOL(API *GHOST_WIN32_WTOverlap)(HCTX, BOOL); -// typedef to user32 functions to disable gestures on windows -typedef BOOL(API *GHOST_WIN32_RegisterTouchWindow)(HWND hwnd, ULONG ulFlags); - // typedefs for user32 functions to allow dynamic loading of Windows 10 DPI scaling functions typedef UINT(API *GHOST_WIN32_GetDpiForWindow)(HWND); #ifndef USER_DEFAULT_SCREEN_DPI # define USER_DEFAULT_SCREEN_DPI 96 #endif // USER_DEFAULT_SCREEN_DPI -// typedefs for user32 functions to allow pointer functions -enum tagPOINTER_INPUT_TYPE { - PT_POINTER = 1, // Generic pointer - PT_TOUCH = 2, // Touch - PT_PEN = 3, // Pen - PT_MOUSE = 4, // Mouse -#if (WINVER >= 0x0603) - PT_TOUCHPAD = 5, // Touchpad -#endif /* WINVER >= 0x0603 */ -}; - -typedef enum tagPOINTER_BUTTON_CHANGE_TYPE { - POINTER_CHANGE_NONE, - POINTER_CHANGE_FIRSTBUTTON_DOWN, - POINTER_CHANGE_FIRSTBUTTON_UP, - POINTER_CHANGE_SECONDBUTTON_DOWN, - POINTER_CHANGE_SECONDBUTTON_UP, - POINTER_CHANGE_THIRDBUTTON_DOWN, - POINTER_CHANGE_THIRDBUTTON_UP, - POINTER_CHANGE_FOURTHBUTTON_DOWN, - POINTER_CHANGE_FOURTHBUTTON_UP, - POINTER_CHANGE_FIFTHBUTTON_DOWN, - POINTER_CHANGE_FIFTHBUTTON_UP, -} POINTER_BUTTON_CHANGE_TYPE; - -typedef DWORD POINTER_INPUT_TYPE; -typedef UINT32 POINTER_FLAGS; - -#define POINTER_FLAG_NONE 0x00000000 -#define POINTER_FLAG_NEW 0x00000001 -#define POINTER_FLAG_INRANGE 0x00000002 -#define POINTER_FLAG_INCONTACT 0x00000004 -#define POINTER_FLAG_FIRSTBUTTON 0x00000010 -#define POINTER_FLAG_SECONDBUTTON 0x00000020 -#define POINTER_FLAG_THIRDBUTTON 0x00000040 -#define POINTER_FLAG_FOURTHBUTTON 0x00000080 -#define POINTER_FLAG_FIFTHBUTTON 0x00000100 -#define POINTER_FLAG_PRIMARY 0x00002000 -#define POINTER_FLAG_CONFIDENCE 0x000004000 -#define POINTER_FLAG_CANCELED 0x000008000 -#define POINTER_FLAG_DOWN 0x00010000 -#define POINTER_FLAG_UPDATE 0x00020000 -#define POINTER_FLAG_UP 0x00040000 -#define POINTER_FLAG_WHEEL 0x00080000 -#define POINTER_FLAG_HWHEEL 0x00100000 -#define POINTER_FLAG_CAPTURECHANGED 0x00200000 -#define POINTER_FLAG_HASTRANSFORM 0x00400000 - -typedef struct tagPOINTER_INFO { - POINTER_INPUT_TYPE pointerType; - UINT32 pointerId; - UINT32 frameId; - POINTER_FLAGS pointerFlags; - HANDLE sourceDevice; - HWND hwndTarget; - POINT ptPixelLocation; - POINT ptHimetricLocation; - POINT ptPixelLocationRaw; - POINT ptHimetricLocationRaw; - DWORD dwTime; - UINT32 historyCount; - INT32 InputData; - DWORD dwKeyStates; - UINT64 PerformanceCount; - POINTER_BUTTON_CHANGE_TYPE ButtonChangeType; -} POINTER_INFO; - -typedef UINT32 PEN_FLAGS; -#define PEN_FLAG_NONE 0x00000000 // Default -#define PEN_FLAG_BARREL 0x00000001 // The barrel button is pressed -#define PEN_FLAG_INVERTED 0x00000002 // The pen is inverted -#define PEN_FLAG_ERASER 0x00000004 // The eraser button is pressed - -typedef UINT32 PEN_MASK; -#define PEN_MASK_NONE 0x00000000 // Default - none of the optional fields are valid -#define PEN_MASK_PRESSURE 0x00000001 // The pressure field is valid -#define PEN_MASK_ROTATION 0x00000002 // The rotation field is valid -#define PEN_MASK_TILT_X 0x00000004 // The tiltX field is valid -#define PEN_MASK_TILT_Y 0x00000008 // The tiltY field is valid - -typedef struct tagPOINTER_PEN_INFO { - POINTER_INFO pointerInfo; - PEN_FLAGS penFlags; - PEN_MASK penMask; - UINT32 pressure; - UINT32 rotation; - INT32 tiltX; - INT32 tiltY; -} POINTER_PEN_INFO; - -/* - * Flags that appear in pointer input message parameters - */ -#define POINTER_MESSAGE_FLAG_NEW 0x00000001 // New pointer -#define POINTER_MESSAGE_FLAG_INRANGE 0x00000002 // Pointer has not departed -#define POINTER_MESSAGE_FLAG_INCONTACT 0x00000004 // Pointer is in contact -#define POINTER_MESSAGE_FLAG_FIRSTBUTTON 0x00000010 // Primary action -#define POINTER_MESSAGE_FLAG_SECONDBUTTON 0x00000020 // Secondary action -#define POINTER_MESSAGE_FLAG_THIRDBUTTON 0x00000040 // Third button -#define POINTER_MESSAGE_FLAG_FOURTHBUTTON 0x00000080 // Fourth button -#define POINTER_MESSAGE_FLAG_FIFTHBUTTON 0x00000100 // Fifth button -#define POINTER_MESSAGE_FLAG_PRIMARY 0x00002000 // Pointer is primary -#define POINTER_MESSAGE_FLAG_CONFIDENCE \ - 0x00004000 // Pointer is considered unlikely to be accidental -#define POINTER_MESSAGE_FLAG_CANCELED 0x00008000 // Pointer is departing in an abnormal manner - -typedef UINT32 TOUCH_FLAGS; -#define TOUCH_FLAG_NONE 0x00000000 // Default - -typedef UINT32 TOUCH_MASK; -#define TOUCH_MASK_NONE 0x00000000 // Default - none of the optional fields are valid -#define TOUCH_MASK_CONTACTAREA 0x00000001 // The rcContact field is valid -#define TOUCH_MASK_ORIENTATION 0x00000002 // The orientation field is valid -#define TOUCH_MASK_PRESSURE 0x00000004 // The pressure field is valid - -typedef struct tagPOINTER_TOUCH_INFO { - POINTER_INFO pointerInfo; - TOUCH_FLAGS touchFlags; - TOUCH_MASK touchMask; - RECT rcContact; - RECT rcContactRaw; - UINT32 orientation; - UINT32 pressure; -} POINTER_TOUCH_INFO; - -/* - * Macros to retrieve information from pointer input message parameters - */ -#define GET_POINTERID_WPARAM(wParam) (LOWORD(wParam)) -#define IS_POINTER_FLAG_SET_WPARAM(wParam, flag) (((DWORD)HIWORD(wParam) & (flag)) == (flag)) -#define IS_POINTER_NEW_WPARAM(wParam) IS_POINTER_FLAG_SET_WPARAM(wParam, POINTER_MESSAGE_FLAG_NEW) -#define IS_POINTER_INRANGE_WPARAM(wParam) \ - IS_POINTER_FLAG_SET_WPARAM(wParam, POINTER_MESSAGE_FLAG_INRANGE) -#define IS_POINTER_INCONTACT_WPARAM(wParam) \ - IS_POINTER_FLAG_SET_WPARAM(wParam, POINTER_MESSAGE_FLAG_INCONTACT) -#define IS_POINTER_FIRSTBUTTON_WPARAM(wParam) \ - IS_POINTER_FLAG_SET_WPARAM(wParam, POINTER_MESSAGE_FLAG_FIRSTBUTTON) -#define IS_POINTER_SECONDBUTTON_WPARAM(wParam) \ - IS_POINTER_FLAG_SET_WPARAM(wParam, POINTER_MESSAGE_FLAG_SECONDBUTTON) -#define IS_POINTER_THIRDBUTTON_WPARAM(wParam) \ - IS_POINTER_FLAG_SET_WPARAM(wParam, POINTER_MESSAGE_FLAG_THIRDBUTTON) -#define IS_POINTER_FOURTHBUTTON_WPARAM(wParam) \ - IS_POINTER_FLAG_SET_WPARAM(wParam, POINTER_MESSAGE_FLAG_FOURTHBUTTON) -#define IS_POINTER_FIFTHBUTTON_WPARAM(wParam) \ - IS_POINTER_FLAG_SET_WPARAM(wParam, POINTER_MESSAGE_FLAG_FIFTHBUTTON) -#define IS_POINTER_PRIMARY_WPARAM(wParam) \ - IS_POINTER_FLAG_SET_WPARAM(wParam, POINTER_MESSAGE_FLAG_PRIMARY) -#define HAS_POINTER_CONFIDENCE_WPARAM(wParam) \ - IS_POINTER_FLAG_SET_WPARAM(wParam, POINTER_MESSAGE_FLAG_CONFIDENCE) -#define IS_POINTER_CANCELED_WPARAM(wParam) \ - IS_POINTER_FLAG_SET_WPARAM(wParam, POINTER_MESSAGE_FLAG_CANCELED) - -typedef BOOL(WINAPI *GHOST_WIN32_GetPointerInfoHistory)(UINT32 pointerId, - UINT32 *entriesCount, - POINTER_INFO *pointerInfo); -typedef BOOL(WINAPI *GHOST_WIN32_GetPointerPenInfoHistory)(UINT32 pointerId, - UINT32 *entriesCount, - POINTER_PEN_INFO *penInfo); -typedef BOOL(WINAPI *GHOST_WIN32_GetPointerTouchInfoHistory)(UINT32 pointerId, - UINT32 *entriesCount, - POINTER_TOUCH_INFO *touchInfo); - struct GHOST_PointerInfoWin32 { GHOST_TInt32 pointerId; GHOST_TInt32 isPrimary; @@ -576,9 +411,6 @@ class GHOST_WindowWin32 : public GHOST_Window { /** `user32.dll` handle */ HMODULE m_user32; - GHOST_WIN32_GetPointerInfoHistory m_fpGetPointerInfoHistory; - GHOST_WIN32_GetPointerPenInfoHistory m_fpGetPointerPenInfoHistory; - GHOST_WIN32_GetPointerTouchInfoHistory m_fpGetPointerTouchInfoHistory; HWND m_parentWindowHwnd; |