Node: Gabor Noise Texture #110802
|
@ -473,7 +473,7 @@ extern "C" int GHOST_HACK_getFirstFile(char buf[FIRSTFILEBUFLG])
|
|||
|
||||
if (![closing_window isKeyWindow]) {
|
||||
/* If the window wasn't key then its either none of the windows are key or another window
|
||||
* is a key. The former situation is a bit strange, but probably forcin a key window is not
|
||||
* is a key. The former situation is a bit strange, but probably forcing a key window is not
|
||||
* something desirable. The latter situation is when we definitely do not want to change the
|
||||
* key window.
|
||||
*
|
||||
|
|
|
@ -4701,14 +4701,9 @@ static void output_handle_done(void *data, wl_output * /*wl_output*/)
|
|||
CLOG_INFO(LOG, 2, "done");
|
||||
|
||||
GWL_Output *output = static_cast<GWL_Output *>(data);
|
||||
int32_t size_native[2];
|
||||
if (output->transform & WL_OUTPUT_TRANSFORM_90) {
|
||||
size_native[0] = output->size_native[1];
|
||||
size_native[1] = output->size_native[0];
|
||||
}
|
||||
else {
|
||||
size_native[0] = output->size_native[0];
|
||||
size_native[1] = output->size_native[1];
|
||||
int32_t size_native[2] = {UNPACK2(output->size_native)};
|
||||
if (ELEM(output->transform, WL_OUTPUT_TRANSFORM_90, WL_OUTPUT_TRANSFORM_270)) {
|
||||
std::swap(size_native[0], size_native[1]);
|
||||
}
|
||||
|
||||
/* If `xdg-output` is present, calculate the true scale of the desktop */
|
||||
|
@ -5684,6 +5679,12 @@ GHOST_SystemWayland::GHOST_SystemWayland(bool background)
|
|||
}
|
||||
}
|
||||
|
||||
/* Without this, the output fractional size from `display->xdg.output_manager` isn't known,
|
||||
* while this isn't essential, the first window creation uses this for setting the size.
|
||||
* Supporting both XDG initialized/uninitialized outputs is possible it complicates logic.
|
||||
* see: #113328 for an example of size on startup issues. */
|
||||
wl_display_roundtrip(display_->wl.display);
|
||||
|
||||
#ifdef USE_EVENT_BACKGROUND_THREAD
|
||||
gwl_display_event_thread_create(display_);
|
||||
|
||||
|
@ -6300,8 +6301,13 @@ void GHOST_SystemWayland::getMainDisplayDimensions(uint32_t &width, uint32_t &he
|
|||
|
||||
if (!display_->outputs.empty()) {
|
||||
/* We assume first output as main. */
|
||||
width = uint32_t(display_->outputs[0]->size_native[0]);
|
||||
height = uint32_t(display_->outputs[0]->size_native[1]);
|
||||
const GWL_Output *output = display_->outputs[0];
|
||||
int32_t size_native[2] = {UNPACK2(output->size_native)};
|
||||
if (ELEM(output->transform, WL_OUTPUT_TRANSFORM_90, WL_OUTPUT_TRANSFORM_270)) {
|
||||
std::swap(size_native[0], size_native[1]);
|
||||
}
|
||||
width = uint32_t(size_native[0]);
|
||||
height = uint32_t(size_native[1]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6316,14 +6322,18 @@ void GHOST_SystemWayland::getAllDisplayDimensions(uint32_t &width, uint32_t &hei
|
|||
|
||||
for (const GWL_Output *output : display_->outputs) {
|
||||
int32_t xy[2] = {0, 0};
|
||||
int32_t size_native[2] = {UNPACK2(output->size_native)};
|
||||
if (output->has_position_logical) {
|
||||
xy[0] = output->position_logical[0];
|
||||
xy[1] = output->position_logical[1];
|
||||
}
|
||||
if (ELEM(output->transform, WL_OUTPUT_TRANSFORM_90, WL_OUTPUT_TRANSFORM_270)) {
|
||||
std::swap(size_native[0], size_native[1]);
|
||||
}
|
||||
xy_min[0] = std::min(xy_min[0], xy[0]);
|
||||
xy_min[1] = std::min(xy_min[1], xy[1]);
|
||||
xy_max[0] = std::max(xy_max[0], xy[0] + output->size_native[0]);
|
||||
xy_max[1] = std::max(xy_max[1], xy[1] + output->size_native[1]);
|
||||
xy_max[0] = std::max(xy_max[0], xy[0] + size_native[0]);
|
||||
xy_max[1] = std::max(xy_max[1], xy[1] + size_native[1]);
|
||||
}
|
||||
|
||||
width = xy_max[0] - xy_min[0];
|
||||
|
|
|
@ -1122,38 +1122,22 @@ GHOST_EventCursor *GHOST_SystemWin32::processCursorEvent(GHOST_WindowWin32 *wind
|
|||
/* Warp within bounds. */
|
||||
{
|
||||
GHOST_Rect bounds;
|
||||
int32_t bounds_margin = 0;
|
||||
GHOST_TAxisFlag bounds_axis = GHOST_kAxisNone;
|
||||
|
||||
if (window->getCursorGrabMode() == GHOST_kGrabHide) {
|
||||
if (window->getCursorGrabBounds(bounds) == GHOST_kFailure) {
|
||||
/* Use custom grab bounds if available, window bounds if not. */
|
||||
if (window->getCursorGrabBounds(bounds) == GHOST_kFailure) {
|
||||
window->getClientBounds(bounds);
|
||||
window->getClientBounds(bounds);
|
||||
}
|
||||
|
||||
/* WARNING(@ideasman42): The current warping logic fails to warp on every event,
|
||||
* so the box needs to small enough not to let the cursor escape the window but large
|
||||
* enough that the cursor isn't being warped every time.
|
||||
* If this was not the case it would be less trouble to simply warp the cursor to the
|
||||
* center of the screen on every motion, see: D16558 (alternative fix for #102346). */
|
||||
const int32_t subregion_div = 4; /* One quarter of the region. */
|
||||
const int32_t size[2] = {bounds.getWidth(), bounds.getHeight()};
|
||||
const int32_t center[2] = {(bounds.m_l + bounds.m_r) / 2, (bounds.m_t + bounds.m_b) / 2};
|
||||
/* Shrink the box to prevent the cursor escaping. */
|
||||
bounds.m_l = center[0] - (size[0] / (subregion_div * 2));
|
||||
bounds.m_r = center[0] + (size[0] / (subregion_div * 2));
|
||||
bounds.m_t = center[1] - (size[1] / (subregion_div * 2));
|
||||
bounds.m_b = center[1] + (size[1] / (subregion_div * 2));
|
||||
}
|
||||
bounds_axis = GHOST_TAxisFlag(GHOST_kAxisX | GHOST_kAxisY);
|
||||
}
|
||||
else {
|
||||
/* Fallback to window bounds. */
|
||||
if (window->getCursorGrabBounds(bounds) == GHOST_kFailure) {
|
||||
window->getClientBounds(bounds);
|
||||
}
|
||||
bounds_margin = 2;
|
||||
bounds_axis = window->getCursorGrabAxis();
|
||||
}
|
||||
/* WARNING(@ideasman42): The current warping logic fails to warp on every event,
|
||||
* so the box needs to small enough not to let the cursor escape the window but large
|
||||
* enough that the cursor isn't being warped every time. If this was not the case it
|
||||
* would be less trouble to simply warp the cursor to the center of the screen on
|
||||
* every motion, see: D16558 (alternative fix for #102346). */
|
||||
|
||||
/* Rather than adjust the bounds, use a margin based on the bounds width. */
|
||||
int32_t bounds_margin = (window->getCursorGrabMode() == GHOST_kGrabHide) ?
|
||||
bounds.getWidth() / 10 :
|
||||
2;
|
||||
GHOST_TAxisFlag bounds_axis = window->getCursorGrabAxis();
|
||||
|
||||
/* Could also clamp to screen bounds wrap with a window outside the view will
|
||||
* fail at the moment. Use inset in case the window is at screen bounds. */
|
||||
|
|
|
@ -101,10 +101,10 @@ void BLF_color3fv_alpha(int fontid, const float rgb[3], float alpha);
|
|||
|
||||
/**
|
||||
* Set a 4x4 matrix to be multiplied before draw the text.
|
||||
* Remember that you need call BLF_enable(BLF_MATRIX)
|
||||
* Remember that you need call `BLF_enable(BLF_MATRIX)`
|
||||
* to enable this.
|
||||
*
|
||||
* The order of the matrix is like GL:
|
||||
* The order of the matrix is column major (following the GPU module):
|
||||
* \code{.unparsed}
|
||||
* | m[0] m[4] m[8] m[12] |
|
||||
* | m[1] m[5] m[9] m[13] |
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
*
|
||||
* Main BlenFont (BLF) API, public functions for font handling.
|
||||
*
|
||||
* Wraps OpenGL and FreeType.
|
||||
* Wraps GPU display and FreeType.
|
||||
*/
|
||||
|
||||
#include <cmath>
|
||||
|
@ -521,7 +521,7 @@ void BLF_batch_draw_end()
|
|||
g_batch.enabled = false;
|
||||
}
|
||||
|
||||
static void blf_draw_gl__start(const FontBLF *font)
|
||||
static void blf_draw_gpu__start(const FontBLF *font)
|
||||
{
|
||||
/*
|
||||
* The pixmap alignment hack is handle
|
||||
|
@ -549,7 +549,7 @@ static void blf_draw_gl__start(const FontBLF *font)
|
|||
}
|
||||
}
|
||||
|
||||
static void blf_draw_gl__end(const FontBLF *font)
|
||||
static void blf_draw_gpu__end(const FontBLF *font)
|
||||
{
|
||||
if ((font->flags & (BLF_ROTATION | BLF_MATRIX | BLF_ASPECT)) != 0) {
|
||||
GPU_matrix_pop();
|
||||
|
@ -563,14 +563,14 @@ void BLF_draw_ex(int fontid, const char *str, const size_t str_len, ResultBLF *r
|
|||
BLF_RESULT_CHECK_INIT(r_info);
|
||||
|
||||
if (font) {
|
||||
blf_draw_gl__start(font);
|
||||
blf_draw_gpu__start(font);
|
||||
if (font->flags & BLF_WORD_WRAP) {
|
||||
blf_font_draw__wrap(font, str, str_len, r_info);
|
||||
}
|
||||
else {
|
||||
blf_font_draw(font, str, str_len, r_info);
|
||||
}
|
||||
blf_draw_gl__end(font);
|
||||
blf_draw_gpu__end(font);
|
||||
}
|
||||
}
|
||||
void BLF_draw(int fontid, const char *str, const size_t str_len)
|
||||
|
@ -595,9 +595,9 @@ int BLF_draw_mono(int fontid, const char *str, const size_t str_len, int cwidth,
|
|||
int columns = 0;
|
||||
|
||||
if (font) {
|
||||
blf_draw_gl__start(font);
|
||||
blf_draw_gpu__start(font);
|
||||
columns = blf_font_draw_mono(font, str, str_len, cwidth, tab_columns);
|
||||
blf_draw_gl__end(font);
|
||||
blf_draw_gpu__end(font);
|
||||
}
|
||||
|
||||
return columns;
|
||||
|
|
|
@ -258,7 +258,7 @@ typedef struct FontBLF {
|
|||
|
||||
/**
|
||||
* Multiplied this matrix with the current one before draw the text!
|
||||
* see #blf_draw_gl__start.
|
||||
* see #blf_draw_gpu__start.
|
||||
*/
|
||||
float m[16];
|
||||
|
||||
|
|
|
@ -1575,12 +1575,12 @@ static ID *lib_override_root_find(Main *bmain, ID *id, const int curr_level, int
|
|||
}
|
||||
|
||||
if (entry->tags & MAINIDRELATIONS_ENTRY_TAGS_INPROGRESS) {
|
||||
/* Re-processing an entry already being processed higher in the callgraph (re-entry caused by a
|
||||
* dependency loops). Just do nothing, there is no more usefull info to provide here. */
|
||||
/* Re-processing an entry already being processed higher in the call-graph (re-entry caused by
|
||||
* a dependency loops). Just do nothing, there is no more useful info to provide here. */
|
||||
return nullptr;
|
||||
}
|
||||
/* Flag this entry to avoid re-processing it in case some dependency loop leads to it again
|
||||
* downwards in the callstack. */
|
||||
* downwards in the call-stack. */
|
||||
entry->tags |= MAINIDRELATIONS_ENTRY_TAGS_INPROGRESS;
|
||||
|
||||
int best_level_candidate = curr_level;
|
||||
|
|
|
@ -67,17 +67,21 @@ set(SRC
|
|||
algorithms/intern/morphological_distance.cc
|
||||
algorithms/intern/morphological_distance_feather.cc
|
||||
algorithms/intern/parallel_reduction.cc
|
||||
algorithms/intern/realize_on_domain.cc
|
||||
algorithms/intern/smaa.cc
|
||||
algorithms/intern/summed_area_table.cc
|
||||
algorithms/intern/symmetric_separable_blur.cc
|
||||
algorithms/intern/transform.cc
|
||||
|
||||
algorithms/COM_algorithm_jump_flooding.hh
|
||||
algorithms/COM_algorithm_morphological_distance.hh
|
||||
algorithms/COM_algorithm_morphological_distance_feather.hh
|
||||
algorithms/COM_algorithm_parallel_reduction.hh
|
||||
algorithms/COM_algorithm_realize_on_domain.hh
|
||||
algorithms/COM_algorithm_smaa.hh
|
||||
algorithms/COM_algorithm_summed_area_table.hh
|
||||
algorithms/COM_algorithm_symmetric_separable_blur.hh
|
||||
algorithms/COM_algorithm_transform.hh
|
||||
|
||||
cached_resources/intern/cached_mask.cc
|
||||
cached_resources/intern/cached_texture.cc
|
||||
|
|
|
@ -16,14 +16,6 @@ namespace blender::realtime_compositor {
|
|||
struct InputRealizationOptions {
|
||||
/* The input should be realized on the operation domain of the operation. */
|
||||
bool realize_on_operation_domain : 1;
|
||||
/* The input should be realized on a domain that is identical to the domain of the input but with
|
||||
* an identity rotation and an increased size that completely fits the image after rotation. This
|
||||
* is useful for operations that are not rotation invariant. */
|
||||
bool realize_rotation : 1;
|
||||
/* The input should be realized on a domain that is identical to the domain of the input but with
|
||||
* an identity scale and an increased/decreased size that completely fits the image after
|
||||
* scaling. This is useful for operations that are not scale invariant. */
|
||||
bool realize_scale : 1;
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
|
|
|
@ -42,40 +42,6 @@ class RealizeOnDomainOperation : public SimpleOperation {
|
|||
protected:
|
||||
/* The operation domain is just the target domain. */
|
||||
Domain compute_domain() override;
|
||||
|
||||
private:
|
||||
/* Get the realization shader of the appropriate type. */
|
||||
GPUShader *get_realization_shader();
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Realize Transformation Operation
|
||||
*
|
||||
* A simple operation that realizes its input on a domain such that its transformations become
|
||||
* identity and its size is increased/decreased to adapt to the new domain. The transformations
|
||||
* that become identity are the ones marked to be realized in the given InputRealizationOptions.
|
||||
* For instance, if InputRealizationOptions.realize_rotation is true and the input is rotated, the
|
||||
* output of the operation will be a result of zero rotation but expanded size to account for the
|
||||
* bounding box of the input after rotation. This is useful for operations that are not rotation
|
||||
* invariant and thus require an input of zero rotation for correct operation.
|
||||
*
|
||||
* Notice that this class is not an actual operation, but constructs a RealizeOnDomainOperation
|
||||
* with the appreciate domain in its construct_if_needed static constructor. */
|
||||
class RealizeTransformationOperation {
|
||||
public:
|
||||
/* Determine if a realize transformation operation is needed for the input with the given result
|
||||
* and descriptor. If it is not needed, return a null pointer. If it is needed, return an
|
||||
* instance of RealizeOnDomainOperation with the appropriate domain. */
|
||||
static SimpleOperation *construct_if_needed(Context &context,
|
||||
const Result &input_result,
|
||||
const InputDescriptor &input_descriptor);
|
||||
|
||||
private:
|
||||
/* Given the domain of an input and its realization options, compute a domain such that the
|
||||
* appropriate transformations specified in the realization options become identity and the size
|
||||
* of the domain is increased/reduced to adapt to the new domain. */
|
||||
static Domain compute_target_domain(const Domain &input_domain,
|
||||
const InputRealizationOptions &realization_options);
|
||||
};
|
||||
|
||||
} // namespace blender::realtime_compositor
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "BLI_math_matrix_types.hh"
|
||||
|
||||
#include "COM_context.hh"
|
||||
#include "COM_domain.hh"
|
||||
#include "COM_result.hh"
|
||||
|
||||
namespace blender::realtime_compositor {
|
||||
|
||||
/* Projects the input on a target domain, copies the area of the input that intersects the target
|
||||
* domain, and fill the rest with zeros or repetitions of the input depending on the realization
|
||||
* options. The transformation and realization options of the input are ignored and the given
|
||||
* input_transformation and realization_options are used instead to allow the caller to change them
|
||||
* without mutating the input result directly. See the discussion in COM_domain.hh for more
|
||||
* information on what realization on domain means. */
|
||||
void realize_on_domain(Context &context,
|
||||
Result &input,
|
||||
Result &output,
|
||||
const Domain &domain,
|
||||
const float3x3 &input_transformation,
|
||||
const RealizationOptions &realization_options);
|
||||
|
||||
} // namespace blender::realtime_compositor
|
|
@ -0,0 +1,33 @@
|
|||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "BLI_math_matrix_types.hh"
|
||||
|
||||
#include "COM_context.hh"
|
||||
#include "COM_domain.hh"
|
||||
#include "COM_result.hh"
|
||||
|
||||
namespace blender::realtime_compositor {
|
||||
|
||||
/* Transforms the given result based on the given transformation and interpolation, writing the
|
||||
* transformed result to the given output.
|
||||
*
|
||||
* The rotation and scale components of the transformation are realized and the size of the result
|
||||
* is increased/reduced to adapt to the new transformation. For instance, if the transformation is
|
||||
* a rotation, the input will be rotated and expanded in size to account for the bounding box of
|
||||
* the input after rotation. The size of the returned result is bound and clipped by the maximum
|
||||
* possible GPU texture size to avoid allocations that surpass hardware limits, which is typically
|
||||
* 16k.
|
||||
*
|
||||
* The translation component of the transformation is delayed and only stored in the domain of the
|
||||
* result to be realized later when needed. */
|
||||
void transform(Context &context,
|
||||
Result &input,
|
||||
Result &output,
|
||||
float3x3 transformation,
|
||||
Interpolation interpolation);
|
||||
|
||||
} // namespace blender::realtime_compositor
|
|
@ -0,0 +1,113 @@
|
|||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "BLI_math_angle_types.hh"
|
||||
#include "BLI_math_matrix.hh"
|
||||
#include "BLI_math_matrix_types.hh"
|
||||
#include "BLI_math_vector_types.hh"
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
#include "GPU_capabilities.h"
|
||||
#include "GPU_shader.h"
|
||||
#include "GPU_texture.h"
|
||||
|
||||
#include "COM_context.hh"
|
||||
#include "COM_domain.hh"
|
||||
#include "COM_result.hh"
|
||||
#include "COM_utilities.hh"
|
||||
|
||||
#include "COM_algorithm_realize_on_domain.hh"
|
||||
|
||||
namespace blender::realtime_compositor {
|
||||
|
||||
static const char *get_realization_shader(Result &input,
|
||||
const RealizationOptions &realization_options)
|
||||
{
|
||||
if (realization_options.interpolation == Interpolation::Bicubic) {
|
||||
switch (input.type()) {
|
||||
case ResultType::Color:
|
||||
return "compositor_realize_on_domain_bicubic_color";
|
||||
case ResultType::Vector:
|
||||
return "compositor_realize_on_domain_bicubic_vector";
|
||||
case ResultType::Float:
|
||||
return "compositor_realize_on_domain_bicubic_float";
|
||||
case ResultType::Int2:
|
||||
/* Realization does not support integer images. */
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
switch (input.type()) {
|
||||
case ResultType::Color:
|
||||
return "compositor_realize_on_domain_color";
|
||||
case ResultType::Vector:
|
||||
return "compositor_realize_on_domain_vector";
|
||||
case ResultType::Float:
|
||||
return "compositor_realize_on_domain_float";
|
||||
case ResultType::Int2:
|
||||
/* Realization does not support integer images. */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
BLI_assert_unreachable();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void realize_on_domain(Context &context,
|
||||
Result &input,
|
||||
Result &output,
|
||||
const Domain &domain,
|
||||
const float3x3 &input_transformation,
|
||||
const RealizationOptions &realization_options)
|
||||
{
|
||||
|
||||
GPUShader *shader = context.shader_manager().get(
|
||||
get_realization_shader(input, realization_options));
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
/* Transform the input space into the domain space. */
|
||||
const float3x3 local_transformation = math::invert(domain.transformation) * input_transformation;
|
||||
|
||||
/* Set the origin of the transformation to be the center of the domain. */
|
||||
const float3x3 transformation = math::from_origin_transform<float3x3>(
|
||||
local_transformation, float2(domain.size) / 2.0f);
|
||||
|
||||
/* Invert the transformation because the shader transforms the domain coordinates instead of the
|
||||
* input image itself and thus expect the inverse. */
|
||||
const float3x3 inverse_transformation = math::invert(transformation);
|
||||
|
||||
GPU_shader_uniform_mat3_as_mat4(shader, "inverse_transformation", inverse_transformation.ptr());
|
||||
|
||||
/* The texture sampler should use bilinear interpolation for both the bilinear and bicubic
|
||||
* cases, as the logic used by the bicubic realization shader expects textures to use bilinear
|
||||
* interpolation. */
|
||||
const bool use_bilinear = ELEM(
|
||||
realization_options.interpolation, Interpolation::Bilinear, Interpolation::Bicubic);
|
||||
GPU_texture_filter_mode(input.texture(), use_bilinear);
|
||||
|
||||
/* If the input repeats, set a repeating wrap mode for out-of-bound texture access. Otherwise,
|
||||
* make out-of-bound texture access return zero by setting a clamp to border extend mode. */
|
||||
GPU_texture_extend_mode_x(input.texture(),
|
||||
realization_options.repeat_x ?
|
||||
GPU_SAMPLER_EXTEND_MODE_REPEAT :
|
||||
GPU_SAMPLER_EXTEND_MODE_CLAMP_TO_BORDER);
|
||||
GPU_texture_extend_mode_y(input.texture(),
|
||||
realization_options.repeat_y ?
|
||||
GPU_SAMPLER_EXTEND_MODE_REPEAT :
|
||||
GPU_SAMPLER_EXTEND_MODE_CLAMP_TO_BORDER);
|
||||
|
||||
input.bind_as_texture(shader, "input_tx");
|
||||
|
||||
output.allocate_texture(domain);
|
||||
output.bind_as_image(shader, "domain_img");
|
||||
|
||||
compute_dispatch_threads_at_least(shader, domain.size);
|
||||
|
||||
input.unbind_as_texture();
|
||||
output.unbind_as_image();
|
||||
GPU_shader_unbind();
|
||||
}
|
||||
|
||||
} // namespace blender::realtime_compositor
|
|
@ -0,0 +1,88 @@
|
|||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "BLI_math_angle_types.hh"
|
||||
#include "BLI_math_matrix.hh"
|
||||
#include "BLI_math_matrix_types.hh"
|
||||
#include "BLI_math_vector_types.hh"
|
||||
|
||||
#include "GPU_capabilities.h"
|
||||
#include "GPU_shader.h"
|
||||
#include "GPU_texture.h"
|
||||
|
||||
#include "COM_algorithm_realize_on_domain.hh"
|
||||
#include "COM_context.hh"
|
||||
#include "COM_domain.hh"
|
||||
#include "COM_result.hh"
|
||||
|
||||
#include "COM_algorithm_transform.hh"
|
||||
|
||||
namespace blender::realtime_compositor {
|
||||
|
||||
/* Given a potentially transformed domain, compute a domain such that its rotation and scale become
|
||||
* identity and the size of the domain is increased/reduced to adapt to the new transformation. For
|
||||
* instance, if the domain is rotated, the returned domain will have zero rotation but expanded
|
||||
* size to account for the bounding box of the domain after rotation. The size of the returned
|
||||
* domain is bound and clipped by the maximum possible GPU texture size to avoid allocations that
|
||||
* surpass hardware limits, which is typically 16k. */
|
||||
static Domain compute_realized_transformation_domain(const Domain &domain)
|
||||
{
|
||||
math::AngleRadian rotation;
|
||||
float2 translation, scale;
|
||||
float2 size = float2(domain.size);
|
||||
math::to_loc_rot_scale(domain.transformation, translation, rotation, scale);
|
||||
|
||||
/* Set the rotation to zero and expand the domain size to fit the bounding box of the rotated
|
||||
* result. */
|
||||
const float sine = math::abs(math::sin(rotation));
|
||||
const float cosine = math::abs(math::cos(rotation));
|
||||
size = float2(size.x * sine + size.y * cosine, size.x * cosine + size.y * sine);
|
||||
rotation = 0.0f;
|
||||
|
||||
/* Set the scale to 1 and scale the domain size to adapt to the new domain. */
|
||||
size *= scale;
|
||||
scale = float2(1.0f);
|
||||
|
||||
const float3x3 transformation = math::from_loc_rot_scale<float3x3>(translation, rotation, scale);
|
||||
|
||||
const int2 domain_size = math::clamp(
|
||||
int2(math::round(size)), int2(1), int2(GPU_max_texture_size()));
|
||||
|
||||
return Domain(domain_size, transformation);
|
||||
}
|
||||
|
||||
void transform(Context &context,
|
||||
Result &input,
|
||||
Result &output,
|
||||
float3x3 transformation,
|
||||
Interpolation interpolation)
|
||||
{
|
||||
math::AngleRadian rotation;
|
||||
float2 translation, scale;
|
||||
math::to_loc_rot_scale(transformation, translation, rotation, scale);
|
||||
|
||||
/* Rotation and scale transformations are immediately realized. */
|
||||
if (rotation != 0.0f || scale != float2(1.0f)) {
|
||||
RealizationOptions realization_options = input.get_realization_options();
|
||||
realization_options.interpolation = interpolation;
|
||||
|
||||
Domain input_domain = input.domain();
|
||||
input_domain.transform(transformation);
|
||||
|
||||
const Domain target_domain = compute_realized_transformation_domain(input_domain);
|
||||
|
||||
realize_on_domain(
|
||||
context, input, output, target_domain, input_domain.transformation, realization_options);
|
||||
}
|
||||
else {
|
||||
input.pass_through(output);
|
||||
}
|
||||
|
||||
/* Translation transformations are delayed and are only stored in the result. */
|
||||
const float3x3 translation_matrix = math::from_location<float3x3>(translation);
|
||||
output.transform(translation_matrix);
|
||||
output.get_realization_options().interpolation = interpolation;
|
||||
}
|
||||
|
||||
} // namespace blender::realtime_compositor
|
|
@ -106,12 +106,6 @@ void Operation::add_and_evaluate_input_processors()
|
|||
add_and_evaluate_input_processor(identifier, conversion);
|
||||
}
|
||||
|
||||
for (const StringRef &identifier : results_mapped_to_inputs_.keys()) {
|
||||
SimpleOperation *realize_transformation = RealizeTransformationOperation::construct_if_needed(
|
||||
context(), get_input(identifier), get_input_descriptor(identifier));
|
||||
add_and_evaluate_input_processor(identifier, realize_transformation);
|
||||
}
|
||||
|
||||
for (const StringRef &identifier : results_mapped_to_inputs_.keys()) {
|
||||
SimpleOperation *realize_on_domain = RealizeOnDomainOperation::construct_if_needed(
|
||||
context(), get_input(identifier), get_input_descriptor(identifier), compute_domain());
|
||||
|
|
|
@ -2,22 +2,13 @@
|
|||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "BLI_assert.h"
|
||||
#include "BLI_math_angle_types.hh"
|
||||
#include "BLI_math_matrix.hh"
|
||||
#include "BLI_math_matrix_types.hh"
|
||||
#include "BLI_math_vector_types.hh"
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
#include "GPU_shader.h"
|
||||
#include "GPU_texture.h"
|
||||
|
||||
#include "COM_algorithm_realize_on_domain.hh"
|
||||
#include "COM_context.hh"
|
||||
#include "COM_domain.hh"
|
||||
#include "COM_input_descriptor.hh"
|
||||
#include "COM_realize_on_domain_operation.hh"
|
||||
#include "COM_result.hh"
|
||||
#include "COM_utilities.hh"
|
||||
|
||||
#include "COM_realize_on_domain_operation.hh"
|
||||
|
||||
namespace blender::realtime_compositor {
|
||||
|
||||
|
@ -38,90 +29,12 @@ RealizeOnDomainOperation::RealizeOnDomainOperation(Context &context,
|
|||
|
||||
void RealizeOnDomainOperation::execute()
|
||||
{
|
||||
Result &input = get_input();
|
||||
Result &result = get_result();
|
||||
|
||||
result.allocate_texture(domain_);
|
||||
|
||||
GPUShader *shader = get_realization_shader();
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
/* Transform the input space into the domain space. */
|
||||
const float3x3 local_transformation = math::invert(domain_.transformation) *
|
||||
input.domain().transformation;
|
||||
|
||||
/* Set the origin of the transformation to be the center of the domain. */
|
||||
const float3x3 transformation = math::from_origin_transform<float3x3>(
|
||||
local_transformation, float2(domain_.size) / 2.0f);
|
||||
|
||||
/* Invert the transformation because the shader transforms the domain coordinates instead of the
|
||||
* input image itself and thus expect the inverse. */
|
||||
const float3x3 inverse_transformation = math::invert(transformation);
|
||||
|
||||
GPU_shader_uniform_mat3_as_mat4(shader, "inverse_transformation", inverse_transformation.ptr());
|
||||
|
||||
/* The texture sampler should use bilinear interpolation for both the bilinear and bicubic
|
||||
* cases, as the logic used by the bicubic realization shader expects textures to use bilinear
|
||||
* interpolation. */
|
||||
const bool use_bilinear = ELEM(input.get_realization_options().interpolation,
|
||||
Interpolation::Bilinear,
|
||||
Interpolation::Bicubic);
|
||||
GPU_texture_filter_mode(input.texture(), use_bilinear);
|
||||
|
||||
/* If the input repeats, set a repeating wrap mode for out-of-bound texture access. Otherwise,
|
||||
* make out-of-bound texture access return zero by setting a clamp to border extend mode. */
|
||||
GPU_texture_extend_mode_x(input.texture(),
|
||||
input.get_realization_options().repeat_x ?
|
||||
GPU_SAMPLER_EXTEND_MODE_REPEAT :
|
||||
GPU_SAMPLER_EXTEND_MODE_CLAMP_TO_BORDER);
|
||||
GPU_texture_extend_mode_y(input.texture(),
|
||||
input.get_realization_options().repeat_y ?
|
||||
GPU_SAMPLER_EXTEND_MODE_REPEAT :
|
||||
GPU_SAMPLER_EXTEND_MODE_CLAMP_TO_BORDER);
|
||||
|
||||
input.bind_as_texture(shader, "input_tx");
|
||||
result.bind_as_image(shader, "domain_img");
|
||||
|
||||
compute_dispatch_threads_at_least(shader, domain_.size);
|
||||
|
||||
input.unbind_as_texture();
|
||||
result.unbind_as_image();
|
||||
GPU_shader_unbind();
|
||||
}
|
||||
|
||||
GPUShader *RealizeOnDomainOperation::get_realization_shader()
|
||||
{
|
||||
if (get_input().get_realization_options().interpolation == Interpolation::Bicubic) {
|
||||
switch (get_result().type()) {
|
||||
case ResultType::Color:
|
||||
return shader_manager().get("compositor_realize_on_domain_bicubic_color");
|
||||
case ResultType::Vector:
|
||||
return shader_manager().get("compositor_realize_on_domain_bicubic_vector");
|
||||
case ResultType::Float:
|
||||
return shader_manager().get("compositor_realize_on_domain_bicubic_float");
|
||||
default:
|
||||
/* Other types are internal and needn't be handled by operations. */
|
||||
BLI_assert_unreachable();
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
else {
|
||||
switch (get_result().type()) {
|
||||
case ResultType::Color:
|
||||
return shader_manager().get("compositor_realize_on_domain_color");
|
||||
case ResultType::Vector:
|
||||
return shader_manager().get("compositor_realize_on_domain_vector");
|
||||
case ResultType::Float:
|
||||
return shader_manager().get("compositor_realize_on_domain_float");
|
||||
default:
|
||||
/* Other types are internal and needn't be handled by operations. */
|
||||
BLI_assert_unreachable();
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
BLI_assert_unreachable();
|
||||
return nullptr;
|
||||
realize_on_domain(context(),
|
||||
get_input(),
|
||||
get_result(),
|
||||
domain_,
|
||||
get_input().domain().transformation,
|
||||
get_input().get_realization_options());
|
||||
}
|
||||
|
||||
Domain RealizeOnDomainOperation::compute_domain()
|
||||
|
@ -161,68 +74,4 @@ SimpleOperation *RealizeOnDomainOperation::construct_if_needed(
|
|||
return new RealizeOnDomainOperation(context, operation_domain, input_descriptor.type);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Realize Transformation Operation
|
||||
*/
|
||||
|
||||
Domain RealizeTransformationOperation::compute_target_domain(
|
||||
const Domain &input_domain, const InputRealizationOptions &realization_options)
|
||||
{
|
||||
if (!realization_options.realize_rotation && !realization_options.realize_scale) {
|
||||
return input_domain;
|
||||
}
|
||||
|
||||
math::AngleRadian rotation;
|
||||
float2 translation, scale;
|
||||
float2 size = float2(input_domain.size);
|
||||
math::to_loc_rot_scale(input_domain.transformation, translation, rotation, scale);
|
||||
|
||||
/* Set the rotation to zero and expand the domain size to fit the bounding box of the rotated
|
||||
* result. */
|
||||
if (realization_options.realize_rotation) {
|
||||
const float sine = math::abs(math::sin(rotation));
|
||||
const float cosine = math::abs(math::cos(rotation));
|
||||
size = float2(size.x * sine + size.y * cosine, size.x * cosine + size.y * sine);
|
||||
rotation = 0.0f;
|
||||
}
|
||||
|
||||
/* Set the scale to 1 and scale the domain size to adapt to the new domain. */
|
||||
if (realization_options.realize_scale) {
|
||||
size *= scale;
|
||||
scale = float2(1.0f);
|
||||
}
|
||||
|
||||
const float3x3 transformation = math::from_loc_rot_scale<float3x3>(translation, rotation, scale);
|
||||
|
||||
return Domain(int2(math::ceil(size)), transformation);
|
||||
}
|
||||
|
||||
SimpleOperation *RealizeTransformationOperation::construct_if_needed(
|
||||
Context &context, const Result &input_result, const InputDescriptor &input_descriptor)
|
||||
{
|
||||
/* The input expects a single value and if no single value is provided, it will be ignored and a
|
||||
* default value will be used, so no need to realize it and the operation is not needed. */
|
||||
if (input_descriptor.expects_single_value) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/* Input result is a single value and does not need realization, the operation is not needed. */
|
||||
if (input_result.is_single_value()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const Domain target_domain = compute_target_domain(input_result.domain(),
|
||||
input_descriptor.realization_options);
|
||||
|
||||
/* The input have an identical domain to the target domain, either because the input doesn't need
|
||||
* to realize its transformations or because it has identity transformations, so no need to
|
||||
* realize it and the operation is not needed. */
|
||||
if (target_domain == input_result.domain()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/* Otherwise, realization on the target domain is needed. */
|
||||
return new RealizeOnDomainOperation(context, target_domain, input_descriptor.type);
|
||||
}
|
||||
|
||||
} // namespace blender::realtime_compositor
|
||||
|
|
|
@ -129,12 +129,6 @@ InputDescriptor input_descriptor_from_input_socket(const bNodeSocket *socket)
|
|||
input_descriptor.realization_options.realize_on_operation_domain = bool(
|
||||
socket_declaration->compositor_realization_options() &
|
||||
CompositorInputRealizationOptions::RealizeOnOperationDomain);
|
||||
input_descriptor.realization_options.realize_rotation = bool(
|
||||
socket_declaration->compositor_realization_options() &
|
||||
CompositorInputRealizationOptions::RealizeRotation);
|
||||
input_descriptor.realization_options.realize_scale = bool(
|
||||
socket_declaration->compositor_realization_options() &
|
||||
CompositorInputRealizationOptions::RealizeScale);
|
||||
|
||||
return input_descriptor;
|
||||
}
|
||||
|
|
|
@ -1099,7 +1099,8 @@ PassMain::Sub *CapturePipeline::surface_material_add(::Material *blender_mat, GP
|
|||
PassMain::Sub &sub_pass = surface_ps_.sub(GPU_material_get_name(gpumat));
|
||||
GPUPass *gpupass = GPU_material_get_pass(gpumat);
|
||||
sub_pass.shader_set(GPU_pass_shader_get(gpupass));
|
||||
sub_pass.push_constant("double_sided", !(blender_mat->blend_flag & MA_BL_CULL_BACKFACE_PROBE));
|
||||
sub_pass.push_constant("is_double_sided",
|
||||
!(blender_mat->blend_flag & MA_BL_CULL_BACKFACE_PROBE));
|
||||
return &sub_pass;
|
||||
}
|
||||
|
||||
|
|
|
@ -60,7 +60,7 @@ float lightprobe_planar_score(ProbePlanarData planar, vec3 P, vec3 V, vec3 L)
|
|||
|
||||
#ifdef PLANAR_PROBES
|
||||
/**
|
||||
* Return the best planar probe index for a given light direction vector and postion.
|
||||
* Return the best planar probe index for a given light direction vector and position.
|
||||
*/
|
||||
int lightprobe_planar_select(vec3 P, vec3 V, vec3 L)
|
||||
{
|
||||
|
|
|
@ -53,10 +53,10 @@ void main()
|
|||
surfel_buf[surfel_id].radiance_direct.front.rgb = g_emission;
|
||||
surfel_buf[surfel_id].radiance_direct.front.a = 0.0;
|
||||
/* TODO(fclem): 2nd surface evaluation. */
|
||||
surfel_buf[surfel_id].albedo_back = double_sided ? albedo : vec3(0);
|
||||
surfel_buf[surfel_id].radiance_direct.back.rgb = double_sided ? g_emission : vec3(0);
|
||||
surfel_buf[surfel_id].albedo_back = is_double_sided ? albedo : vec3(0);
|
||||
surfel_buf[surfel_id].radiance_direct.back.rgb = is_double_sided ? g_emission : vec3(0);
|
||||
surfel_buf[surfel_id].radiance_direct.back.a = 0.0;
|
||||
surfel_buf[surfel_id].double_sided = double_sided;
|
||||
surfel_buf[surfel_id].double_sided = is_double_sided;
|
||||
|
||||
if (!capture_info_buf.capture_emission) {
|
||||
surfel_buf[surfel_id].radiance_direct.front.rgb = vec3(0.0);
|
||||
|
|
|
@ -182,7 +182,7 @@ GPU_SHADER_CREATE_INFO(eevee_surf_capture)
|
|||
.define("MAT_CAPTURE")
|
||||
.storage_buf(SURFEL_BUF_SLOT, Qualifier::WRITE, "Surfel", "surfel_buf[]")
|
||||
.storage_buf(CAPTURE_BUF_SLOT, Qualifier::READ_WRITE, "CaptureInfoData", "capture_info_buf")
|
||||
.push_constant(Type::BOOL, "double_sided")
|
||||
.push_constant(Type::BOOL, "is_double_sided")
|
||||
.fragment_source("eevee_surf_capture_frag.glsl")
|
||||
.additional_info("eevee_global_ubo", "eevee_utility_texture");
|
||||
|
||||
|
|
|
@ -118,17 +118,21 @@ struct uiViewItemHandle;
|
|||
|
||||
/** #uiBlock.emboss and #uiBut.emboss */
|
||||
enum eUIEmbossType {
|
||||
UI_EMBOSS = 0, /* use widget style for drawing */
|
||||
UI_EMBOSS_NONE = 1, /* Nothing, only icon and/or text */
|
||||
UI_EMBOSS_PULLDOWN = 2, /* Pull-down menu style */
|
||||
UI_EMBOSS_RADIAL = 3, /* Pie Menu */
|
||||
/** Use widget style for drawing. */
|
||||
UI_EMBOSS = 0,
|
||||
/** Nothing, only icon and/or text */
|
||||
UI_EMBOSS_NONE = 1,
|
||||
/** Pull-down menu style */
|
||||
UI_EMBOSS_PULLDOWN = 2,
|
||||
/** Pie Menu */
|
||||
UI_EMBOSS_RADIAL = 3,
|
||||
/**
|
||||
* The same as #UI_EMBOSS_NONE, unless the button has
|
||||
* a coloring status like an animation state or red alert.
|
||||
*/
|
||||
UI_EMBOSS_NONE_OR_STATUS = 4,
|
||||
|
||||
UI_EMBOSS_UNDEFINED = 255, /* For layout engine, use emboss from block. */
|
||||
/** For layout engine, use emboss from block. */
|
||||
UI_EMBOSS_UNDEFINED = 255,
|
||||
};
|
||||
|
||||
/** #uiBlock::direction */
|
||||
|
@ -2834,7 +2838,11 @@ void uiItemPointerR(uiLayout *layout,
|
|||
const char *name,
|
||||
int icon);
|
||||
|
||||
/* Create a list of enum items. Active is an optional item to highlight. */
|
||||
/**
|
||||
* Create a list of enum items.
|
||||
|
||||
* \param active: an optional item to highlight.
|
||||
*/
|
||||
void uiItemsFullEnumO(uiLayout *layout,
|
||||
const char *opname,
|
||||
const char *propname,
|
||||
|
@ -2846,7 +2854,7 @@ void uiItemsFullEnumO(uiLayout *layout,
|
|||
* Create UI items for enum items in \a item_array.
|
||||
*
|
||||
* A version of #uiItemsFullEnumO that takes pre-calculated item array.
|
||||
* active, if not -1, will highlight that item.
|
||||
* \param active: if not -1, will highlight that item.
|
||||
*/
|
||||
void uiItemsFullEnumO_items(uiLayout *layout,
|
||||
wmOperatorType *ot,
|
||||
|
|
|
@ -159,7 +159,7 @@ static void gpu_viewport_textures_create(GPUViewport *viewport)
|
|||
}
|
||||
}
|
||||
|
||||
/* Can be shared with GPUOffscreen. */
|
||||
/* Can be shared with #GPUOffscreen. */
|
||||
if (viewport->depth_tx == nullptr) {
|
||||
/* Depth texture can be read back by gizmos #view3d_depths_create. */
|
||||
/* Swizzle flag is needed by Workbench Volumes to read the stencil view. */
|
||||
|
|
|
@ -266,7 +266,8 @@ static void detect_workarounds()
|
|||
/* Although an OpenGL 4.3 feature, our implementation requires shader_draw_parameters_support.
|
||||
* NOTE: we should untangle this by checking both features for clarity. */
|
||||
GLContext::multi_draw_indirect_support = false;
|
||||
|
||||
/* Turn off extensions. */
|
||||
GLContext::layered_rendering_support = false;
|
||||
/* Turn off vendor specific extensions. */
|
||||
GLContext::native_barycentric_support = false;
|
||||
GLContext::framebuffer_fetch_support = false;
|
||||
|
@ -281,7 +282,6 @@ static void detect_workarounds()
|
|||
GLContext::debug_layer_support = false;
|
||||
GLContext::fixed_restart_index_support = false;
|
||||
GLContext::geometry_shader_invocations = false;
|
||||
GLContext::layered_rendering_support = false;
|
||||
GLContext::texture_cube_map_array_support = false;
|
||||
GLContext::texture_gather_support = false;
|
||||
GLContext::texture_storage_support = false;
|
||||
|
|
|
@ -113,8 +113,8 @@ class VKFrameBuffer : public FrameBuffer {
|
|||
* Return the number of color attachments of this frame buffer, including unused color
|
||||
* attachments.
|
||||
*
|
||||
* Framebuffers can have unused attachments. When higher attachment slots are being used, unused
|
||||
* lower attachment slots will be counted as they are required resources in renderpasses.
|
||||
* Frame-buffers can have unused attachments. When higher attachment slots are being used, unused
|
||||
* lower attachment slots will be counted as they are required resources in render-passes.
|
||||
*/
|
||||
int color_attachments_resource_size() const;
|
||||
|
||||
|
|
|
@ -52,10 +52,9 @@ enum class OutputSocketFieldType {
|
|||
enum class CompositorInputRealizationOptions : uint8_t {
|
||||
None = 0,
|
||||
RealizeOnOperationDomain = (1 << 0),
|
||||
RealizeRotation = (1 << 1),
|
||||
RealizeScale = (1 << 2),
|
||||
};
|
||||
ENUM_OPERATORS(CompositorInputRealizationOptions, CompositorInputRealizationOptions::RealizeScale)
|
||||
ENUM_OPERATORS(CompositorInputRealizationOptions,
|
||||
CompositorInputRealizationOptions::RealizeOnOperationDomain)
|
||||
|
||||
/**
|
||||
* Contains information about how a node output's field state depends on inputs of the same node.
|
||||
|
|
|
@ -30,7 +30,7 @@ static void cmp_node_bokehblur_declare(NodeDeclarationBuilder &b)
|
|||
.compositor_domain_priority(0);
|
||||
b.add_input<decl::Color>("Bokeh")
|
||||
.default_value({1.0f, 1.0f, 1.0f, 1.0f})
|
||||
.compositor_realization_options(CompositorInputRealizationOptions::RealizeRotation);
|
||||
.compositor_realization_options(CompositorInputRealizationOptions::None);
|
||||
b.add_input<decl::Float>("Size")
|
||||
.default_value(1.0f)
|
||||
.min(0.0f)
|
||||
|
|
|
@ -7,11 +7,13 @@
|
|||
*/
|
||||
|
||||
#include "BLI_assert.h"
|
||||
#include "BLI_math_angle_types.hh"
|
||||
#include "BLI_math_matrix.hh"
|
||||
|
||||
#include "UI_interface.hh"
|
||||
#include "UI_resources.hh"
|
||||
|
||||
#include "COM_algorithm_transform.hh"
|
||||
#include "COM_node_operation.hh"
|
||||
|
||||
#include "node_composite_util.hh"
|
||||
|
@ -53,15 +55,12 @@ class RotateOperation : public NodeOperation {
|
|||
void execute() override
|
||||
{
|
||||
Result &input = get_input("Image");
|
||||
Result &result = get_result("Image");
|
||||
input.pass_through(result);
|
||||
Result &output = get_result("Image");
|
||||
|
||||
const math::AngleRadian rotation = get_input("Degr").get_float_value_default(0.0f);
|
||||
|
||||
const float3x3 transformation = math::from_rotation<float3x3>(rotation);
|
||||
|
||||
result.transform(transformation);
|
||||
result.get_realization_options().interpolation = get_interpolation();
|
||||
transform(context(), input, output, transformation, get_interpolation());
|
||||
}
|
||||
|
||||
Interpolation get_interpolation()
|
||||
|
|
|
@ -7,8 +7,10 @@
|
|||
*/
|
||||
|
||||
#include "BLI_assert.h"
|
||||
#include "BLI_math_angle_types.hh"
|
||||
#include "BLI_math_base.hh"
|
||||
#include "BLI_math_matrix.hh"
|
||||
#include "BLI_math_matrix_types.hh"
|
||||
#include "BLI_math_vector_types.hh"
|
||||
#include "BLI_string.h"
|
||||
|
||||
|
@ -17,6 +19,7 @@
|
|||
#include "UI_interface.hh"
|
||||
#include "UI_resources.hh"
|
||||
|
||||
#include "COM_algorithm_transform.hh"
|
||||
#include "COM_node_operation.hh"
|
||||
|
||||
#include "node_composite_util.hh"
|
||||
|
@ -82,13 +85,16 @@ class ScaleOperation : public NodeOperation {
|
|||
void execute() override
|
||||
{
|
||||
Result &input = get_input("Image");
|
||||
Result &result = get_result("Image");
|
||||
input.pass_through(result);
|
||||
Result &output = get_result("Image");
|
||||
|
||||
const float2 scale = get_scale();
|
||||
const math::AngleRadian rotation = 0.0f;
|
||||
const float2 translation = get_translation();
|
||||
const float3x3 transformation = math::from_loc_rot_scale<float3x3>(
|
||||
get_translation(), math::AngleRadian(0.0f), get_scale());
|
||||
translation, rotation, scale);
|
||||
|
||||
result.transform(transformation);
|
||||
const Interpolation interpolation = input.get_realization_options().interpolation;
|
||||
transform(context(), input, output, transformation, interpolation);
|
||||
}
|
||||
|
||||
float2 get_scale()
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "BKE_movieclip.h"
|
||||
#include "BKE_tracking.h"
|
||||
|
||||
#include "COM_algorithm_transform.hh"
|
||||
#include "COM_node_operation.hh"
|
||||
|
||||
#include "node_composite_util.hh"
|
||||
|
@ -82,17 +83,17 @@ class Stabilize2DOperation : public NodeOperation {
|
|||
|
||||
void execute() override
|
||||
{
|
||||
Result &input_image = get_input("Image");
|
||||
Result &output_image = get_result("Image");
|
||||
input_image.pass_through(output_image);
|
||||
Result &input = get_input("Image");
|
||||
Result &output = get_result("Image");
|
||||
|
||||
MovieClip *movie_clip = get_movie_clip();
|
||||
if (input_image.is_single_value() || !movie_clip) {
|
||||
if (input.is_single_value() || !movie_clip) {
|
||||
input.pass_through(output);
|
||||
return;
|
||||
}
|
||||
|
||||
const int width = input_image.domain().size.x;
|
||||
const int height = input_image.domain().size.y;
|
||||
const int width = input.domain().size.x;
|
||||
const int height = input.domain().size.y;
|
||||
const int frame_number = BKE_movieclip_remap_scene_to_clip_frame(movie_clip,
|
||||
context().get_frame_number());
|
||||
|
||||
|
@ -107,8 +108,7 @@ class Stabilize2DOperation : public NodeOperation {
|
|||
transformation = math::invert(transformation);
|
||||
}
|
||||
|
||||
output_image.transform(transformation);
|
||||
output_image.get_realization_options().interpolation = get_interpolation();
|
||||
transform(context(), input, output, transformation, get_interpolation());
|
||||
}
|
||||
|
||||
Interpolation get_interpolation()
|
||||
|
|
|
@ -7,12 +7,14 @@
|
|||
*/
|
||||
|
||||
#include "BLI_assert.h"
|
||||
#include "BLI_math_angle_types.hh"
|
||||
#include "BLI_math_matrix.hh"
|
||||
#include "BLI_math_vector.h"
|
||||
|
||||
#include "UI_interface.hh"
|
||||
#include "UI_resources.hh"
|
||||
|
||||
#include "COM_algorithm_transform.hh"
|
||||
#include "COM_node_operation.hh"
|
||||
|
||||
#include "node_composite_util.hh"
|
||||
|
@ -56,7 +58,6 @@ static void node_composit_buts_transform(uiLayout *layout, bContext * /*C*/, Poi
|
|||
}
|
||||
|
||||
using namespace blender::realtime_compositor;
|
||||
using namespace blender::math;
|
||||
|
||||
class TransformOperation : public NodeOperation {
|
||||
public:
|
||||
|
@ -65,18 +66,16 @@ class TransformOperation : public NodeOperation {
|
|||
void execute() override
|
||||
{
|
||||
Result &input = get_input("Image");
|
||||
Result &result = get_result("Image");
|
||||
input.pass_through(result);
|
||||
Result &output = get_result("Image");
|
||||
|
||||
const float2 translation = float2(get_input("X").get_float_value_default(0.0f),
|
||||
get_input("Y").get_float_value_default(0.0f));
|
||||
const AngleRadian rotation = AngleRadian(get_input("Angle").get_float_value_default(0.0f));
|
||||
const math::AngleRadian rotation = get_input("Angle").get_float_value_default(0.0f);
|
||||
const float2 scale = float2(get_input("Scale").get_float_value_default(1.0f));
|
||||
const float3x3 transformation = math::from_loc_rot_scale<float3x3>(
|
||||
translation, rotation, scale);
|
||||
|
||||
const float3x3 transformation = from_loc_rot_scale<float3x3>(translation, rotation, scale);
|
||||
|
||||
result.transform(transformation);
|
||||
result.get_realization_options().interpolation = get_interpolation();
|
||||
transform(context(), input, output, transformation, get_interpolation());
|
||||
}
|
||||
|
||||
Interpolation get_interpolation()
|
||||
|
|
|
@ -64,7 +64,7 @@ static bool pygpu_buffer_pyobj_as_shape(PyObject *shape_obj,
|
|||
Py_ssize_t shape_len = 0;
|
||||
if (PyLong_Check(shape_obj)) {
|
||||
shape_len = 1;
|
||||
if ((r_shape[0] = PyLong_AsLong(shape_obj)) < 1) {
|
||||
if ((r_shape[0] = PyLong_AsSsize_t(shape_obj)) < 1) {
|
||||
PyErr_SetString(PyExc_AttributeError, "dimension must be greater than or equal to 1");
|
||||
return false;
|
||||
}
|
||||
|
@ -92,7 +92,7 @@ static bool pygpu_buffer_pyobj_as_shape(PyObject *shape_obj,
|
|||
return false;
|
||||
}
|
||||
|
||||
r_shape[i] = PyLong_AsLong(ob);
|
||||
r_shape[i] = PyLong_AsSsize_t(ob);
|
||||
Py_DECREF(ob);
|
||||
|
||||
if (r_shape[i] < 1) {
|
||||
|
|
|
@ -232,6 +232,13 @@ static void wm_software_cursor_motion_clear()
|
|||
g_software_cursor.xy[1] = -1;
|
||||
}
|
||||
|
||||
static void wm_software_cursor_motion_clear_with_window(const wmWindow *win)
|
||||
{
|
||||
if (g_software_cursor.winid == win->winid) {
|
||||
wm_software_cursor_motion_clear();
|
||||
}
|
||||
}
|
||||
|
||||
static void wm_software_cursor_draw_bitmap(const int event_xy[2],
|
||||
const GHOST_CursorBitmapRef *bitmap)
|
||||
{
|
||||
|
@ -1144,7 +1151,8 @@ static void wm_draw_window_onscreen(bContext *C, wmWindow *win, int view)
|
|||
wm_software_cursor_motion_update(win);
|
||||
}
|
||||
else {
|
||||
wm_software_cursor_motion_clear();
|
||||
/* Checking the window is needed so one window doesn't clear the cursor state of another. */
|
||||
wm_software_cursor_motion_clear_with_window(win);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1158,7 +1166,7 @@ static void wm_draw_window(bContext *C, wmWindow *win)
|
|||
bScreen *screen = WM_window_get_active_screen(win);
|
||||
bool stereo = WM_stereo3d_enabled(win, false);
|
||||
|
||||
/* Avoid any BGL call issued before this to alter the window drawin. */
|
||||
/* Avoid any BGL call issued before this to alter the window drawing. */
|
||||
GPU_bgl_end();
|
||||
|
||||
/* Draw area regions into their own frame-buffer. This way we can redraw
|
||||
|
@ -1486,7 +1494,7 @@ static bool wm_draw_update_test_window(Main *bmain, bContext *C, wmWindow *win)
|
|||
else {
|
||||
/* Detect the edge case when the previous draw used the software cursor but this one doesn't,
|
||||
* it's important to redraw otherwise the software cursor will remain displayed. */
|
||||
if (g_software_cursor.winid != -1) {
|
||||
if (g_software_cursor.winid == win->winid) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2490,7 +2490,8 @@ static eHandlerActionFlag wm_handler_operator_call(bContext *C,
|
|||
if (retval & (OPERATOR_CANCELLED | OPERATOR_FINISHED)) {
|
||||
wm_operator_reports(C, op, retval, false);
|
||||
|
||||
if (op->type->modalkeymap) {
|
||||
wmOperator *op_test = handler->op->opm ? handler->op->opm : handler->op;
|
||||
if (op_test->type->modalkeymap) {
|
||||
WM_window_status_area_tag_redraw(win);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue