Merge branch 'master' into temp-image-engine
This commit is contained in:
@@ -1670,7 +1670,7 @@ class CyclesPreferences(bpy.types.AddonPreferences):
|
||||
col.label(text="and Windows driver version 101.3430 or newer", icon='BLANK1')
|
||||
elif sys.platform.startswith("linux"):
|
||||
col.label(text="Requires Intel GPU with Xe-HPG architecture and", icon='BLANK1')
|
||||
col.label(text=" - Linux driver version xx.xx.23904 or newer", icon='BLANK1')
|
||||
col.label(text=" - intel-level-zero-gpu version 1.3.23904 or newer", icon='BLANK1')
|
||||
col.label(text=" - oneAPI Level-Zero Loader", icon='BLANK1')
|
||||
elif device_type == 'METAL':
|
||||
col.label(text="Requires Apple Silicon with macOS 12.2 or newer", icon='BLANK1')
|
||||
|
@@ -410,10 +410,10 @@ class CYCLES_RENDER_PT_sampling_lights(CyclesButtonsPanel, Panel):
|
||||
cscene = scene.cycles
|
||||
|
||||
col = layout.column(align=True)
|
||||
#col.prop(cscene, "use_light_tree")
|
||||
col.prop(cscene, "use_light_tree")
|
||||
sub = col.row()
|
||||
sub.prop(cscene, "light_sampling_threshold", text="Light Threshold")
|
||||
#sub.active = not cscene.use_light_tree
|
||||
sub.active = not cscene.use_light_tree
|
||||
|
||||
|
||||
class CYCLES_RENDER_PT_subdivision(CyclesButtonsPanel, Panel):
|
||||
|
@@ -347,7 +347,7 @@ void BlenderSync::sync_integrator(BL::ViewLayer &b_view_layer, bool background)
|
||||
integrator->set_motion_blur(view_layer.use_motion_blur);
|
||||
}
|
||||
|
||||
bool use_light_tree = false; // get_boolean(cscene, "use_light_tree");
|
||||
bool use_light_tree = get_boolean(cscene, "use_light_tree");
|
||||
integrator->set_use_light_tree(use_light_tree);
|
||||
integrator->set_light_sampling_threshold(
|
||||
(use_light_tree) ? 0.0f : get_float(cscene, "light_sampling_threshold"));
|
||||
|
@@ -117,6 +117,8 @@ class MetalDevice : public Device {
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* low-level memory management */
|
||||
|
||||
bool max_working_set_exceeded(size_t safety_margin = 8 * 1024 * 1024) const;
|
||||
|
||||
MetalMem *generic_alloc(device_memory &mem);
|
||||
|
||||
void generic_copy_to(device_memory &mem);
|
||||
|
@@ -446,6 +446,14 @@ void MetalDevice::erase_allocation(device_memory &mem)
|
||||
}
|
||||
}
|
||||
|
||||
bool MetalDevice::max_working_set_exceeded(size_t safety_margin) const
|
||||
{
|
||||
/* We're allowed to allocate beyond the safe working set size, but then if all resources are made
|
||||
* resident we will get command buffer failures at render time. */
|
||||
size_t available = [mtlDevice recommendedMaxWorkingSetSize] - safety_margin;
|
||||
return (stats.mem_used > available);
|
||||
}
|
||||
|
||||
MetalDevice::MetalMem *MetalDevice::generic_alloc(device_memory &mem)
|
||||
{
|
||||
size_t size = mem.memory_size();
|
||||
@@ -523,6 +531,11 @@ MetalDevice::MetalMem *MetalDevice::generic_alloc(device_memory &mem)
|
||||
mmem->use_UMA = false;
|
||||
}
|
||||
|
||||
if (max_working_set_exceeded()) {
|
||||
set_error("System is out of GPU memory");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return mmem;
|
||||
}
|
||||
|
||||
@@ -921,9 +934,8 @@ void MetalDevice::tex_alloc(device_texture &mem)
|
||||
<< string_human_readable_size(mem.memory_size()) << ")";
|
||||
|
||||
mtlTexture = [mtlDevice newTextureWithDescriptor:desc];
|
||||
assert(mtlTexture);
|
||||
|
||||
if (!mtlTexture) {
|
||||
set_error("System is out of GPU memory");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -955,7 +967,10 @@ void MetalDevice::tex_alloc(device_texture &mem)
|
||||
<< string_human_readable_size(mem.memory_size()) << ")";
|
||||
|
||||
mtlTexture = [mtlDevice newTextureWithDescriptor:desc];
|
||||
assert(mtlTexture);
|
||||
if (!mtlTexture) {
|
||||
set_error("System is out of GPU memory");
|
||||
return;
|
||||
}
|
||||
|
||||
[mtlTexture replaceRegion:MTLRegionMake2D(0, 0, mem.data_width, mem.data_height)
|
||||
mipmapLevel:0
|
||||
@@ -1017,6 +1032,10 @@ void MetalDevice::tex_alloc(device_texture &mem)
|
||||
need_texture_info = true;
|
||||
|
||||
texture_info[slot].data = uint64_t(slot) | (sampler_index << 32);
|
||||
|
||||
if (max_working_set_exceeded()) {
|
||||
set_error("System is out of GPU memory");
|
||||
}
|
||||
}
|
||||
|
||||
void MetalDevice::tex_free(device_texture &mem)
|
||||
@@ -1077,6 +1096,10 @@ void MetalDevice::build_bvh(BVH *bvh, Progress &progress, bool refit)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (max_working_set_exceeded()) {
|
||||
set_error("System is out of GPU memory");
|
||||
}
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
@@ -8,7 +8,10 @@
|
||||
|
||||
#include "kernel/light/distribution.h"
|
||||
#include "kernel/light/light.h"
|
||||
#include "kernel/light/tree.h"
|
||||
|
||||
#ifdef __LIGHT_TREE__
|
||||
# include "kernel/light/tree.h"
|
||||
#endif
|
||||
|
||||
#include "kernel/sample/mapping.h"
|
||||
#include "kernel/sample/mis.h"
|
||||
@@ -522,7 +525,7 @@ ccl_device_inline bool light_sample_new_position(KernelGlobals kg,
|
||||
else
|
||||
#endif
|
||||
{
|
||||
/* Handled in triangle_light_sample for effeciency. */
|
||||
/* Handled in triangle_light_sample for efficiency. */
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@@ -796,11 +796,11 @@ ccl_device float bits_to_01(uint bits)
|
||||
ccl_device_inline uint popcount(uint x)
|
||||
{
|
||||
/* TODO(Stefan): pop-count intrinsic for Windows with fallback for older CPUs. */
|
||||
uint i = x & 0xaaaaaaaa;
|
||||
uint i = x;
|
||||
i = i - ((i >> 1) & 0x55555555);
|
||||
i = (i & 0x33333333) + ((i >> 2) & 0x33333333);
|
||||
i = (((i + (i >> 4)) & 0xF0F0F0F) * 0x1010101) >> 24;
|
||||
return i & 1;
|
||||
return i;
|
||||
}
|
||||
# endif
|
||||
#elif defined(__KERNEL_ONEAPI__)
|
||||
|
@@ -58,7 +58,7 @@ ccl_device_inline float4 madd4(const float4 a, const float4 b, const float4 c)
|
||||
ccl_device_inline int fast_rint(float x)
|
||||
{
|
||||
/* used by sin/cos/tan range reduction. */
|
||||
#ifdef __KERNEL_SSE4__
|
||||
#ifdef __KERNEL_SSE41__
|
||||
/* Single `roundps` instruction on SSE4.1+ (for gcc/clang at least). */
|
||||
return float_to_int(rintf(x));
|
||||
#else
|
||||
|
@@ -27,7 +27,13 @@ typedef enum {
|
||||
|
||||
} NDOF_DeviceT;
|
||||
|
||||
/* NDOF device button event types */
|
||||
/**
|
||||
* NDOF device button event types.
|
||||
*
|
||||
* \note Button values are stored in DNA as part of key-map items.
|
||||
* Existing values should not be changed. Otherwise, a mapping must be used,
|
||||
* see #NDOF_BUTTON_INDEX_AS_EVENT.
|
||||
*/
|
||||
typedef enum {
|
||||
/* Used internally, never sent or used as an index. */
|
||||
NDOF_BUTTON_NONE = -1,
|
||||
@@ -58,6 +64,11 @@ typedef enum {
|
||||
NDOF_BUTTON_DOMINANT,
|
||||
NDOF_BUTTON_PLUS,
|
||||
NDOF_BUTTON_MINUS,
|
||||
/* Store Views. */
|
||||
NDOF_BUTTON_V1,
|
||||
NDOF_BUTTON_V2,
|
||||
NDOF_BUTTON_V3,
|
||||
_NDOF_UNUSED_0,
|
||||
/* General-purpose buttons.
|
||||
* Users can assign functions via keymap editor. */
|
||||
NDOF_BUTTON_1,
|
||||
@@ -74,11 +85,8 @@ typedef enum {
|
||||
NDOF_BUTTON_A,
|
||||
NDOF_BUTTON_B,
|
||||
NDOF_BUTTON_C,
|
||||
/* Store Views. */
|
||||
NDOF_BUTTON_V1,
|
||||
NDOF_BUTTON_V2,
|
||||
NDOF_BUTTON_V3,
|
||||
/* Keyboard emulation. */
|
||||
|
||||
/* Keyboard emulation (keep last as they are mapped to regular keyboard events). */
|
||||
NDOF_BUTTON_ESC,
|
||||
NDOF_BUTTON_ENTER,
|
||||
NDOF_BUTTON_DELETE,
|
||||
|
@@ -40,6 +40,25 @@
|
||||
</screenshot>
|
||||
</screenshots>
|
||||
<releases>
|
||||
<release version="3.4" date="2022-12-07">
|
||||
<description>
|
||||
<p>New features:</p>
|
||||
<ul>
|
||||
<li>Cycles Path Guiding</li>
|
||||
<li>Sculpt geometry-based relax brush</li>
|
||||
<li>Viewport overlay for Geometry Nodes Viewer Node</li>
|
||||
<li>EEVEE headless rendering support on Linux</li>
|
||||
</ul>
|
||||
<p>Enhancements:</p>
|
||||
<ul>
|
||||
<li>Many new Geometry Nodes for meshes, curves and more</li>
|
||||
<li>NLA editor usability improvements</li>
|
||||
<li>FFmpeg AV1 codec encoding</li>
|
||||
<li>Improved font thumbnails</li>
|
||||
<li>Blender as a Python Module</li>
|
||||
</ul>
|
||||
</description>
|
||||
</release>
|
||||
<release version="3.3" date="2022-09-07">
|
||||
<description>
|
||||
<p>New features:</p>
|
||||
|
@@ -154,97 +154,14 @@ class DATA_PT_bone_groups(ArmatureButtonsPanel, Panel):
|
||||
sub.operator("pose.group_deselect", text="Deselect")
|
||||
|
||||
|
||||
class DATA_PT_pose_library(ArmatureButtonsPanel, Panel):
|
||||
bl_label = "Pose Library (Legacy)"
|
||||
bl_options = {'DEFAULT_CLOSED'}
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return (context.object and context.object.type == 'ARMATURE' and context.object.pose)
|
||||
|
||||
@staticmethod
|
||||
def get_manual_url():
|
||||
url_fmt = "https://docs.blender.org/manual/en/%d.%d/animation/armatures/posing/editing/pose_library.html"
|
||||
return url_fmt % bpy.app.version[:2]
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
col = layout.column(align=True)
|
||||
col.label(text="This panel is a remainder of the old pose library,")
|
||||
col.label(text="which was replaced by the Asset Browser")
|
||||
|
||||
url = self.get_manual_url()
|
||||
col.operator("wm.url_open", text="More Info", icon='URL').url = url
|
||||
|
||||
layout.separator()
|
||||
|
||||
ob = context.object
|
||||
poselib = ob.pose_library
|
||||
|
||||
col = layout.column(align=True)
|
||||
col.template_ID(ob, "pose_library", new="poselib.new", unlink="poselib.unlink")
|
||||
|
||||
if poselib:
|
||||
if hasattr(bpy.types, "POSELIB_OT_convert_old_object_poselib"):
|
||||
col.operator("poselib.convert_old_object_poselib",
|
||||
text="Convert to Pose Assets", icon='ASSET_MANAGER')
|
||||
else:
|
||||
col.label(text="Enable the Pose Library add-on to convert", icon='ERROR')
|
||||
col.label(text="this legacy pose library to pose assets", icon='BLANK1')
|
||||
|
||||
# Put the deprecated stuff in its own sub-layout.
|
||||
|
||||
dep_layout = layout.column()
|
||||
dep_layout.active = False
|
||||
|
||||
# warning about poselib being in an invalid state
|
||||
if poselib.fcurves and not poselib.pose_markers:
|
||||
dep_layout.label(
|
||||
icon='ERROR',
|
||||
text="Error: Potentially corrupt library, run 'Sanitize' operator to fix",
|
||||
)
|
||||
|
||||
# list of poses in pose library
|
||||
row = dep_layout.row()
|
||||
row.template_list("UI_UL_list", "pose_markers", poselib, "pose_markers",
|
||||
poselib.pose_markers, "active_index", rows=3)
|
||||
|
||||
# column of operators for active pose
|
||||
# - goes beside list
|
||||
col = row.column(align=True)
|
||||
|
||||
# invoke should still be used for 'add', as it is needed to allow
|
||||
# add/replace options to be used properly
|
||||
col.operator("poselib.pose_add", icon='ADD', text="")
|
||||
|
||||
col.operator_context = 'EXEC_DEFAULT' # exec not invoke, so that menu doesn't need showing
|
||||
|
||||
pose_marker_active = poselib.pose_markers.active
|
||||
|
||||
if pose_marker_active is not None:
|
||||
col.operator("poselib.pose_remove", icon='REMOVE', text="")
|
||||
col.operator(
|
||||
"poselib.apply_pose",
|
||||
icon='ZOOM_SELECTED',
|
||||
text="",
|
||||
).pose_index = poselib.pose_markers.active_index
|
||||
|
||||
col.operator("poselib.action_sanitize", icon='HELP', text="") # XXX: put in menu?
|
||||
|
||||
if pose_marker_active is not None:
|
||||
col.operator("poselib.pose_move", icon='TRIA_UP', text="").direction = 'UP'
|
||||
col.operator("poselib.pose_move", icon='TRIA_DOWN', text="").direction = 'DOWN'
|
||||
|
||||
|
||||
class DATA_PT_iksolver_itasc(ArmatureButtonsPanel, Panel):
|
||||
bl_label = "Inverse Kinematics"
|
||||
bl_options = {'DEFAULT_CLOSED'}
|
||||
bl_options = {"DEFAULT_CLOSED"}
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
ob = context.object
|
||||
return (ob and ob.pose)
|
||||
return ob and ob.pose
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
@@ -341,7 +258,6 @@ classes = (
|
||||
DATA_PT_skeleton,
|
||||
DATA_MT_bone_group_context_menu,
|
||||
DATA_PT_bone_groups,
|
||||
DATA_PT_pose_library,
|
||||
DATA_PT_motion_paths,
|
||||
DATA_PT_motion_paths_display,
|
||||
DATA_PT_display,
|
||||
|
@@ -88,8 +88,16 @@ class CURVES_UL_attributes(UIList):
|
||||
flags = []
|
||||
indices = [i for i in range(len(attributes))]
|
||||
|
||||
for item in attributes:
|
||||
flags.append(0 if item.is_internal else self.bitflag_filter_item)
|
||||
# Filtering by name
|
||||
if self.filter_name:
|
||||
flags = bpy.types.UI_UL_list.filter_items_by_name(
|
||||
self.filter_name, self.bitflag_filter_item, attributes, "name", reverse=self.use_filter_invert)
|
||||
if not flags:
|
||||
flags = [self.bitflag_filter_item] * len(attributes)
|
||||
|
||||
# Filtering internal attributes
|
||||
for idx, item in enumerate(attributes):
|
||||
flags[idx] = 0 if item.is_internal else flags[idx]
|
||||
|
||||
return flags, indices
|
||||
|
||||
|
@@ -537,8 +537,16 @@ class MESH_UL_attributes(UIList):
|
||||
flags = []
|
||||
indices = [i for i in range(len(attributes))]
|
||||
|
||||
for item in attributes:
|
||||
flags.append(0 if item.is_internal else self.bitflag_filter_item)
|
||||
# Filtering by name
|
||||
if self.filter_name:
|
||||
flags = bpy.types.UI_UL_list.filter_items_by_name(
|
||||
self.filter_name, self.bitflag_filter_item, attributes, "name", reverse=self.use_filter_invert)
|
||||
if not flags:
|
||||
flags = [self.bitflag_filter_item] * len(attributes)
|
||||
|
||||
# Filtering internal attributes
|
||||
for idx, item in enumerate(attributes):
|
||||
flags[idx] = 0 if item.is_internal else flags[idx]
|
||||
|
||||
return flags, indices
|
||||
|
||||
@@ -626,20 +634,26 @@ class ColorAttributesListBase():
|
||||
}
|
||||
|
||||
def filter_items(self, _context, data, property):
|
||||
attrs = getattr(data, property)
|
||||
ret = []
|
||||
idxs = []
|
||||
attributes = getattr(data, property)
|
||||
flags = []
|
||||
indices = [i for i in range(len(attributes))]
|
||||
|
||||
for idx, item in enumerate(attrs):
|
||||
# Filtering by name
|
||||
if self.filter_name:
|
||||
flags = bpy.types.UI_UL_list.filter_items_by_name(
|
||||
self.filter_name, self.bitflag_filter_item, attributes, "name", reverse=self.use_filter_invert)
|
||||
if not flags:
|
||||
flags = [self.bitflag_filter_item] * len(attributes)
|
||||
|
||||
for idx, item in enumerate(attributes):
|
||||
skip = (
|
||||
(item.domain not in {"POINT", "CORNER"}) or
|
||||
(item.data_type not in {"FLOAT_COLOR", "BYTE_COLOR"}) or
|
||||
item.is_internal
|
||||
)
|
||||
ret.append(0 if skip else self.bitflag_filter_item)
|
||||
idxs.append(idx)
|
||||
flags[idx] = 0 if skip else flags[idx]
|
||||
|
||||
return ret, idxs
|
||||
return flags, indices
|
||||
|
||||
|
||||
class MESH_UL_color_attributes(UIList, ColorAttributesListBase):
|
||||
|
@@ -70,8 +70,16 @@ class POINTCLOUD_UL_attributes(UIList):
|
||||
flags = []
|
||||
indices = [i for i in range(len(attributes))]
|
||||
|
||||
for item in attributes:
|
||||
flags.append(0 if item.is_internal else self.bitflag_filter_item)
|
||||
# Filtering by name
|
||||
if self.filter_name:
|
||||
flags = bpy.types.UI_UL_list.filter_items_by_name(
|
||||
self.filter_name, self.bitflag_filter_item, attributes, "name", reverse=self.use_filter_invert)
|
||||
if not flags:
|
||||
flags = [self.bitflag_filter_item] * len(attributes)
|
||||
|
||||
# Filtering internal attributes
|
||||
for idx, item in enumerate(attributes):
|
||||
flags[idx] = 0 if item.is_internal else flags[idx]
|
||||
|
||||
return flags, indices
|
||||
|
||||
|
@@ -851,6 +851,8 @@ static void object_blend_read_lib(BlendLibReader *reader, ID *id)
|
||||
|
||||
BLO_read_id_address(reader, ob->id.lib, &ob->parent);
|
||||
BLO_read_id_address(reader, ob->id.lib, &ob->track);
|
||||
|
||||
/* XXX deprecated - old pose library, deprecated in Blender 3.5. */
|
||||
BLO_read_id_address(reader, ob->id.lib, &ob->poselib);
|
||||
|
||||
/* 2.8x drops support for non-empty dupli instances. */
|
||||
|
@@ -289,7 +289,11 @@ static void curves_batch_cache_ensure_data_edit_points(const Curves &curves_id,
|
||||
const bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id.geometry);
|
||||
|
||||
static GPUVertFormat format_data = {0};
|
||||
uint data = GPU_vertformat_attr_add(&format_data, "data", GPU_COMP_U8, 1, GPU_FETCH_INT);
|
||||
static uint data;
|
||||
if (format_data.attr_len == 0) {
|
||||
data = GPU_vertformat_attr_add(&format_data, "data", GPU_COMP_U8, 1, GPU_FETCH_INT);
|
||||
}
|
||||
|
||||
GPU_vertbuf_init_with_format(cache.data_edit_points, &format_data);
|
||||
GPU_vertbuf_data_alloc(cache.data_edit_points, curves.points_num());
|
||||
|
||||
|
@@ -21,6 +21,7 @@ namespace blender::editor::animation::tests {
|
||||
const float KEYLIST_NEAR_ERROR = 0.1;
|
||||
const float FRAME_STEP = 0.005;
|
||||
|
||||
/* Build FCurve with keys on frames 10, 20, and 30. */
|
||||
static void build_fcurve(FCurve &fcurve)
|
||||
{
|
||||
fcurve.totvert = 3;
|
||||
@@ -51,92 +52,88 @@ static void assert_act_key_column(const ActKeyColumn *column,
|
||||
const std::optional<float> expected_frame)
|
||||
{
|
||||
if (expected_frame.has_value()) {
|
||||
EXPECT_NE(column, nullptr);
|
||||
ASSERT_NE(column, nullptr) << "Expected a frame to be found at " << *expected_frame;
|
||||
EXPECT_NEAR(column->cfra, *expected_frame, KEYLIST_NEAR_ERROR);
|
||||
}
|
||||
else {
|
||||
EXPECT_EQ(column, nullptr);
|
||||
EXPECT_EQ(column, nullptr) << "Expected no frame to be found, but found " << column->cfra;
|
||||
}
|
||||
}
|
||||
|
||||
using KeylistFindFunction = std::function<const ActKeyColumn *(const AnimKeylist *, float)>;
|
||||
|
||||
static float check_keylist_find_range(const AnimKeylist *keylist,
|
||||
KeylistFindFunction keylist_find_func,
|
||||
const float frame_from,
|
||||
const float frame_to,
|
||||
const std::optional<float> expected_frame)
|
||||
static void check_keylist_find_range(const AnimKeylist *keylist,
|
||||
KeylistFindFunction keylist_find_func,
|
||||
const float frame_from,
|
||||
const float frame_to,
|
||||
const std::optional<float> expected_frame)
|
||||
{
|
||||
float cfra = frame_from;
|
||||
for (; cfra < frame_to; cfra += FRAME_STEP) {
|
||||
const ActKeyColumn *found = keylist_find_func(keylist, cfra);
|
||||
assert_act_key_column(found, expected_frame);
|
||||
}
|
||||
return cfra;
|
||||
}
|
||||
|
||||
static float check_keylist_find_next_range(const AnimKeylist *keylist,
|
||||
const float frame_from,
|
||||
const float frame_to,
|
||||
const std::optional<float> expected_frame)
|
||||
static void check_keylist_find_next_range(const AnimKeylist *keylist,
|
||||
const float frame_from,
|
||||
const float frame_to,
|
||||
const std::optional<float> expected_frame)
|
||||
{
|
||||
return check_keylist_find_range(
|
||||
keylist, ED_keylist_find_next, frame_from, frame_to, expected_frame);
|
||||
check_keylist_find_range(keylist, ED_keylist_find_next, frame_from, frame_to, expected_frame);
|
||||
}
|
||||
|
||||
TEST(keylist, find_next)
|
||||
{
|
||||
AnimKeylist *keylist = create_test_keylist();
|
||||
|
||||
float cfra = check_keylist_find_next_range(keylist, 0.0f, 9.99f, 10.0f);
|
||||
cfra = check_keylist_find_next_range(keylist, cfra, 19.99f, 20.0f);
|
||||
cfra = check_keylist_find_next_range(keylist, cfra, 29.99f, 30.0f);
|
||||
cfra = check_keylist_find_next_range(keylist, cfra, 39.99f, std::nullopt);
|
||||
check_keylist_find_next_range(keylist, 0.0f, 9.99f, 10.0f);
|
||||
check_keylist_find_next_range(keylist, 10.0f, 19.99f, 20.0f);
|
||||
check_keylist_find_next_range(keylist, 20.0f, 29.99f, 30.0f);
|
||||
check_keylist_find_next_range(keylist, 30.0f, 39.99f, std::nullopt);
|
||||
|
||||
ED_keylist_free(keylist);
|
||||
}
|
||||
|
||||
static float check_keylist_find_prev_range(const AnimKeylist *keylist,
|
||||
const float frame_from,
|
||||
const float frame_to,
|
||||
const std::optional<float> expected_frame)
|
||||
static void check_keylist_find_prev_range(const AnimKeylist *keylist,
|
||||
const float frame_from,
|
||||
const float frame_to,
|
||||
const std::optional<float> expected_frame)
|
||||
{
|
||||
return check_keylist_find_range(
|
||||
keylist, ED_keylist_find_prev, frame_from, frame_to, expected_frame);
|
||||
check_keylist_find_range(keylist, ED_keylist_find_prev, frame_from, frame_to, expected_frame);
|
||||
}
|
||||
|
||||
TEST(keylist, find_prev)
|
||||
{
|
||||
AnimKeylist *keylist = create_test_keylist();
|
||||
|
||||
float cfra = check_keylist_find_prev_range(keylist, 0.0f, 10.01f, std::nullopt);
|
||||
cfra = check_keylist_find_prev_range(keylist, cfra, 20.01f, 10.0f);
|
||||
cfra = check_keylist_find_prev_range(keylist, cfra, 30.01f, 20.0f);
|
||||
cfra = check_keylist_find_prev_range(keylist, cfra, 49.99f, 30.0f);
|
||||
check_keylist_find_prev_range(keylist, 0.0f, 10.00f, std::nullopt);
|
||||
check_keylist_find_prev_range(keylist, 10.01f, 20.00f, 10.0f);
|
||||
check_keylist_find_prev_range(keylist, 20.01f, 30.00f, 20.0f);
|
||||
check_keylist_find_prev_range(keylist, 30.01f, 49.99f, 30.0f);
|
||||
|
||||
ED_keylist_free(keylist);
|
||||
}
|
||||
|
||||
static float check_keylist_find_exact_range(const AnimKeylist *keylist,
|
||||
const float frame_from,
|
||||
const float frame_to,
|
||||
const std::optional<float> expected_frame)
|
||||
static void check_keylist_find_exact_range(const AnimKeylist *keylist,
|
||||
const float frame_from,
|
||||
const float frame_to,
|
||||
const std::optional<float> expected_frame)
|
||||
{
|
||||
return check_keylist_find_range(
|
||||
keylist, ED_keylist_find_exact, frame_from, frame_to, expected_frame);
|
||||
check_keylist_find_range(keylist, ED_keylist_find_exact, frame_from, frame_to, expected_frame);
|
||||
}
|
||||
|
||||
TEST(keylist, find_exact)
|
||||
{
|
||||
AnimKeylist *keylist = create_test_keylist();
|
||||
|
||||
float cfra = check_keylist_find_exact_range(keylist, 0.0f, 9.99f, std::nullopt);
|
||||
cfra = check_keylist_find_exact_range(keylist, cfra, 10.01f, 10.0f);
|
||||
cfra = check_keylist_find_exact_range(keylist, cfra, 19.99f, std::nullopt);
|
||||
cfra = check_keylist_find_exact_range(keylist, cfra, 20.01f, 20.0f);
|
||||
cfra = check_keylist_find_exact_range(keylist, cfra, 29.99f, std::nullopt);
|
||||
cfra = check_keylist_find_exact_range(keylist, cfra, 30.01f, 30.0f);
|
||||
cfra = check_keylist_find_exact_range(keylist, cfra, 49.99f, std::nullopt);
|
||||
check_keylist_find_exact_range(keylist, 0.0f, 9.99f, std::nullopt);
|
||||
check_keylist_find_exact_range(keylist, 9.9901f, 10.01f, 10.0f);
|
||||
check_keylist_find_exact_range(keylist, 10.01f, 19.99f, std::nullopt);
|
||||
check_keylist_find_exact_range(keylist, 19.9901f, 20.01f, 20.0f);
|
||||
check_keylist_find_exact_range(keylist, 20.01f, 29.99f, std::nullopt);
|
||||
check_keylist_find_exact_range(keylist, 29.9901f, 30.01f, 30.0f);
|
||||
check_keylist_find_exact_range(keylist, 30.01f, 49.99f, std::nullopt);
|
||||
|
||||
ED_keylist_free(keylist);
|
||||
}
|
||||
|
@@ -33,7 +33,6 @@ set(SRC
|
||||
pose_backup.cc
|
||||
pose_edit.c
|
||||
pose_group.c
|
||||
pose_lib.c
|
||||
pose_lib_2.c
|
||||
pose_select.c
|
||||
pose_slide.c
|
||||
|
@@ -201,21 +201,6 @@ LinkData *poseAnim_mapping_getNextFCurve(ListBase *fcuLinks, LinkData *prev, con
|
||||
/** \name PoseLib
|
||||
* \{ */
|
||||
|
||||
/* pose_lib.c */
|
||||
|
||||
void POSELIB_OT_new(struct wmOperatorType *ot);
|
||||
void POSELIB_OT_unlink(struct wmOperatorType *ot);
|
||||
|
||||
void POSELIB_OT_action_sanitize(struct wmOperatorType *ot);
|
||||
|
||||
void POSELIB_OT_pose_add(struct wmOperatorType *ot);
|
||||
void POSELIB_OT_pose_remove(struct wmOperatorType *ot);
|
||||
void POSELIB_OT_pose_rename(struct wmOperatorType *ot);
|
||||
void POSELIB_OT_pose_move(struct wmOperatorType *ot);
|
||||
|
||||
void POSELIB_OT_browse_interactive(struct wmOperatorType *ot);
|
||||
void POSELIB_OT_apply_pose(struct wmOperatorType *ot);
|
||||
|
||||
/* pose_lib_2.c */
|
||||
|
||||
void POSELIB_OT_apply_pose_asset(struct wmOperatorType *ot);
|
||||
|
@@ -114,21 +114,9 @@ void ED_operatortypes_armature(void)
|
||||
WM_operatortype_append(POSE_OT_propagate);
|
||||
|
||||
/* POSELIB */
|
||||
WM_operatortype_append(POSELIB_OT_browse_interactive);
|
||||
WM_operatortype_append(POSELIB_OT_apply_pose);
|
||||
WM_operatortype_append(POSELIB_OT_apply_pose_asset);
|
||||
WM_operatortype_append(POSELIB_OT_blend_pose_asset);
|
||||
|
||||
WM_operatortype_append(POSELIB_OT_pose_add);
|
||||
WM_operatortype_append(POSELIB_OT_pose_remove);
|
||||
WM_operatortype_append(POSELIB_OT_pose_rename);
|
||||
WM_operatortype_append(POSELIB_OT_pose_move);
|
||||
|
||||
WM_operatortype_append(POSELIB_OT_new);
|
||||
WM_operatortype_append(POSELIB_OT_unlink);
|
||||
|
||||
WM_operatortype_append(POSELIB_OT_action_sanitize);
|
||||
|
||||
/* POSE SLIDING */
|
||||
WM_operatortype_append(POSE_OT_push);
|
||||
WM_operatortype_append(POSE_OT_relax);
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -332,12 +332,7 @@ struct UVMapUDIM_Params {
|
||||
const struct Image *image;
|
||||
/** Copied from #SpaceImage.tile_grid_shape */
|
||||
int grid_shape[2];
|
||||
bool use_target_udim;
|
||||
int target_udim;
|
||||
};
|
||||
bool ED_uvedit_udim_params_from_image_space(const struct SpaceImage *sima,
|
||||
bool use_active,
|
||||
struct UVMapUDIM_Params *udim_params);
|
||||
|
||||
typedef enum {
|
||||
ED_UVPACK_MARGIN_SCALED = 0, /* Use scale of existing UVs to multiply margin. */
|
||||
@@ -356,6 +351,7 @@ struct UVPackIsland_Params {
|
||||
bool pin_unselected; /* Treat unselected UVs as if they were pinned. */
|
||||
eUVPackIsland_MarginMethod margin_method; /* Which formula to use when scaling island margin. */
|
||||
float margin; /* Additional space to add around each island. */
|
||||
float udim_base_offset[2]; /* Additional translation for bottom left corner. */
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -382,7 +378,7 @@ void ED_uvedit_pack_islands_multi(const struct Scene *scene,
|
||||
Object **objects,
|
||||
uint objects_len,
|
||||
struct BMesh **bmesh_override,
|
||||
const struct UVMapUDIM_Params *udim_params,
|
||||
const struct UVMapUDIM_Params *closest_udim,
|
||||
const struct UVPackIsland_Params *params);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@@ -910,13 +910,15 @@ static int sculpt_mask_by_color_invoke(bContext *C, wmOperator *op, const wmEven
|
||||
v3d->shading.color_type = V3D_SHADING_VERTEX_COLOR;
|
||||
}
|
||||
|
||||
BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true, false);
|
||||
|
||||
/* Color data is not available in multi-resolution or dynamic topology. */
|
||||
if (!SCULPT_handles_colors_report(ss, op->reports)) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
MultiresModifierData *mmd = BKE_sculpt_multires_active(CTX_data_scene(C), ob);
|
||||
BKE_sculpt_mask_layers_ensure(depsgraph, CTX_data_main(C), ob, mmd);
|
||||
|
||||
BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true, false);
|
||||
SCULPT_vertex_random_access_ensure(ss);
|
||||
|
||||
/* Tools that are not brushes do not have the brush gizmo to update the vertex as the mouse move,
|
||||
|
@@ -667,35 +667,47 @@ static int image_view_zoom_modal(bContext *C, wmOperator *op, const wmEvent *eve
|
||||
{
|
||||
ViewZoomData *vpd = op->customdata;
|
||||
short event_code = VIEW_PASS;
|
||||
int ret = OPERATOR_RUNNING_MODAL;
|
||||
|
||||
/* execute the events */
|
||||
if (event->type == TIMER && event->customdata == vpd->timer) {
|
||||
/* continuous zoom */
|
||||
/* Execute the events. */
|
||||
if (event->type == MOUSEMOVE) {
|
||||
event_code = VIEW_APPLY;
|
||||
}
|
||||
else if (event->type == MOUSEMOVE) {
|
||||
event_code = VIEW_APPLY;
|
||||
else if (event->type == TIMER) {
|
||||
/* Continuous zoom. */
|
||||
if (event->customdata == vpd->timer) {
|
||||
event_code = VIEW_APPLY;
|
||||
}
|
||||
}
|
||||
else if (event->type == vpd->launch_event && event->val == KM_RELEASE) {
|
||||
event_code = VIEW_CONFIRM;
|
||||
else if (event->type == vpd->launch_event) {
|
||||
if (event->val == KM_RELEASE) {
|
||||
event_code = VIEW_CONFIRM;
|
||||
}
|
||||
}
|
||||
|
||||
if (event_code == VIEW_APPLY) {
|
||||
const bool use_cursor_init = RNA_boolean_get(op->ptr, "use_cursor_init");
|
||||
image_zoom_apply(vpd,
|
||||
op,
|
||||
event->xy[0],
|
||||
event->xy[1],
|
||||
U.viewzoom,
|
||||
(U.uiflag & USER_ZOOM_INVERT) != 0,
|
||||
(use_cursor_init && (U.uiflag & USER_ZOOM_TO_MOUSEPOS)));
|
||||
switch (event_code) {
|
||||
case VIEW_APPLY: {
|
||||
const bool use_cursor_init = RNA_boolean_get(op->ptr, "use_cursor_init");
|
||||
image_zoom_apply(vpd,
|
||||
op,
|
||||
event->xy[0],
|
||||
event->xy[1],
|
||||
U.viewzoom,
|
||||
(U.uiflag & USER_ZOOM_INVERT) != 0,
|
||||
(use_cursor_init && (U.uiflag & USER_ZOOM_TO_MOUSEPOS)));
|
||||
break;
|
||||
}
|
||||
case VIEW_CONFIRM: {
|
||||
ret = OPERATOR_FINISHED;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (event_code == VIEW_CONFIRM) {
|
||||
|
||||
if ((ret & OPERATOR_RUNNING_MODAL) == 0) {
|
||||
image_view_zoom_exit(C, op, false);
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
return OPERATOR_RUNNING_MODAL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void image_view_zoom_cancel(bContext *C, wmOperator *op)
|
||||
|
@@ -278,9 +278,6 @@ static void outliner_add_object_contents(SpaceOutliner *space_outliner,
|
||||
outliner_add_element(space_outliner, &te->subtree, ob, te, TSE_ANIM_DATA, 0);
|
||||
}
|
||||
|
||||
/* FIXME: add a special type for this. */
|
||||
outliner_add_element(space_outliner, &te->subtree, ob->poselib, te, TSE_SOME_ID, 0);
|
||||
|
||||
outliner_add_element(space_outliner, &te->subtree, ob->data, te, TSE_SOME_ID, 0);
|
||||
|
||||
if (ob->pose) {
|
||||
|
@@ -298,6 +298,7 @@ ViewOpsData *viewops_data_create(bContext *C, const wmEvent *event, enum eViewOp
|
||||
else {
|
||||
vod->use_dyn_ofs = false;
|
||||
}
|
||||
vod->init.persp = rv3d->persp;
|
||||
|
||||
if (viewops_flag & VIEWOPS_FLAG_PERSP_ENSURE) {
|
||||
if (ED_view3d_persp_ensure(depsgraph, vod->v3d, vod->region)) {
|
||||
@@ -311,7 +312,9 @@ ViewOpsData *viewops_data_create(bContext *C, const wmEvent *event, enum eViewOp
|
||||
* we may want to make this optional but for now its needed always */
|
||||
ED_view3d_camera_lock_init(depsgraph, vod->v3d, vod->rv3d);
|
||||
|
||||
vod->init.persp = rv3d->persp;
|
||||
vod->init.persp_with_auto_persp_applied = rv3d->persp;
|
||||
vod->init.view = rv3d->view;
|
||||
vod->init.view_axis_roll = rv3d->view_axis_roll;
|
||||
vod->init.dist = rv3d->dist;
|
||||
vod->init.camzoom = rv3d->camzoom;
|
||||
copy_qt_qt(vod->init.quat, rv3d->viewquat);
|
||||
@@ -332,6 +335,10 @@ ViewOpsData *viewops_data_create(bContext *C, const wmEvent *event, enum eViewOp
|
||||
|
||||
copy_qt_qt(vod->curr.viewquat, rv3d->viewquat);
|
||||
|
||||
copy_v3_v3(vod->init.ofs_lock, rv3d->ofs_lock);
|
||||
vod->init.camdx = rv3d->camdx;
|
||||
vod->init.camdy = rv3d->camdy;
|
||||
|
||||
if (viewops_flag & VIEWOPS_FLAG_ORBIT_SELECT) {
|
||||
float ofs[3];
|
||||
if (view3d_orbit_calc_center(C, ofs) || (vod->use_dyn_ofs == false)) {
|
||||
@@ -585,6 +592,23 @@ void viewmove_apply(ViewOpsData *vod, int x, int y)
|
||||
ED_region_tag_redraw(vod->region);
|
||||
}
|
||||
|
||||
void viewmove_apply_reset(ViewOpsData *vod)
|
||||
{
|
||||
if ((vod->rv3d->persp == RV3D_CAMOB) && !ED_view3d_camera_lock_check(vod->v3d, vod->rv3d)) {
|
||||
vod->rv3d->camdx = vod->init.camdx;
|
||||
vod->rv3d->camdy = vod->init.camdy;
|
||||
}
|
||||
else if (ED_view3d_offset_lock_check(vod->v3d, vod->rv3d)) {
|
||||
copy_v2_v2(vod->rv3d->ofs_lock, vod->init.ofs_lock);
|
||||
}
|
||||
else {
|
||||
copy_v3_v3(vod->rv3d->ofs, vod->init.ofs);
|
||||
if (RV3D_LOCK_FLAGS(vod->rv3d) & RV3D_BOXVIEW) {
|
||||
view3d_boxview_sync(vod->area, vod->region);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
@@ -41,6 +41,8 @@ enum {
|
||||
VIEW_PASS = 0,
|
||||
VIEW_APPLY,
|
||||
VIEW_CONFIRM,
|
||||
/** Only supported by some viewport operators. */
|
||||
VIEW_CANCEL,
|
||||
};
|
||||
|
||||
/* NOTE: these defines are saved in keymap files, do not change values but just add new ones */
|
||||
@@ -95,9 +97,14 @@ typedef struct ViewOpsData {
|
||||
/** #wmEvent.type that triggered the operator. */
|
||||
int event_type;
|
||||
float ofs[3];
|
||||
/** #RegionView3D.ofs_lock */
|
||||
float ofs_lock[2];
|
||||
/** Initial distance to 'ofs'. */
|
||||
float zfac;
|
||||
|
||||
/** Camera offset. */
|
||||
float camdx, camdy;
|
||||
|
||||
/** Trackball rotation only. */
|
||||
float trackvec[3];
|
||||
/** Dolly only. */
|
||||
@@ -107,7 +114,13 @@ typedef struct ViewOpsData {
|
||||
* #RegionView3D.persp set after auto-perspective is applied.
|
||||
* If we want the value before running the operator, add a separate member.
|
||||
*/
|
||||
char persp_with_auto_persp_applied;
|
||||
/** #RegionView3D.persp set after before auto-perspective is applied. */
|
||||
char persp;
|
||||
/** #RegionView3D.view */
|
||||
char view;
|
||||
/** #RegionView3D.view_axis_roll */
|
||||
char view_axis_roll;
|
||||
|
||||
/** Used for roll */
|
||||
struct Dial *dial;
|
||||
@@ -145,6 +158,7 @@ bool view3d_zoom_or_dolly_poll(struct bContext *C);
|
||||
enum eViewOpsFlag viewops_flag_from_prefs(void);
|
||||
void calctrackballvec(const struct rcti *rect, const int event_xy[2], float r_dir[3]);
|
||||
void viewmove_apply(ViewOpsData *vod, int x, int y);
|
||||
void viewmove_apply_reset(ViewOpsData *vod);
|
||||
void view3d_orbit_apply_dyn_ofs(float r_ofs[3],
|
||||
const float ofs_old[3],
|
||||
const float viewquat_old[4],
|
||||
|
@@ -142,11 +142,8 @@ static int viewdolly_modal(bContext *C, wmOperator *op, const wmEvent *event)
|
||||
bool use_autokey = false;
|
||||
int ret = OPERATOR_RUNNING_MODAL;
|
||||
|
||||
/* execute the events */
|
||||
if (event->type == MOUSEMOVE) {
|
||||
event_code = VIEW_APPLY;
|
||||
}
|
||||
else if (event->type == EVT_MODAL_MAP) {
|
||||
/* Execute the events. */
|
||||
if (event->type == EVT_MODAL_MAP) {
|
||||
switch (event->val) {
|
||||
case VIEW_MODAL_CONFIRM:
|
||||
event_code = VIEW_CONFIRM;
|
||||
@@ -161,27 +158,52 @@ static int viewdolly_modal(bContext *C, wmOperator *op, const wmEvent *event)
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (event->type == vod->init.event_type && event->val == KM_RELEASE) {
|
||||
event_code = VIEW_CONFIRM;
|
||||
}
|
||||
|
||||
if (event_code == VIEW_APPLY) {
|
||||
viewdolly_apply(vod, event->xy, (U.uiflag & USER_ZOOM_INVERT) != 0);
|
||||
if (ED_screen_animation_playing(CTX_wm_manager(C))) {
|
||||
use_autokey = true;
|
||||
else {
|
||||
if (event->type == MOUSEMOVE) {
|
||||
event_code = VIEW_APPLY;
|
||||
}
|
||||
else if (event->type == vod->init.event_type) {
|
||||
if (event->val == KM_RELEASE) {
|
||||
event_code = VIEW_CONFIRM;
|
||||
}
|
||||
}
|
||||
else if (ELEM(event->type, EVT_ESCKEY, RIGHTMOUSE)) {
|
||||
if (event->val == KM_PRESS) {
|
||||
event_code = VIEW_CANCEL;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (event_code == VIEW_CONFIRM) {
|
||||
use_autokey = true;
|
||||
ret = OPERATOR_FINISHED;
|
||||
|
||||
switch (event_code) {
|
||||
case VIEW_APPLY: {
|
||||
viewdolly_apply(vod, event->xy, (U.uiflag & USER_ZOOM_INVERT) != 0);
|
||||
if (ED_screen_animation_playing(CTX_wm_manager(C))) {
|
||||
use_autokey = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case VIEW_CONFIRM: {
|
||||
use_autokey = true;
|
||||
ret = OPERATOR_FINISHED;
|
||||
break;
|
||||
}
|
||||
case VIEW_CANCEL: {
|
||||
/* Note this does not remove auto-keys on locked cameras. */
|
||||
copy_v3_v3(vod->rv3d->ofs, vod->init.ofs);
|
||||
ED_view3d_camera_lock_sync(vod->depsgraph, vod->v3d, vod->rv3d);
|
||||
ret = OPERATOR_CANCELLED;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (use_autokey) {
|
||||
ED_view3d_camera_lock_autokey(vod->v3d, vod->rv3d, C, false, true);
|
||||
}
|
||||
|
||||
if (ret & OPERATOR_FINISHED) {
|
||||
ED_view3d_camera_lock_undo_push(op->type->name, vod->v3d, vod->rv3d, C);
|
||||
if ((ret & OPERATOR_RUNNING_MODAL) == 0) {
|
||||
if (ret & OPERATOR_FINISHED) {
|
||||
ED_view3d_camera_lock_undo_push(op->type->name, vod->v3d, vod->rv3d, C);
|
||||
}
|
||||
viewops_data_free(C, vod);
|
||||
op->customdata = NULL;
|
||||
}
|
||||
|
@@ -4,6 +4,8 @@
|
||||
* \ingroup spview3d
|
||||
*/
|
||||
|
||||
#include "BLI_math_vector.h"
|
||||
|
||||
#include "BKE_context.h"
|
||||
|
||||
#include "WM_api.h"
|
||||
@@ -101,11 +103,8 @@ static int viewmove_modal(bContext *C, wmOperator *op, const wmEvent *event)
|
||||
bool use_autokey = false;
|
||||
int ret = OPERATOR_RUNNING_MODAL;
|
||||
|
||||
/* execute the events */
|
||||
if (event->type == MOUSEMOVE) {
|
||||
event_code = VIEW_APPLY;
|
||||
}
|
||||
else if (event->type == EVT_MODAL_MAP) {
|
||||
/* Execute the events. */
|
||||
if (event->type == EVT_MODAL_MAP) {
|
||||
switch (event->val) {
|
||||
case VIEW_MODAL_CONFIRM:
|
||||
event_code = VIEW_CONFIRM;
|
||||
@@ -120,27 +119,51 @@ static int viewmove_modal(bContext *C, wmOperator *op, const wmEvent *event)
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (event->type == vod->init.event_type && event->val == KM_RELEASE) {
|
||||
event_code = VIEW_CONFIRM;
|
||||
}
|
||||
|
||||
if (event_code == VIEW_APPLY) {
|
||||
viewmove_apply(vod, event->xy[0], event->xy[1]);
|
||||
if (ED_screen_animation_playing(CTX_wm_manager(C))) {
|
||||
use_autokey = true;
|
||||
else {
|
||||
if (event->type == MOUSEMOVE) {
|
||||
event_code = VIEW_APPLY;
|
||||
}
|
||||
else if (event->type == vod->init.event_type) {
|
||||
if (event->val == KM_RELEASE) {
|
||||
event_code = VIEW_CONFIRM;
|
||||
}
|
||||
}
|
||||
else if (ELEM(event->type, EVT_ESCKEY, RIGHTMOUSE)) {
|
||||
if (event->val == KM_PRESS) {
|
||||
event_code = VIEW_CANCEL;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (event_code == VIEW_CONFIRM) {
|
||||
use_autokey = true;
|
||||
ret = OPERATOR_FINISHED;
|
||||
|
||||
switch (event_code) {
|
||||
case VIEW_APPLY: {
|
||||
viewmove_apply(vod, event->xy[0], event->xy[1]);
|
||||
if (ED_screen_animation_playing(CTX_wm_manager(C))) {
|
||||
use_autokey = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case VIEW_CONFIRM: {
|
||||
use_autokey = true;
|
||||
ret = OPERATOR_FINISHED;
|
||||
break;
|
||||
}
|
||||
case VIEW_CANCEL: {
|
||||
viewmove_apply_reset(vod);
|
||||
ED_view3d_camera_lock_sync(vod->depsgraph, vod->v3d, vod->rv3d);
|
||||
ret = OPERATOR_CANCELLED;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (use_autokey) {
|
||||
ED_view3d_camera_lock_autokey(vod->v3d, vod->rv3d, C, false, true);
|
||||
}
|
||||
|
||||
if (ret & OPERATOR_FINISHED) {
|
||||
ED_view3d_camera_lock_undo_push(op->type->name, vod->v3d, vod->rv3d, C);
|
||||
if ((ret & OPERATOR_RUNNING_MODAL) == 0) {
|
||||
if (ret & OPERATOR_FINISHED) {
|
||||
ED_view3d_camera_lock_undo_push(op->type->name, vod->v3d, vod->rv3d, C);
|
||||
}
|
||||
viewops_data_free(C, op->customdata);
|
||||
op->customdata = NULL;
|
||||
}
|
||||
|
@@ -87,11 +87,8 @@ static int viewroll_modal(bContext *C, wmOperator *op, const wmEvent *event)
|
||||
bool use_autokey = false;
|
||||
int ret = OPERATOR_RUNNING_MODAL;
|
||||
|
||||
/* execute the events */
|
||||
if (event->type == MOUSEMOVE) {
|
||||
event_code = VIEW_APPLY;
|
||||
}
|
||||
else if (event->type == EVT_MODAL_MAP) {
|
||||
/* Execute the events. */
|
||||
if (event->type == EVT_MODAL_MAP) {
|
||||
switch (event->val) {
|
||||
case VIEW_MODAL_CONFIRM:
|
||||
event_code = VIEW_CONFIRM;
|
||||
@@ -106,40 +103,51 @@ static int viewroll_modal(bContext *C, wmOperator *op, const wmEvent *event)
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (event->type == vod->init.event_type) {
|
||||
/* Check `vod->init.event_type` first in case RMB was used to invoke.
|
||||
* in this case confirming takes precedence over canceling, see: T102937. */
|
||||
if (event->val == KM_RELEASE) {
|
||||
event_code = VIEW_CONFIRM;
|
||||
else {
|
||||
if (event->type == MOUSEMOVE) {
|
||||
event_code = VIEW_APPLY;
|
||||
}
|
||||
}
|
||||
else if (ELEM(event->type, EVT_ESCKEY, RIGHTMOUSE)) {
|
||||
if (event->val == KM_PRESS) {
|
||||
/* Note this does not remove auto-keys on locked cameras. */
|
||||
copy_qt_qt(vod->rv3d->viewquat, vod->init.quat);
|
||||
ED_view3d_camera_lock_sync(vod->depsgraph, vod->v3d, vod->rv3d);
|
||||
viewops_data_free(C, op->customdata);
|
||||
op->customdata = NULL;
|
||||
return OPERATOR_CANCELLED;
|
||||
else if (event->type == vod->init.event_type) {
|
||||
/* Check `vod->init.event_type` first in case RMB was used to invoke.
|
||||
* in this case confirming takes precedence over canceling, see: T102937. */
|
||||
if (event->val == KM_RELEASE) {
|
||||
event_code = VIEW_CONFIRM;
|
||||
}
|
||||
}
|
||||
else if (ELEM(event->type, EVT_ESCKEY, RIGHTMOUSE)) {
|
||||
if (event->val == KM_PRESS) {
|
||||
event_code = VIEW_CANCEL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (event_code == VIEW_APPLY) {
|
||||
viewroll_apply(vod, event->xy[0], event->xy[1]);
|
||||
if (ED_screen_animation_playing(CTX_wm_manager(C))) {
|
||||
use_autokey = true;
|
||||
switch (event_code) {
|
||||
case VIEW_APPLY: {
|
||||
viewroll_apply(vod, event->xy[0], event->xy[1]);
|
||||
if (ED_screen_animation_playing(CTX_wm_manager(C))) {
|
||||
use_autokey = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case VIEW_CONFIRM: {
|
||||
use_autokey = true;
|
||||
ret = OPERATOR_FINISHED;
|
||||
break;
|
||||
}
|
||||
case VIEW_CANCEL: {
|
||||
/* Note this does not remove auto-keys on locked cameras. */
|
||||
copy_qt_qt(vod->rv3d->viewquat, vod->init.quat);
|
||||
ED_view3d_camera_lock_sync(vod->depsgraph, vod->v3d, vod->rv3d);
|
||||
ret = OPERATOR_CANCELLED;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (event_code == VIEW_CONFIRM) {
|
||||
use_autokey = true;
|
||||
ret = OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
if (use_autokey) {
|
||||
ED_view3d_camera_lock_autokey(vod->v3d, vod->rv3d, C, true, false);
|
||||
}
|
||||
|
||||
if (ret & OPERATOR_FINISHED) {
|
||||
if ((ret & OPERATOR_RUNNING_MODAL) == 0) {
|
||||
viewops_data_free(C, op->customdata);
|
||||
op->customdata = NULL;
|
||||
}
|
||||
|
@@ -182,7 +182,7 @@ static void viewrotate_apply_snap(ViewOpsData *vod)
|
||||
}
|
||||
}
|
||||
else if (U.uiflag & USER_AUTOPERSP) {
|
||||
rv3d->persp = vod->init.persp;
|
||||
rv3d->persp = vod->init.persp_with_auto_persp_applied;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -327,11 +327,8 @@ static int viewrotate_modal(bContext *C, wmOperator *op, const wmEvent *event)
|
||||
bool use_autokey = false;
|
||||
int ret = OPERATOR_RUNNING_MODAL;
|
||||
|
||||
/* execute the events */
|
||||
if (event->type == MOUSEMOVE) {
|
||||
event_code = VIEW_APPLY;
|
||||
}
|
||||
else if (event->type == EVT_MODAL_MAP) {
|
||||
/* Execute the events. */
|
||||
if (event->type == EVT_MODAL_MAP) {
|
||||
switch (event->val) {
|
||||
case VIEW_MODAL_CONFIRM:
|
||||
event_code = VIEW_CONFIRM;
|
||||
@@ -341,7 +338,7 @@ static int viewrotate_modal(bContext *C, wmOperator *op, const wmEvent *event)
|
||||
event_code = VIEW_APPLY;
|
||||
break;
|
||||
case VIEWROT_MODAL_AXIS_SNAP_DISABLE:
|
||||
vod->rv3d->persp = vod->init.persp;
|
||||
vod->rv3d->persp = vod->init.persp_with_auto_persp_applied;
|
||||
vod->axis_snap = false;
|
||||
event_code = VIEW_APPLY;
|
||||
break;
|
||||
@@ -355,27 +352,64 @@ static int viewrotate_modal(bContext *C, wmOperator *op, const wmEvent *event)
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (event->type == vod->init.event_type && event->val == KM_RELEASE) {
|
||||
event_code = VIEW_CONFIRM;
|
||||
}
|
||||
|
||||
if (event_code == VIEW_APPLY) {
|
||||
viewrotate_apply(vod, event->xy);
|
||||
if (ED_screen_animation_playing(CTX_wm_manager(C))) {
|
||||
use_autokey = true;
|
||||
else {
|
||||
if (event->type == MOUSEMOVE) {
|
||||
event_code = VIEW_APPLY;
|
||||
}
|
||||
else if (event->type == vod->init.event_type) {
|
||||
if (event->val == KM_RELEASE) {
|
||||
event_code = VIEW_CONFIRM;
|
||||
}
|
||||
}
|
||||
else if (ELEM(event->type, EVT_ESCKEY, RIGHTMOUSE)) {
|
||||
if (event->val == KM_PRESS) {
|
||||
event_code = VIEW_CANCEL;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (event_code == VIEW_CONFIRM) {
|
||||
use_autokey = true;
|
||||
ret = OPERATOR_FINISHED;
|
||||
|
||||
switch (event_code) {
|
||||
case VIEW_APPLY: {
|
||||
viewrotate_apply(vod, event->xy);
|
||||
if (ED_screen_animation_playing(CTX_wm_manager(C))) {
|
||||
use_autokey = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case VIEW_CONFIRM: {
|
||||
use_autokey = true;
|
||||
ret = OPERATOR_FINISHED;
|
||||
break;
|
||||
}
|
||||
case VIEW_CANCEL: {
|
||||
/* Note this does not remove auto-keys on locked cameras. */
|
||||
copy_qt_qt(vod->rv3d->viewquat, vod->init.quat);
|
||||
/* The offset may have change when rotating around objects or last-brush. */
|
||||
copy_v3_v3(vod->rv3d->ofs, vod->init.ofs);
|
||||
/* The dist may have changed when orbiting from a camera view.
|
||||
* In this case the `dist` is calculated based on the camera relative to the `ofs`. */
|
||||
vod->rv3d->dist = vod->init.dist;
|
||||
|
||||
vod->rv3d->persp = vod->init.persp;
|
||||
vod->rv3d->view = vod->init.view;
|
||||
vod->rv3d->view_axis_roll = vod->init.view_axis_roll;
|
||||
|
||||
/* NOTE: there is no need to restore "last" values (as set by #ED_view3d_lastview_store). */
|
||||
|
||||
ED_view3d_camera_lock_sync(vod->depsgraph, vod->v3d, vod->rv3d);
|
||||
ret = OPERATOR_CANCELLED;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (use_autokey) {
|
||||
ED_view3d_camera_lock_autokey(vod->v3d, vod->rv3d, C, true, true);
|
||||
}
|
||||
|
||||
if (ret & OPERATOR_FINISHED) {
|
||||
ED_view3d_camera_lock_undo_push(op->type->name, vod->v3d, vod->rv3d, C);
|
||||
if ((ret & OPERATOR_RUNNING_MODAL) == 0) {
|
||||
if (ret & OPERATOR_FINISHED) {
|
||||
ED_view3d_camera_lock_undo_push(op->type->name, vod->v3d, vod->rv3d, C);
|
||||
}
|
||||
viewops_data_free(C, op->customdata);
|
||||
op->customdata = NULL;
|
||||
}
|
||||
|
@@ -377,15 +377,8 @@ static int viewzoom_modal(bContext *C, wmOperator *op, const wmEvent *event)
|
||||
bool use_autokey = false;
|
||||
int ret = OPERATOR_RUNNING_MODAL;
|
||||
|
||||
/* execute the events */
|
||||
if (event->type == TIMER && event->customdata == vod->timer) {
|
||||
/* continuous zoom */
|
||||
event_code = VIEW_APPLY;
|
||||
}
|
||||
else if (event->type == MOUSEMOVE) {
|
||||
event_code = VIEW_APPLY;
|
||||
}
|
||||
else if (event->type == EVT_MODAL_MAP) {
|
||||
/* Execute the events. */
|
||||
if (event->type == EVT_MODAL_MAP) {
|
||||
switch (event->val) {
|
||||
case VIEW_MODAL_CONFIRM:
|
||||
event_code = VIEW_CONFIRM;
|
||||
@@ -400,32 +393,70 @@ static int viewzoom_modal(bContext *C, wmOperator *op, const wmEvent *event)
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (event->type == vod->init.event_type && event->val == KM_RELEASE) {
|
||||
event_code = VIEW_CONFIRM;
|
||||
}
|
||||
|
||||
if (event_code == VIEW_APPLY) {
|
||||
const bool use_cursor_init = RNA_boolean_get(op->ptr, "use_cursor_init");
|
||||
viewzoom_apply(vod,
|
||||
event->xy,
|
||||
(eViewZoom_Style)U.viewzoom,
|
||||
(U.uiflag & USER_ZOOM_INVERT) != 0,
|
||||
(use_cursor_init && (U.uiflag & USER_ZOOM_TO_MOUSEPOS)));
|
||||
if (ED_screen_animation_playing(CTX_wm_manager(C))) {
|
||||
use_autokey = true;
|
||||
else {
|
||||
if (event->type == MOUSEMOVE) {
|
||||
event_code = VIEW_APPLY;
|
||||
}
|
||||
else if (event->type == TIMER) {
|
||||
if (event->customdata == vod->timer) {
|
||||
/* Continuous zoom. */
|
||||
event_code = VIEW_APPLY;
|
||||
}
|
||||
}
|
||||
else if (event->type == vod->init.event_type) {
|
||||
if (event->val == KM_RELEASE) {
|
||||
event_code = VIEW_CONFIRM;
|
||||
}
|
||||
}
|
||||
else if (ELEM(event->type, EVT_ESCKEY, RIGHTMOUSE)) {
|
||||
if (event->val == KM_PRESS) {
|
||||
event_code = VIEW_CANCEL;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (event_code == VIEW_CONFIRM) {
|
||||
use_autokey = true;
|
||||
ret = OPERATOR_FINISHED;
|
||||
|
||||
switch (event_code) {
|
||||
case VIEW_APPLY: {
|
||||
const bool use_cursor_init = RNA_boolean_get(op->ptr, "use_cursor_init");
|
||||
viewzoom_apply(vod,
|
||||
event->xy,
|
||||
(eViewZoom_Style)U.viewzoom,
|
||||
(U.uiflag & USER_ZOOM_INVERT) != 0,
|
||||
(use_cursor_init && (U.uiflag & USER_ZOOM_TO_MOUSEPOS)));
|
||||
if (ED_screen_animation_playing(CTX_wm_manager(C))) {
|
||||
use_autokey = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case VIEW_CONFIRM: {
|
||||
use_autokey = true;
|
||||
ret = OPERATOR_FINISHED;
|
||||
break;
|
||||
}
|
||||
case VIEW_CANCEL: {
|
||||
/* Note this does not remove auto-keys on locked cameras. */
|
||||
vod->rv3d->dist = vod->init.dist;
|
||||
/* The offset may have change when zooming to mouse position. */
|
||||
copy_v3_v3(vod->rv3d->ofs, vod->init.ofs);
|
||||
vod->rv3d->camzoom = vod->init.camzoom;
|
||||
/* Zoom to mouse position in camera view changes these values. */
|
||||
vod->rv3d->camdx = vod->init.camdx;
|
||||
vod->rv3d->camdy = vod->init.camdy;
|
||||
|
||||
ED_view3d_camera_lock_sync(vod->depsgraph, vod->v3d, vod->rv3d);
|
||||
ret = OPERATOR_CANCELLED;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (use_autokey) {
|
||||
ED_view3d_camera_lock_autokey(vod->v3d, vod->rv3d, C, false, true);
|
||||
}
|
||||
|
||||
if (ret & OPERATOR_FINISHED) {
|
||||
ED_view3d_camera_lock_undo_push(op->type->name, vod->v3d, vod->rv3d, C);
|
||||
if ((ret & OPERATOR_RUNNING_MODAL) == 0) {
|
||||
if (ret & OPERATOR_FINISHED) {
|
||||
ED_view3d_camera_lock_undo_push(op->type->name, vod->v3d, vod->rv3d, C);
|
||||
}
|
||||
viewops_data_free(C, op->customdata);
|
||||
op->customdata = NULL;
|
||||
}
|
||||
|
@@ -647,7 +647,7 @@ void ED_uvedit_pack_islands_multi(const Scene *scene,
|
||||
Object **objects,
|
||||
const uint objects_len,
|
||||
BMesh **bmesh_override,
|
||||
const struct UVMapUDIM_Params *udim_params,
|
||||
const struct UVMapUDIM_Params *closest_udim,
|
||||
const struct UVPackIsland_Params *params)
|
||||
{
|
||||
blender::Vector<FaceIsland *> island_vector;
|
||||
@@ -716,19 +716,12 @@ void ED_uvedit_pack_islands_multi(const Scene *scene,
|
||||
|
||||
for (int index = 0; index < island_vector.size(); index++) {
|
||||
FaceIsland *island = island_vector[index];
|
||||
/* Skip calculation if using specified UDIM option. */
|
||||
if (udim_params && (udim_params->use_target_udim == false)) {
|
||||
float bounds_min[2], bounds_max[2];
|
||||
INIT_MINMAX2(bounds_min, bounds_max);
|
||||
if (closest_udim) {
|
||||
/* Only calculate selection bounding box if using closest_udim. */
|
||||
for (int i = 0; i < island->faces_len; i++) {
|
||||
BMFace *f = island->faces[i];
|
||||
BM_face_uv_minmax(f, bounds_min, bounds_max, island->cd_loop_uv_offset);
|
||||
BM_face_uv_minmax(f, selection_min_co, selection_max_co, island->cd_loop_uv_offset);
|
||||
}
|
||||
|
||||
selection_min_co[0] = MIN2(bounds_min[0], selection_min_co[0]);
|
||||
selection_min_co[1] = MIN2(bounds_min[1], selection_min_co[1]);
|
||||
selection_max_co[0] = MAX2(bounds_max[0], selection_max_co[0]);
|
||||
selection_max_co[1] = MAX2(bounds_max[1], selection_max_co[1]);
|
||||
}
|
||||
|
||||
if (params->rotate) {
|
||||
@@ -741,7 +734,7 @@ void ED_uvedit_pack_islands_multi(const Scene *scene,
|
||||
|
||||
/* Center of bounding box containing all selected UVs. */
|
||||
float selection_center[2];
|
||||
if (udim_params && (udim_params->use_target_udim == false)) {
|
||||
if (closest_udim) {
|
||||
selection_center[0] = (selection_min_co[0] + selection_max_co[0]) / 2.0f;
|
||||
selection_center[1] = (selection_min_co[1] + selection_max_co[1]) / 2.0f;
|
||||
}
|
||||
@@ -749,25 +742,12 @@ void ED_uvedit_pack_islands_multi(const Scene *scene,
|
||||
float scale[2] = {1.0f, 1.0f};
|
||||
BoxPack *box_array = pack_islands_params(island_vector, *params, scale);
|
||||
|
||||
/* Tile offset. */
|
||||
float base_offset[2] = {0.0f, 0.0f};
|
||||
copy_v2_v2(base_offset, params->udim_base_offset);
|
||||
|
||||
/* CASE: ignore UDIM. */
|
||||
if (udim_params == nullptr) {
|
||||
/* pass */
|
||||
}
|
||||
/* CASE: Active/specified(smart uv project) UDIM. */
|
||||
else if (udim_params->use_target_udim) {
|
||||
|
||||
/* Calculate offset based on specified_tile_index. */
|
||||
base_offset[0] = (udim_params->target_udim - 1001) % 10;
|
||||
base_offset[1] = (udim_params->target_udim - 1001) / 10;
|
||||
}
|
||||
|
||||
/* CASE: Closest UDIM. */
|
||||
else {
|
||||
const Image *image = udim_params->image;
|
||||
const int *udim_grid = udim_params->grid_shape;
|
||||
if (closest_udim) {
|
||||
const Image *image = closest_udim->image;
|
||||
const int *udim_grid = closest_udim->grid_shape;
|
||||
/* Check if selection lies on a valid UDIM grid tile. */
|
||||
bool is_valid_udim = uv_coords_isect_udim(image, udim_grid, selection_center);
|
||||
if (is_valid_udim) {
|
||||
|
@@ -134,54 +134,32 @@ static bool ED_uvedit_ensure_uvs(Object *obedit)
|
||||
/** \name UDIM Access
|
||||
* \{ */
|
||||
|
||||
bool ED_uvedit_udim_params_from_image_space(const SpaceImage *sima,
|
||||
bool use_active,
|
||||
struct UVMapUDIM_Params *udim_params)
|
||||
static void ED_uvedit_udim_params_from_image_space(const SpaceImage *sima,
|
||||
struct UVPackIsland_Params *r_params)
|
||||
{
|
||||
memset(udim_params, 0, sizeof(*udim_params));
|
||||
|
||||
udim_params->grid_shape[0] = 1;
|
||||
udim_params->grid_shape[1] = 1;
|
||||
udim_params->target_udim = 0;
|
||||
udim_params->use_target_udim = false;
|
||||
|
||||
if (sima == NULL) {
|
||||
return false;
|
||||
if (!sima) {
|
||||
return; /* Nothing to do. */
|
||||
}
|
||||
|
||||
udim_params->image = sima->image;
|
||||
udim_params->grid_shape[0] = sima->tile_grid_shape[0];
|
||||
udim_params->grid_shape[1] = sima->tile_grid_shape[1];
|
||||
|
||||
if (use_active) {
|
||||
int active_udim = 1001;
|
||||
/* NOTE: Presently, when UDIM grid and tiled image are present together, only active tile for
|
||||
* the tiled image is considered. */
|
||||
const Image *image = sima->image;
|
||||
if (image && image->source == IMA_SRC_TILED) {
|
||||
ImageTile *active_tile = BLI_findlink(&image->tiles, image->active_tile_index);
|
||||
if (active_tile) {
|
||||
active_udim = active_tile->tile_number;
|
||||
}
|
||||
/* NOTE: Presently, when UDIM grid and tiled image are present together, only active tile for
|
||||
* the tiled image is considered. */
|
||||
const Image *image = sima->image;
|
||||
if (image && image->source == IMA_SRC_TILED) {
|
||||
ImageTile *active_tile = BLI_findlink(&image->tiles, image->active_tile_index);
|
||||
if (active_tile) {
|
||||
r_params->udim_base_offset[0] = (active_tile->tile_number - 1001) % 10;
|
||||
r_params->udim_base_offset[1] = (active_tile->tile_number - 1001) / 10;
|
||||
}
|
||||
else {
|
||||
/* TODO: Support storing an active UDIM when there are no tiles present.
|
||||
* Until then, use 2D cursor to find the active tile index for the UDIM grid. */
|
||||
if (uv_coords_isect_udim(sima->image, sima->tile_grid_shape, sima->cursor)) {
|
||||
int tile_number = 1001;
|
||||
tile_number += floorf(sima->cursor[1]) * 10;
|
||||
tile_number += floorf(sima->cursor[0]);
|
||||
active_udim = tile_number;
|
||||
}
|
||||
}
|
||||
|
||||
udim_params->target_udim = active_udim;
|
||||
udim_params->use_target_udim = true;
|
||||
return;
|
||||
}
|
||||
|
||||
return true;
|
||||
/* TODO: Support storing an active UDIM when there are no tiles present.
|
||||
* Until then, use 2D cursor to find the active tile index for the UDIM grid. */
|
||||
if (uv_coords_isect_udim(sima->image, sima->tile_grid_shape, sima->cursor)) {
|
||||
r_params->udim_base_offset[0] = floorf(sima->cursor[0]);
|
||||
r_params->udim_base_offset[1] = floorf(sima->cursor[1]);
|
||||
}
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
@@ -1088,12 +1066,7 @@ static int pack_islands_exec(bContext *C, wmOperator *op)
|
||||
RNA_float_set(op->ptr, "margin", scene->toolsettings->uvcalc_margin);
|
||||
}
|
||||
|
||||
struct UVMapUDIM_Params udim_params;
|
||||
const bool use_active = (udim_source == PACK_UDIM_SRC_ACTIVE);
|
||||
const bool use_udim_params = ED_uvedit_udim_params_from_image_space(
|
||||
sima, use_active, &udim_params);
|
||||
|
||||
const struct UVPackIsland_Params pack_island_params = {
|
||||
struct UVPackIsland_Params pack_island_params = {
|
||||
.rotate = RNA_boolean_get(op->ptr, "rotate"),
|
||||
.only_selected_uvs = options.only_selected_uvs,
|
||||
.only_selected_faces = options.only_selected_faces,
|
||||
@@ -1104,12 +1077,22 @@ static int pack_islands_exec(bContext *C, wmOperator *op)
|
||||
.margin_method = RNA_enum_get(op->ptr, "margin_method"),
|
||||
.margin = RNA_float_get(op->ptr, "margin"),
|
||||
};
|
||||
ED_uvedit_pack_islands_multi(scene,
|
||||
objects,
|
||||
objects_len,
|
||||
NULL,
|
||||
use_udim_params ? &udim_params : NULL,
|
||||
&pack_island_params);
|
||||
|
||||
struct UVMapUDIM_Params closest_udim_buf;
|
||||
struct UVMapUDIM_Params *closest_udim = NULL;
|
||||
if (udim_source == PACK_UDIM_SRC_ACTIVE) {
|
||||
ED_uvedit_udim_params_from_image_space(sima, &pack_island_params);
|
||||
}
|
||||
else if (sima) {
|
||||
BLI_assert(udim_source == PACK_UDIM_SRC_CLOSEST);
|
||||
closest_udim = &closest_udim_buf;
|
||||
closest_udim->image = sima->image;
|
||||
closest_udim->grid_shape[0] = sima->tile_grid_shape[0];
|
||||
closest_udim->grid_shape[1] = sima->tile_grid_shape[1];
|
||||
}
|
||||
|
||||
ED_uvedit_pack_islands_multi(
|
||||
scene, objects, objects_len, NULL, closest_udim, &pack_island_params);
|
||||
|
||||
MEM_freeN(objects);
|
||||
return OPERATOR_FINISHED;
|
||||
|
@@ -2215,8 +2215,8 @@ struct ImBuf *imb_load_filepath_thumbnail_openexr(const char *filepath,
|
||||
|
||||
float scale_factor = MIN2(float(max_thumb_size) / float(source_w),
|
||||
float(max_thumb_size) / float(source_h));
|
||||
int dest_w = int(source_w * scale_factor);
|
||||
int dest_h = int(source_h * scale_factor);
|
||||
int dest_w = MAX2(int(source_w * scale_factor), 1);
|
||||
int dest_h = MAX2(int(source_h * scale_factor), 1);
|
||||
|
||||
struct ImBuf *ibuf = IMB_allocImBuf(dest_w, dest_h, 32, IB_rectfloat);
|
||||
|
||||
|
@@ -112,8 +112,8 @@ struct ImBuf *imb_load_filepath_thumbnail_webp(const char *filepath,
|
||||
*r_height = (size_t)config.input.height;
|
||||
|
||||
const float scale = (float)max_thumb_size / MAX2(config.input.width, config.input.height);
|
||||
const int dest_w = (int)(config.input.width * scale);
|
||||
const int dest_h = (int)(config.input.height * scale);
|
||||
const int dest_w = MAX2((int)(config.input.width * scale), 1);
|
||||
const int dest_h = MAX2((int)(config.input.height * scale), 1);
|
||||
|
||||
colorspace_set_default_role(colorspace, IM_MAX_SPACE, COLOR_ROLE_DEFAULT_BYTE);
|
||||
struct ImBuf *ibuf = IMB_allocImBuf(dest_w, dest_h, 32, IB_rect);
|
||||
|
@@ -250,7 +250,7 @@ void OBJWriter::write_vertex_coords(FormatHandler &fh,
|
||||
{
|
||||
const int tot_count = obj_mesh_data.tot_vertices();
|
||||
|
||||
Mesh *mesh = obj_mesh_data.get_mesh();
|
||||
const Mesh *mesh = obj_mesh_data.get_mesh();
|
||||
const CustomDataLayer *colors_layer = nullptr;
|
||||
if (write_colors) {
|
||||
colors_layer = BKE_id_attributes_active_color_get(&mesh->id);
|
||||
|
@@ -33,21 +33,23 @@ OBJMesh::OBJMesh(Depsgraph *depsgraph, const OBJExportParams &export_params, Obj
|
||||
/* We need to copy the object because it may be in temporary space. */
|
||||
Object *obj_eval = DEG_get_evaluated_object(depsgraph, mesh_object);
|
||||
export_object_eval_ = dna::shallow_copy(*obj_eval);
|
||||
export_mesh_eval_ = export_params.apply_modifiers ?
|
||||
BKE_object_get_evaluated_mesh(&export_object_eval_) :
|
||||
BKE_object_get_pre_modified_mesh(&export_object_eval_);
|
||||
mesh_eval_needs_free_ = false;
|
||||
|
||||
if (!export_mesh_eval_) {
|
||||
export_mesh_ = export_params.apply_modifiers ?
|
||||
BKE_object_get_evaluated_mesh(&export_object_eval_) :
|
||||
BKE_object_get_pre_modified_mesh(&export_object_eval_);
|
||||
if (export_mesh_) {
|
||||
mesh_verts_ = export_mesh_->verts();
|
||||
mesh_edges_ = export_mesh_->edges();
|
||||
mesh_polys_ = export_mesh_->polys();
|
||||
mesh_loops_ = export_mesh_->loops();
|
||||
}
|
||||
else {
|
||||
/* Curves and NURBS surfaces need a new mesh when they're
|
||||
* exported in the form of vertices and edges.
|
||||
*/
|
||||
export_mesh_eval_ = BKE_mesh_new_from_object(depsgraph, &export_object_eval_, true, true);
|
||||
/* Since a new mesh been allocated, it needs to be freed in the destructor. */
|
||||
mesh_eval_needs_free_ = true;
|
||||
this->set_mesh(BKE_mesh_new_from_object(depsgraph, &export_object_eval_, true, true));
|
||||
}
|
||||
if (export_params.export_triangulated_mesh && export_object_eval_.type == OB_MESH) {
|
||||
std::tie(export_mesh_eval_, mesh_eval_needs_free_) = triangulate_mesh_eval();
|
||||
this->triangulate_mesh_eval();
|
||||
}
|
||||
set_world_axes_transform(export_params.forward_axis, export_params.up_axis);
|
||||
}
|
||||
@@ -60,18 +62,26 @@ OBJMesh::~OBJMesh()
|
||||
clear();
|
||||
}
|
||||
|
||||
void OBJMesh::free_mesh_if_needed()
|
||||
void OBJMesh::set_mesh(Mesh *mesh)
|
||||
{
|
||||
if (mesh_eval_needs_free_ && export_mesh_eval_) {
|
||||
BKE_id_free(nullptr, export_mesh_eval_);
|
||||
export_mesh_eval_ = nullptr;
|
||||
mesh_eval_needs_free_ = false;
|
||||
if (owned_export_mesh_) {
|
||||
BKE_id_free(nullptr, owned_export_mesh_);
|
||||
}
|
||||
owned_export_mesh_ = mesh;
|
||||
export_mesh_ = owned_export_mesh_;
|
||||
mesh_verts_ = mesh->verts();
|
||||
mesh_edges_ = mesh->edges();
|
||||
mesh_polys_ = mesh->polys();
|
||||
mesh_loops_ = mesh->loops();
|
||||
}
|
||||
|
||||
void OBJMesh::clear()
|
||||
{
|
||||
free_mesh_if_needed();
|
||||
if (owned_export_mesh_) {
|
||||
BKE_id_free(nullptr, owned_export_mesh_);
|
||||
owned_export_mesh_ = nullptr;
|
||||
}
|
||||
export_mesh_ = nullptr;
|
||||
uv_indices_.clear_and_make_inline();
|
||||
uv_coords_.clear_and_make_inline();
|
||||
loop_to_normal_index_.clear_and_make_inline();
|
||||
@@ -83,10 +93,10 @@ void OBJMesh::clear()
|
||||
}
|
||||
}
|
||||
|
||||
std::pair<Mesh *, bool> OBJMesh::triangulate_mesh_eval()
|
||||
void OBJMesh::triangulate_mesh_eval()
|
||||
{
|
||||
if (export_mesh_eval_->totpoly <= 0) {
|
||||
return {export_mesh_eval_, false};
|
||||
if (export_mesh_->totpoly <= 0) {
|
||||
return;
|
||||
}
|
||||
const BMeshCreateParams bm_create_params = {false};
|
||||
BMeshFromMeshParams bm_convert_params{};
|
||||
@@ -99,7 +109,7 @@ std::pair<Mesh *, bool> OBJMesh::triangulate_mesh_eval()
|
||||
* triangulated here. */
|
||||
const int triangulate_min_verts = 4;
|
||||
|
||||
BMesh *bmesh = BKE_mesh_to_bmesh_ex(export_mesh_eval_, &bm_create_params, &bm_convert_params);
|
||||
BMesh *bmesh = BKE_mesh_to_bmesh_ex(export_mesh_, &bm_create_params, &bm_convert_params);
|
||||
BM_mesh_triangulate(bmesh,
|
||||
MOD_TRIANGULATE_NGON_BEAUTY,
|
||||
MOD_TRIANGULATE_QUAD_SHORTEDGE,
|
||||
@@ -108,11 +118,9 @@ std::pair<Mesh *, bool> OBJMesh::triangulate_mesh_eval()
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr);
|
||||
|
||||
Mesh *triangulated = BKE_mesh_from_bmesh_for_eval_nomain(bmesh, nullptr, export_mesh_eval_);
|
||||
Mesh *triangulated = BKE_mesh_from_bmesh_for_eval_nomain(bmesh, nullptr, export_mesh_);
|
||||
BM_mesh_free(bmesh);
|
||||
free_mesh_if_needed();
|
||||
return {triangulated, true};
|
||||
this->set_mesh(triangulated);
|
||||
}
|
||||
|
||||
void OBJMesh::set_world_axes_transform(const eIOAxis forward, const eIOAxis up)
|
||||
@@ -137,12 +145,12 @@ void OBJMesh::set_world_axes_transform(const eIOAxis forward, const eIOAxis up)
|
||||
|
||||
int OBJMesh::tot_vertices() const
|
||||
{
|
||||
return export_mesh_eval_->totvert;
|
||||
return export_mesh_->totvert;
|
||||
}
|
||||
|
||||
int OBJMesh::tot_polygons() const
|
||||
{
|
||||
return export_mesh_eval_->totpoly;
|
||||
return export_mesh_->totpoly;
|
||||
}
|
||||
|
||||
int OBJMesh::tot_uv_vertices() const
|
||||
@@ -152,12 +160,12 @@ int OBJMesh::tot_uv_vertices() const
|
||||
|
||||
int OBJMesh::tot_edges() const
|
||||
{
|
||||
return export_mesh_eval_->totedge;
|
||||
return export_mesh_->totedge;
|
||||
}
|
||||
|
||||
int16_t OBJMesh::tot_materials() const
|
||||
{
|
||||
return export_mesh_eval_->totcol;
|
||||
return export_mesh_->totcol;
|
||||
}
|
||||
|
||||
int OBJMesh::tot_normal_indices() const
|
||||
@@ -175,27 +183,25 @@ int OBJMesh::ith_smooth_group(const int poly_index) const
|
||||
|
||||
void OBJMesh::ensure_mesh_normals() const
|
||||
{
|
||||
BKE_mesh_calc_normals_split(export_mesh_eval_);
|
||||
/* Const cast can be removed when calculating face corner normals lazily is possible. */
|
||||
BKE_mesh_calc_normals_split(const_cast<Mesh *>(export_mesh_));
|
||||
}
|
||||
|
||||
void OBJMesh::calc_smooth_groups(const bool use_bitflags)
|
||||
{
|
||||
const Span<MEdge> edges = export_mesh_eval_->edges();
|
||||
const Span<MPoly> polys = export_mesh_eval_->polys();
|
||||
const Span<MLoop> loops = export_mesh_eval_->loops();
|
||||
poly_smooth_groups_ = BKE_mesh_calc_smoothgroups(edges.data(),
|
||||
edges.size(),
|
||||
polys.data(),
|
||||
polys.size(),
|
||||
loops.data(),
|
||||
loops.size(),
|
||||
poly_smooth_groups_ = BKE_mesh_calc_smoothgroups(mesh_edges_.data(),
|
||||
mesh_edges_.size(),
|
||||
mesh_polys_.data(),
|
||||
mesh_polys_.size(),
|
||||
mesh_loops_.data(),
|
||||
mesh_loops_.size(),
|
||||
&tot_smooth_groups_,
|
||||
use_bitflags);
|
||||
}
|
||||
|
||||
void OBJMesh::calc_poly_order()
|
||||
{
|
||||
const bke::AttributeAccessor attributes = export_mesh_eval_->attributes();
|
||||
const bke::AttributeAccessor attributes = export_mesh_->attributes();
|
||||
const VArray<int> material_indices = attributes.lookup_or_default<int>(
|
||||
"material_index", ATTR_DOMAIN_FACE, 0);
|
||||
if (material_indices.is_single() && material_indices.get_internal_single() == 0) {
|
||||
@@ -234,8 +240,7 @@ const Material *OBJMesh::get_object_material(const int16_t mat_nr) const
|
||||
|
||||
bool OBJMesh::is_ith_poly_smooth(const int poly_index) const
|
||||
{
|
||||
const Span<MPoly> polys = export_mesh_eval_->polys();
|
||||
return polys[poly_index].flag & ME_SMOOTH;
|
||||
return mesh_polys_[poly_index].flag & ME_SMOOTH;
|
||||
}
|
||||
|
||||
const char *OBJMesh::get_object_name() const
|
||||
@@ -245,7 +250,7 @@ const char *OBJMesh::get_object_name() const
|
||||
|
||||
const char *OBJMesh::get_object_mesh_name() const
|
||||
{
|
||||
return export_mesh_eval_->id.name + 2;
|
||||
return export_mesh_->id.name + 2;
|
||||
}
|
||||
|
||||
const char *OBJMesh::get_object_material_name(const int16_t mat_nr) const
|
||||
@@ -260,8 +265,7 @@ const char *OBJMesh::get_object_material_name(const int16_t mat_nr) const
|
||||
float3 OBJMesh::calc_vertex_coords(const int vert_index, const float global_scale) const
|
||||
{
|
||||
float3 r_coords;
|
||||
const Span<MVert> verts = export_mesh_eval_->verts();
|
||||
copy_v3_v3(r_coords, verts[vert_index].co);
|
||||
copy_v3_v3(r_coords, mesh_verts_[vert_index].co);
|
||||
mul_m4_v3(world_and_axes_transform_, r_coords);
|
||||
mul_v3_fl(r_coords, global_scale);
|
||||
return r_coords;
|
||||
@@ -269,10 +273,8 @@ float3 OBJMesh::calc_vertex_coords(const int vert_index, const float global_scal
|
||||
|
||||
Vector<int> OBJMesh::calc_poly_vertex_indices(const int poly_index) const
|
||||
{
|
||||
const Span<MPoly> polys = export_mesh_eval_->polys();
|
||||
const Span<MLoop> loops = export_mesh_eval_->loops();
|
||||
const MPoly &mpoly = polys[poly_index];
|
||||
const MLoop *mloop = &loops[mpoly.loopstart];
|
||||
const MPoly &mpoly = mesh_polys_[poly_index];
|
||||
const MLoop *mloop = &mesh_loops_[mpoly.loopstart];
|
||||
const int totloop = mpoly.totloop;
|
||||
Vector<int> r_poly_vertex_indices(totloop);
|
||||
for (int loop_index = 0; loop_index < totloop; loop_index++) {
|
||||
@@ -283,29 +285,27 @@ Vector<int> OBJMesh::calc_poly_vertex_indices(const int poly_index) const
|
||||
|
||||
void OBJMesh::store_uv_coords_and_indices()
|
||||
{
|
||||
const Span<MPoly> polys = export_mesh_eval_->polys();
|
||||
const Span<MLoop> loops = export_mesh_eval_->loops();
|
||||
const int totvert = export_mesh_eval_->totvert;
|
||||
const int totvert = export_mesh_->totvert;
|
||||
const MLoopUV *mloopuv = static_cast<const MLoopUV *>(
|
||||
CustomData_get_layer(&export_mesh_eval_->ldata, CD_MLOOPUV));
|
||||
CustomData_get_layer(&export_mesh_->ldata, CD_MLOOPUV));
|
||||
if (!mloopuv) {
|
||||
tot_uv_vertices_ = 0;
|
||||
return;
|
||||
}
|
||||
const float limit[2] = {STD_UV_CONNECT_LIMIT, STD_UV_CONNECT_LIMIT};
|
||||
|
||||
UvVertMap *uv_vert_map = BKE_mesh_uv_vert_map_create(polys.data(),
|
||||
UvVertMap *uv_vert_map = BKE_mesh_uv_vert_map_create(mesh_polys_.data(),
|
||||
nullptr,
|
||||
nullptr,
|
||||
loops.data(),
|
||||
mesh_loops_.data(),
|
||||
mloopuv,
|
||||
polys.size(),
|
||||
mesh_polys_.size(),
|
||||
totvert,
|
||||
limit,
|
||||
false,
|
||||
false);
|
||||
|
||||
uv_indices_.resize(polys.size());
|
||||
uv_indices_.resize(mesh_polys_.size());
|
||||
/* At least total vertices of a mesh will be present in its texture map. So
|
||||
* reserve minimum space early. */
|
||||
uv_coords_.reserve(totvert);
|
||||
@@ -317,11 +317,11 @@ void OBJMesh::store_uv_coords_and_indices()
|
||||
if (uv_vert->separate) {
|
||||
tot_uv_vertices_ += 1;
|
||||
}
|
||||
const int verts_in_poly = polys[uv_vert->poly_index].totloop;
|
||||
const int verts_in_poly = mesh_polys_[uv_vert->poly_index].totloop;
|
||||
|
||||
/* Store UV vertex coordinates. */
|
||||
uv_coords_.resize(tot_uv_vertices_);
|
||||
const int loopstart = polys[uv_vert->poly_index].loopstart;
|
||||
const int loopstart = mesh_polys_[uv_vert->poly_index].loopstart;
|
||||
Span<float> vert_uv_coords(mloopuv[loopstart + uv_vert->loop_of_poly_index].uv, 2);
|
||||
uv_coords_[tot_uv_vertices_ - 1] = float2(vert_uv_coords[0], vert_uv_coords[1]);
|
||||
|
||||
@@ -339,7 +339,7 @@ Span<int> OBJMesh::calc_poly_uv_indices(const int poly_index) const
|
||||
if (uv_indices_.size() <= 0) {
|
||||
return {};
|
||||
}
|
||||
BLI_assert(poly_index < export_mesh_eval_->totpoly);
|
||||
BLI_assert(poly_index < export_mesh_->totpoly);
|
||||
BLI_assert(poly_index < uv_indices_.size());
|
||||
return uv_indices_[poly_index];
|
||||
}
|
||||
@@ -347,11 +347,9 @@ Span<int> OBJMesh::calc_poly_uv_indices(const int poly_index) const
|
||||
float3 OBJMesh::calc_poly_normal(const int poly_index) const
|
||||
{
|
||||
float3 r_poly_normal;
|
||||
const Span<MVert> verts = export_mesh_eval_->verts();
|
||||
const Span<MPoly> polys = export_mesh_eval_->polys();
|
||||
const Span<MLoop> loops = export_mesh_eval_->loops();
|
||||
const MPoly &poly = polys[poly_index];
|
||||
BKE_mesh_calc_poly_normal(&poly, &loops[poly.loopstart], verts.data(), r_poly_normal);
|
||||
const MPoly &poly = mesh_polys_[poly_index];
|
||||
BKE_mesh_calc_poly_normal(
|
||||
&poly, &mesh_loops_[poly.loopstart], mesh_verts_.data(), r_poly_normal);
|
||||
mul_m3_v3(world_and_axes_normal_transform_, r_poly_normal);
|
||||
normalize_v3(r_poly_normal);
|
||||
return r_poly_normal;
|
||||
@@ -375,8 +373,6 @@ static float3 round_float3_to_n_digits(const float3 &v, int round_digits)
|
||||
|
||||
void OBJMesh::store_normal_coords_and_indices()
|
||||
{
|
||||
const Span<MPoly> polys = export_mesh_eval_->polys();
|
||||
|
||||
/* We'll round normal components to 4 digits.
|
||||
* This will cover up some minor differences
|
||||
* between floating point calculations on different platforms.
|
||||
@@ -386,19 +382,19 @@ void OBJMesh::store_normal_coords_and_indices()
|
||||
int cur_normal_index = 0;
|
||||
Map<float3, int> normal_to_index;
|
||||
/* We don't know how many unique normals there will be, but this is a guess. */
|
||||
normal_to_index.reserve(export_mesh_eval_->totpoly);
|
||||
loop_to_normal_index_.resize(export_mesh_eval_->totloop);
|
||||
normal_to_index.reserve(export_mesh_->totpoly);
|
||||
loop_to_normal_index_.resize(export_mesh_->totloop);
|
||||
loop_to_normal_index_.fill(-1);
|
||||
const float(*lnors)[3] = static_cast<const float(*)[3]>(
|
||||
CustomData_get_layer(&export_mesh_eval_->ldata, CD_NORMAL));
|
||||
for (int poly_index = 0; poly_index < export_mesh_eval_->totpoly; ++poly_index) {
|
||||
const MPoly &mpoly = polys[poly_index];
|
||||
CustomData_get_layer(&export_mesh_->ldata, CD_NORMAL));
|
||||
for (int poly_index = 0; poly_index < export_mesh_->totpoly; ++poly_index) {
|
||||
const MPoly &mpoly = mesh_polys_[poly_index];
|
||||
bool need_per_loop_normals = lnors != nullptr || (mpoly.flag & ME_SMOOTH);
|
||||
if (need_per_loop_normals) {
|
||||
for (int loop_of_poly = 0; loop_of_poly < mpoly.totloop; ++loop_of_poly) {
|
||||
float3 loop_normal;
|
||||
int loop_index = mpoly.loopstart + loop_of_poly;
|
||||
BLI_assert(loop_index < export_mesh_eval_->totloop);
|
||||
BLI_assert(loop_index < export_mesh_->totloop);
|
||||
copy_v3_v3(loop_normal, lnors[loop_index]);
|
||||
mul_m3_v3(world_and_axes_normal_transform_, loop_normal);
|
||||
normalize_v3(loop_normal);
|
||||
@@ -423,7 +419,7 @@ void OBJMesh::store_normal_coords_and_indices()
|
||||
}
|
||||
for (int i = 0; i < mpoly.totloop; ++i) {
|
||||
int loop_index = mpoly.loopstart + i;
|
||||
BLI_assert(loop_index < export_mesh_eval_->totloop);
|
||||
BLI_assert(loop_index < export_mesh_->totloop);
|
||||
loop_to_normal_index_[loop_index] = poly_norm_index;
|
||||
}
|
||||
}
|
||||
@@ -436,8 +432,7 @@ Vector<int> OBJMesh::calc_poly_normal_indices(const int poly_index) const
|
||||
if (loop_to_normal_index_.is_empty()) {
|
||||
return {};
|
||||
}
|
||||
const Span<MPoly> polys = export_mesh_eval_->polys();
|
||||
const MPoly &mpoly = polys[poly_index];
|
||||
const MPoly &mpoly = mesh_polys_[poly_index];
|
||||
const int totloop = mpoly.totloop;
|
||||
Vector<int> r_poly_normal_indices(totloop);
|
||||
for (int poly_loop_index = 0; poly_loop_index < totloop; poly_loop_index++) {
|
||||
@@ -458,19 +453,17 @@ int OBJMesh::tot_deform_groups() const
|
||||
int16_t OBJMesh::get_poly_deform_group_index(const int poly_index,
|
||||
MutableSpan<float> group_weights) const
|
||||
{
|
||||
BLI_assert(poly_index < export_mesh_eval_->totpoly);
|
||||
BLI_assert(poly_index < export_mesh_->totpoly);
|
||||
BLI_assert(group_weights.size() == BKE_object_defgroup_count(&export_object_eval_));
|
||||
const Span<MPoly> polys = export_mesh_eval_->polys();
|
||||
const Span<MLoop> loops = export_mesh_eval_->loops();
|
||||
const Span<MDeformVert> dverts = export_mesh_eval_->deform_verts();
|
||||
const Span<MDeformVert> dverts = export_mesh_->deform_verts();
|
||||
if (dverts.is_empty()) {
|
||||
return NOT_FOUND;
|
||||
}
|
||||
|
||||
group_weights.fill(0);
|
||||
bool found_any_group = false;
|
||||
const MPoly &mpoly = polys[poly_index];
|
||||
const MLoop *mloop = &loops[mpoly.loopstart];
|
||||
const MPoly &mpoly = mesh_polys_[poly_index];
|
||||
const MLoop *mloop = &mesh_loops_[mpoly.loopstart];
|
||||
for (int loop_i = 0; loop_i < mpoly.totloop; ++loop_i, ++mloop) {
|
||||
const MDeformVert &dv = dverts[mloop->v];
|
||||
for (int weight_i = 0; weight_i < dv.totweight; ++weight_i) {
|
||||
|
@@ -35,11 +35,15 @@ class OBJMesh : NonCopyable {
|
||||
* sometimes builds an Object in a temporary space that doesn't persist.
|
||||
*/
|
||||
Object export_object_eval_;
|
||||
Mesh *export_mesh_eval_;
|
||||
/**
|
||||
* For curves which are converted to mesh, and triangulated meshes, a new mesh is allocated.
|
||||
*/
|
||||
bool mesh_eval_needs_free_ = false;
|
||||
/** A pointer to #owned_export_mesh_ or the object'ed evaluated/original mesh. */
|
||||
const Mesh *export_mesh_;
|
||||
/** A mesh owned here, if created or modified for the export. May be null. */
|
||||
Mesh *owned_export_mesh_ = nullptr;
|
||||
Span<MVert> mesh_verts_;
|
||||
Span<MEdge> mesh_edges_;
|
||||
Span<MPoly> mesh_polys_;
|
||||
Span<MLoop> mesh_loops_;
|
||||
|
||||
/**
|
||||
* Final transform of an object obtained from export settings (up_axis, forward_axis) and the
|
||||
* object's world transform matrix.
|
||||
@@ -216,23 +220,19 @@ class OBJMesh : NonCopyable {
|
||||
return i < 0 || i >= poly_order_.size() ? i : poly_order_[i];
|
||||
}
|
||||
|
||||
Mesh *get_mesh() const
|
||||
const Mesh *get_mesh() const
|
||||
{
|
||||
return export_mesh_eval_;
|
||||
return export_mesh_;
|
||||
}
|
||||
|
||||
private:
|
||||
/** Override the mesh from the export scene's object. Takes ownership of the mesh. */
|
||||
void set_mesh(Mesh *mesh);
|
||||
/**
|
||||
* Free the mesh if _the exporter_ created it.
|
||||
* Triangulate the mesh pointed to by this object, potentially replacing it with a newly created
|
||||
* mesh.
|
||||
*/
|
||||
void free_mesh_if_needed();
|
||||
/**
|
||||
* Allocate a new Mesh with triangulated polygons.
|
||||
*
|
||||
* The returned mesh can be the same as the old one.
|
||||
* \return Owning pointer to the new Mesh, and whether a new Mesh was created.
|
||||
*/
|
||||
std::pair<Mesh *, bool> triangulate_mesh_eval();
|
||||
void triangulate_mesh_eval();
|
||||
/**
|
||||
* Set the final transform after applying axes settings and an Object's world transform.
|
||||
*/
|
||||
|
@@ -266,8 +266,8 @@ typedef struct Object {
|
||||
/** Old animation system, deprecated for 2.5. */
|
||||
struct Ipo *ipo DNA_DEPRECATED;
|
||||
/* struct Path *path; */
|
||||
struct bAction *action DNA_DEPRECATED; /* XXX deprecated... old animation system */
|
||||
struct bAction *poselib;
|
||||
struct bAction *action DNA_DEPRECATED; /* XXX deprecated... old animation system */
|
||||
struct bAction *poselib DNA_DEPRECATED; /* Pre-Blender 3.0 pose library, deprecated in 3.5. */
|
||||
/** Pose data, armature objects only. */
|
||||
struct bPose *pose;
|
||||
/** Pointer to objects data - an 'ID' or NULL. */
|
||||
|
@@ -1033,6 +1033,7 @@ static void rna_def_tex_slot(BlenderRNA *brna)
|
||||
RNA_def_property_string_funcs(
|
||||
prop, "rna_TexPaintSlot_name_get", "rna_TexPaintSlot_name_length", NULL);
|
||||
RNA_def_property_ui_text(prop, "Name", "Name of the slot");
|
||||
RNA_def_struct_name_property(srna, prop);
|
||||
|
||||
prop = RNA_def_property(srna, "icon_value", PROP_INT, PROP_NONE);
|
||||
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
|
||||
|
@@ -3750,15 +3750,6 @@ static void rna_def_object(BlenderRNA *brna)
|
||||
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_GPencil_update");
|
||||
|
||||
/* pose */
|
||||
prop = RNA_def_property(srna, "pose_library", PROP_POINTER, PROP_NONE);
|
||||
RNA_def_property_pointer_sdna(prop, NULL, "poselib");
|
||||
RNA_def_property_struct_type(prop, "Action");
|
||||
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT);
|
||||
RNA_def_property_ui_text(prop,
|
||||
"Pose Library",
|
||||
"Deprecated, will be removed in Blender 3.3. "
|
||||
"Action used as a pose library for armatures");
|
||||
|
||||
prop = RNA_def_property(srna, "pose", PROP_POINTER, PROP_NONE);
|
||||
RNA_def_property_pointer_sdna(prop, NULL, "pose");
|
||||
RNA_def_property_struct_type(prop, "Pose");
|
||||
|
@@ -99,6 +99,10 @@ static const EnumPropertyItem event_ndof_type_items[] = {
|
||||
{NDOF_BUTTON_DOMINANT, "NDOF_BUTTON_DOMINANT", 0, "Dominant", ""},
|
||||
{NDOF_BUTTON_PLUS, "NDOF_BUTTON_PLUS", 0, "Plus", ""},
|
||||
{NDOF_BUTTON_MINUS, "NDOF_BUTTON_MINUS", 0, "Minus", ""},
|
||||
/* View buttons. */
|
||||
{NDOF_BUTTON_V1, "NDOF_BUTTON_V1", 0, "View 1", ""},
|
||||
{NDOF_BUTTON_V2, "NDOF_BUTTON_V2", 0, "View 2", ""},
|
||||
{NDOF_BUTTON_V3, "NDOF_BUTTON_V3", 0, "View 3", ""},
|
||||
/* general-purpose buttons */
|
||||
{NDOF_BUTTON_1, "NDOF_BUTTON_1", 0, "Button 1", ""},
|
||||
{NDOF_BUTTON_2, "NDOF_BUTTON_2", 0, "Button 2", ""},
|
||||
@@ -113,10 +117,6 @@ static const EnumPropertyItem event_ndof_type_items[] = {
|
||||
{NDOF_BUTTON_A, "NDOF_BUTTON_A", 0, "Button A", ""},
|
||||
{NDOF_BUTTON_B, "NDOF_BUTTON_B", 0, "Button B", ""},
|
||||
{NDOF_BUTTON_C, "NDOF_BUTTON_C", 0, "Button C", ""},
|
||||
/* View buttons. */
|
||||
{NDOF_BUTTON_V1, "NDOF_BUTTON_V1", 0, "View 1", ""},
|
||||
{NDOF_BUTTON_V2, "NDOF_BUTTON_V2", 0, "View 2", ""},
|
||||
{NDOF_BUTTON_V3, "NDOF_BUTTON_V3", 0, "View 3", ""},
|
||||
# if 0 /* Never used (converted to keyboard events by GHOST). */
|
||||
/* keyboard emulation */
|
||||
{NDOF_BUTTON_ESC, "NDOF_BUTTON_ESC", 0, "Esc"},
|
||||
@@ -347,6 +347,10 @@ const EnumPropertyItem rna_enum_event_type_items[] = {
|
||||
{NDOF_BUTTON_SHIFT, "NDOF_BUTTON_SHIFT", 0, "NDOF Shift", "NdofShift"},
|
||||
{NDOF_BUTTON_CTRL, "NDOF_BUTTON_CTRL", 0, "NDOF Ctrl", "NdofCtrl"},
|
||||
#endif
|
||||
/* View buttons. */
|
||||
{NDOF_BUTTON_V1, "NDOF_BUTTON_V1", 0, "NDOF View 1", ""},
|
||||
{NDOF_BUTTON_V2, "NDOF_BUTTON_V2", 0, "NDOF View 2", ""},
|
||||
{NDOF_BUTTON_V3, "NDOF_BUTTON_V3", 0, "NDOF View 3", ""},
|
||||
/* general-purpose buttons */
|
||||
{NDOF_BUTTON_1, "NDOF_BUTTON_1", 0, "NDOF Button 1", "NdofB1"},
|
||||
{NDOF_BUTTON_2, "NDOF_BUTTON_2", 0, "NDOF Button 2", "NdofB2"},
|
||||
|
@@ -372,104 +372,110 @@ static void calculate_cone_faces(const ConeConfig &config,
|
||||
MutableSpan<MLoop> loops,
|
||||
MutableSpan<MPoly> polys)
|
||||
{
|
||||
int loop_index = 0;
|
||||
int poly_index = 0;
|
||||
|
||||
int rings_poly_start;
|
||||
int rings_loop_start;
|
||||
if (config.top_has_center_vert) {
|
||||
rings_poly_start = config.circle_segments;
|
||||
rings_loop_start = config.circle_segments * 3;
|
||||
|
||||
/* Top cone tip or center triangle fan in the fill. */
|
||||
const int top_center_vert = 0;
|
||||
const int top_fan_edges_start = 0;
|
||||
|
||||
for (const int i : IndexRange(config.circle_segments)) {
|
||||
MPoly &poly = polys[poly_index++];
|
||||
poly.loopstart = loop_index;
|
||||
const int loop_start = i * 3;
|
||||
MPoly &poly = polys[i];
|
||||
poly.loopstart = loop_start;
|
||||
poly.totloop = 3;
|
||||
|
||||
MLoop &loop_a = loops[loop_index++];
|
||||
loop_a.v = config.first_ring_verts_start + i;
|
||||
loop_a.e = config.first_ring_edges_start + i;
|
||||
MLoop &loop_b = loops[loop_index++];
|
||||
loop_b.v = config.first_ring_verts_start + ((i + 1) % config.circle_segments);
|
||||
loop_b.e = top_fan_edges_start + ((i + 1) % config.circle_segments);
|
||||
MLoop &loop_c = loops[loop_index++];
|
||||
loop_c.v = top_center_vert;
|
||||
loop_c.e = top_fan_edges_start + i;
|
||||
loops[loop_start + 0].v = config.first_ring_verts_start + i;
|
||||
loops[loop_start + 0].e = config.first_ring_edges_start + i;
|
||||
|
||||
loops[loop_start + 1].v = config.first_ring_verts_start + ((i + 1) % config.circle_segments);
|
||||
loops[loop_start + 1].e = top_fan_edges_start + ((i + 1) % config.circle_segments);
|
||||
|
||||
loops[loop_start + 2].v = top_center_vert;
|
||||
loops[loop_start + 2].e = top_fan_edges_start + i;
|
||||
}
|
||||
}
|
||||
else if (config.fill_type == GEO_NODE_MESH_CIRCLE_FILL_NGON) {
|
||||
rings_poly_start = 1;
|
||||
rings_loop_start = config.circle_segments;
|
||||
|
||||
/* Center n-gon in the fill. */
|
||||
MPoly &poly = polys[poly_index++];
|
||||
poly.loopstart = loop_index;
|
||||
MPoly &poly = polys[0];
|
||||
poly.loopstart = 0;
|
||||
poly.totloop = config.circle_segments;
|
||||
for (const int i : IndexRange(config.circle_segments)) {
|
||||
MLoop &loop = loops[loop_index++];
|
||||
loop.v = i;
|
||||
loop.e = i;
|
||||
loops[i].v = i;
|
||||
loops[i].e = i;
|
||||
}
|
||||
}
|
||||
|
||||
/* Quads connect one edge ring to the next one. */
|
||||
if (config.tot_quad_rings > 0) {
|
||||
for (const int i : IndexRange(config.tot_quad_rings)) {
|
||||
const int this_ring_vert_start = config.first_ring_verts_start +
|
||||
(i * config.circle_segments);
|
||||
const int next_ring_vert_start = this_ring_vert_start + config.circle_segments;
|
||||
for (const int i : IndexRange(config.tot_quad_rings)) {
|
||||
const int this_ring_poly_start = rings_poly_start + i * config.circle_segments;
|
||||
const int this_ring_loop_start = rings_loop_start + i * config.circle_segments * 4;
|
||||
const int this_ring_vert_start = config.first_ring_verts_start + (i * config.circle_segments);
|
||||
const int next_ring_vert_start = this_ring_vert_start + config.circle_segments;
|
||||
|
||||
const int this_ring_edges_start = config.first_ring_edges_start +
|
||||
(i * 2 * config.circle_segments);
|
||||
const int next_ring_edges_start = this_ring_edges_start + (2 * config.circle_segments);
|
||||
const int ring_connections_start = this_ring_edges_start + config.circle_segments;
|
||||
const int this_ring_edges_start = config.first_ring_edges_start +
|
||||
(i * 2 * config.circle_segments);
|
||||
const int next_ring_edges_start = this_ring_edges_start + (2 * config.circle_segments);
|
||||
const int ring_connections_start = this_ring_edges_start + config.circle_segments;
|
||||
|
||||
for (const int j : IndexRange(config.circle_segments)) {
|
||||
MPoly &poly = polys[poly_index++];
|
||||
poly.loopstart = loop_index;
|
||||
poly.totloop = 4;
|
||||
for (const int j : IndexRange(config.circle_segments)) {
|
||||
const int loop_start = this_ring_loop_start + j * 4;
|
||||
MPoly &poly = polys[this_ring_poly_start + j];
|
||||
poly.loopstart = loop_start;
|
||||
poly.totloop = 4;
|
||||
|
||||
MLoop &loop_a = loops[loop_index++];
|
||||
loop_a.v = this_ring_vert_start + j;
|
||||
loop_a.e = ring_connections_start + j;
|
||||
MLoop &loop_b = loops[loop_index++];
|
||||
loop_b.v = next_ring_vert_start + j;
|
||||
loop_b.e = next_ring_edges_start + j;
|
||||
MLoop &loop_c = loops[loop_index++];
|
||||
loop_c.v = next_ring_vert_start + ((j + 1) % config.circle_segments);
|
||||
loop_c.e = ring_connections_start + ((j + 1) % config.circle_segments);
|
||||
MLoop &loop_d = loops[loop_index++];
|
||||
loop_d.v = this_ring_vert_start + ((j + 1) % config.circle_segments);
|
||||
loop_d.e = this_ring_edges_start + j;
|
||||
}
|
||||
loops[loop_start + 0].v = this_ring_vert_start + j;
|
||||
loops[loop_start + 0].e = ring_connections_start + j;
|
||||
|
||||
loops[loop_start + 1].v = next_ring_vert_start + j;
|
||||
loops[loop_start + 1].e = next_ring_edges_start + j;
|
||||
|
||||
loops[loop_start + 2].v = next_ring_vert_start + ((j + 1) % config.circle_segments);
|
||||
loops[loop_start + 2].e = ring_connections_start + ((j + 1) % config.circle_segments);
|
||||
|
||||
loops[loop_start + 3].v = this_ring_vert_start + ((j + 1) % config.circle_segments);
|
||||
loops[loop_start + 3].e = this_ring_edges_start + j;
|
||||
}
|
||||
}
|
||||
|
||||
const int bottom_poly_start = rings_poly_start + config.tot_quad_rings * config.circle_segments;
|
||||
const int bottom_loop_start = rings_loop_start +
|
||||
config.tot_quad_rings * config.circle_segments * 4;
|
||||
|
||||
if (config.bottom_has_center_vert) {
|
||||
/* Bottom cone tip or center triangle fan in the fill. */
|
||||
for (const int i : IndexRange(config.circle_segments)) {
|
||||
MPoly &poly = polys[poly_index++];
|
||||
poly.loopstart = loop_index;
|
||||
const int loop_start = bottom_loop_start + i * 3;
|
||||
MPoly &poly = polys[bottom_poly_start + i];
|
||||
poly.loopstart = loop_start;
|
||||
poly.totloop = 3;
|
||||
|
||||
MLoop &loop_a = loops[loop_index++];
|
||||
loop_a.v = config.last_ring_verts_start + i;
|
||||
loop_a.e = config.last_fan_edges_start + i;
|
||||
MLoop &loop_b = loops[loop_index++];
|
||||
loop_b.v = config.last_vert;
|
||||
loop_b.e = config.last_fan_edges_start + (i + 1) % config.circle_segments;
|
||||
MLoop &loop_c = loops[loop_index++];
|
||||
loop_c.v = config.last_ring_verts_start + (i + 1) % config.circle_segments;
|
||||
loop_c.e = config.last_ring_edges_start + i;
|
||||
loops[loop_start + 0].v = config.last_ring_verts_start + i;
|
||||
loops[loop_start + 0].e = config.last_fan_edges_start + i;
|
||||
|
||||
loops[loop_start + 1].v = config.last_vert;
|
||||
loops[loop_start + 1].e = config.last_fan_edges_start + (i + 1) % config.circle_segments;
|
||||
|
||||
loops[loop_start + 2].v = config.last_ring_verts_start + (i + 1) % config.circle_segments;
|
||||
loops[loop_start + 2].e = config.last_ring_edges_start + i;
|
||||
}
|
||||
}
|
||||
else if (config.fill_type == GEO_NODE_MESH_CIRCLE_FILL_NGON) {
|
||||
/* Center n-gon in the fill. */
|
||||
MPoly &poly = polys[poly_index++];
|
||||
poly.loopstart = loop_index;
|
||||
MPoly &poly = polys[bottom_poly_start];
|
||||
poly.loopstart = bottom_loop_start;
|
||||
poly.totloop = config.circle_segments;
|
||||
|
||||
for (const int i : IndexRange(config.circle_segments)) {
|
||||
/* Go backwards to reverse surface normal. */
|
||||
MLoop &loop = loops[loop_index++];
|
||||
loop.v = config.last_vert - i;
|
||||
loop.e = config.last_edge - ((i + 1) % config.circle_segments);
|
||||
loops[bottom_loop_start + i].v = config.last_vert - i;
|
||||
loops[bottom_loop_start + i].e = config.last_edge - ((i + 1) % config.circle_segments);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -184,71 +184,74 @@ BLI_NOINLINE static void calculate_sphere_corners(MutableSpan<MLoop> loops,
|
||||
const int segments,
|
||||
const int rings)
|
||||
{
|
||||
int loop_index = 0;
|
||||
auto segment_next_or_first = [&](const int segment) {
|
||||
return segment == segments - 1 ? 0 : segment + 1;
|
||||
};
|
||||
|
||||
/* Add the triangles connected to the top vertex. */
|
||||
const int first_vert_ring_index_start = 1;
|
||||
const int first_vert_ring_start = 1;
|
||||
for (const int segment : IndexRange(segments)) {
|
||||
const int loop_start = segment * 3;
|
||||
const int segment_next = segment_next_or_first(segment);
|
||||
|
||||
MLoop &loop_a = loops[loop_index++];
|
||||
loop_a.v = 0;
|
||||
loop_a.e = segment;
|
||||
MLoop &loop_b = loops[loop_index++];
|
||||
loop_b.v = first_vert_ring_index_start + segment;
|
||||
loop_b.e = segments + segment;
|
||||
MLoop &loop_c = loops[loop_index++];
|
||||
loop_c.v = first_vert_ring_index_start + segment_next;
|
||||
loop_c.e = segment_next;
|
||||
loops[loop_start + 0].v = 0;
|
||||
loops[loop_start + 0].e = segment;
|
||||
|
||||
loops[loop_start + 1].v = first_vert_ring_start + segment;
|
||||
loops[loop_start + 1].e = segments + segment;
|
||||
|
||||
loops[loop_start + 2].v = first_vert_ring_start + segment_next;
|
||||
loops[loop_start + 2].e = segment_next;
|
||||
}
|
||||
|
||||
int ring_vert_index_start = 1;
|
||||
int ring_edge_index_start = segments;
|
||||
for ([[maybe_unused]] const int ring : IndexRange(1, rings - 2)) {
|
||||
const int next_ring_vert_index_start = ring_vert_index_start + segments;
|
||||
const int next_ring_edge_index_start = ring_edge_index_start + segments * 2;
|
||||
const int ring_vertical_edge_index_start = ring_edge_index_start + segments;
|
||||
const int rings_vert_start = 1;
|
||||
const int rings_edge_start = segments;
|
||||
const int rings_loop_start = segments * 3;
|
||||
for (const int ring : IndexRange(1, rings - 2)) {
|
||||
const int ring_vert_start = rings_vert_start + (ring - 1) * segments;
|
||||
const int ring_edge_start = rings_edge_start + (ring - 1) * segments * 2;
|
||||
const int ring_loop_start = rings_loop_start + (ring - 1) * segments * 4;
|
||||
|
||||
const int next_ring_vert_start = ring_vert_start + segments;
|
||||
const int next_ring_edge_start = ring_edge_start + segments * 2;
|
||||
const int ring_vertical_edge_start = ring_edge_start + segments;
|
||||
|
||||
for (const int segment : IndexRange(segments)) {
|
||||
const int loop_start = ring_loop_start + segment * 4;
|
||||
const int segment_next = segment_next_or_first(segment);
|
||||
|
||||
MLoop &loop_a = loops[loop_index++];
|
||||
loop_a.v = ring_vert_index_start + segment;
|
||||
loop_a.e = ring_vertical_edge_index_start + segment;
|
||||
MLoop &loop_b = loops[loop_index++];
|
||||
loop_b.v = next_ring_vert_index_start + segment;
|
||||
loop_b.e = next_ring_edge_index_start + segment;
|
||||
MLoop &loop_c = loops[loop_index++];
|
||||
loop_c.v = next_ring_vert_index_start + segment_next;
|
||||
loop_c.e = ring_vertical_edge_index_start + segment_next;
|
||||
MLoop &loop_d = loops[loop_index++];
|
||||
loop_d.v = ring_vert_index_start + segment_next;
|
||||
loop_d.e = ring_edge_index_start + segment;
|
||||
loops[loop_start + 0].v = ring_vert_start + segment;
|
||||
loops[loop_start + 0].e = ring_vertical_edge_start + segment;
|
||||
|
||||
loops[loop_start + 1].v = next_ring_vert_start + segment;
|
||||
loops[loop_start + 1].e = next_ring_edge_start + segment;
|
||||
|
||||
loops[loop_start + 2].v = next_ring_vert_start + segment_next;
|
||||
loops[loop_start + 2].e = ring_vertical_edge_start + segment_next;
|
||||
|
||||
loops[loop_start + 3].v = ring_vert_start + segment_next;
|
||||
loops[loop_start + 3].e = ring_edge_start + segment;
|
||||
}
|
||||
ring_vert_index_start += segments;
|
||||
ring_edge_index_start += segments * 2;
|
||||
}
|
||||
|
||||
/* Add the triangles connected to the bottom vertex. */
|
||||
const int bottom_loop_start = rings_loop_start + segments * (rings - 2) * 4;
|
||||
const int last_edge_ring_start = segments * (rings - 2) * 2 + segments;
|
||||
const int bottom_edge_fan_start = last_edge_ring_start + segments;
|
||||
const int last_vert_index = sphere_vert_total(segments, rings) - 1;
|
||||
const int last_vert_ring_start = last_vert_index - segments;
|
||||
for (const int segment : IndexRange(segments)) {
|
||||
const int loop_start = bottom_loop_start + segment * 3;
|
||||
const int segment_next = segment_next_or_first(segment);
|
||||
|
||||
MLoop &loop_a = loops[loop_index++];
|
||||
loop_a.v = last_vert_index;
|
||||
loop_a.e = bottom_edge_fan_start + segment_next;
|
||||
MLoop &loop_b = loops[loop_index++];
|
||||
loop_b.v = last_vert_ring_start + segment_next;
|
||||
loop_b.e = last_edge_ring_start + segment;
|
||||
MLoop &loop_c = loops[loop_index++];
|
||||
loop_c.v = last_vert_ring_start + segment;
|
||||
loop_c.e = bottom_edge_fan_start + segment;
|
||||
loops[loop_start + 0].v = last_vert_index;
|
||||
loops[loop_start + 0].e = bottom_edge_fan_start + segment_next;
|
||||
|
||||
loops[loop_start + 1].v = last_vert_ring_start + segment_next;
|
||||
loops[loop_start + 1].e = last_edge_ring_start + segment;
|
||||
|
||||
loops[loop_start + 2].v = last_vert_ring_start + segment;
|
||||
loops[loop_start + 2].e = bottom_edge_fan_start + segment;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -260,34 +263,39 @@ BLI_NOINLINE static void calculate_sphere_uvs(Mesh *mesh, const float segments,
|
||||
"uv_map", ATTR_DOMAIN_CORNER);
|
||||
MutableSpan<float2> uvs = uv_attribute.span;
|
||||
|
||||
int loop_index = 0;
|
||||
const float dy = 1.0f / rings;
|
||||
|
||||
const float segments_inv = 1.0f / segments;
|
||||
|
||||
for (const int i_segment : IndexRange(segments)) {
|
||||
const int loop_start = i_segment * 3;
|
||||
const float segment = float(i_segment);
|
||||
uvs[loop_index++] = float2((segment + 0.5f) * segments_inv, 0.0f);
|
||||
uvs[loop_index++] = float2(segment * segments_inv, dy);
|
||||
uvs[loop_index++] = float2((segment + 1.0f) * segments_inv, dy);
|
||||
uvs[loop_start + 0] = float2((segment + 0.5f) * segments_inv, 0.0f);
|
||||
uvs[loop_start + 1] = float2(segment * segments_inv, dy);
|
||||
uvs[loop_start + 2] = float2((segment + 1.0f) * segments_inv, dy);
|
||||
}
|
||||
|
||||
const int rings_loop_start = segments * 3;
|
||||
for (const int i_ring : IndexRange(1, rings - 2)) {
|
||||
const int ring_loop_start = rings_loop_start + (i_ring - 1) * segments * 4;
|
||||
const float ring = float(i_ring);
|
||||
for (const int i_segment : IndexRange(segments)) {
|
||||
const int loop_start = ring_loop_start + i_segment * 4;
|
||||
const float segment = float(i_segment);
|
||||
uvs[loop_index++] = float2(segment * segments_inv, ring / rings);
|
||||
uvs[loop_index++] = float2(segment * segments_inv, (ring + 1.0f) / rings);
|
||||
uvs[loop_index++] = float2((segment + 1.0f) * segments_inv, (ring + 1.0f) / rings);
|
||||
uvs[loop_index++] = float2((segment + 1.0f) * segments_inv, ring / rings);
|
||||
uvs[loop_start + 0] = float2(segment * segments_inv, ring / rings);
|
||||
uvs[loop_start + 1] = float2(segment * segments_inv, (ring + 1.0f) / rings);
|
||||
uvs[loop_start + 2] = float2((segment + 1.0f) * segments_inv, (ring + 1.0f) / rings);
|
||||
uvs[loop_start + 3] = float2((segment + 1.0f) * segments_inv, ring / rings);
|
||||
}
|
||||
}
|
||||
|
||||
const int bottom_loop_start = rings_loop_start + segments * (rings - 2) * 4;
|
||||
for (const int i_segment : IndexRange(segments)) {
|
||||
const int loop_start = bottom_loop_start + i_segment * 3;
|
||||
const float segment = float(i_segment);
|
||||
uvs[loop_index++] = float2((segment + 0.5f) * segments_inv, 1.0f);
|
||||
uvs[loop_index++] = float2((segment + 1.0f) * segments_inv, 1.0f - dy);
|
||||
uvs[loop_index++] = float2(segment * segments_inv, 1.0f - dy);
|
||||
uvs[loop_start + 0] = float2((segment + 0.5f) * segments_inv, 1.0f);
|
||||
uvs[loop_start + 1] = float2((segment + 1.0f) * segments_inv, 1.0f - dy);
|
||||
uvs[loop_start + 2] = float2(segment * segments_inv, 1.0f - dy);
|
||||
}
|
||||
|
||||
uv_attribute.finish();
|
||||
@@ -321,6 +329,8 @@ static Mesh *create_uv_sphere_mesh(const float radius, const int segments, const
|
||||
|
||||
mesh->loose_edges_tag_none();
|
||||
|
||||
BLI_assert(BKE_mesh_is_valid(mesh));
|
||||
|
||||
return mesh;
|
||||
}
|
||||
|
||||
|
@@ -1052,10 +1052,10 @@ static void shader_node_disconnect_inactive_mix_branch(bNodeTree *ntree,
|
||||
static void ntree_shader_disconnect_inactive_mix_branches(bNodeTree *ntree)
|
||||
{
|
||||
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
|
||||
if (node->type == SH_NODE_MIX_SHADER) {
|
||||
if (node->typeinfo->type == SH_NODE_MIX_SHADER) {
|
||||
shader_node_disconnect_inactive_mix_branch(ntree, node, 0, 1, 2, true);
|
||||
}
|
||||
else if (node->type == SH_NODE_MIX) {
|
||||
else if (node->typeinfo->type == SH_NODE_MIX) {
|
||||
const NodeShaderMix *storage = static_cast<NodeShaderMix *>(node->storage);
|
||||
if (storage->data_type == SOCK_FLOAT) {
|
||||
shader_node_disconnect_inactive_mix_branch(ntree, node, 0, 2, 3, storage->clamp_factor);
|
||||
|
@@ -115,8 +115,8 @@ static const struct PyC_StringEnumItems pygpu_imagetype_items[] = {
|
||||
{int(ImageType::FLOAT_1D), "FLOAT_1D"},
|
||||
{int(ImageType::FLOAT_1D_ARRAY), "FLOAT_1D_ARRAY"},
|
||||
{int(ImageType::FLOAT_2D), "FLOAT_2D"},
|
||||
{int(ImageType::FLOAT_2D_ARRAY), "FLOAT"},
|
||||
{int(ImageType::FLOAT_3D), "FLOAT_2D_ARRAY"},
|
||||
{int(ImageType::FLOAT_2D_ARRAY), "FLOAT_2D_ARRAY"},
|
||||
{int(ImageType::FLOAT_3D), "FLOAT_3D"},
|
||||
{int(ImageType::FLOAT_CUBE), "FLOAT_CUBE"},
|
||||
{int(ImageType::FLOAT_CUBE_ARRAY), "FLOAT_CUBE_ARRAY"},
|
||||
{int(ImageType::INT_BUFFER), "INT_BUFFER"},
|
||||
|
@@ -279,25 +279,25 @@ enum {
|
||||
NDOF_BUTTON_DOMINANT = 0x01a3, /* 419 */
|
||||
NDOF_BUTTON_PLUS = 0x01a4, /* 420 */
|
||||
NDOF_BUTTON_MINUS = 0x01a5, /* 421 */
|
||||
/* General-purpose buttons. */
|
||||
NDOF_BUTTON_1 = 0x01a6, /* 422 */
|
||||
NDOF_BUTTON_2 = 0x01a7, /* 423 */
|
||||
NDOF_BUTTON_3 = 0x01a8, /* 424 */
|
||||
NDOF_BUTTON_4 = 0x01a9, /* 425 */
|
||||
NDOF_BUTTON_5 = 0x01aa, /* 426 */
|
||||
NDOF_BUTTON_6 = 0x01ab, /* 427 */
|
||||
NDOF_BUTTON_7 = 0x01ac, /* 428 */
|
||||
NDOF_BUTTON_8 = 0x01ad, /* 429 */
|
||||
NDOF_BUTTON_9 = 0x01ae, /* 430 */
|
||||
NDOF_BUTTON_10 = 0x01af, /* 431 */
|
||||
/* more general-purpose buttons */
|
||||
NDOF_BUTTON_A = 0x01b0, /* 432 */
|
||||
NDOF_BUTTON_B = 0x01b1, /* 433 */
|
||||
NDOF_BUTTON_C = 0x01b2, /* 434 */
|
||||
/* Store/restore views. */
|
||||
NDOF_BUTTON_V1 = 0x01b3, /* 435 */
|
||||
NDOF_BUTTON_V2 = 0x01b4, /* 436 */
|
||||
NDOF_BUTTON_V3 = 0x01b5, /* 437 */
|
||||
NDOF_BUTTON_V1 = 0x01a6, /* 422 */
|
||||
NDOF_BUTTON_V2 = 0x01a7, /* 423 */
|
||||
NDOF_BUTTON_V3 = 0x01a8, /* 424 */
|
||||
/* General-purpose buttons. */
|
||||
NDOF_BUTTON_1 = 0x01aa, /* 426 */
|
||||
NDOF_BUTTON_2 = 0x01ab, /* 427 */
|
||||
NDOF_BUTTON_3 = 0x01ac, /* 428 */
|
||||
NDOF_BUTTON_4 = 0x01ad, /* 429 */
|
||||
NDOF_BUTTON_5 = 0x01ae, /* 430 */
|
||||
NDOF_BUTTON_6 = 0x01af, /* 431 */
|
||||
NDOF_BUTTON_7 = 0x01b0, /* 432 */
|
||||
NDOF_BUTTON_8 = 0x01b1, /* 433 */
|
||||
NDOF_BUTTON_9 = 0x01b2, /* 434 */
|
||||
NDOF_BUTTON_10 = 0x01b3, /* 435 */
|
||||
/* more general-purpose buttons */
|
||||
NDOF_BUTTON_A = 0x01b4, /* 436 */
|
||||
NDOF_BUTTON_B = 0x01b5, /* 437 */
|
||||
NDOF_BUTTON_C = 0x01b6, /* 438 */
|
||||
|
||||
/* Disabled as GHOST converts these to keyboard events
|
||||
* which use regular keyboard event handling logic. */
|
||||
@@ -313,8 +313,8 @@ enum {
|
||||
NDOF_BUTTON_CTRL = 0x01bd, /* 445 */
|
||||
#endif
|
||||
|
||||
#define _NDOF_MAX NDOF_BUTTON_V3
|
||||
#define _NDOF_BUTTON_MAX NDOF_BUTTON_V3
|
||||
#define _NDOF_MAX NDOF_BUTTON_C
|
||||
#define _NDOF_BUTTON_MAX NDOF_BUTTON_C
|
||||
|
||||
/* ********** End of Input devices. ********** */
|
||||
|
||||
|
Reference in New Issue
Block a user