Merge branch 'master' into sculpt-dev

This commit is contained in:
Pablo Dobarro 2021-05-14 19:08:19 +02:00
commit 13bdc4a7e6
82 changed files with 2115 additions and 647 deletions

View File

@ -19,16 +19,16 @@ from __future__ import annotations
def _is_using_buggy_driver():
import bgl
import gpu
# We need to be conservative here because in multi-GPU systems display card
# might be quite old, but others one might be just good.
#
# So We shouldn't disable possible good dedicated cards just because display
# card seems weak. And instead we only blacklist configurations which are
# proven to cause problems.
if bgl.glGetString(bgl.GL_VENDOR) == "ATI Technologies Inc.":
if gpu.platform.vendor_get() == "ATI Technologies Inc.":
import re
version = bgl.glGetString(bgl.GL_VERSION)
version = gpu.platform.version_get()
if version.endswith("Compatibility Profile Context"):
# Old HD 4xxx and 5xxx series drivers did not have driver version
# in the version string, but those cards do not quite work and

View File

@ -46,6 +46,12 @@ CCL_NAMESPACE_BEGIN
/* Geometry */
PackFlags operator|=(PackFlags &pack_flags, uint32_t value)
{
pack_flags = (PackFlags)((uint32_t)pack_flags | value);
return pack_flags;
}
NODE_ABSTRACT_DEFINE(Geometry)
{
NodeType *type = NodeType::add("geometry_base", NULL);
@ -1236,7 +1242,16 @@ void GeometryManager::device_update_bvh(Device *device,
const bool can_refit = scene->bvh != nullptr &&
(bparams.bvh_layout == BVHLayout::BVH_LAYOUT_OPTIX);
const bool pack_all = scene->bvh == nullptr;
PackFlags pack_flags = PackFlags::PACK_NONE;
if (scene->bvh == nullptr) {
pack_flags |= PackFlags::PACK_ALL;
}
if (dscene->prim_visibility.is_modified()) {
pack_flags |= PackFlags::PACK_VISIBILITY;
}
BVH *bvh = scene->bvh;
if (!scene->bvh) {
@ -1274,10 +1289,14 @@ void GeometryManager::device_update_bvh(Device *device,
pack.root_index = -1;
if (!pack_all) {
if (pack_flags != PackFlags::PACK_ALL) {
/* if we do not need to recreate the BVH, then only the vertices are updated, so we can
* safely retake the memory */
dscene->prim_tri_verts.give_data(pack.prim_tri_verts);
if ((pack_flags & PackFlags::PACK_VISIBILITY) != 0) {
dscene->prim_visibility.give_data(pack.prim_visibility);
}
}
else {
/* It is not strictly necessary to skip those resizes we if do not have to repack, as the OS
@ -1306,13 +1325,21 @@ void GeometryManager::device_update_bvh(Device *device,
// Iterate over scene mesh list instead of objects, since 'optix_prim_offset' was calculated
// based on that list, which may be ordered differently from the object list.
foreach (Geometry *geom, scene->geometry) {
if (!pack_all && !geom->is_modified()) {
/* Make a copy of the pack_flags so the current geometry's flags do not pollute the others'.
*/
PackFlags geom_pack_flags = pack_flags;
if (geom->is_modified()) {
geom_pack_flags |= PackFlags::PACK_VERTICES;
}
if (geom_pack_flags == PACK_NONE) {
continue;
}
const pair<int, uint> &info = geometry_to_object_info[geom];
pool.push(function_bind(
&Geometry::pack_primitives, geom, &pack, info.first, info.second, pack_all));
&Geometry::pack_primitives, geom, &pack, info.first, info.second, geom_pack_flags));
}
pool.wait_work();
}
@ -1347,7 +1374,7 @@ void GeometryManager::device_update_bvh(Device *device,
dscene->prim_type.steal_data(pack.prim_type);
dscene->prim_type.copy_to_device();
}
if (pack.prim_visibility.size() && (dscene->prim_visibility.need_realloc() || has_bvh2_layout)) {
if (pack.prim_visibility.size() && (dscene->prim_visibility.is_modified() || has_bvh2_layout)) {
dscene->prim_visibility.steal_data(pack.prim_visibility);
dscene->prim_visibility.copy_to_device();
}
@ -1595,6 +1622,10 @@ void GeometryManager::device_update_preprocess(Device *device, Scene *scene, Pro
}
}
if ((update_flags & VISIBILITY_MODIFIED) != 0) {
dscene->prim_visibility.tag_modified();
}
if (device_update_flags & ATTR_FLOAT_NEEDS_REALLOC) {
dscene->attributes_map.tag_realloc();
dscene->attributes_float.tag_realloc();
@ -1921,7 +1952,8 @@ void GeometryManager::device_update(Device *device,
* Also update the BVH if the transformations change, we cannot rely on tagging the Geometry
* as modified in this case, as we may accumulate displacement if the vertices do not also
* change. */
bool need_update_scene_bvh = (scene->bvh == nullptr || (update_flags & TRANSFORM_MODIFIED) != 0);
bool need_update_scene_bvh = (scene->bvh == nullptr ||
(update_flags & (TRANSFORM_MODIFIED | VISIBILITY_MODIFIED)) != 0);
{
scoped_callback_timer timer([scene](double time) {
if (scene->update_stats) {

View File

@ -43,6 +43,24 @@ class Shader;
class Volume;
struct PackedBVH;
/* Flags used to determine which geometry data need to be packed. */
enum PackFlags : uint32_t {
PACK_NONE = 0u,
/* Pack the geometry information (e.g. triangle or curve keys indices). */
PACK_GEOMETRY = (1u << 0),
/* Pack the vertices, for Meshes and Volumes' bounding meshes. */
PACK_VERTICES = (1u << 1),
/* Pack the visibility flags for each triangle or curve. */
PACK_VISIBILITY = (1u << 2),
PACK_ALL = (PACK_GEOMETRY | PACK_VERTICES | PACK_VISIBILITY),
};
PackFlags operator|=(PackFlags &pack_flags, uint32_t value);
/* Geometry
*
* Base class for geometric types like Mesh and Hair. */
@ -126,7 +144,10 @@ class Geometry : public Node {
int n,
int total);
virtual void pack_primitives(PackedBVH *pack, int object, uint visibility, bool pack_all) = 0;
virtual void pack_primitives(PackedBVH *pack,
int object,
uint visibility,
PackFlags pack_flags) = 0;
/* Check whether the geometry should have own BVH built separately. Briefly,
* own BVH is needed for geometry, if:
@ -191,6 +212,8 @@ class GeometryManager {
TRANSFORM_MODIFIED = (1 << 10),
VISIBILITY_MODIFIED = (1 << 11),
/* tag everything in the manager for an update */
UPDATE_ALL = ~0u,

View File

@ -494,38 +494,47 @@ void Hair::pack_curves(Scene *scene,
}
}
void Hair::pack_primitives(PackedBVH *pack, int object, uint visibility, bool pack_all)
void Hair::pack_primitives(PackedBVH *pack, int object, uint visibility, PackFlags pack_flags)
{
if (curve_first_key.empty())
return;
/* If the BVH does not have to be recreated, we can bail out. */
if (!pack_all) {
return;
/* Separate loop as other arrays are not initialized if their packing is not required. */
if ((pack_flags & PACK_VISIBILITY) != 0) {
unsigned int *prim_visibility = &pack->prim_visibility[optix_prim_offset];
size_t index = 0;
for (size_t j = 0; j < num_curves(); ++j) {
Curve curve = get_curve(j);
for (size_t k = 0; k < curve.num_segments(); ++k, ++index) {
prim_visibility[index] = visibility;
}
}
}
unsigned int *prim_tri_index = &pack->prim_tri_index[optix_prim_offset];
int *prim_type = &pack->prim_type[optix_prim_offset];
unsigned int *prim_visibility = &pack->prim_visibility[optix_prim_offset];
int *prim_index = &pack->prim_index[optix_prim_offset];
int *prim_object = &pack->prim_object[optix_prim_offset];
// 'pack->prim_time' is unused by Embree and OptiX
if ((pack_flags & PACK_GEOMETRY) != 0) {
unsigned int *prim_tri_index = &pack->prim_tri_index[optix_prim_offset];
int *prim_type = &pack->prim_type[optix_prim_offset];
int *prim_index = &pack->prim_index[optix_prim_offset];
int *prim_object = &pack->prim_object[optix_prim_offset];
// 'pack->prim_time' is unused by Embree and OptiX
uint type = has_motion_blur() ?
((curve_shape == CURVE_RIBBON) ? PRIMITIVE_MOTION_CURVE_RIBBON :
PRIMITIVE_MOTION_CURVE_THICK) :
((curve_shape == CURVE_RIBBON) ? PRIMITIVE_CURVE_RIBBON : PRIMITIVE_CURVE_THICK);
uint type = has_motion_blur() ?
((curve_shape == CURVE_RIBBON) ? PRIMITIVE_MOTION_CURVE_RIBBON :
PRIMITIVE_MOTION_CURVE_THICK) :
((curve_shape == CURVE_RIBBON) ? PRIMITIVE_CURVE_RIBBON :
PRIMITIVE_CURVE_THICK);
size_t index = 0;
for (size_t j = 0; j < num_curves(); ++j) {
Curve curve = get_curve(j);
for (size_t k = 0; k < curve.num_segments(); ++k, ++index) {
prim_tri_index[index] = -1;
prim_type[index] = PRIMITIVE_PACK_SEGMENT(type, k);
prim_visibility[index] = visibility;
// Each curve segment points back to its curve index
prim_index[index] = j + prim_offset;
prim_object[index] = object;
size_t index = 0;
for (size_t j = 0; j < num_curves(); ++j) {
Curve curve = get_curve(j);
for (size_t k = 0; k < curve.num_segments(); ++k, ++index) {
prim_tri_index[index] = -1;
prim_type[index] = PRIMITIVE_PACK_SEGMENT(type, k);
// Each curve segment points back to its curve index
prim_index[index] = j + prim_offset;
prim_object[index] = object;
}
}
}
}

View File

@ -146,7 +146,10 @@ class Hair : public Geometry {
/* BVH */
void pack_curves(Scene *scene, float4 *curve_key_co, float4 *curve_data, size_t curvekey_offset);
void pack_primitives(PackedBVH *pack, int object, uint visibility, bool pack_all) override;
void pack_primitives(PackedBVH *pack,
int object,
uint visibility,
PackFlags pack_flags) override;
};
CCL_NAMESPACE_END

View File

@ -805,7 +805,7 @@ void Mesh::pack_patches(uint *patch_data, uint vert_offset, uint face_offset, ui
}
}
void Mesh::pack_primitives(ccl::PackedBVH *pack, int object, uint visibility, bool pack_all)
void Mesh::pack_primitives(ccl::PackedBVH *pack, int object, uint visibility, PackFlags pack_flags)
{
if (triangles.empty())
return;
@ -819,28 +819,38 @@ void Mesh::pack_primitives(ccl::PackedBVH *pack, int object, uint visibility, bo
uint type = has_motion_blur() ? PRIMITIVE_MOTION_TRIANGLE : PRIMITIVE_TRIANGLE;
if (pack_all) {
/* Use optix_prim_offset for indexing as those arrays also contain data for Hair geometries. */
unsigned int *prim_tri_index = &pack->prim_tri_index[optix_prim_offset];
int *prim_type = &pack->prim_type[optix_prim_offset];
/* Separate loop as other arrays are not initialized if their packing is not required. */
if ((pack_flags & PackFlags::PACK_VISIBILITY) != 0) {
unsigned int *prim_visibility = &pack->prim_visibility[optix_prim_offset];
int *prim_index = &pack->prim_index[optix_prim_offset];
int *prim_object = &pack->prim_object[optix_prim_offset];
for (size_t k = 0; k < num_prims; ++k) {
prim_tri_index[k] = (prim_offset + k) * 3;
prim_type[k] = type;
prim_index[k] = prim_offset + k;
prim_object[k] = object;
prim_visibility[k] = visibility;
}
}
for (size_t k = 0; k < num_prims; ++k) {
const Mesh::Triangle t = get_triangle(k);
prim_tri_verts[k * 3] = float3_to_float4(verts[t.v[0]]);
prim_tri_verts[k * 3 + 1] = float3_to_float4(verts[t.v[1]]);
prim_tri_verts[k * 3 + 2] = float3_to_float4(verts[t.v[2]]);
if ((pack_flags & PackFlags::PACK_GEOMETRY) != 0) {
/* Use optix_prim_offset for indexing as those arrays also contain data for Hair geometries. */
unsigned int *prim_tri_index = &pack->prim_tri_index[optix_prim_offset];
int *prim_type = &pack->prim_type[optix_prim_offset];
int *prim_index = &pack->prim_index[optix_prim_offset];
int *prim_object = &pack->prim_object[optix_prim_offset];
for (size_t k = 0; k < num_prims; ++k) {
if ((pack_flags & PackFlags::PACK_GEOMETRY) != 0) {
prim_tri_index[k] = (prim_offset + k) * 3;
prim_type[k] = type;
prim_index[k] = prim_offset + k;
prim_object[k] = object;
}
}
}
if ((pack_flags & PackFlags::PACK_VERTICES) != 0) {
for (size_t k = 0; k < num_prims; ++k) {
const Mesh::Triangle t = get_triangle(k);
prim_tri_verts[k * 3] = float3_to_float4(verts[t.v[0]]);
prim_tri_verts[k * 3 + 1] = float3_to_float4(verts[t.v[1]]);
prim_tri_verts[k * 3 + 2] = float3_to_float4(verts[t.v[2]]);
}
}
}

View File

@ -232,7 +232,10 @@ class Mesh : public Geometry {
size_t tri_offset);
void pack_patches(uint *patch_data, uint vert_offset, uint face_offset, uint corner_offset);
void pack_primitives(PackedBVH *pack, int object, uint visibility, bool pack_all) override;
void pack_primitives(PackedBVH *pack,
int object,
uint visibility,
PackFlags pack_flags) override;
void tessellate(DiagSplit *split);

View File

@ -220,6 +220,10 @@ void Object::tag_update(Scene *scene)
flag |= ObjectManager::TRANSFORM_MODIFIED;
}
if (visibility_is_modified()) {
flag |= ObjectManager::VISIBILITY_MODIFIED;
}
foreach (Node *node, geometry->get_used_shaders()) {
Shader *shader = static_cast<Shader *>(node);
if (shader->get_use_mis() && shader->has_surface_emission)
@ -914,6 +918,10 @@ void ObjectManager::tag_update(Scene *scene, uint32_t flag)
geometry_flag |= GeometryManager::TRANSFORM_MODIFIED;
}
if ((flag & VISIBILITY_MODIFIED) != 0) {
geometry_flag |= GeometryManager::VISIBILITY_MODIFIED;
}
scene->geometry_manager->tag_update(scene, geometry_flag);
}

View File

@ -134,6 +134,7 @@ class ObjectManager {
OBJECT_MODIFIED = (1 << 5),
HOLDOUT_MODIFIED = (1 << 6),
TRANSFORM_MODIFIED = (1 << 7),
VISIBILITY_MODIFIED = (1 << 8),
/* tag everything in the manager for an update */
UPDATE_ALL = ~0u,

@ -1 +1 @@
Subproject commit 2cef4877edc40875978c4e95322bb5193f5815bf
Subproject commit 5ab29b1331d2103dae634b987f121c4599459d7f

@ -1 +1 @@
Subproject commit bcd08a9506d33bdd7358201031b04d041ef22d94
Subproject commit bb16aba5bd3873794eefe167497118b6063b9a85

@ -1 +1 @@
Subproject commit f948f658ba33eb670a65e0bba058d43138abea7e
Subproject commit 7d78c8a63f2f4b146f9327ddc0d567a5921b94ea

View File

@ -21,7 +21,7 @@
def url_prefill_from_blender(addon_info=None):
import bpy
import bgl
import gpu
import struct
import platform
import urllib.parse
@ -38,9 +38,9 @@ def url_prefill_from_blender(addon_info=None):
)
fh.write(
"Graphics card: %s %s %s\n" % (
bgl.glGetString(bgl.GL_RENDERER),
bgl.glGetString(bgl.GL_VENDOR),
bgl.glGetString(bgl.GL_VERSION),
gpu.platform.renderer_get(),
gpu.platform.vendor_get(),
gpu.platform.version_get(),
)
)
fh.write(

View File

@ -235,7 +235,7 @@ def draw(layout, context, context_member, property_type, use_edit=True):
assert(isinstance(rna_item, property_type))
items = rna_item.items()
items = list(rna_item.items())
items.sort()
# TODO: Allow/support adding new custom props to overrides.

View File

@ -28,7 +28,7 @@ def write_sysinfo(filepath):
import subprocess
import bpy
import bgl
import gpu
# pretty repr
def prepr(v):
@ -190,46 +190,29 @@ def write_sysinfo(filepath):
if bpy.app.background:
output.write("\nOpenGL: missing, background mode\n")
else:
output.write(title("OpenGL"))
version = bgl.glGetString(bgl.GL_RENDERER)
output.write("renderer:\t%r\n" % version)
output.write("vendor:\t\t%r\n" % (bgl.glGetString(bgl.GL_VENDOR)))
output.write("version:\t%r\n" % (bgl.glGetString(bgl.GL_VERSION)))
output.write(title("GPU"))
output.write("renderer:\t%r\n" % gpu.platform.renderer_get())
output.write("vendor:\t\t%r\n" % gpu.platform.vendor_get())
output.write("version:\t%r\n" % gpu.platform.version_get())
output.write("extensions:\n")
limit = bgl.Buffer(bgl.GL_INT, 1)
bgl.glGetIntegerv(bgl.GL_NUM_EXTENSIONS, limit)
glext = []
for i in range(limit[0]):
glext.append(bgl.glGetStringi(bgl.GL_EXTENSIONS, i))
glext = sorted(glext)
glext = sorted(gpu.capabilities.extensions_get())
for l in glext:
output.write("\t%s\n" % l)
output.write(title("Implementation Dependent OpenGL Limits"))
bgl.glGetIntegerv(bgl.GL_MAX_ELEMENTS_VERTICES, limit)
output.write("Maximum DrawElements Vertices:\t%d\n" % limit[0])
bgl.glGetIntegerv(bgl.GL_MAX_ELEMENTS_INDICES, limit)
output.write("Maximum DrawElements Indices:\t%d\n" % limit[0])
output.write(title("Implementation Dependent GPU Limits"))
output.write("Maximum Batch Vertices:\t%d\n" % gpu.capabilities.max_batch_vertices_get())
output.write("Maximum Batch Indices:\t%d\n" % gpu.capabilities.max_batch_indices_get())
output.write("\nGLSL:\n")
bgl.glGetIntegerv(bgl.GL_MAX_VARYING_FLOATS, limit)
output.write("Maximum Varying Floats:\t%d\n" % limit[0])
bgl.glGetIntegerv(bgl.GL_MAX_VERTEX_ATTRIBS, limit)
output.write("Maximum Vertex Attributes:\t%d\n" % limit[0])
bgl.glGetIntegerv(bgl.GL_MAX_VERTEX_UNIFORM_COMPONENTS, limit)
output.write("Maximum Vertex Uniform Components:\t%d\n" % limit[0])
bgl.glGetIntegerv(bgl.GL_MAX_FRAGMENT_UNIFORM_COMPONENTS, limit)
output.write("Maximum Fragment Uniform Components:\t%d\n" % limit[0])
bgl.glGetIntegerv(bgl.GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, limit)
output.write("Maximum Vertex Image Units:\t%d\n" % limit[0])
bgl.glGetIntegerv(bgl.GL_MAX_TEXTURE_IMAGE_UNITS, limit)
output.write("Maximum Fragment Image Units:\t%d\n" % limit[0])
bgl.glGetIntegerv(bgl.GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, limit)
output.write("Maximum Pipeline Image Units:\t%d\n" % limit[0])
output.write("Maximum Varying Floats:\t%d\n" % gpu.capabilities.max_varying_floats_get())
output.write("Maximum Vertex Attributes:\t%d\n" % gpu.capabilities.max_vertex_attribs_get())
output.write("Maximum Vertex Uniform Components:\t%d\n" % gpu.capabilities.max_uniforms_vert_get())
output.write("Maximum Fragment Uniform Components:\t%d\n" % gpu.capabilities.max_uniforms_frag_get())
output.write("Maximum Vertex Image Units:\t%d\n" % gpu.capabilities.max_textures_vert_get())
output.write("Maximum Fragment Image Units:\t%d\n" % gpu.capabilities.max_textures_frag_get())
output.write("Maximum Pipeline Image Units:\t%d\n" % gpu.capabilities.max_textures_get())
if bpy.app.build_options.cycles:
import cycles

View File

@ -501,7 +501,11 @@ typedef struct SculptSession {
/* Total number of polys of the base mesh. */
int totfaces;
/* Face sets store its visibility in the sign of the integer, using the absolute value as the
* Face Set ID. Positive IDs are visible, negative IDs are hidden. */
* Face Set ID. Positive IDs are visible, negative IDs are hidden.
* The 0 ID is not used by the tools or the visibility system, it is just used when creating new
* geometry (the trim tool, for example) to detect which geometry was just added, so it can be
* assigned a valid Face Set after creation. Tools are not intended to run with Face Sets IDs set
* to 0. */
int *face_sets;
/* BMesh for dynamic topology sculpting */

View File

@ -947,7 +947,7 @@ static bool nlastrips_path_rename_fix(ID *owner_id,
owner_id, prefix, oldName, newName, oldKey, newKey, &strip->act->curves, verify_paths);
}
/* Ignore own F-Curves, since those are local. */
/* Check sub-strips (if metas) */
/* Check sub-strips (if meta-strips). */
is_changed |= nlastrips_path_rename_fix(
owner_id, prefix, oldName, newName, oldKey, newKey, &strip->strips, verify_paths);
}
@ -1177,7 +1177,7 @@ static bool nlastrips_path_remove_fix(const char *prefix, ListBase *strips)
any_removed |= fcurves_path_remove_fix(prefix, &strip->act->curves);
}
/* check sub-strips (if metas) */
/* Check sub-strips (if meta-strips). */
any_removed |= nlastrips_path_remove_fix(prefix, &strip->strips);
}
return any_removed;
@ -1245,7 +1245,7 @@ static void nlastrips_apply_all_curves_cb(ID *id, ListBase *strips, AllFCurvesCb
fcurves_apply_cb(id, &strip->act->curves, wrapper->func, wrapper->user_data);
}
/* check sub-strips (if metas) */
/* Check sub-strips (if meta-strips). */
nlastrips_apply_all_curves_cb(id, &strip->strips, wrapper);
}
}

View File

@ -1794,7 +1794,7 @@ static void nlaevalchan_combine_quaternion(NlaEvalChannelSnapshot *lower_necs,
}
/**
* Based on blendmode and mixmode, blend lower necs with upper necs into blended necs.
* Based on blend-mode and mix-mode, blend lower necs with upper necs into blended necs.
*
* Each upper value's blend domain determines whether to blend or to copy directly
* from lower.
@ -1879,7 +1879,7 @@ static void nlaevalchan_blend_value_get_inverted_upper_evalchan(
}
/**
* Based on mixmode, solve for the upper values such that when lower combined with upper then we
* Based on mix-mode, solve for the upper values such that when lower combined with upper then we
* get blended values as a result.
*
* Only processes blended values in the remap domain. Successfully remapped upper values are placed
@ -2407,12 +2407,12 @@ static void nla_eval_domain_strips(PointerRNA *ptr,
GSet *touched_actions)
{
LISTBASE_FOREACH (NlaStrip *, strip, strips) {
/* check strip's action */
/* Check strip's action. */
if (strip->act) {
nla_eval_domain_action(ptr, channels, strip->act, touched_actions);
}
/* check sub-strips (if metas) */
/* Check sub-strips (if meta-strips). */
nla_eval_domain_strips(ptr, channels, &strip->strips, touched_actions);
}
}
@ -2859,9 +2859,9 @@ void nlasnapshot_ensure_channels(NlaEvalData *eval_data, NlaEvalSnapshot *snapsh
* Blends the \a lower_snapshot with the \a upper_snapshot into \a r_blended_snapshot according
* to the given \a upper_blendmode and \a upper_influence.
*
* For \a upper_snapshot, blending limited to values in the \a blend_domain. For Replace blendmode,
* this allows the upper snapshot to have a location XYZ channel where only a subset of values are
* blended.
* For \a upper_snapshot, blending limited to values in the \a blend_domain.
* For Replace blend-mode, this allows the upper snapshot to have a location XYZ channel
* where only a subset of values are blended.
*/
void nlasnapshot_blend(NlaEvalData *eval_data,
NlaEvalSnapshot *lower_snapshot,

View File

@ -162,7 +162,7 @@ static void make_box_from_metaelem(Box *r, const MetaElem *ml)
}
/**
* Partitions part of mainb array [start, end) along axis s. Returns i,
* Partitions part of #process.mainb array [start, end) along axis s. Returns i,
* where centroids of elements in the [start, i) segment lie "on the right side" of div,
* and elements in the [i, end) segment lie "on the left"
*/
@ -1170,8 +1170,9 @@ static void polygonize(PROCESS *process)
/**
* Iterates over ALL objects in the scene and all of its sets, including
* making all duplis(not only metas). Copies metas to mainb array.
* Computes bounding boxes for building BVH. */
* making all duplis (not only meta-elements). Copies meta-elements to #process.mainb array.
* Computes bounding boxes for building BVH.
*/
static void init_meta(Depsgraph *depsgraph, PROCESS *process, Scene *scene, Object *ob)
{
Scene *sce_iter = scene;

View File

@ -2258,6 +2258,17 @@ bNodeTree *ntreeCopyTree_ex_new_pointers(const bNodeTree *ntree,
return new_ntree;
}
static int node_count_links(const bNodeTree *ntree, const bNodeSocket *socket)
{
int count = 0;
LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {
if (ELEM(socket, link->fromsock, link->tosock)) {
count++;
}
}
return count;
}
/* also used via rna api, so we check for proper input output direction */
bNodeLink *nodeAddLink(
bNodeTree *ntree, bNode *fromnode, bNodeSocket *fromsock, bNode *tonode, bNodeSocket *tosock)
@ -2294,6 +2305,10 @@ bNodeLink *nodeAddLink(
ntree->update |= NTREE_UPDATE_LINKS;
}
if (link->tosock->flag & SOCK_MULTI_INPUT) {
link->multi_input_socket_index = node_count_links(ntree, link->tosock) - 1;
}
return link;
}
@ -4312,7 +4327,7 @@ void ntreeUpdateAllUsers(Main *main, ID *id)
if (GS(id->name) == ID_NT) {
bNodeTree *ngroup = (bNodeTree *)id;
if (ngroup->type == NTREE_GEOMETRY) {
if (ngroup->type == NTREE_GEOMETRY && (ngroup->update & NTREE_UPDATE_GROUP)) {
LISTBASE_FOREACH (Object *, object, &main->objects) {
LISTBASE_FOREACH (ModifierData *, md, &object->modifiers) {
if (md->type == eModifierType_Nodes) {

View File

@ -31,6 +31,7 @@
#include "BKE_lib_id.h"
#include "BKE_main.h"
#include "BKE_node.h"
#include "BLO_readfile.h"
#include "readfile.h"
@ -57,6 +58,30 @@ void do_versions_after_linking_300(Main *bmain, ReportList *UNUSED(reports))
*/
{
/* Keep this block, even when empty. */
/* Use new texture socket in Attribute Sample Texture node. */
LISTBASE_FOREACH (bNodeTree *, ntree, &bmain->nodetrees) {
if (ntree->type != NTREE_GEOMETRY) {
continue;
}
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (node->type != GEO_NODE_ATTRIBUTE_SAMPLE_TEXTURE) {
continue;
}
if (node->id == NULL) {
continue;
}
LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) {
if (socket->type == SOCK_TEXTURE) {
bNodeSocketValueTexture *socket_value = (bNodeSocketValueTexture *)
socket->default_value;
socket_value->value = (Tex *)node->id;
break;
}
}
node->id = NULL;
}
}
}
}

View File

@ -30,4 +30,4 @@ double ChunkOrderHotspot::calc_distance(int x, int y)
return result;
}
} // namespace blender::compositor
} // namespace blender::compositor

View File

@ -478,6 +478,7 @@ add_dependencies(bf_draw bf_dna)
if(WITH_GTESTS)
if(WITH_OPENGL_DRAW_TESTS)
set(TEST_SRC
tests/draw_testing.cc
tests/shaders_test.cc
)
set(TEST_INC

View File

@ -0,0 +1,18 @@
/* Apache License, Version 2.0 */
#include "draw_testing.hh"
#include "GPU_shader.h"
#include "draw_manager_testing.h"
namespace blender::draw {
/* Base class for draw test cases. It will setup and tear down the GPU part around each test. */
void DrawTest::SetUp()
{
GPUTest::SetUp();
DRW_draw_state_init_gtests(GPU_SHADER_CFG_DEFAULT);
}
} // namespace blender::draw

View File

@ -0,0 +1,13 @@
/* Apache License, Version 2.0 */
#include "gpu_testing.hh"
namespace blender::draw {
/* Base class for draw test cases. It will setup and tear down the GPU part around each test. */
class DrawTest : public blender::gpu::GPUTest {
public:
void SetUp() override;
};
} // namespace blender::draw

View File

@ -2,12 +2,12 @@
#include "testing/testing.h"
#include "draw_testing.hh"
#include "intern/draw_manager_testing.h"
#include "GPU_context.h"
#include "GPU_init_exit.h"
#include "GPU_shader.h"
#include "gpu_testing.hh"
#include "engines/eevee/eevee_private.h"
#include "engines/gpencil/gpencil_engine.h"
@ -17,19 +17,9 @@
namespace blender::draw {
/* Base class for draw test cases. It will setup and tear down the GPU part around each test. */
class DrawTest : public blender::gpu::GPUTest {
void SetUp() override
{
GPUTest::SetUp();
DRW_draw_state_init_gtests(GPU_SHADER_CFG_DEFAULT);
}
};
TEST_F(DrawTest, workbench_glsl_shaders)
{
workbench_shader_library_ensure();
DRW_draw_state_init_gtests(GPU_SHADER_CFG_DEFAULT);
const int MAX_WPD = 6;
WORKBENCH_PrivateData wpds[MAX_WPD];

View File

@ -17,6 +17,7 @@
set(INC
../include
../../blenfont
../../blenkernel
../../blenlib
../../blentranslation

View File

@ -33,6 +33,7 @@
#include "DNA_armature_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_vec_types.h"
#include "BKE_fcurve.h"
#include "BKE_nla.h"
@ -50,15 +51,28 @@
#include "WM_types.h"
#include "UI_interface.h"
#include "UI_resources.h"
#include "ED_armature.h"
#include "ED_keyframes_draw.h"
#include "ED_markers.h"
#include "ED_numinput.h"
#include "ED_screen.h"
#include "ED_space_api.h"
#include "GPU_immediate.h"
#include "GPU_immediate_util.h"
#include "GPU_matrix.h"
#include "GPU_state.h"
#include "armature_intern.h"
#include "BLF_api.h"
/* Pixel distance from 0% to 100%. */
#define SLIDE_PIXEL_DISTANCE (300 * U.pixelsize)
#define OVERSHOOT_RANGE_DELTA 0.2f
/* **************************************************** */
/* == POSE 'SLIDING' TOOLS ==
*
@ -110,15 +124,36 @@ typedef struct tPoseSlideOp {
/** unused for now, but can later get used for storing runtime settings.... */
short flag;
/* Store overlay settings when invoking the operator. Bones will be temporarily hidden. */
int overlay_flag;
/** which transforms/channels are affected (ePoseSlide_Channels) */
short channels;
/** axis-limits for transforms (ePoseSlide_AxisLock) */
short axislock;
/** 0-1 value for determining the influence of whatever is relevant */
/* Allow overshoot or clamp between 0% and 100%. */
bool overshoot;
/* Reduces percentage delta from mouse movement. */
bool precision;
/* Move percentage in 10% steps. */
bool increments;
/* Draw callback handler. */
void *draw_handle;
/* Accumulative, unclamped and unrounded percentage. */
float raw_percentage;
/* 0-1 value for determining the influence of whatever is relevant. */
float percentage;
/** numeric input */
/* Last cursor position in screen space used for mouse movement delta calculation. */
int last_cursor_x;
/* Numeric input. */
NumInput num;
struct tPoseSlideObject *ob_data_array;
@ -187,6 +222,240 @@ static const EnumPropertyItem prop_axis_lock_types[] = {
/* ------------------------------------ */
static void draw_overshoot_triangle(const uint8_t color[4],
const bool facing_right,
const float x,
const float y)
{
const uint shdr_pos_2d = GPU_vertformat_attr_add(
immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
GPU_blend(GPU_BLEND_ALPHA);
GPU_polygon_smooth(true);
immUniformColor3ubvAlpha(color, 225);
const float triangle_side_length = facing_right ? 6 * U.pixelsize : -6 * U.pixelsize;
const float triangle_offset = facing_right ? 2 * U.pixelsize : -2 * U.pixelsize;
immBegin(GPU_PRIM_TRIS, 3);
immVertex2f(shdr_pos_2d, x + triangle_offset + triangle_side_length, y);
immVertex2f(shdr_pos_2d, x + triangle_offset, y + triangle_side_length / 2);
immVertex2f(shdr_pos_2d, x + triangle_offset, y - triangle_side_length / 2);
immEnd();
GPU_polygon_smooth(false);
GPU_blend(GPU_BLEND_NONE);
immUnbindProgram();
}
static void draw_ticks(const float start_percentage,
const float end_percentage,
const struct vec2f line_start,
const float base_tick_height,
const float line_width,
const uint8_t color_overshoot[4],
const uint8_t color_line[4])
{
/* Use percentage represented as 0-100 int to avoid floating point precision problems. */
const int tick_increment = 10;
/* Round initial_tick_percentage up to the next tick_increment. */
int tick_percentage = ceil((start_percentage * 100) / tick_increment) * tick_increment;
float tick_height = base_tick_height;
while (tick_percentage <= (int)(end_percentage * 100)) {
/* Different ticks have different heights. Multiples of 100% are the tallest, 50% is a bit
* smaller and the rest is the minimum size. */
if (tick_percentage % 100 == 0) {
tick_height = base_tick_height;
}
else if (tick_percentage % 50 == 0) {
tick_height = base_tick_height * 0.8;
}
else {
tick_height = base_tick_height * 0.5;
}
const float x = line_start.x +
(((float)tick_percentage / 100) - start_percentage) * SLIDE_PIXEL_DISTANCE;
const struct rctf tick_rect = {.xmin = x - (line_width / 2),
.xmax = x + (line_width / 2),
.ymin = line_start.y - (tick_height / 2),
.ymax = line_start.y + (tick_height / 2)};
if (tick_percentage < 0 || tick_percentage > 100) {
UI_draw_roundbox_3ub_alpha(&tick_rect, true, 1, color_overshoot, 255);
}
else {
UI_draw_roundbox_3ub_alpha(&tick_rect, true, 1, color_line, 255);
}
tick_percentage += tick_increment;
}
}
static void draw_main_line(const struct rctf main_line_rect,
const float percentage,
const bool overshoot,
const uint8_t color_overshoot[4],
const uint8_t color_line[4])
{
if (overshoot) {
/* In overshoot mode, draw the 0-100% range differently to provide a visual reference. */
const float line_zero_percent = main_line_rect.xmin -
((percentage - 0.5f - OVERSHOOT_RANGE_DELTA) *
SLIDE_PIXEL_DISTANCE);
const float clamped_line_zero_percent = clamp_f(
line_zero_percent, main_line_rect.xmin, main_line_rect.xmax);
const float clamped_line_hundred_percent = clamp_f(
line_zero_percent + SLIDE_PIXEL_DISTANCE, main_line_rect.xmin, main_line_rect.xmax);
const struct rctf left_overshoot_line_rect = {.xmin = main_line_rect.xmin,
.xmax = clamped_line_zero_percent,
.ymin = main_line_rect.ymin,
.ymax = main_line_rect.ymax};
const struct rctf right_overshoot_line_rect = {.xmin = clamped_line_hundred_percent,
.xmax = main_line_rect.xmax,
.ymin = main_line_rect.ymin,
.ymax = main_line_rect.ymax};
UI_draw_roundbox_3ub_alpha(&left_overshoot_line_rect, true, 0, color_overshoot, 255);
UI_draw_roundbox_3ub_alpha(&right_overshoot_line_rect, true, 0, color_overshoot, 255);
const struct rctf non_overshoot_line_rect = {.xmin = clamped_line_zero_percent,
.xmax = clamped_line_hundred_percent,
.ymin = main_line_rect.ymin,
.ymax = main_line_rect.ymax};
UI_draw_roundbox_3ub_alpha(&non_overshoot_line_rect, true, 0, color_line, 255);
}
else {
UI_draw_roundbox_3ub_alpha(&main_line_rect, true, 0, color_line, 255);
}
}
static void draw_backdrop(const int fontid,
const struct rctf main_line_rect,
const float color_bg[4],
const short region_y_size,
const float base_tick_height)
{
float string_pixel_size[2];
const char *percentage_placeholder = "000%%";
BLF_width_and_height(fontid,
percentage_placeholder,
sizeof(percentage_placeholder),
&string_pixel_size[0],
&string_pixel_size[1]);
const struct vec2f pad = {.x = (region_y_size - base_tick_height) / 2, .y = 2.0f * U.pixelsize};
const struct rctf backdrop_rect = {.xmin = main_line_rect.xmin - string_pixel_size[0] - pad.x,
.xmax = main_line_rect.xmax + pad.x,
.ymin = pad.y,
.ymax = region_y_size - pad.y};
UI_draw_roundbox_aa(&backdrop_rect, true, 4.0f, color_bg);
}
/* Draw an on screen Slider for a Pose Slide Operator. */
static void pose_slide_draw_2d_slider(const struct bContext *UNUSED(C), ARegion *region, void *arg)
{
tPoseSlideOp *pso = arg;
/* Only draw in region from which the Operator was started. */
if (region != pso->region) {
return;
}
uint8_t color_text[4];
uint8_t color_line[4];
uint8_t color_handle[4];
uint8_t color_overshoot[4];
float color_bg[4];
/* Get theme colors. */
UI_GetThemeColor4ubv(TH_TEXT, color_text);
UI_GetThemeColor4ubv(TH_TEXT, color_line);
UI_GetThemeColor4ubv(TH_TEXT, color_overshoot);
UI_GetThemeColor4ubv(TH_ACTIVE, color_handle);
UI_GetThemeColor3fv(TH_BACK, color_bg);
color_bg[3] = 0.5f;
color_overshoot[0] = color_overshoot[0] * 0.7;
color_overshoot[1] = color_overshoot[1] * 0.7;
color_overshoot[2] = color_overshoot[2] * 0.7;
/* Get the default font. */
const uiStyle *style = UI_style_get();
const uiFontStyle *fstyle = &style->widget;
const int fontid = fstyle->uifont_id;
BLF_color3ubv(fontid, color_text);
BLF_rotation(fontid, 0.0f);
const float line_width = 1.5 * U.pixelsize;
const float base_tick_height = 12.0 * U.pixelsize;
const float line_y = region->winy / 2;
struct rctf main_line_rect = {.xmin = (region->winx / 2) - (SLIDE_PIXEL_DISTANCE / 2),
.xmax = (region->winx / 2) + (SLIDE_PIXEL_DISTANCE / 2),
.ymin = line_y - line_width / 2,
.ymax = line_y + line_width / 2};
float line_start_percentage = 0;
int handle_pos_x = main_line_rect.xmin + SLIDE_PIXEL_DISTANCE * pso->percentage;
if (pso->overshoot) {
main_line_rect.xmin = main_line_rect.xmin - SLIDE_PIXEL_DISTANCE * OVERSHOOT_RANGE_DELTA;
main_line_rect.xmax = main_line_rect.xmax + SLIDE_PIXEL_DISTANCE * OVERSHOOT_RANGE_DELTA;
line_start_percentage = pso->percentage - 0.5f - OVERSHOOT_RANGE_DELTA;
handle_pos_x = region->winx / 2;
}
draw_backdrop(fontid, main_line_rect, color_bg, pso->region->winy, base_tick_height);
draw_main_line(main_line_rect, pso->percentage, pso->overshoot, color_overshoot, color_line);
const float percentage_range = pso->overshoot ? 1 + OVERSHOOT_RANGE_DELTA * 2 : 1;
const struct vec2f line_start_position = {.x = main_line_rect.xmin, .y = line_y};
draw_ticks(line_start_percentage,
line_start_percentage + percentage_range,
line_start_position,
base_tick_height,
line_width,
color_overshoot,
color_line);
/* Draw triangles at the ends of the line in overshoot mode to indicate direction of 0-100%
* range.*/
if (pso->overshoot) {
if (pso->percentage > 1 + OVERSHOOT_RANGE_DELTA + 0.5) {
draw_overshoot_triangle(color_line, false, main_line_rect.xmin, line_y);
}
if (pso->percentage < 0 - OVERSHOOT_RANGE_DELTA - 0.5) {
draw_overshoot_triangle(color_line, true, main_line_rect.xmax, line_y);
}
}
char percentage_string[256];
/* Draw handle indicating current percentage. */
const struct rctf handle_rect = {.xmin = handle_pos_x - (line_width),
.xmax = handle_pos_x + (line_width),
.ymin = line_y - (base_tick_height / 2),
.ymax = line_y + (base_tick_height / 2)};
UI_draw_roundbox_3ub_alpha(&handle_rect, true, 1, color_handle, 255);
BLI_snprintf(percentage_string, sizeof(percentage_string), "%.0f%%", pso->percentage * 100);
/* Draw percentage string. */
float percentage_pixel_size[2];
BLF_width_and_height(fontid,
percentage_string,
sizeof(percentage_string),
&percentage_pixel_size[0],
&percentage_pixel_size[1]);
BLF_position(fontid,
main_line_rect.xmin - 24.0 * U.pixelsize - percentage_pixel_size[0] / 2,
(region->winy / 2) - percentage_pixel_size[1] / 2,
0.0f);
BLF_draw(fontid, percentage_string, sizeof(percentage_string));
}
/* operator init */
static int pose_slide_init(bContext *C, wmOperator *op, ePoseSlide_Modes mode)
{
@ -205,6 +474,7 @@ static int pose_slide_init(bContext *C, wmOperator *op, ePoseSlide_Modes mode)
/* set range info from property values - these may get overridden for the invoke() */
pso->percentage = RNA_float_get(op->ptr, "percentage");
pso->raw_percentage = pso->percentage;
pso->prevFrame = RNA_int_get(op->ptr, "prev_frame");
pso->nextFrame = RNA_int_get(op->ptr, "next_frame");
@ -257,6 +527,17 @@ static int pose_slide_init(bContext *C, wmOperator *op, ePoseSlide_Modes mode)
pso->num.val_flag[0] |= NUM_NO_NEGATIVE;
pso->num.unit_type[0] = B_UNIT_NONE; /* percentages don't have any units... */
/* Register UI drawing callback. */
/* pso->draw_handle = ED_region_draw_cb_activate(
pso->region->type, pose_slide_draw_2d_slider, pso, REGION_DRAW_POST_PIXEL); */
LISTBASE_FOREACH (ARegion *, region, &pso->area->regionbase) {
if (region->regiontype == RGN_TYPE_HEADER) {
pso->region = region;
pso->draw_handle = ED_region_draw_cb_activate(
region->type, pose_slide_draw_2d_slider, pso, REGION_DRAW_POST_PIXEL);
}
}
/* return status is whether we've got all the data we were requested to get */
return 1;
}
@ -266,6 +547,13 @@ static void pose_slide_exit(wmOperator *op)
{
tPoseSlideOp *pso = op->customdata;
/* Hide Bone Overlay. */
View3D *v3d = pso->area->spacedata.first;
v3d->overlay.flag = pso->overlay_flag;
/* Remove UI drawing callback. */
ED_region_draw_cb_exit(pso->region->type, pso->draw_handle);
/* if data exists, clear its data and exit */
if (pso) {
/* free the temp pchan links and their data */
@ -602,7 +890,7 @@ static void pose_slide_apply_quat(tPoseSlideOp *pso, tPChanFCurveLink *pfl)
static void pose_slide_rest_pose_apply_vec3(tPoseSlideOp *pso, float vec[3], float default_value)
{
/* We only slide to the rest pose. So only use the default rest pose value */
/* We only slide to the rest pose. So only use the default rest pose value. */
const int lock = pso->axislock;
for (int idx = 0; idx < 3; idx++) {
if ((lock == 0) || ((lock & PS_LOCK_X) && (idx == 0)) || ((lock & PS_LOCK_Y) && (idx == 1)) ||
@ -621,7 +909,7 @@ static void pose_slide_rest_pose_apply_vec3(tPoseSlideOp *pso, float vec[3], flo
static void pose_slide_rest_pose_apply_other_rot(tPoseSlideOp *pso, float vec[4], bool quat)
{
/* We only slide to the rest pose. So only use the default rest pose value */
/* We only slide to the rest pose. So only use the default rest pose value. */
float default_values[] = {1.0f, 0.0f, 0.0f, 0.0f};
if (!quat) {
/* Axis Angle */
@ -789,14 +1077,18 @@ static void pose_slide_reset(tPoseSlideOp *pso)
/* ------------------------------------ */
/* draw percentage indicator in header */
/* Draw percentage indicator in workspace footer. */
/* TODO: Include hints about locks here... */
static void pose_slide_draw_status(tPoseSlideOp *pso)
static void pose_slide_draw_status(bContext *C, tPoseSlideOp *pso)
{
char status_str[UI_MAX_DRAW_STR];
char limits_str[UI_MAX_DRAW_STR];
char axis_str[50];
char mode_str[32];
char overshoot_str[50];
char precision_str[50];
char increments_str[50];
char bone_vis_str[50];
switch (pso->mode) {
case POSESLIDE_PUSH:
@ -871,25 +1163,51 @@ static void pose_slide_draw_status(tPoseSlideOp *pso)
break;
}
if (pso->overshoot) {
BLI_strncpy(overshoot_str, TIP_("[E] - Disable overshoot"), sizeof(overshoot_str));
}
else {
BLI_strncpy(overshoot_str, TIP_("E - Enable overshoot"), sizeof(overshoot_str));
}
if (pso->precision) {
BLI_strncpy(precision_str, TIP_("[Shift] - Precision active"), sizeof(precision_str));
}
else {
BLI_strncpy(precision_str, TIP_("Shift - Hold for precision"), sizeof(precision_str));
}
if (pso->increments) {
BLI_strncpy(increments_str, TIP_("[Ctrl] - Increments active"), sizeof(increments_str));
}
else {
BLI_strncpy(increments_str, TIP_("Ctrl - Hold for 10% increments"), sizeof(increments_str));
}
BLI_strncpy(bone_vis_str, TIP_("[H] - Toggle bone visibility"), sizeof(increments_str));
if (hasNumInput(&pso->num)) {
Scene *scene = pso->scene;
char str_ofs[NUM_STR_REP_LEN];
char str_offs[NUM_STR_REP_LEN];
outputNumInput(&pso->num, str_ofs, &scene->unit);
outputNumInput(&pso->num, str_offs, &scene->unit);
BLI_snprintf(
status_str, sizeof(status_str), "%s: %s | %s", mode_str, str_ofs, limits_str);
BLI_snprintf(status_str, sizeof(status_str), "%s: %s | %s", mode_str, str_offs, limits_str);
}
else {
BLI_snprintf(status_str,
sizeof(status_str),
"%s: %d %% | %s",
mode_str,
(int)(pso->percentage * 100.0f),
limits_str);
sizeof(status_str),
"%s: %s | %s | %s | %s | %s",
mode_str,
limits_str,
overshoot_str,
precision_str,
increments_str,
bone_vis_str);
}
ED_area_status_text(pso->area, status_str);
ED_workspace_status_text(C, status_str);
ED_area_status_text(pso->area, "");
}
/* common code for invoke() methods */
@ -975,21 +1293,40 @@ static int pose_slide_invoke_common(bContext *C, wmOperator *op, tPoseSlideOp *p
WM_cursor_modal_set(win, WM_CURSOR_EW_SCROLL);
/* header print */
pose_slide_draw_status(pso);
pose_slide_draw_status(C, pso);
/* add a modal handler for this operator */
WM_event_add_modal_handler(C, op);
/* Hide Bone Overlay. */
View3D *v3d = pso->area->spacedata.first;
pso->overlay_flag = v3d->overlay.flag;
v3d->overlay.flag |= V3D_OVERLAY_HIDE_BONES;
return OPERATOR_RUNNING_MODAL;
}
/* calculate percentage based on position of mouse (we only use x-axis for now.
* since this is more convenient for users to do), and store new percentage value
/* Calculate percentage based on mouse movement, clamp or round to increments if
* enabled by the user. Store the new percentage value.
*/
static void pose_slide_mouse_update_percentage(tPoseSlideOp *pso,
wmOperator *op,
const wmEvent *event)
{
pso->percentage = (event->x - pso->region->winrct.xmin) / ((float)pso->region->winx);
const float percentage_delta = (event->x - pso->last_cursor_x) / ((float)(SLIDE_PIXEL_DISTANCE));
/* Reduced percentage delta in precision mode (shift held). */
pso->raw_percentage += pso->precision ? (percentage_delta / 8) : percentage_delta;
pso->percentage = pso->raw_percentage;
pso->last_cursor_x = event->x;
if (!pso->overshoot) {
pso->percentage = clamp_f(pso->percentage, 0, 1);
}
if (pso->increments) {
pso->percentage = round(pso->percentage * 10) / 10;
}
RNA_float_set(op->ptr, "percentage", pso->percentage);
}
@ -1056,9 +1393,13 @@ static int pose_slide_modal(bContext *C, wmOperator *op, const wmEvent *event)
case EVT_PADENTER: {
if (event->val == KM_PRESS) {
/* return to normal cursor and header status */
ED_workspace_status_text(C, NULL);
ED_area_status_text(pso->area, NULL);
WM_cursor_modal_restore(win);
/* Depsgraph updates + redraws. Redraw needed to remove UI. */
pose_slide_refresh(C, pso);
/* insert keyframes as required... */
pose_slide_autoKeyframe(C, pso);
pose_slide_exit(op);
@ -1073,13 +1414,14 @@ static int pose_slide_modal(bContext *C, wmOperator *op, const wmEvent *event)
case RIGHTMOUSE: {
if (event->val == KM_PRESS) {
/* return to normal cursor and header status */
ED_workspace_status_text(C, NULL);
ED_area_status_text(pso->area, NULL);
WM_cursor_modal_restore(win);
/* reset transforms back to original state */
pose_slide_reset(pso);
/* depsgraph updates + redraws */
/* Depsgraph updates + redraws.*/
pose_slide_refresh(C, pso);
/* clean up temp data */
@ -1178,10 +1520,58 @@ static int pose_slide_modal(bContext *C, wmOperator *op, const wmEvent *event)
break;
}
/* Overshoot. */
case EVT_EKEY: {
pso->overshoot = !pso->overshoot;
do_pose_update = true;
break;
}
/* Precision mode. */
case EVT_LEFTSHIFTKEY:
case EVT_RIGHTSHIFTKEY: {
pso->precision = true;
do_pose_update = true;
break;
}
/* Increments mode. */
case EVT_LEFTCTRLKEY:
case EVT_RIGHTCTRLKEY: {
pso->increments = true;
do_pose_update = true;
break;
}
/* Toggle Bone visibility. */
case EVT_HKEY: {
View3D *v3d = pso->area->spacedata.first;
v3d->overlay.flag ^= V3D_OVERLAY_HIDE_BONES;
}
default: /* Some other unhandled key... */
break;
}
}
/* Precision and stepping only active while button is held. */
else if (event->val == KM_RELEASE) {
switch (event->type) {
case EVT_LEFTSHIFTKEY:
case EVT_RIGHTSHIFTKEY: {
pso->precision = false;
do_pose_update = true;
break;
}
case EVT_LEFTCTRLKEY:
case EVT_RIGHTCTRLKEY: {
pso->increments = false;
do_pose_update = true;
break;
}
default:
break;
}
}
else {
/* unhandled event - maybe it was some view manipulation? */
/* allow to pass through */
@ -1193,8 +1583,10 @@ static int pose_slide_modal(bContext *C, wmOperator *op, const wmEvent *event)
/* Perform pose updates - in response to some user action
* (e.g. pressing a key or moving the mouse). */
if (do_pose_update) {
pose_slide_mouse_update_percentage(pso, op, event);
/* update percentage indicator in header */
pose_slide_draw_status(pso);
pose_slide_draw_status(C, pso);
/* reset transforms (to avoid accumulation errors) */
pose_slide_reset(pso);
@ -1247,11 +1639,11 @@ static void pose_slide_opdef_properties(wmOperatorType *ot)
PropertyRNA *prop;
prop = RNA_def_float_factor(ot->srna,
"factor",
"percentage",
0.5f,
0.0f,
1.0f,
"Factor",
"Percentage",
"Weighting factor for which keyframe is favored more",
0.0,
1.0);
@ -1310,6 +1702,8 @@ static int pose_slide_push_invoke(bContext *C, wmOperator *op, const wmEvent *ev
pso = op->customdata;
pso->last_cursor_x = event->x;
/* Initialize percentage so that it won't pop on first mouse move. */
pose_slide_mouse_update_percentage(pso, op, event);
@ -1349,7 +1743,7 @@ void POSE_OT_push(wmOperatorType *ot)
ot->poll = ED_operator_posemode;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR_X;
/* Properties */
pose_slide_opdef_properties(ot);
@ -1370,6 +1764,8 @@ static int pose_slide_relax_invoke(bContext *C, wmOperator *op, const wmEvent *e
pso = op->customdata;
pso->last_cursor_x = event->x;
/* Initialize percentage so that it won't pop on first mouse move. */
pose_slide_mouse_update_percentage(pso, op, event);
@ -1409,7 +1805,7 @@ void POSE_OT_relax(wmOperatorType *ot)
ot->poll = ED_operator_posemode;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR_X;
/* Properties */
pose_slide_opdef_properties(ot);
@ -1429,6 +1825,8 @@ static int pose_slide_push_rest_invoke(bContext *C, wmOperator *op, const wmEven
pso = op->customdata;
pso->last_cursor_x = event->x;
/* Initialize percentage so that it won't pop on first mouse move. */
pose_slide_mouse_update_percentage(pso, op, event);
@ -1468,7 +1866,7 @@ void POSE_OT_push_rest(wmOperatorType *ot)
ot->poll = ED_operator_posemode;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR_X;
/* Properties */
pose_slide_opdef_properties(ot);
@ -1489,6 +1887,8 @@ static int pose_slide_relax_rest_invoke(bContext *C, wmOperator *op, const wmEve
pso = op->customdata;
pso->last_cursor_x = event->x;
/* Initialize percentage so that it won't pop on first mouse move. */
pose_slide_mouse_update_percentage(pso, op, event);
@ -1528,7 +1928,7 @@ void POSE_OT_relax_rest(wmOperatorType *ot)
ot->poll = ED_operator_posemode;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR_X;
/* Properties */
pose_slide_opdef_properties(ot);
@ -1549,6 +1949,8 @@ static int pose_slide_breakdown_invoke(bContext *C, wmOperator *op, const wmEven
pso = op->customdata;
pso->last_cursor_x = event->x;
/* Initialize percentage so that it won't pop on first mouse move. */
pose_slide_mouse_update_percentage(pso, op, event);
@ -1588,7 +1990,7 @@ void POSE_OT_breakdown(wmOperatorType *ot)
ot->poll = ED_operator_posemode;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR_X;
/* Properties */
pose_slide_opdef_properties(ot);

View File

@ -200,8 +200,6 @@ ScrArea *ED_screen_areas_iter_next(const bScreen *screen, const ScrArea *area);
/* screens */
void ED_screens_init(struct Main *bmain, struct wmWindowManager *wm);
void ED_screen_draw_edges(struct wmWindow *win);
void ED_screen_draw_join_highlight(struct ScrArea *sa1, struct ScrArea *sa2);
void ED_screen_draw_split_preview(struct ScrArea *area, const int dir, const float fac);
void ED_screen_refresh(struct wmWindowManager *wm, struct wmWindow *win);
void ED_screen_ensure_updated(struct wmWindowManager *wm,
struct wmWindow *win,
@ -450,10 +448,10 @@ enum {
};
/* SCREEN_OT_space_context_cycle direction */
enum {
typedef enum eScreenCycle {
SPACE_CONTEXT_CYCLE_PREV,
SPACE_CONTEXT_CYCLE_NEXT,
};
} eScreenCycle;
#ifdef __cplusplus
}

View File

@ -801,7 +801,7 @@ bool ED_object_parent_set(ReportList *reports,
* so we check this by assuming that the parent is selected too.
*/
/* XXX currently this should only happen for meshes, curves, surfaces,
* and lattices - this stuff isn't available for metas yet */
* and lattices - this stuff isn't available for meta-balls yet. */
if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_LATTICE)) {
ModifierData *md;

View File

@ -1172,12 +1172,12 @@ static void region_azones_add(const bScreen *screen, ScrArea *area, ARegion *reg
}
/* dir is direction to check, not the splitting edge direction! */
static int rct_fits(const rcti *rect, char dir, int size)
static int rct_fits(const rcti *rect, const eScreenAxis dir_axis, int size)
{
if (dir == 'h') {
if (dir_axis == SCREEN_AXIS_H) {
return BLI_rcti_size_x(rect) + 1 - size;
}
/* 'v' */
/* Vertical. */
return BLI_rcti_size_y(rect) + 1 - size;
}
@ -1398,7 +1398,8 @@ static void region_rect_recursive(
region->flag |= RGN_FLAG_TOO_SMALL;
}
}
else if (rct_fits(remainder, 'v', 1) < 0 || rct_fits(remainder, 'h', 1) < 0) {
else if (rct_fits(remainder, SCREEN_AXIS_V, 1) < 0 ||
rct_fits(remainder, SCREEN_AXIS_H, 1) < 0) {
/* remainder is too small for any usage */
region->flag |= RGN_FLAG_TOO_SMALL;
}
@ -1410,11 +1411,11 @@ static void region_rect_recursive(
else if (ELEM(alignment, RGN_ALIGN_TOP, RGN_ALIGN_BOTTOM)) {
rcti *winrct = (region->overlap) ? overlap_remainder : remainder;
if ((prefsizey == 0) || (rct_fits(winrct, 'v', prefsizey) < 0)) {
if ((prefsizey == 0) || (rct_fits(winrct, SCREEN_AXIS_V, prefsizey) < 0)) {
region->flag |= RGN_FLAG_TOO_SMALL;
}
else {
int fac = rct_fits(winrct, 'v', prefsizey);
int fac = rct_fits(winrct, SCREEN_AXIS_V, prefsizey);
if (fac < 0) {
prefsizey += fac;
@ -1436,11 +1437,11 @@ static void region_rect_recursive(
else if (ELEM(alignment, RGN_ALIGN_LEFT, RGN_ALIGN_RIGHT)) {
rcti *winrct = (region->overlap) ? overlap_remainder : remainder;
if ((prefsizex == 0) || (rct_fits(winrct, 'h', prefsizex) < 0)) {
if ((prefsizex == 0) || (rct_fits(winrct, SCREEN_AXIS_H, prefsizex) < 0)) {
region->flag |= RGN_FLAG_TOO_SMALL;
}
else {
int fac = rct_fits(winrct, 'h', prefsizex);
int fac = rct_fits(winrct, SCREEN_AXIS_H, prefsizex);
if (fac < 0) {
prefsizex += fac;
@ -1464,7 +1465,7 @@ static void region_rect_recursive(
region->winrct = *remainder;
if (alignment == RGN_ALIGN_HSPLIT) {
if (rct_fits(remainder, 'h', prefsizex) > 4) {
if (rct_fits(remainder, SCREEN_AXIS_H, prefsizex) > 4) {
region->winrct.xmax = BLI_rcti_cent_x(remainder);
remainder->xmin = region->winrct.xmax + 1;
}
@ -1473,7 +1474,7 @@ static void region_rect_recursive(
}
}
else {
if (rct_fits(remainder, 'v', prefsizey) > 4) {
if (rct_fits(remainder, SCREEN_AXIS_V, prefsizey) > 4) {
region->winrct.ymax = BLI_rcti_cent_y(remainder);
remainder->ymin = region->winrct.ymax + 1;
}

View File

@ -237,23 +237,25 @@ void ED_screen_draw_edges(wmWindow *win)
* \param sa1: Area from which the resultant originates.
* \param sa2: Target area that will be replaced.
*/
void ED_screen_draw_join_highlight(ScrArea *sa1, ScrArea *sa2)
void screen_draw_join_highlight(ScrArea *sa1, ScrArea *sa2)
{
int dir = area_getorientation(sa1, sa2);
if (dir == -1) {
const eScreenDir dir = area_getorientation(sa1, sa2);
if (dir == SCREEN_DIR_NONE) {
return;
}
/* Rect of the combined areas.*/
bool vertical = ELEM(dir, 1, 3);
rctf combined = {.xmin = vertical ? MAX2(sa1->totrct.xmin, sa2->totrct.xmin) :
MIN2(sa1->totrct.xmin, sa2->totrct.xmin),
.xmax = vertical ? MIN2(sa1->totrct.xmax, sa2->totrct.xmax) :
MAX2(sa1->totrct.xmax, sa2->totrct.xmax),
.ymin = vertical ? MIN2(sa1->totrct.ymin, sa2->totrct.ymin) :
MAX2(sa1->totrct.ymin, sa2->totrct.ymin),
.ymax = vertical ? MAX2(sa1->totrct.ymax, sa2->totrct.ymax) :
MIN2(sa1->totrct.ymax, sa2->totrct.ymax)};
const bool vertical = SCREEN_DIR_IS_VERTICAL(dir);
const rctf combined = {
.xmin = vertical ? MAX2(sa1->totrct.xmin, sa2->totrct.xmin) :
MIN2(sa1->totrct.xmin, sa2->totrct.xmin),
.xmax = vertical ? MIN2(sa1->totrct.xmax, sa2->totrct.xmax) :
MAX2(sa1->totrct.xmax, sa2->totrct.xmax),
.ymin = vertical ? MIN2(sa1->totrct.ymin, sa2->totrct.ymin) :
MAX2(sa1->totrct.ymin, sa2->totrct.ymin),
.ymax = vertical ? MAX2(sa1->totrct.ymax, sa2->totrct.ymax) :
MIN2(sa1->totrct.ymax, sa2->totrct.ymax),
};
uint pos_id = GPU_vertformat_attr_add(
immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
@ -320,7 +322,7 @@ void ED_screen_draw_join_highlight(ScrArea *sa1, ScrArea *sa2)
UI_draw_roundbox_4fv(&combined, false, 7 * U.pixelsize, (float[4]){1.0f, 1.0f, 1.0f, 0.8f});
}
void ED_screen_draw_split_preview(ScrArea *area, const int dir, const float fac)
void screen_draw_split_preview(ScrArea *area, const eScreenAxis dir_axis, const float fac)
{
uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
@ -332,7 +334,7 @@ void ED_screen_draw_split_preview(ScrArea *area, const int dir, const float fac)
immBegin(GPU_PRIM_LINES, 2);
if (dir == 'h') {
if (dir_axis == SCREEN_AXIS_H) {
const float y = (1 - fac) * area->totrct.ymin + fac * area->totrct.ymax;
immVertex2f(pos, area->totrct.xmin, y);
@ -350,7 +352,7 @@ void ED_screen_draw_split_preview(ScrArea *area, const int dir, const float fac)
immEnd();
}
else {
BLI_assert(dir == 'v');
BLI_assert(dir_axis == SCREEN_AXIS_V);
const float x = (1 - fac) * area->totrct.xmin + fac * area->totrct.xmax;
immVertex2f(pos, x, area->totrct.ymin);

View File

@ -107,7 +107,7 @@ static void screen_delarea(bContext *C, bScreen *screen, ScrArea *area)
ScrArea *area_split(const wmWindow *win,
bScreen *screen,
ScrArea *area,
char dir,
const eScreenAxis dir_axis,
const float fac,
const bool merge)
{
@ -120,7 +120,7 @@ ScrArea *area_split(const wmWindow *win,
rcti window_rect;
WM_window_rect_calc(win, &window_rect);
short split = screen_geom_find_area_split_point(area, &window_rect, dir, fac);
short split = screen_geom_find_area_split_point(area, &window_rect, dir_axis, fac);
if (split == 0) {
return NULL;
}
@ -129,7 +129,7 @@ ScrArea *area_split(const wmWindow *win,
* normally it shouldn't matter which is used since the copy should match the original
* however with viewport rendering and python console this isn't the case. - campbell */
if (dir == 'h') {
if (dir_axis == SCREEN_AXIS_H) {
/* new vertices */
ScrVert *sv1 = screen_geom_vertex_add(screen, area->v1->vec.x, split);
ScrVert *sv2 = screen_geom_vertex_add(screen, area->v4->vec.x, split);
@ -288,10 +288,10 @@ void screen_new_activate_prepare(const wmWindow *win, bScreen *screen_new)
* -1 = not valid check.
* used with join operator.
*/
int area_getorientation(ScrArea *sa_a, ScrArea *sa_b)
eScreenDir area_getorientation(ScrArea *sa_a, ScrArea *sa_b)
{
if (sa_a == NULL || sa_b == NULL || sa_a == sa_b) {
return -1;
return SCREEN_DIR_NONE;
}
const vec2s *sa_bl = &sa_a->v1->vec;
@ -331,29 +331,31 @@ int area_getorientation(ScrArea *sa_a, ScrArea *sa_b)
/**
* Get alignment offset of adjacent areas. 'dir' value is like #area_getorientation().
*/
void area_getoffsets(ScrArea *sa_a, ScrArea *sa_b, const int dir, int *r_offset1, int *r_offset2)
void area_getoffsets(
ScrArea *sa_a, ScrArea *sa_b, const eScreenDir dir, int *r_offset1, int *r_offset2)
{
if (sa_a == NULL || sa_b == NULL) {
*r_offset1 = INT_MAX;
*r_offset2 = INT_MAX;
}
else if (dir == 0) { /* West: sa on right and sa_b to the left. */
else if (dir == SCREEN_DIR_W) { /* West: sa on right and sa_b to the left. */
*r_offset1 = sa_b->v3->vec.y - sa_a->v2->vec.y;
*r_offset2 = sa_b->v4->vec.y - sa_a->v1->vec.y;
}
else if (dir == 1) { /* North: sa below and sa_b above. */
else if (dir == SCREEN_DIR_N) { /* North: sa below and sa_b above. */
*r_offset1 = sa_a->v2->vec.x - sa_b->v1->vec.x;
*r_offset2 = sa_a->v3->vec.x - sa_b->v4->vec.x;
}
else if (dir == 2) { /* East: sa on left and sa_b to the right. */
else if (dir == SCREEN_DIR_E) { /* East: sa on left and sa_b to the right. */
*r_offset1 = sa_b->v2->vec.y - sa_a->v3->vec.y;
*r_offset2 = sa_b->v1->vec.y - sa_a->v4->vec.y;
}
else if (dir == 3) { /* South: sa above and sa_b below. */
else if (dir == SCREEN_DIR_S) { /* South: sa above and sa_b below. */
*r_offset1 = sa_a->v1->vec.x - sa_b->v2->vec.x;
*r_offset2 = sa_a->v4->vec.x - sa_b->v3->vec.x;
}
else {
BLI_assert(dir == SCREEN_DIR_NONE);
*r_offset1 = INT_MAX;
*r_offset2 = INT_MAX;
}
@ -390,11 +392,11 @@ static void screen_verts_valign(const wmWindow *win,
/* Adjust all screen edges to allow joining two areas. 'dir' value is like area_getorientation().
*/
static void screen_areas_align(
bContext *C, bScreen *screen, ScrArea *sa1, ScrArea *sa2, const int dir)
bContext *C, bScreen *screen, ScrArea *sa1, ScrArea *sa2, const eScreenDir dir)
{
wmWindow *win = CTX_wm_window(C);
if (ELEM(dir, 0, 2)) {
if (SCREEN_DIR_IS_HORIZONTAL(dir)) {
/* horizontal join, use average for new top and bottom. */
int top = (sa1->v2->vec.y + sa2->v2->vec.y) / 2;
int bottom = (sa1->v4->vec.y + sa2->v4->vec.y) / 2;
@ -425,8 +427,8 @@ static void screen_areas_align(
/* Simple join of two areas without any splitting. Will return false if not possible. */
static bool screen_area_join_aligned(bContext *C, bScreen *screen, ScrArea *sa1, ScrArea *sa2)
{
int dir = area_getorientation(sa1, sa2);
if (dir == -1) {
const eScreenDir dir = area_getorientation(sa1, sa2);
if (dir == SCREEN_DIR_NONE) {
return false;
}
@ -434,7 +436,7 @@ static bool screen_area_join_aligned(bContext *C, bScreen *screen, ScrArea *sa1,
int offset2;
area_getoffsets(sa1, sa2, dir, &offset1, &offset2);
int tolerance = ELEM(dir, 0, 2) ? AREAJOINTOLERANCEY : AREAJOINTOLERANCEX;
int tolerance = SCREEN_DIR_IS_HORIZONTAL(dir) ? AREAJOINTOLERANCEY : AREAJOINTOLERANCEX;
if ((abs(offset1) >= tolerance) || (abs(offset2) >= tolerance)) {
return false;
}
@ -442,27 +444,27 @@ static bool screen_area_join_aligned(bContext *C, bScreen *screen, ScrArea *sa1,
/* Align areas if they are not. */
screen_areas_align(C, screen, sa1, sa2, dir);
if (dir == 0) { /* sa1 to right of sa2 = W */
sa1->v1 = sa2->v1; /* BL */
sa1->v2 = sa2->v2; /* TL */
if (dir == SCREEN_DIR_W) { /* sa1 to right of sa2 = West. */
sa1->v1 = sa2->v1; /* BL */
sa1->v2 = sa2->v2; /* TL */
screen_geom_edge_add(screen, sa1->v2, sa1->v3);
screen_geom_edge_add(screen, sa1->v1, sa1->v4);
}
else if (dir == 1) { /* sa1 to bottom of sa2 = N */
sa1->v2 = sa2->v2; /* TL */
sa1->v3 = sa2->v3; /* TR */
else if (dir == SCREEN_DIR_N) { /* sa1 to bottom of sa2 = North. */
sa1->v2 = sa2->v2; /* TL */
sa1->v3 = sa2->v3; /* TR */
screen_geom_edge_add(screen, sa1->v1, sa1->v2);
screen_geom_edge_add(screen, sa1->v3, sa1->v4);
}
else if (dir == 2) { /* sa1 to left of sa2 = E */
sa1->v3 = sa2->v3; /* TR */
sa1->v4 = sa2->v4; /* BR */
else if (dir == SCREEN_DIR_E) { /* sa1 to left of sa2 = East. */
sa1->v3 = sa2->v3; /* TR */
sa1->v4 = sa2->v4; /* BR */
screen_geom_edge_add(screen, sa1->v2, sa1->v3);
screen_geom_edge_add(screen, sa1->v1, sa1->v4);
}
else if (dir == 3) { /* sa1 on top of sa2 = S */
sa1->v1 = sa2->v1; /* BL */
sa1->v4 = sa2->v4; /* BR */
else if (dir == SCREEN_DIR_S) { /* sa1 on top of sa2 = South. */
sa1->v1 = sa2->v1; /* BL */
sa1->v4 = sa2->v4; /* BR */
screen_geom_edge_add(screen, sa1->v1, sa1->v2);
screen_geom_edge_add(screen, sa1->v3, sa1->v4);
}
@ -477,9 +479,9 @@ static bool screen_area_join_aligned(bContext *C, bScreen *screen, ScrArea *sa1,
/* Slice off and return new area. "Reverse" gives right/bottom, rather than left/top. */
static ScrArea *screen_area_trim(
bContext *C, bScreen *screen, ScrArea **area, int size, int dir, bool reverse)
bContext *C, bScreen *screen, ScrArea **area, int size, eScreenDir dir, bool reverse)
{
bool vertical = ELEM(dir, 1, 3);
const bool vertical = SCREEN_DIR_IS_VERTICAL(dir);
if (abs(size) < (vertical ? AREAJOINTOLERANCEX : AREAJOINTOLERANCEY)) {
return NULL;
}
@ -488,7 +490,8 @@ static ScrArea *screen_area_trim(
float fac = abs(size) / (float)(vertical ? ((*area)->v3->vec.x - (*area)->v1->vec.x) :
((*area)->v3->vec.y - (*area)->v1->vec.y));
fac = (reverse == vertical) ? 1.0f - fac : fac;
ScrArea *newsa = area_split(CTX_wm_window(C), screen, *area, vertical ? 'v' : 'h', fac, true);
ScrArea *newsa = area_split(
CTX_wm_window(C), screen, *area, vertical ? SCREEN_AXIS_V : SCREEN_AXIS_H, fac, true);
/* area_split always returns smallest of the two areas, so might have to swap. */
if (((fac > 0.5f) == vertical) != reverse) {
@ -504,8 +507,8 @@ static ScrArea *screen_area_trim(
static bool screen_area_join_ex(
bContext *C, bScreen *screen, ScrArea *sa1, ScrArea *sa2, bool close_all_remainders)
{
int dir = area_getorientation(sa1, sa2);
if (dir == -1) {
const eScreenDir dir = area_getorientation(sa1, sa2);
if (dir == SCREEN_DIR_NONE) {
return false;
}
@ -549,14 +552,15 @@ bool screen_area_close(struct bContext *C, bScreen *screen, ScrArea *area)
float best_alignment = 0.0f;
LISTBASE_FOREACH (ScrArea *, neighbor, &screen->areabase) {
int dir = area_getorientation(area, neighbor);
const eScreenDir dir = area_getorientation(area, neighbor);
/* Must at least partially share an edge and not be a global area. */
if (dir != -1 && !neighbor->global) {
if ((dir != SCREEN_DIR_NONE) && (neighbor->global == NULL)) {
/* Winx/Winy might not be updated yet, so get lengths from verts. */
int area_length = ELEM(dir, 1, 3) ? area->v3->vec.x - area->v1->vec.x :
area->v3->vec.y - area->v1->vec.y;
int ar_length = ELEM(dir, 1, 3) ? neighbor->v3->vec.x - neighbor->v1->vec.x :
neighbor->v3->vec.y - neighbor->v1->vec.y;
const bool vertical = SCREEN_DIR_IS_VERTICAL(dir);
const int area_length = vertical ? (area->v3->vec.x - area->v1->vec.x) :
(area->v3->vec.y - area->v1->vec.y);
const int ar_length = vertical ? (neighbor->v3->vec.x - neighbor->v1->vec.x) :
(neighbor->v3->vec.y - neighbor->v1->vec.y);
/* Calculate the ratio of the lengths of the shared edges. */
float alignment = MIN2(area_length, ar_length) / (float)MAX2(area_length, ar_length);
if (alignment > best_alignment) {

View File

@ -304,7 +304,7 @@ void screen_geom_vertices_scale(const wmWindow *win, bScreen *screen)
*/
short screen_geom_find_area_split_point(const ScrArea *area,
const rcti *window_rect,
char dir,
const eScreenAxis dir_axis,
float fac)
{
const int cur_area_width = screen_geom_area_width(area);
@ -313,17 +313,21 @@ short screen_geom_find_area_split_point(const ScrArea *area,
const short area_min_y = ED_area_headersize();
/* area big enough? */
if ((dir == 'v') && (cur_area_width <= 2 * area_min_x)) {
return 0;
if (dir_axis == SCREEN_AXIS_V) {
if (cur_area_width <= 2 * area_min_x) {
return 0;
}
}
if ((dir == 'h') && (cur_area_height <= 2 * area_min_y)) {
return 0;
else if (dir_axis == SCREEN_AXIS_H) {
if (cur_area_height <= 2 * area_min_y) {
return 0;
}
}
/* to be sure */
CLAMP(fac, 0.0f, 1.0f);
if (dir == 'h') {
if (dir_axis == SCREEN_AXIS_H) {
short y = area->v1->vec.y + round_fl_to_short(fac * cur_area_height);
int area_min = area_min_y;
@ -373,13 +377,13 @@ void screen_geom_select_connected_edge(const wmWindow *win, ScrEdge *edge)
{
bScreen *screen = WM_window_get_active_screen(win);
/* 'dir' is the direction of EDGE */
char dir;
/* 'dir_axis' is the direction of EDGE */
eScreenAxis dir_axis;
if (edge->v1->vec.x == edge->v2->vec.x) {
dir = 'v';
dir_axis = SCREEN_AXIS_V;
}
else {
dir = 'h';
dir_axis = SCREEN_AXIS_H;
}
ED_screen_verts_iter(win, screen, sv)
@ -396,13 +400,13 @@ void screen_geom_select_connected_edge(const wmWindow *win, ScrEdge *edge)
oneselected = false;
LISTBASE_FOREACH (ScrEdge *, se, &screen->edgebase) {
if (se->v1->flag + se->v2->flag == 1) {
if (dir == 'h') {
if (dir_axis == SCREEN_AXIS_H) {
if (se->v1->vec.y == se->v2->vec.y) {
se->v1->flag = se->v2->flag = 1;
oneselected = true;
}
}
if (dir == 'v') {
else if (dir_axis == SCREEN_AXIS_V) {
if (se->v1->vec.x == se->v2->vec.x) {
se->v1->flag = se->v2->flag = 1;
oneselected = true;

View File

@ -29,6 +29,29 @@ struct bContextDataResult;
/* internal exports only */
typedef enum eScreenDir {
/** This can mean unset, unknown or invalid. */
SCREEN_DIR_NONE = -1,
/** West/Left. */
SCREEN_DIR_W = 0,
/** North/Up. */
SCREEN_DIR_N = 1,
/** East/Right. */
SCREEN_DIR_E = 2,
/** South/Down. */
SCREEN_DIR_S = 3,
} eScreenDir;
#define SCREEN_DIR_IS_VERTICAL(dir) (ELEM(dir, SCREEN_DIR_N, SCREEN_DIR_S))
#define SCREEN_DIR_IS_HORIZONTAL(dir) (ELEM(dir, SCREEN_DIR_W, SCREEN_DIR_E))
typedef enum eScreenAxis {
/** Horizontal. */
SCREEN_AXIS_H = 'h',
/** Vertical. */
SCREEN_AXIS_V = 'v',
} eScreenAxis;
#define AZONESPOTW UI_HEADER_OFFSET /* width of corner #AZone - max */
#define AZONESPOTH (0.6f * U.widget_unit) /* height of corner #AZone */
#define AZONEFADEIN (5.0f * U.widget_unit) /* when #AZone is totally visible */
@ -46,6 +69,10 @@ void ED_area_data_copy(ScrArea *area_dst, ScrArea *area_src, const bool do_free)
void ED_area_data_swap(ScrArea *area_dst, ScrArea *area_src);
void region_toggle_hidden(struct bContext *C, ARegion *region, const bool do_fade);
/* screen_draw.c */
void screen_draw_join_highlight(struct ScrArea *sa1, struct ScrArea *sa2);
void screen_draw_split_preview(struct ScrArea *area, const eScreenAxis dir_axis, const float fac);
/* screen_edit.c */
bScreen *screen_add(struct Main *bmain, const char *name, const rcti *rect);
void screen_data_copy(bScreen *to, bScreen *from);
@ -59,12 +86,13 @@ void screen_change_prepare(bScreen *screen_old,
ScrArea *area_split(const wmWindow *win,
bScreen *screen,
ScrArea *area,
char dir,
const eScreenAxis dir_axis,
const float fac,
const bool merge);
int screen_area_join(struct bContext *C, bScreen *screen, ScrArea *sa1, ScrArea *sa2);
int area_getorientation(ScrArea *sa_a, ScrArea *sa_b);
void area_getoffsets(ScrArea *sa_a, ScrArea *sa_b, const int dir, int *r_offset1, int *r_offset2);
eScreenDir area_getorientation(ScrArea *sa_a, ScrArea *sa_b);
void area_getoffsets(
ScrArea *sa_a, ScrArea *sa_b, const eScreenDir dir, int *r_offset1, int *r_offset2);
bool screen_area_close(struct bContext *C, bScreen *screen, ScrArea *area);
struct AZone *ED_area_actionzone_find_xy(ScrArea *area, const int xy[2]);
@ -87,7 +115,7 @@ ScrEdge *screen_geom_find_active_scredge(const wmWindow *win,
void screen_geom_vertices_scale(const wmWindow *win, bScreen *screen);
short screen_geom_find_area_split_point(const ScrArea *area,
const rcti *window_rect,
char dir,
const eScreenAxis dir_axis,
float fac);
void screen_geom_select_connected_edge(const wmWindow *win, ScrEdge *edge);

View File

@ -694,7 +694,9 @@ static bool screen_active_editable(bContext *C)
typedef struct sActionzoneData {
ScrArea *sa1, *sa2;
AZone *az;
int x, y, gesture_dir, modifier;
int x, y;
eScreenDir gesture_dir;
int modifier;
} sActionzoneData;
/* quick poll to save operators to be created and handled */
@ -1045,16 +1047,16 @@ static int actionzone_modal(bContext *C, wmOperator *op, const wmEvent *event)
/* Calculate gesture cardinal direction. */
if (delta_y > abs(delta_x)) {
sad->gesture_dir = 'n';
sad->gesture_dir = SCREEN_DIR_N;
}
else if (delta_x >= abs(delta_y)) {
sad->gesture_dir = 'e';
sad->gesture_dir = SCREEN_DIR_E;
}
else if (delta_y < -abs(delta_x)) {
sad->gesture_dir = 's';
sad->gesture_dir = SCREEN_DIR_S;
}
else {
sad->gesture_dir = 'w';
sad->gesture_dir = SCREEN_DIR_W;
}
bool is_gesture;
@ -1071,22 +1073,24 @@ static int actionzone_modal(bContext *C, wmOperator *op, const wmEvent *event)
/* Are we still in same area? */
if (BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, event->x, event->y) == sad->sa1) {
/* Same area, so possible split. */
WM_cursor_set(
win, (ELEM(sad->gesture_dir, 'n', 's')) ? WM_CURSOR_H_SPLIT : WM_CURSOR_V_SPLIT);
WM_cursor_set(win,
SCREEN_DIR_IS_VERTICAL(sad->gesture_dir) ? WM_CURSOR_H_SPLIT :
WM_CURSOR_V_SPLIT);
is_gesture = (delta_max > split_threshold);
}
else {
/* Different area, so possible join. */
if (sad->gesture_dir == 'n') {
if (sad->gesture_dir == SCREEN_DIR_N) {
WM_cursor_set(win, WM_CURSOR_N_ARROW);
}
else if (sad->gesture_dir == 's') {
else if (sad->gesture_dir == SCREEN_DIR_S) {
WM_cursor_set(win, WM_CURSOR_S_ARROW);
}
else if (sad->gesture_dir == 'e') {
else if (sad->gesture_dir == SCREEN_DIR_E) {
WM_cursor_set(win, WM_CURSOR_E_ARROW);
}
else {
BLI_assert(sad->gesture_dir == SCREEN_DIR_W);
WM_cursor_set(win, WM_CURSOR_W_ARROW);
}
is_gesture = (delta_max > join_threshold);
@ -1480,7 +1484,7 @@ static void SCREEN_OT_area_close(wmOperatorType *ot)
typedef struct sAreaMoveData {
int bigger, smaller, origval, step;
char dir;
eScreenAxis dir_axis;
enum AreaMoveSnapType {
/* Snapping disabled */
SNAP_NONE = 0,
@ -1499,7 +1503,7 @@ typedef struct sAreaMoveData {
* need window bounds in order to get correct limits */
static void area_move_set_limits(wmWindow *win,
bScreen *screen,
int dir,
const eScreenAxis dir_axis,
int *bigger,
int *smaller,
bool *use_bigger_smaller_snap)
@ -1552,7 +1556,7 @@ static void area_move_set_limits(wmWindow *win,
WM_window_rect_calc(win, &window_rect);
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
if (dir == 'h') {
if (dir_axis == SCREEN_AXIS_H) {
int areamin = ED_area_headersize();
if (area->v1->vec.y > window_rect.ymin) {
@ -1615,8 +1619,8 @@ static bool area_move_init(bContext *C, wmOperator *op)
sAreaMoveData *md = MEM_callocN(sizeof(sAreaMoveData), "sAreaMoveData");
op->customdata = md;
md->dir = screen_geom_edge_is_horizontal(actedge) ? 'h' : 'v';
if (md->dir == 'h') {
md->dir_axis = screen_geom_edge_is_horizontal(actedge) ? SCREEN_AXIS_H : SCREEN_AXIS_V;
if (md->dir_axis == SCREEN_AXIS_H) {
md->origval = actedge->v1->vec.y;
}
else {
@ -1631,7 +1635,8 @@ static bool area_move_init(bContext *C, wmOperator *op)
}
bool use_bigger_smaller_snap = false;
area_move_set_limits(win, screen, md->dir, &md->bigger, &md->smaller, &use_bigger_smaller_snap);
area_move_set_limits(
win, screen, md->dir_axis, &md->bigger, &md->smaller, &use_bigger_smaller_snap);
md->snap_type = use_bigger_smaller_snap ? SNAP_BIGGER_SMALLER_ONLY : SNAP_AREAGRID;
@ -1642,7 +1647,7 @@ static int area_snap_calc_location(const bScreen *screen,
const enum AreaMoveSnapType snap_type,
const int delta,
const int origval,
const int dir,
const eScreenAxis dir_axis,
const int bigger,
const int smaller)
{
@ -1667,7 +1672,7 @@ static int area_snap_calc_location(const bScreen *screen,
break;
case SNAP_FRACTION_AND_ADJACENT: {
const int axis = (dir == 'v') ? 0 : 1;
const int axis = (dir_axis == SCREEN_AXIS_V) ? 0 : 1;
int snap_dist_best = INT_MAX;
{
const float div_array[] = {
@ -1735,7 +1740,7 @@ static int area_snap_calc_location(const bScreen *screen,
static void area_move_apply_do(const bContext *C,
int delta,
const int origval,
const int dir,
const eScreenAxis dir_axis,
const int bigger,
const int smaller,
const enum AreaMoveSnapType snap_type)
@ -1753,11 +1758,12 @@ static void area_move_apply_do(const bContext *C,
final_loc = origval + delta;
}
else {
final_loc = area_snap_calc_location(screen, snap_type, delta, origval, dir, bigger, smaller);
final_loc = area_snap_calc_location(
screen, snap_type, delta, origval, dir_axis, bigger, smaller);
}
BLI_assert(final_loc != -1);
short axis = (dir == 'v') ? 0 : 1;
short axis = (dir_axis == SCREEN_AXIS_V) ? 0 : 1;
ED_screen_verts_iter(win, screen, v1)
{
@ -1813,7 +1819,7 @@ static void area_move_apply(bContext *C, wmOperator *op)
sAreaMoveData *md = op->customdata;
int delta = RNA_int_get(op->ptr, "delta");
area_move_apply_do(C, delta, md->origval, md->dir, md->bigger, md->smaller, md->snap_type);
area_move_apply_do(C, delta, md->origval, md->dir_axis, md->bigger, md->smaller, md->snap_type);
}
static void area_move_exit(bContext *C, wmOperator *op)
@ -1878,7 +1884,7 @@ static int area_move_modal(bContext *C, wmOperator *op, const wmEvent *event)
int x = RNA_int_get(op->ptr, "x");
int y = RNA_int_get(op->ptr, "y");
int delta = (md->dir == 'v') ? event->x - x : event->y - y;
const int delta = (md->dir_axis == SCREEN_AXIS_V) ? event->x - x : event->y - y;
RNA_int_set(op->ptr, "delta", delta);
area_move_apply(C, op);
@ -1944,7 +1950,7 @@ static void SCREEN_OT_area_move(wmOperatorType *ot)
/*
* operator state vars:
* fac spit point
* dir direction 'v' or 'h'
* dir direction #SCREEN_AXIS_V or #SCREEN_AXIS_H
*
* operator customdata:
* area pointer to (active) area
@ -1981,7 +1987,7 @@ typedef struct sAreaSplitData {
int delta; /* delta move edge */
int origmin, origsize; /* to calculate fac, for property storage */
int previewmode; /* draw previewline, then split */
void *draw_callback; /* call `ED_screen_draw_split_preview` */
void *draw_callback; /* call `screen_draw_split_preview` */
bool do_snap;
ScrEdge *nedge; /* new edge */
@ -1996,10 +2002,10 @@ static void area_split_draw_cb(const struct wmWindow *UNUSED(win), void *userdat
sAreaSplitData *sd = op->customdata;
if (sd->sarea) {
int dir = RNA_enum_get(op->ptr, "direction");
const eScreenAxis dir_axis = RNA_enum_get(op->ptr, "direction");
float fac = RNA_float_get(op->ptr, "factor");
ED_screen_draw_split_preview(sd->sarea, dir, fac);
screen_draw_split_preview(sd->sarea, dir_axis, fac);
}
}
@ -2026,14 +2032,18 @@ static bool area_split_init(bContext *C, wmOperator *op)
}
/* required properties */
int dir = RNA_enum_get(op->ptr, "direction");
const eScreenAxis dir_axis = RNA_enum_get(op->ptr, "direction");
/* minimal size */
if (dir == 'v' && area->winx < 2 * AREAMINX) {
return false;
if (dir_axis == SCREEN_AXIS_V) {
if (area->winx < 2 * AREAMINX) {
return false;
}
}
if (dir == 'h' && area->winy < 2 * ED_area_headersize()) {
return false;
else {
if (area->winy < 2 * ED_area_headersize()) {
return false;
}
}
/* custom data */
@ -2041,7 +2051,7 @@ static bool area_split_init(bContext *C, wmOperator *op)
op->customdata = sd;
sd->sarea = area;
if (dir == 'v') {
if (dir_axis == SCREEN_AXIS_V) {
sd->origmin = area->v1->vec.x;
sd->origsize = area->v4->vec.x - sd->origmin;
}
@ -2090,9 +2100,9 @@ static bool area_split_apply(bContext *C, wmOperator *op)
sAreaSplitData *sd = (sAreaSplitData *)op->customdata;
float fac = RNA_float_get(op->ptr, "factor");
int dir = RNA_enum_get(op->ptr, "direction");
const eScreenAxis dir_axis = RNA_enum_get(op->ptr, "direction");
sd->narea = area_split(win, screen, sd->sarea, dir, fac, false); /* false = no merge */
sd->narea = area_split(win, screen, sd->sarea, dir_axis, fac, false); /* false = no merge */
if (sd->narea == NULL) {
return false;
@ -2109,7 +2119,7 @@ static bool area_split_apply(bContext *C, wmOperator *op)
sd->nedge->v1->editflag = 1;
sd->nedge->v2->editflag = 1;
if (dir == 'h') {
if (dir_axis == SCREEN_AXIS_H) {
sd->origval = sd->nedge->v1->vec.y;
}
else {
@ -2158,8 +2168,8 @@ static void area_split_exit(bContext *C, wmOperator *op)
static void area_split_preview_update_cursor(bContext *C, wmOperator *op)
{
wmWindow *win = CTX_wm_window(C);
int dir = RNA_enum_get(op->ptr, "direction");
WM_cursor_set(win, dir == 'h' ? WM_CURSOR_H_SPLIT : WM_CURSOR_V_SPLIT);
const eScreenAxis dir_axis = RNA_enum_get(op->ptr, "direction");
WM_cursor_set(win, (dir_axis == SCREEN_AXIS_H) ? WM_CURSOR_H_SPLIT : WM_CURSOR_V_SPLIT);
}
/* UI callback, adds new handler */
@ -2175,7 +2185,7 @@ static int area_split_invoke(bContext *C, wmOperator *op, const wmEvent *event)
PropertyRNA *prop_factor = RNA_struct_find_property(op->ptr, "factor");
PropertyRNA *prop_cursor = RNA_struct_find_property(op->ptr, "cursor");
int dir;
eScreenAxis dir_axis;
if (event->type == EVT_ACTIONZONE_AREA) {
sActionzoneData *sad = event->customdata;
@ -2203,12 +2213,12 @@ static int area_split_invoke(bContext *C, wmOperator *op, const wmEvent *event)
float factor;
/* Prepare operator state vars. */
if (ELEM(sad->gesture_dir, 'n', 's')) {
dir = 'h';
if (SCREEN_DIR_IS_VERTICAL(sad->gesture_dir)) {
dir_axis = SCREEN_AXIS_H;
factor = factor_h;
}
else {
dir = 'v';
dir_axis = SCREEN_AXIS_V;
factor = factor_v;
}
@ -2218,7 +2228,7 @@ static int area_split_invoke(bContext *C, wmOperator *op, const wmEvent *event)
RNA_property_float_set(op->ptr, prop_factor, factor);
RNA_property_enum_set(op->ptr, prop_dir, dir);
RNA_property_enum_set(op->ptr, prop_dir, dir_axis);
/* general init, also non-UI case, adds customdata, sets area and defaults */
if (!area_split_init(C, op)) {
@ -2230,8 +2240,8 @@ static int area_split_invoke(bContext *C, wmOperator *op, const wmEvent *event)
if (area == NULL) {
return OPERATOR_CANCELLED;
}
dir = RNA_property_enum_get(op->ptr, prop_dir);
if (dir == 'h') {
dir_axis = RNA_property_enum_get(op->ptr, prop_dir);
if (dir_axis == SCREEN_AXIS_H) {
RNA_property_float_set(
op->ptr, prop_factor, ((float)(event->x - area->v1->vec.x)) / (float)area->winx);
}
@ -2264,9 +2274,9 @@ static int area_split_invoke(bContext *C, wmOperator *op, const wmEvent *event)
return OPERATOR_CANCELLED;
}
dir = screen_geom_edge_is_horizontal(actedge) ? 'v' : 'h';
dir_axis = screen_geom_edge_is_horizontal(actedge) ? SCREEN_AXIS_V : SCREEN_AXIS_H;
RNA_property_enum_set(op->ptr, prop_dir, dir);
RNA_property_enum_set(op->ptr, prop_dir, dir_axis);
/* special case, adds customdata, sets defaults */
if (!area_split_menu_init(C, op)) {
@ -2279,7 +2289,7 @@ static int area_split_invoke(bContext *C, wmOperator *op, const wmEvent *event)
if (event->type == EVT_ACTIONZONE_AREA) {
/* do the split */
if (area_split_apply(C, op)) {
area_move_set_limits(win, screen, dir, &sd->bigger, &sd->smaller, NULL);
area_move_set_limits(win, screen, dir_axis, &sd->bigger, &sd->smaller, NULL);
/* add temp handler for edge move or cancel */
G.moving |= G_TRANSFORM_WM;
@ -2367,8 +2377,9 @@ static int area_split_modal(bContext *C, wmOperator *op, const wmEvent *event)
else {
if (event->val == KM_PRESS) {
if (sd->sarea) {
int dir = RNA_property_enum_get(op->ptr, prop_dir);
RNA_property_enum_set(op->ptr, prop_dir, (dir == 'v') ? 'h' : 'v');
const eScreenAxis dir_axis = RNA_property_enum_get(op->ptr, prop_dir);
RNA_property_enum_set(
op->ptr, prop_dir, (dir_axis == SCREEN_AXIS_V) ? SCREEN_AXIS_H : SCREEN_AXIS_V);
area_split_preview_update_cursor(C, op);
update_factor = true;
}
@ -2389,9 +2400,9 @@ static int area_split_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
if (update_factor) {
const int dir = RNA_property_enum_get(op->ptr, prop_dir);
const eScreenAxis dir_axis = RNA_property_enum_get(op->ptr, prop_dir);
sd->delta = (dir == 'v') ? event->x - sd->origval : event->y - sd->origval;
sd->delta = (dir_axis == SCREEN_AXIS_V) ? event->x - sd->origval : event->y - sd->origval;
if (sd->previewmode == 0) {
if (sd->do_snap) {
@ -2399,12 +2410,12 @@ static int area_split_modal(bContext *C, wmOperator *op, const wmEvent *event)
SNAP_FRACTION_AND_ADJACENT,
sd->delta,
sd->origval,
dir,
dir_axis,
sd->bigger,
sd->smaller);
sd->delta = snap_loc - sd->origval;
}
area_move_apply_do(C, sd->delta, sd->origval, dir, sd->bigger, sd->smaller, SNAP_NONE);
area_move_apply_do(C, sd->delta, sd->origval, dir_axis, sd->bigger, sd->smaller, SNAP_NONE);
}
else {
if (sd->sarea) {
@ -2415,7 +2426,7 @@ static int area_split_modal(bContext *C, wmOperator *op, const wmEvent *event)
if (sd->sarea) {
ScrArea *area = sd->sarea;
if (dir == 'v') {
if (dir_axis == SCREEN_AXIS_V) {
sd->origmin = area->v1->vec.x;
sd->origsize = area->v4->vec.x - sd->origmin;
}
@ -2431,7 +2442,7 @@ static int area_split_modal(bContext *C, wmOperator *op, const wmEvent *event)
SNAP_FRACTION_AND_ADJACENT,
sd->delta,
sd->origval,
dir,
dir_axis,
sd->origmin + sd->origsize,
-sd->origmin);
@ -2453,8 +2464,8 @@ static int area_split_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
static const EnumPropertyItem prop_direction_items[] = {
{'h', "HORIZONTAL", 0, "Horizontal", ""},
{'v', "VERTICAL", 0, "Vertical", ""},
{SCREEN_AXIS_H, "HORIZONTAL", 0, "Horizontal", ""},
{SCREEN_AXIS_V, "VERTICAL", 0, "Vertical", ""},
{0, NULL, 0, NULL, NULL},
};
@ -2475,7 +2486,7 @@ static void SCREEN_OT_area_split(wmOperatorType *ot)
ot->flag = OPTYPE_BLOCKING | OPTYPE_INTERNAL;
/* rna */
RNA_def_enum(ot->srna, "direction", prop_direction_items, 'h', "Direction", "");
RNA_def_enum(ot->srna, "direction", prop_direction_items, SCREEN_AXIS_H, "Direction", "");
RNA_def_float(ot->srna, "factor", 0.5f, 0.0, 1.0, "Factor", "", 0.0, 1.0);
RNA_def_int_vector(
ot->srna, "cursor", 2, NULL, INT_MIN, INT_MAX, "Cursor", "", INT_MIN, INT_MAX);
@ -3272,8 +3283,8 @@ static void SCREEN_OT_screen_full_area(wmOperatorType *ot)
typedef struct sAreaJoinData {
ScrArea *sa1; /* Potential source area (kept). */
ScrArea *sa2; /* Potential target area (removed or reduced). */
int dir; /* Direction of potential join. */
void *draw_callback; /* call 'ED_screen_draw_join_highlight' */
eScreenDir dir; /* Direction of potential join. */
void *draw_callback; /* call #screen_draw_join_highlight */
} sAreaJoinData;
@ -3282,8 +3293,8 @@ static void area_join_draw_cb(const struct wmWindow *UNUSED(win), void *userdata
const wmOperator *op = userdata;
sAreaJoinData *sd = op->customdata;
if (sd->sa1 && sd->sa2 && (sd->dir != -1)) {
ED_screen_draw_join_highlight(sd->sa1, sd->sa2);
if (sd->sa1 && sd->sa2 && (sd->dir != SCREEN_DIR_NONE)) {
screen_draw_join_highlight(sd->sa1, sd->sa2);
}
}
@ -3305,7 +3316,7 @@ static bool area_join_init(bContext *C, wmOperator *op, ScrArea *sa1, ScrArea *s
jd->sa1 = sa1;
jd->sa2 = sa2;
jd->dir = -1;
jd->dir = SCREEN_DIR_NONE;
op->customdata = jd;
@ -3318,7 +3329,7 @@ static bool area_join_init(bContext *C, wmOperator *op, ScrArea *sa1, ScrArea *s
static bool area_join_apply(bContext *C, wmOperator *op)
{
sAreaJoinData *jd = (sAreaJoinData *)op->customdata;
if (!jd || (jd->dir == -1)) {
if (!jd || (jd->dir == SCREEN_DIR_NONE)) {
return false;
}
@ -3429,21 +3440,21 @@ static int area_join_modal(bContext *C, wmOperator *op, const wmEvent *event)
jd->dir = area_getorientation(jd->sa1, jd->sa2);
}
else if (area != jd->sa2) {
jd->dir = -1;
jd->dir = SCREEN_DIR_NONE;
}
WM_event_add_notifier(C, NC_WINDOW, NULL);
if (jd->dir == 1) {
if (jd->dir == SCREEN_DIR_N) {
WM_cursor_set(win, WM_CURSOR_N_ARROW);
}
else if (jd->dir == 3) {
else if (jd->dir == SCREEN_DIR_S) {
WM_cursor_set(win, WM_CURSOR_S_ARROW);
}
else if (jd->dir == 2) {
else if (jd->dir == SCREEN_DIR_E) {
WM_cursor_set(win, WM_CURSOR_E_ARROW);
}
else if (jd->dir == 0) {
else if (jd->dir == SCREEN_DIR_W) {
WM_cursor_set(win, WM_CURSOR_W_ARROW);
}
else {
@ -3454,7 +3465,7 @@ static int area_join_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
case LEFTMOUSE:
if (event->val == KM_RELEASE) {
if (jd->dir == -1) {
if (jd->dir == SCREEN_DIR_NONE) {
area_join_cancel(C, op);
return OPERATOR_CANCELLED;
}
@ -3528,7 +3539,7 @@ static int screen_area_options_invoke(bContext *C, wmOperator *op, const wmEvent
&ptr);
/* store initial mouse cursor position. */
RNA_int_set_array(&ptr, "cursor", &event->x);
RNA_enum_set(&ptr, "direction", 'v');
RNA_enum_set(&ptr, "direction", SCREEN_AXIS_V);
/* Horizontal Split */
uiItemFullO(layout,
@ -3541,7 +3552,7 @@ static int screen_area_options_invoke(bContext *C, wmOperator *op, const wmEvent
&ptr);
/* store initial mouse cursor position. */
RNA_int_set_array(&ptr, "cursor", &event->x);
RNA_enum_set(&ptr, "direction", 'h');
RNA_enum_set(&ptr, "direction", SCREEN_AXIS_H);
if (sa1 && sa2) {
uiItemS(layout);
@ -4126,7 +4137,7 @@ static void screen_area_menu_items(ScrArea *area, uiLayout *layout)
&ptr);
RNA_int_set_array(&ptr, "cursor", loc);
RNA_enum_set(&ptr, "direction", 'v');
RNA_enum_set(&ptr, "direction", SCREEN_AXIS_V);
/* Horizontal Split */
uiItemFullO(layout,
@ -4139,7 +4150,7 @@ static void screen_area_menu_items(ScrArea *area, uiLayout *layout)
&ptr);
RNA_int_set_array(&ptr, "cursor", &loc[0]);
RNA_enum_set(&ptr, "direction", 'h');
RNA_enum_set(&ptr, "direction", SCREEN_AXIS_H);
uiItemS(layout);
@ -5420,7 +5431,7 @@ static void context_cycle_prop_get(bScreen *screen,
static int space_context_cycle_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
const int direction = RNA_enum_get(op->ptr, "direction");
const eScreenCycle direction = RNA_enum_get(op->ptr, "direction");
PointerRNA ptr;
PropertyRNA *prop;
@ -5469,7 +5480,7 @@ static int space_workspace_cycle_invoke(bContext *C, wmOperator *op, const wmEve
}
Main *bmain = CTX_data_main(C);
const int direction = RNA_enum_get(op->ptr, "direction");
const eScreenCycle direction = RNA_enum_get(op->ptr, "direction");
WorkSpace *workspace_src = WM_window_get_active_workspace(win);
WorkSpace *workspace_dst = NULL;

View File

@ -1324,6 +1324,13 @@ static bool paint_cursor_context_init(bContext *C,
copy_v3_fl(pcontext->outline_col, 0.8f);
}
const bool is_brush_tool = PAINT_brush_tool_poll(C);
if (!is_brush_tool) {
/* Use a default color for tools that are not brushes. */
pcontext->outline_alpha = 0.8f;
copy_v3_fl(pcontext->outline_col, 0.8f);
}
pcontext->is_stroke_active = pcontext->ups->stroke_active;
return true;
@ -1610,9 +1617,11 @@ static void paint_cursor_draw_3d_view_brush_cursor_inactive(PaintCursorContext *
pcontext->radius);
}
const bool is_brush_tool = PAINT_brush_tool_poll(pcontext->C);
/* Pose brush updates and rotation origins. */
if (brush->sculpt_tool == SCULPT_TOOL_POSE) {
if (is_brush_tool && brush->sculpt_tool == SCULPT_TOOL_POSE) {
/* Just after switching to the Pose Brush, the active vertex can be the same and the
* cursor won't be tagged to update, so always initialize the preview chain if it is
* null before drawing it. */
@ -1650,7 +1659,8 @@ static void paint_cursor_draw_3d_view_brush_cursor_inactive(PaintCursorContext *
cursor_draw_point_screen_space(
pcontext->pos, pcontext->region, pcontext->ss->pivot_pos, pcontext->vc.obact->obmat, 2);
}
if (brush->sculpt_tool == SCULPT_TOOL_BOUNDARY) {
if (is_brush_tool && brush->sculpt_tool == SCULPT_TOOL_BOUNDARY) {
paint_cursor_preview_boundary_data_update(pcontext, update_previews);
paint_cursor_preview_boundary_data_pivot_draw(pcontext);
}
@ -1671,17 +1681,18 @@ static void paint_cursor_draw_3d_view_brush_cursor_inactive(PaintCursorContext *
GPU_matrix_mul(pcontext->vc.obact->obmat);
/* Drawing Cursor overlays in 3D object space. */
if (brush->sculpt_tool == SCULPT_TOOL_GRAB && (brush->flag & BRUSH_GRAB_ACTIVE_VERTEX)) {
if (is_brush_tool && brush->sculpt_tool == SCULPT_TOOL_GRAB &&
(brush->flag & BRUSH_GRAB_ACTIVE_VERTEX)) {
SCULPT_geometry_preview_lines_update(pcontext->C, pcontext->ss, pcontext->radius);
sculpt_geometry_preview_lines_draw(
pcontext->pos, pcontext->brush, pcontext->is_multires, pcontext->ss);
}
if (brush->sculpt_tool == SCULPT_TOOL_POSE) {
if (is_brush_tool && brush->sculpt_tool == SCULPT_TOOL_POSE) {
paint_cursor_pose_brush_segments_draw(pcontext);
}
if (brush->sculpt_tool == SCULPT_TOOL_BOUNDARY) {
if (is_brush_tool && brush->sculpt_tool == SCULPT_TOOL_BOUNDARY) {
SCULPT_boundary_edges_preview_draw(
pcontext->pos, pcontext->ss, pcontext->outline_col, pcontext->outline_alpha);
SCULPT_boundary_pivot_line_preview_draw(pcontext->pos, pcontext->ss);
@ -1697,7 +1708,7 @@ static void paint_cursor_draw_3d_view_brush_cursor_inactive(PaintCursorContext *
paint_cursor_draw_main_inactive_cursor(pcontext);
/* Cloth brush local simulation areas. */
if (brush->sculpt_tool == SCULPT_TOOL_CLOTH &&
if (is_brush_tool && brush->sculpt_tool == SCULPT_TOOL_CLOTH &&
brush->cloth_simulation_area_type != BRUSH_CLOTH_SIMULATION_AREA_GLOBAL) {
const float white[3] = {1.0f, 1.0f, 1.0f};
const float zero_v[3] = {0.0f};
@ -1709,7 +1720,7 @@ static void paint_cursor_draw_3d_view_brush_cursor_inactive(PaintCursorContext *
}
/* Layer brush height. */
if (brush->sculpt_tool == SCULPT_TOOL_LAYER) {
if (is_brush_tool && brush->sculpt_tool == SCULPT_TOOL_LAYER) {
SCULPT_layer_brush_height_preview_draw(pcontext->pos,
brush,
pcontext->radius,

View File

@ -87,7 +87,7 @@ struct ViewContext *paint_stroke_view_context(struct PaintStroke *stroke);
void *paint_stroke_mode_data(struct PaintStroke *stroke);
float paint_stroke_distance_get(struct PaintStroke *stroke);
void paint_stroke_set_mode_data(struct PaintStroke *stroke, void *mode_data);
bool paint_poll(struct bContext *C);
bool PAINT_brush_tool_poll(struct bContext *C);
void paint_cursor_start(struct Paint *p, bool (*poll)(struct bContext *C));
void paint_cursor_delete_textures(void);

View File

@ -1468,7 +1468,7 @@ int paint_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event)
if (paint_supports_smooth_stroke(br, mode)) {
stroke->stroke_cursor = WM_paint_cursor_activate(
SPACE_TYPE_ANY, RGN_TYPE_ANY, paint_poll, paint_draw_smooth_cursor, stroke);
SPACE_TYPE_ANY, RGN_TYPE_ANY, PAINT_brush_tool_poll, paint_draw_smooth_cursor, stroke);
}
stroke->stroke_init = true;
@ -1495,7 +1495,7 @@ int paint_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event)
if (br->flag & BRUSH_LINE) {
stroke->stroke_cursor = WM_paint_cursor_activate(
SPACE_TYPE_ANY, RGN_TYPE_ANY, paint_poll, paint_draw_line_cursor, stroke);
SPACE_TYPE_ANY, RGN_TYPE_ANY, PAINT_brush_tool_poll, paint_draw_line_cursor, stroke);
}
first_dab = true;
@ -1665,7 +1665,7 @@ void paint_stroke_set_mode_data(PaintStroke *stroke, void *mode_data)
stroke->mode_data = mode_data;
}
bool paint_poll(bContext *C)
bool PAINT_brush_tool_poll(bContext *C)
{
Paint *p = BKE_paint_get_active_from_context(C);
Object *ob = CTX_data_active_object(C);

View File

@ -820,7 +820,8 @@ static void sculpt_vertex_neighbors_get_faces(SculptSession *ss,
iter->neighbors = iter->neighbors_fixed;
for (int i = 0; i < ss->pmap[index].count; i++) {
if (ss->face_sets[vert_map->indices[i]] <= 0) {
if (ss->face_sets[vert_map->indices[i]] < 0) {
/* Skip connectivity from hidden faces. */
continue;
}
const MPoly *p = &ss->mpoly[vert_map->indices[i]];
@ -7167,7 +7168,7 @@ bool SCULPT_poll_view3d(bContext *C)
bool SCULPT_poll(bContext *C)
{
return SCULPT_mode_poll(C) && paint_poll(C);
return SCULPT_mode_poll(C) && PAINT_brush_tool_poll(C);
}
static const char *sculpt_tool_name(Sculpt *sd)

View File

@ -35,6 +35,7 @@ struct bContext;
struct bContextDataResult;
struct bNode;
struct bNodeTree;
struct bNodeSocket;
struct wmOperatorType;
struct SpaceProperties_Runtime {
@ -66,6 +67,7 @@ typedef struct ButsTextureUser {
struct bNodeTree *ntree;
struct bNode *node;
struct bNodeSocket *socket;
const char *category;
int icon;

View File

@ -75,15 +75,16 @@ static SpaceProperties *find_space_properties(const bContext *C);
/************************* Texture User **************************/
static void buttons_texture_user_node_property_add(ListBase *users,
ID *id,
PointerRNA ptr,
PropertyRNA *prop,
bNodeTree *ntree,
bNode *node,
const char *category,
int icon,
const char *name)
static void buttons_texture_user_socket_property_add(ListBase *users,
ID *id,
PointerRNA ptr,
PropertyRNA *prop,
bNodeTree *ntree,
bNode *node,
bNodeSocket *socket,
const char *category,
int icon,
const char *name)
{
ButsTextureUser *user = MEM_callocN(sizeof(ButsTextureUser), "ButsTextureUser");
@ -92,6 +93,7 @@ static void buttons_texture_user_node_property_add(ListBase *users,
user->prop = prop;
user->ntree = ntree;
user->node = node;
user->socket = socket;
user->category = category;
user->icon = icon;
user->name = name;
@ -181,25 +183,29 @@ static void buttons_texture_modifier_geonodes_users_add(Object *ob,
/* Recurse into the node group */
buttons_texture_modifier_geonodes_users_add(ob, nmd, (bNodeTree *)node->id, users);
}
else if (node->type == GEO_NODE_ATTRIBUTE_SAMPLE_TEXTURE) {
RNA_pointer_create(&node_tree->id, &RNA_Node, node, &ptr);
prop = RNA_struct_find_property(&ptr, "texture");
if (prop == NULL) {
LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) {
if (socket->flag & SOCK_UNAVAIL) {
continue;
}
if (socket->type != SOCK_TEXTURE) {
continue;
}
RNA_pointer_create(&node_tree->id, &RNA_NodeSocket, socket, &ptr);
prop = RNA_struct_find_property(&ptr, "default_value");
PointerRNA texptr = RNA_property_pointer_get(&ptr, prop);
Tex *tex = (RNA_struct_is_a(texptr.type, &RNA_Texture)) ? (Tex *)texptr.data : NULL;
if (tex != NULL) {
buttons_texture_user_node_property_add(users,
&ob->id,
ptr,
prop,
node_tree,
node,
N_("Geometry Nodes"),
RNA_struct_ui_icon(ptr.type),
nmd->modifier.name);
buttons_texture_user_socket_property_add(users,
&ob->id,
ptr,
prop,
node_tree,
node,
socket,
N_("Geometry Nodes"),
RNA_struct_ui_icon(ptr.type),
nmd->modifier.name);
}
}
}

View File

@ -266,7 +266,7 @@ static void nla_strip_get_color_inside(AnimData *adt, NlaStrip *strip, float col
}
else if (strip->type == NLASTRIP_TYPE_META) {
/* Meta Clip */
/* TODO: should temporary metas get different colors too? */
/* TODO: should temporary meta-strips get different colors too? */
if (strip->flag & NLASTRIP_FLAG_SELECT) {
/* selected - use a bold purple color */
UI_GetThemeColor3fv(TH_NLA_META_SEL, color);

View File

@ -1713,8 +1713,6 @@ static int node_mute_exec(bContext *C, wmOperator *UNUSED(op))
}
}
do_tag_update |= ED_node_is_geometry(snode);
snode_notify(C, snode);
if (do_tag_update) {
snode_dag_update(C, snode);
@ -1755,8 +1753,6 @@ static int node_delete_exec(bContext *C, wmOperator *UNUSED(op))
}
}
do_tag_update |= ED_node_is_geometry(snode);
ntreeUpdateTree(CTX_data_main(C), snode->edittree);
snode_notify(C, snode);

View File

@ -852,8 +852,6 @@ static void node_link_exit(bContext *C, wmOperator *op, bool apply_links)
}
ntree->is_updating = false;
do_tag_update |= ED_node_is_geometry(snode);
ntreeUpdateTree(bmain, ntree);
snode_notify(C, snode);
if (do_tag_update) {
@ -1291,8 +1289,6 @@ static int cut_links_exec(bContext *C, wmOperator *op)
}
}
do_tag_update |= ED_node_is_geometry(snode);
if (found) {
ntreeUpdateTree(CTX_data_main(C), snode->edittree);
snode_notify(C, snode);
@ -1399,8 +1395,6 @@ static int mute_links_exec(bContext *C, wmOperator *op)
link->flag &= ~NODE_LINK_TEST;
}
do_tag_update |= ED_node_is_geometry(snode);
ntreeUpdateTree(CTX_data_main(C), snode->edittree);
snode_notify(C, snode);
if (do_tag_update) {
@ -1882,28 +1876,63 @@ void ED_node_link_intersect_test(ScrArea *area, int test)
}
}
/* assumes sockets in list */
static bNodeSocket *socket_best_match(ListBase *sockets)
static int get_main_socket_priority(const bNodeSocket *socket)
{
/* find type range */
int maxtype = 0;
switch ((eNodeSocketDatatype)socket->type) {
case __SOCK_MESH:
case SOCK_CUSTOM:
return -1;
case SOCK_BOOLEAN:
return 0;
case SOCK_INT:
return 1;
case SOCK_FLOAT:
return 2;
case SOCK_VECTOR:
return 3;
case SOCK_RGBA:
return 4;
case SOCK_STRING:
case SOCK_SHADER:
case SOCK_OBJECT:
case SOCK_IMAGE:
case SOCK_GEOMETRY:
case SOCK_COLLECTION:
case SOCK_TEXTURE:
case SOCK_MATERIAL:
return 5;
}
return -1;
}
/** Get the "main" socket of a socket list using a heuristic based on socket types. */
static bNodeSocket *get_main_socket(ListBase *sockets)
{
/* find priority range */
int maxpriority = -1;
LISTBASE_FOREACH (bNodeSocket *, sock, sockets) {
maxtype = max_ii(sock->type, maxtype);
if (sock->flag & SOCK_UNAVAIL) {
continue;
}
maxpriority = max_ii(get_main_socket_priority(sock), maxpriority);
}
/* try all types, starting from 'highest' (i.e. colors, vectors, values) */
for (int type = maxtype; type >= 0; type--) {
/* try all priorities, starting from 'highest' */
for (int priority = maxpriority; priority >= 0; priority--) {
LISTBASE_FOREACH (bNodeSocket *, sock, sockets) {
if (!nodeSocketIsHidden(sock) && type == sock->type) {
if (!nodeSocketIsHidden(sock) && priority == get_main_socket_priority(sock)) {
return sock;
}
}
}
/* no visible sockets, unhide first of highest type */
for (int type = maxtype; type >= 0; type--) {
/* no visible sockets, unhide first of highest priority */
for (int priority = maxpriority; priority >= 0; priority--) {
LISTBASE_FOREACH (bNodeSocket *, sock, sockets) {
if (type == sock->type) {
if (sock->flag & SOCK_UNAVAIL) {
continue;
}
if (priority == get_main_socket_priority(sock)) {
sock->flag &= ~SOCK_HIDDEN;
return sock;
}
@ -2248,8 +2277,8 @@ void ED_node_link_insert(Main *bmain, ScrArea *area)
}
if (link) {
bNodeSocket *best_input = socket_best_match(&select->inputs);
bNodeSocket *best_output = socket_best_match(&select->outputs);
bNodeSocket *best_input = get_main_socket(&select->inputs);
bNodeSocket *best_output = get_main_socket(&select->outputs);
if (best_input && best_output) {
bNode *node = link->tonode;

View File

@ -290,7 +290,7 @@ static int sequencer_snap_exec(bContext *C, wmOperator *op)
snap_frame = RNA_int_get(op->ptr, "frame");
/* Check metas. */
/* Check meta-strips. */
for (seq = ed->seqbasep->first; seq; seq = seq->next) {
if (seq->flag & SELECT && !(seq->depth == 0 && seq->flag & SEQ_LOCK) &&
SEQ_transform_sequence_can_be_translated(seq)) {
@ -1867,13 +1867,13 @@ static int sequencer_meta_toggle_exec(bContext *C, wmOperator *UNUSED(op))
Sequence *active_seq = SEQ_select_active_get(scene);
if (active_seq && active_seq->type == SEQ_TYPE_META && active_seq->flag & SELECT) {
/* Enter metastrip. */
/* Enter meta-strip. */
SEQ_meta_stack_alloc(ed, active_seq);
SEQ_seqbase_active_set(ed, &active_seq->seqbase);
SEQ_select_active_set(scene, NULL);
}
else {
/* Exit metastrip if possible. */
/* Exit meta-strip if possible. */
if (BLI_listbase_is_empty(&ed->metastack)) {
return OPERATOR_CANCELLED;
}
@ -1895,7 +1895,7 @@ void SEQUENCER_OT_meta_toggle(wmOperatorType *ot)
/* Identifiers. */
ot->name = "Toggle Meta Strip";
ot->idname = "SEQUENCER_OT_meta_toggle";
ot->description = "Toggle a metastrip (to edit enclosed strips)";
ot->description = "Toggle a meta-strip (to edit enclosed strips)";
/* Api callbacks. */
ot->exec = sequencer_meta_toggle_exec;
@ -1963,7 +1963,7 @@ void SEQUENCER_OT_meta_make(wmOperatorType *ot)
/* Identifiers. */
ot->name = "Make Meta Strip";
ot->idname = "SEQUENCER_OT_meta_make";
ot->description = "Group selected strips into a metastrip";
ot->description = "Group selected strips into a meta-strip";
/* Api callbacks. */
ot->exec = sequencer_meta_make_exec;
@ -2026,7 +2026,7 @@ void SEQUENCER_OT_meta_separate(wmOperatorType *ot)
/* Identifiers. */
ot->name = "UnMeta Strip";
ot->idname = "SEQUENCER_OT_meta_separate";
ot->description = "Put the contents of a metastrip back in the sequencer";
ot->description = "Put the contents of a meta-strip back in the sequencer";
/* Api callbacks. */
ot->exec = sequencer_meta_separate_exec;

View File

@ -707,7 +707,7 @@ static void flushTransSeq(TransInfo *t)
/* originally TFM_TIME_EXTEND, transform changes */
if (ELEM(t->mode, TFM_SEQ_SLIDE, TFM_TIME_TRANSLATE)) {
/* Special annoying case here, need to calc metas with TFM_TIME_EXTEND only */
/* Special annoying case here, need to calc meta-strips with TFM_TIME_EXTEND only */
/* calc all meta's then effects T27953. */
for (seq = seqbasep->first; seq; seq = seq->next) {

View File

@ -1273,7 +1273,7 @@ void transform_mode_init(TransInfo *t, wmOperator *op, const int mode)
}
/**
* When in modal nad not set, initializes a default orientation for the mode.
* When in modal and not set, initializes a default orientation for the mode.
*/
void transform_mode_default_modal_orientation_set(TransInfo *t, int type)
{

View File

@ -220,11 +220,19 @@ class GVMutableArray : public GVArray {
void fill(const void *value);
/* Copy the values from the source buffer to all elements in the virtual array. */
void set_all(const void *src)
{
this->set_all_impl(src);
}
protected:
virtual void set_by_copy_impl(const int64_t index, const void *value);
virtual void set_by_relocate_impl(const int64_t index, void *value);
virtual void set_by_move_impl(const int64_t index, void *value) = 0;
virtual void set_all_impl(const void *src);
virtual void *try_get_internal_mutable_varray_impl();
};
@ -554,6 +562,11 @@ template<typename T> class GVMutableArray_For_VMutableArray : public GVMutableAr
varray_->set(index, std::move(value_));
}
void set_all_impl(const void *src)
{
varray_->set_all(Span((T *)src, size_));
}
void materialize_impl(const IndexMask mask, void *dst) const override
{
varray_->materialize(mask, MutableSpan((T *)dst, mask.min_array_size()));

View File

@ -160,6 +160,19 @@ void GVMutableArray::set_by_relocate_impl(const int64_t index, void *value)
type_->destruct(value);
}
void GVMutableArray::set_all_impl(const void *src)
{
if (this->is_span()) {
const GMutableSpan span = this->get_internal_span();
type_->copy_to_initialized_n(src, span.data(), size_);
}
else {
for (int64_t i : IndexRange(size_)) {
this->set_by_copy(i, POINTER_OFFSET(src, type_->size() * i));
}
}
}
void *GVMutableArray::try_get_internal_mutable_varray_impl()
{
return nullptr;

View File

@ -37,6 +37,15 @@ int GPU_max_textures(void);
int GPU_max_textures_vert(void);
int GPU_max_textures_geom(void);
int GPU_max_textures_frag(void);
int GPU_max_uniforms_vert(void);
int GPU_max_uniforms_frag(void);
int GPU_max_batch_indices(void);
int GPU_max_batch_vertices(void);
int GPU_max_vertex_attribs(void);
int GPU_max_varying_floats(void);
int GPU_extensions_len(void);
const char *GPU_extension_get(int i);
int GPU_texture_size_with_limit(int res, bool limit_gl_texture_size);

View File

@ -68,6 +68,9 @@ extern "C" {
bool GPU_type_matches(eGPUDeviceType device, eGPUOSType os, eGPUDriverType driver);
eGPUSupportLevel GPU_platform_support_level(void);
const char *GPU_platform_vendor(void);
const char *GPU_platform_renderer(void);
const char *GPU_platform_version(void);
const char *GPU_platform_support_level_key(void);
const char *GPU_platform_gpu_name(void);

View File

@ -82,6 +82,46 @@ int GPU_max_textures(void)
return GCaps.max_textures;
}
int GPU_max_uniforms_vert(void)
{
return GCaps.max_uniforms_vert;
}
int GPU_max_uniforms_frag(void)
{
return GCaps.max_uniforms_frag;
}
int GPU_max_batch_indices(void)
{
return GCaps.max_batch_indices;
}
int GPU_max_batch_vertices(void)
{
return GCaps.max_batch_vertices;
}
int GPU_max_vertex_attribs(void)
{
return GCaps.max_vertex_attribs;
}
int GPU_max_varying_floats(void)
{
return GCaps.max_varying_floats;
}
int GPU_extensions_len(void)
{
return GCaps.extensions_len;
}
const char *GPU_extension_get(int i)
{
return GCaps.extension_get ? GCaps.extension_get(i) : "\0";
}
bool GPU_mip_render_workaround(void)
{
return GCaps.mip_render_workaround;

View File

@ -41,6 +41,15 @@ struct GPUCapabilities {
int max_textures_vert = 0;
int max_textures_geom = 0;
int max_textures_frag = 0;
int max_uniforms_vert = 0;
int max_uniforms_frag = 0;
int max_batch_indices = 0;
int max_batch_vertices = 0;
int max_vertex_attribs = 0;
int max_varying_floats = 0;
int extensions_len = 0;
const char *(*extension_get)(int);
bool mem_stats_support = false;
bool shader_image_load_store_support = false;
/* OpenGL related workarounds. */

View File

@ -41,10 +41,10 @@ namespace blender::gpu {
GPUPlatformGlobal GPG;
void GPUPlatformGlobal::create_key(eGPUSupportLevel support_level,
const char *vendor,
const char *renderer,
const char *version)
static char *create_key(eGPUSupportLevel support_level,
const char *vendor,
const char *renderer,
const char *version)
{
DynStr *ds = BLI_dynstr_new();
BLI_dynstr_appendf(ds, "{%s/%s/%s}=", vendor, renderer, version);
@ -58,29 +58,56 @@ void GPUPlatformGlobal::create_key(eGPUSupportLevel support_level,
BLI_dynstr_append(ds, "UNSUPPORTED");
}
support_key = BLI_dynstr_get_cstring(ds);
char *support_key = BLI_dynstr_get_cstring(ds);
BLI_dynstr_free(ds);
BLI_str_replace_char(support_key, '\n', ' ');
BLI_str_replace_char(support_key, '\r', ' ');
return support_key;
}
void GPUPlatformGlobal::create_gpu_name(const char *vendor,
const char *renderer,
const char *version)
static char *create_gpu_name(const char *vendor, const char *renderer, const char *version)
{
DynStr *ds = BLI_dynstr_new();
BLI_dynstr_appendf(ds, "%s %s %s", vendor, renderer, version);
gpu_name = BLI_dynstr_get_cstring(ds);
char *gpu_name = BLI_dynstr_get_cstring(ds);
BLI_dynstr_free(ds);
BLI_str_replace_char(gpu_name, '\n', ' ');
BLI_str_replace_char(gpu_name, '\r', ' ');
return gpu_name;
}
void GPUPlatformGlobal::init(eGPUDeviceType gpu_device,
eGPUOSType os_type,
eGPUDriverType driver_type,
eGPUSupportLevel gpu_support_level,
const char *vendor_str,
const char *renderer_str,
const char *version_str)
{
this->clear();
this->initialized = true;
this->device = gpu_device;
this->os = os_type;
this->driver = driver_type;
this->support_level = gpu_support_level;
this->vendor = BLI_strdup(vendor_str);
this->renderer = BLI_strdup(renderer_str);
this->version = BLI_strdup(version_str);
this->support_key = create_key(gpu_support_level, vendor_str, renderer_str, version_str);
this->gpu_name = create_gpu_name(vendor_str, renderer_str, version_str);
}
void GPUPlatformGlobal::clear()
{
MEM_SAFE_FREE(GPG.support_key);
MEM_SAFE_FREE(GPG.gpu_name);
MEM_SAFE_FREE(vendor);
MEM_SAFE_FREE(renderer);
MEM_SAFE_FREE(version);
MEM_SAFE_FREE(support_key);
MEM_SAFE_FREE(gpu_name);
initialized = false;
}
@ -96,22 +123,44 @@ using namespace blender::gpu;
eGPUSupportLevel GPU_platform_support_level()
{
BLI_assert(GPG.initialized);
return GPG.support_level;
}
const char *GPU_platform_support_level_key()
const char *GPU_platform_vendor(void)
{
BLI_assert(GPG.initialized);
return GPG.vendor;
}
const char *GPU_platform_renderer(void)
{
BLI_assert(GPG.initialized);
return GPG.renderer;
}
const char *GPU_platform_version(void)
{
BLI_assert(GPG.initialized);
return GPG.version;
}
const char *GPU_platform_support_level_key(void)
{
BLI_assert(GPG.initialized);
return GPG.support_key;
}
const char *GPU_platform_gpu_name(void)
{
BLI_assert(GPG.initialized);
return GPG.gpu_name;
}
/* GPU Types */
bool GPU_type_matches(eGPUDeviceType device, eGPUOSType os, eGPUDriverType driver)
{
BLI_assert(GPG.initialized);
return (GPG.device & device) && (GPG.os & os) && (GPG.driver & driver);
}

View File

@ -34,16 +34,20 @@ class GPUPlatformGlobal {
eGPUOSType os;
eGPUDriverType driver;
eGPUSupportLevel support_level;
char *vendor = nullptr;
char *renderer = nullptr;
char *version = nullptr;
char *support_key = nullptr;
char *gpu_name = nullptr;
public:
void create_key(eGPUSupportLevel support_level,
const char *vendor,
const char *renderer,
const char *version);
void create_gpu_name(const char *vendor, const char *renderer, const char *version);
void init(eGPUDeviceType gpu_device,
eGPUOSType os_type,
eGPUDriverType driver_type,
eGPUSupportLevel gpu_support_level,
const char *vendor_str,
const char *renderer_str,
const char *version_str);
void clear(void);
};

View File

@ -41,39 +41,42 @@ namespace blender::gpu {
void GLBackend::platform_init()
{
BLI_assert(!GPG.initialized);
GPG.initialized = true;
#ifdef _WIN32
GPG.os = GPU_OS_WIN;
#elif defined(__APPLE__)
GPG.os = GPU_OS_MAC;
#else
GPG.os = GPU_OS_UNIX;
#endif
const char *vendor = (const char *)glGetString(GL_VENDOR);
const char *renderer = (const char *)glGetString(GL_RENDERER);
const char *version = (const char *)glGetString(GL_VERSION);
eGPUDeviceType device = GPU_DEVICE_ANY;
eGPUOSType os = GPU_OS_ANY;
eGPUDriverType driver = GPU_DRIVER_ANY;
eGPUSupportLevel support_level = GPU_SUPPORT_LEVEL_SUPPORTED;
#ifdef _WIN32
os = GPU_OS_WIN;
#elif defined(__APPLE__)
os = GPU_OS_MAC;
#else
os = GPU_OS_UNIX;
#endif
if (strstr(vendor, "ATI") || strstr(vendor, "AMD")) {
GPG.device = GPU_DEVICE_ATI;
GPG.driver = GPU_DRIVER_OFFICIAL;
device = GPU_DEVICE_ATI;
driver = GPU_DRIVER_OFFICIAL;
}
else if (strstr(vendor, "NVIDIA")) {
GPG.device = GPU_DEVICE_NVIDIA;
GPG.driver = GPU_DRIVER_OFFICIAL;
device = GPU_DEVICE_NVIDIA;
driver = GPU_DRIVER_OFFICIAL;
}
else if (strstr(vendor, "Intel") ||
/* src/mesa/drivers/dri/intel/intel_context.c */
strstr(renderer, "Mesa DRI Intel") || strstr(renderer, "Mesa DRI Mobile Intel")) {
GPG.device = GPU_DEVICE_INTEL;
GPG.driver = GPU_DRIVER_OFFICIAL;
device = GPU_DEVICE_INTEL;
driver = GPU_DRIVER_OFFICIAL;
if (strstr(renderer, "UHD Graphics") ||
/* Not UHD but affected by the same bugs. */
strstr(renderer, "HD Graphics 530") || strstr(renderer, "Kaby Lake GT2") ||
strstr(renderer, "Whiskey Lake")) {
GPG.device |= GPU_DEVICE_INTEL_UHD;
device |= GPU_DEVICE_INTEL_UHD;
}
}
else if ((strstr(renderer, "Mesa DRI R")) ||
@ -81,49 +84,47 @@ void GLBackend::platform_init()
(strstr(renderer, "AMD") && strstr(vendor, "X.Org")) ||
(strstr(renderer, "Gallium ") && strstr(renderer, " on ATI ")) ||
(strstr(renderer, "Gallium ") && strstr(renderer, " on AMD "))) {
GPG.device = GPU_DEVICE_ATI;
GPG.driver = GPU_DRIVER_OPENSOURCE;
device = GPU_DEVICE_ATI;
driver = GPU_DRIVER_OPENSOURCE;
}
else if (strstr(renderer, "Nouveau") || strstr(vendor, "nouveau")) {
GPG.device = GPU_DEVICE_NVIDIA;
GPG.driver = GPU_DRIVER_OPENSOURCE;
device = GPU_DEVICE_NVIDIA;
driver = GPU_DRIVER_OPENSOURCE;
}
else if (strstr(vendor, "Mesa")) {
GPG.device = GPU_DEVICE_SOFTWARE;
GPG.driver = GPU_DRIVER_SOFTWARE;
device = GPU_DEVICE_SOFTWARE;
driver = GPU_DRIVER_SOFTWARE;
}
else if (strstr(vendor, "Microsoft")) {
GPG.device = GPU_DEVICE_SOFTWARE;
GPG.driver = GPU_DRIVER_SOFTWARE;
device = GPU_DEVICE_SOFTWARE;
driver = GPU_DRIVER_SOFTWARE;
}
else if (strstr(vendor, "Apple")) {
/* Apple Silicon. */
GPG.device = GPU_DEVICE_APPLE;
GPG.driver = GPU_DRIVER_OFFICIAL;
device = GPU_DEVICE_APPLE;
driver = GPU_DRIVER_OFFICIAL;
}
else if (strstr(renderer, "Apple Software Renderer")) {
GPG.device = GPU_DEVICE_SOFTWARE;
GPG.driver = GPU_DRIVER_SOFTWARE;
device = GPU_DEVICE_SOFTWARE;
driver = GPU_DRIVER_SOFTWARE;
}
else if (strstr(renderer, "llvmpipe") || strstr(renderer, "softpipe")) {
GPG.device = GPU_DEVICE_SOFTWARE;
GPG.driver = GPU_DRIVER_SOFTWARE;
device = GPU_DEVICE_SOFTWARE;
driver = GPU_DRIVER_SOFTWARE;
}
else {
printf("Warning: Could not find a matching GPU name. Things may not behave as expected.\n");
printf("Detected OpenGL configuration:\n");
printf("Vendor: %s\n", vendor);
printf("Renderer: %s\n", renderer);
GPG.device = GPU_DEVICE_ANY;
GPG.driver = GPU_DRIVER_ANY;
}
/* Detect support level */
if (!GLEW_VERSION_3_3) {
GPG.support_level = GPU_SUPPORT_LEVEL_UNSUPPORTED;
support_level = GPU_SUPPORT_LEVEL_UNSUPPORTED;
}
else {
if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_WIN, GPU_DRIVER_ANY)) {
if ((device & GPU_DEVICE_INTEL) && (os & GPU_OS_WIN)) {
/* Old Intel drivers with known bugs that cause material properties to crash.
* Version Build 10.18.14.5067 is the latest available and appears to be working
* ok with our workarounds, so excluded from this list. */
@ -132,19 +133,19 @@ void GLBackend::platform_init()
strstr(version, "Build 9.18") || strstr(version, "Build 10.18.10.3") ||
strstr(version, "Build 10.18.10.4") || strstr(version, "Build 10.18.10.5") ||
strstr(version, "Build 10.18.14.4")) {
GPG.support_level = GPU_SUPPORT_LEVEL_LIMITED;
support_level = GPU_SUPPORT_LEVEL_LIMITED;
}
}
if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_UNIX, GPU_DRIVER_ANY)) {
if ((device & GPU_DEVICE_ATI) && (os & GPU_OS_UNIX)) {
/* Platform seems to work when SB backend is disabled. This can be done
* by adding the environment variable `R600_DEBUG=nosb`. */
if (strstr(renderer, "AMD CEDAR")) {
GPG.support_level = GPU_SUPPORT_LEVEL_LIMITED;
support_level = GPU_SUPPORT_LEVEL_LIMITED;
}
}
}
GPG.create_key(GPG.support_level, vendor, renderer, version);
GPG.create_gpu_name(vendor, renderer, version);
GPG.init(device, os, driver, support_level, vendor, renderer, version);
}
void GLBackend::platform_exit()
@ -204,6 +205,11 @@ static bool detect_mip_render_workaround()
return enable_workaround;
}
const char *gl_extension_get(int i)
{
return (char *)glGetStringi(GL_EXTENSIONS, i);
}
static void detect_workarounds()
{
const char *vendor = (const char *)glGetString(GL_VENDOR);
@ -419,6 +425,16 @@ void GLBackend::capabilities_init()
glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &GCaps.max_textures_vert);
glGetIntegerv(GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS, &GCaps.max_textures_geom);
glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &GCaps.max_textures);
glGetIntegerv(GL_MAX_VERTEX_UNIFORM_COMPONENTS, &GCaps.max_uniforms_vert);
glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_COMPONENTS, &GCaps.max_uniforms_frag);
glGetIntegerv(GL_MAX_ELEMENTS_INDICES, &GCaps.max_batch_indices);
glGetIntegerv(GL_MAX_ELEMENTS_VERTICES, &GCaps.max_batch_vertices);
glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &GCaps.max_vertex_attribs);
glGetIntegerv(GL_MAX_VARYING_FLOATS, &GCaps.max_varying_floats);
glGetIntegerv(GL_NUM_EXTENSIONS, &GCaps.extensions_len);
GCaps.extension_get = gl_extension_get;
GCaps.mem_stats_support = GLEW_NVX_gpu_memory_info || GLEW_ATI_meminfo;
GCaps.shader_image_load_store_support = GLEW_ARB_shader_image_load_store;
/* GL specific capabilities. */

View File

@ -133,6 +133,19 @@ void MaterialNode::add_link(bNode *from_node, int from_index, bNode *to_node, in
nodeAddLink(ntree, from_node, from_socket, to_node, to_socket);
}
void MaterialNode::add_link(bNode *from_node,
const char *from_label,
bNode *to_node,
const char *to_label)
{
bNodeSocket *from_socket = nodeFindSocket(from_node, SOCK_OUT, from_label);
bNodeSocket *to_socket = nodeFindSocket(to_node, SOCK_IN, to_label);
if (from_socket && to_socket) {
nodeAddLink(ntree, from_node, from_socket, to_node, to_socket);
}
}
void MaterialNode::set_reflectivity(COLLADAFW::FloatOrParam &val)
{
float reflectivity = val.getFloatValue();
@ -326,7 +339,7 @@ void MaterialNode::set_emission(COLLADAFW::ColorOrTexture &cot)
else if (cot.isTexture()) {
bNode *texture_node = add_texture_node(cot, -300, locy, "Emission");
if (texture_node != nullptr) {
add_link(texture_node, 0, shader_node, 0);
add_link(texture_node, "Color", shader_node, "Emission");
}
}

View File

@ -48,6 +48,7 @@ class MaterialNode {
bNodeTree *prepare_material_nodetree();
bNode *add_node(int node_type, int locx, int locy, std::string label);
void add_link(bNode *from_node, int from_index, bNode *to_node, int to_index);
void add_link(bNode *from_node, const char *from_label, bNode *to_node, const char *to_label);
bNode *add_texture_node(COLLADAFW::ColorOrTexture &cot, int locx, int locy, std::string label);
void setShaderType();

View File

@ -521,7 +521,7 @@ enum {
SEQ_SCENE_NO_GPENCIL = (1 << 28),
SEQ_USE_VIEWS = (1 << 29),
/* access scene strips directly (like a metastrip) */
/* Access scene strips directly (like a meta-strip). */
SEQ_SCENE_STRIPS = (1 << 30),
SEQ_INVALID_EFFECT = (1u << 31),

View File

@ -9510,19 +9510,6 @@ static void def_geo_point_translate(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
}
static void def_geo_attribute_sample_texture(StructRNA *srna)
{
PropertyRNA *prop;
prop = RNA_def_property(srna, "texture", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "id");
RNA_def_property_struct_type(prop, "Texture");
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT);
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_ui_text(prop, "Texture", "Texture to sample values from");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update_relations");
}
static void def_geo_object_info(StructRNA *srna)
{
PropertyRNA *prop;

View File

@ -684,8 +684,11 @@ static void reset_tree_ui_storage(Span<const blender::nodes::NodeTreeRef *> tree
static Vector<SpaceSpreadsheet *> find_spreadsheet_editors(Main *bmain)
{
Vector<SpaceSpreadsheet *> spreadsheets;
wmWindowManager *wm = (wmWindowManager *)bmain->wm.first;
if (wm == nullptr) {
return {};
}
Vector<SpaceSpreadsheet *> spreadsheets;
LISTBASE_FOREACH (wmWindow *, window, &wm->windows) {
bScreen *screen = BKE_workspace_active_screen_get(window->workspace_hook);
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {

View File

@ -281,7 +281,7 @@ DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_MIX, def_geo_attribute_mix, "ATTRIBUTE_
DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_PROXIMITY, def_geo_attribute_proximity, "ATTRIBUTE_PROXIMITY", AttributeProximity, "Attribute Proximity", "")
DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_RANDOMIZE, def_geo_attribute_randomize, "ATTRIBUTE_RANDOMIZE", AttributeRandomize, "Attribute Randomize", "")
DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_REMOVE, 0, "ATTRIBUTE_REMOVE", AttributeRemove, "Attribute Remove", "")
DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_SAMPLE_TEXTURE, def_geo_attribute_sample_texture, "ATTRIBUTE_SAMPLE_TEXTURE", AttributeSampleTexture, "Attribute Sample Texture", "")
DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_SAMPLE_TEXTURE, 0, "ATTRIBUTE_SAMPLE_TEXTURE", AttributeSampleTexture, "Attribute Sample Texture", "")
DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_SEPARATE_XYZ, def_geo_attribute_separate_xyz, "ATTRIBUTE_SEPARATE_XYZ", AttributeSeparateXYZ, "Attribute Separate XYZ", "")
DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_TRANSFER, def_geo_attribute_transfer, "ATTRIBUTE_TRANSFER", AttributeTransfer, "Attribute Transfer", "")
DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_VECTOR_MATH, def_geo_attribute_vector_math, "ATTRIBUTE_VECTOR_MATH", AttributeVectorMath, "Attribute Vector Math", "")

View File

@ -30,6 +30,7 @@
static bNodeSocketTemplate geo_node_attribute_sample_texture_in[] = {
{SOCK_GEOMETRY, N_("Geometry")},
{SOCK_TEXTURE, N_("Texture")},
{SOCK_STRING, N_("Mapping")},
{SOCK_STRING, N_("Result")},
{-1, ""},
@ -40,13 +41,6 @@ static bNodeSocketTemplate geo_node_attribute_sample_texture_out[] = {
{-1, ""},
};
static void geo_node_attribute_sample_texture_layout(uiLayout *layout,
bContext *C,
PointerRNA *ptr)
{
uiTemplateID(layout, C, ptr, "texture", "texture.new", nullptr, nullptr, 0, ICON_NONE, nullptr);
}
namespace blender::nodes {
static AttributeDomain get_result_domain(const GeometryComponent &component,
@ -71,8 +65,7 @@ static AttributeDomain get_result_domain(const GeometryComponent &component,
static void execute_on_component(GeometryComponent &component, const GeoNodeExecParams &params)
{
const bNode &node = params.node();
Tex *texture = reinterpret_cast<Tex *>(node.id);
Tex *texture = params.get_input<Tex *>("Texture");
if (texture == nullptr) {
return;
}
@ -144,6 +137,5 @@ void register_node_type_geo_sample_texture()
node_type_socket_templates(
&ntype, geo_node_attribute_sample_texture_in, geo_node_attribute_sample_texture_out);
ntype.geometry_node_execute = blender::nodes::geo_node_attribute_sample_texture_exec;
ntype.draw_buttons = geo_node_attribute_sample_texture_layout;
nodeRegisterType(&ntype);
}

View File

@ -42,6 +42,18 @@ extern bool pyrna_id_FromPyObject(PyObject *obj, ID **id);
extern PyObject *pyrna_id_CreatePyObject(ID *id);
extern bool pyrna_id_CheckPyObject(PyObject *obj);
/* Currently there is no need to expose this publicly. */
static PyObject *BPy_IDGroup_IterKeys_CreatePyObject(BPy_IDProperty *group, const bool reversed);
static PyObject *BPy_IDGroup_IterValues_CreatePyObject(BPy_IDProperty *group, const bool reversed);
static PyObject *BPy_IDGroup_IterItems_CreatePyObject(BPy_IDProperty *group, const bool reversed);
static PyObject *BPy_IDGroup_ViewKeys_CreatePyObject(BPy_IDProperty *group);
static PyObject *BPy_IDGroup_ViewValues_CreatePyObject(BPy_IDProperty *group);
static PyObject *BPy_IDGroup_ViewItems_CreatePyObject(BPy_IDProperty *group);
static BPy_IDGroup_View *IDGroup_View_New_WithType(BPy_IDProperty *group, PyTypeObject *type);
static int BPy_IDGroup_Contains(BPy_IDProperty *self, PyObject *value);
/* -------------------------------------------------------------------- */
/** \name Python from ID-Property (Internal Conversions)
*
@ -756,17 +768,11 @@ static int BPy_IDGroup_Map_SetItem(BPy_IDProperty *self, PyObject *key, PyObject
static PyObject *BPy_IDGroup_iter(BPy_IDProperty *self)
{
BPy_IDGroup_Iter *iter = PyObject_GC_New(BPy_IDGroup_Iter, &BPy_IDGroup_Iter_Type);
iter->group = self;
Py_INCREF(self);
iter->mode = IDPROP_ITER_KEYS;
iter->cur = self->prop->data.group.first;
PyObject_GC_Track(iter);
return (PyObject *)iter;
return BPy_IDGroup_ViewKeys_CreatePyObject(self);
}
/* for simple, non nested types this is the same as BPy_IDGroup_WrapData */
static PyObject *BPy_IDGroup_MapDataToPy(IDProperty *prop)
PyObject *BPy_IDGroup_MapDataToPy(IDProperty *prop)
{
switch (prop->type) {
case IDP_STRING:
@ -874,6 +880,370 @@ static PyObject *BPy_IDGroup_MapDataToPy(IDProperty *prop)
/** \} */
/* -------------------------------------------------------------------- */
/** \name ID-Property Group Iterator Type
* \{ */
static PyObject *BPy_IDGroup_Iter_repr(BPy_IDGroup_Iter *self)
{
if (self->group == NULL) {
return PyUnicode_FromFormat("<%s>", Py_TYPE(self)->tp_name);
}
return PyUnicode_FromFormat("<%s \"%s\">", Py_TYPE(self)->tp_name, self->group->prop->name);
}
static void BPy_IDGroup_Iter_dealloc(BPy_IDGroup_Iter *self)
{
if (self->group != NULL) {
PyObject_GC_UnTrack(self);
}
Py_CLEAR(self->group);
PyObject_GC_Del(self);
}
static int BPy_IDGroup_Iter_traverse(BPy_IDGroup_Iter *self, visitproc visit, void *arg)
{
Py_VISIT(self->group);
return 0;
}
static int BPy_IDGroup_Iter_clear(BPy_IDGroup_Iter *self)
{
Py_CLEAR(self->group);
return 0;
}
static bool BPy_Group_Iter_same_size_or_raise_error(BPy_IDGroup_Iter *self)
{
if (self->len_init == self->group->prop->len) {
return true;
}
PyErr_SetString(PyExc_RuntimeError, "IDPropertyGroup changed size during iteration");
return false;
}
static PyObject *BPy_Group_IterKeys_next(BPy_IDGroup_Iter *self)
{
if (self->cur != NULL) {
/* When `cur` is set, `group` cannot be NULL. */
if (!BPy_Group_Iter_same_size_or_raise_error(self)) {
return NULL;
}
IDProperty *cur = self->cur;
self->cur = self->reversed ? self->cur->prev : self->cur->next;
return PyUnicode_FromString(cur->name);
}
PyErr_SetNone(PyExc_StopIteration);
return NULL;
}
static PyObject *BPy_Group_IterValues_next(BPy_IDGroup_Iter *self)
{
if (self->cur != NULL) {
/* When `cur` is set, `group` cannot be NULL. */
if (!BPy_Group_Iter_same_size_or_raise_error(self)) {
return NULL;
}
IDProperty *cur = self->cur;
self->cur = self->reversed ? self->cur->prev : self->cur->next;
return BPy_IDGroup_WrapData(self->group->id, cur, self->group->prop);
}
PyErr_SetNone(PyExc_StopIteration);
return NULL;
}
static PyObject *BPy_Group_IterItems_next(BPy_IDGroup_Iter *self)
{
if (self->cur != NULL) {
/* When `cur` is set, `group` cannot be NULL. */
if (!BPy_Group_Iter_same_size_or_raise_error(self)) {
return NULL;
}
IDProperty *cur = self->cur;
self->cur = self->reversed ? self->cur->prev : self->cur->next;
PyObject *ret = PyTuple_New(2);
PyTuple_SET_ITEMS(ret,
PyUnicode_FromString(cur->name),
BPy_IDGroup_WrapData(self->group->id, cur, self->group->prop));
return ret;
}
PyErr_SetNone(PyExc_StopIteration);
return NULL;
}
PyTypeObject BPy_IDGroup_IterKeys_Type = {PyVarObject_HEAD_INIT(NULL, 0)};
PyTypeObject BPy_IDGroup_IterValues_Type = {PyVarObject_HEAD_INIT(NULL, 0)};
PyTypeObject BPy_IDGroup_IterItems_Type = {PyVarObject_HEAD_INIT(NULL, 0)};
/* ID Property Group Iterator. */
static void IDGroup_Iter_init_type(void)
{
#define SHARED_MEMBER_SET(member, value) \
{ \
k_ty->member = v_ty->member = i_ty->member = value; \
} \
((void)0)
PyTypeObject *k_ty = &BPy_IDGroup_IterKeys_Type;
PyTypeObject *v_ty = &BPy_IDGroup_IterValues_Type;
PyTypeObject *i_ty = &BPy_IDGroup_IterItems_Type;
/* Unique members. */
k_ty->tp_name = "IDPropertyGroupIterKeys";
v_ty->tp_name = "IDPropertyGroupIterValues";
i_ty->tp_name = "IDPropertyGroupIterItems";
k_ty->tp_iternext = (iternextfunc)BPy_Group_IterKeys_next;
v_ty->tp_iternext = (iternextfunc)BPy_Group_IterValues_next;
i_ty->tp_iternext = (iternextfunc)BPy_Group_IterItems_next;
/* Shared members. */
SHARED_MEMBER_SET(tp_basicsize, sizeof(BPy_IDGroup_Iter));
SHARED_MEMBER_SET(tp_dealloc, (destructor)BPy_IDGroup_Iter_dealloc);
SHARED_MEMBER_SET(tp_repr, (reprfunc)BPy_IDGroup_Iter_repr);
SHARED_MEMBER_SET(tp_flags, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC);
SHARED_MEMBER_SET(tp_traverse, (traverseproc)BPy_IDGroup_Iter_traverse);
SHARED_MEMBER_SET(tp_clear, (inquiry)BPy_IDGroup_Iter_clear);
SHARED_MEMBER_SET(tp_iter, PyObject_SelfIter);
#undef SHARED_MEMBER_SET
}
static PyObject *IDGroup_Iter_New_WithType(BPy_IDProperty *group,
const bool reversed,
PyTypeObject *type)
{
BLI_assert(group ? group->prop->type == IDP_GROUP : true);
BPy_IDGroup_Iter *iter = PyObject_GC_New(BPy_IDGroup_Iter, type);
iter->reversed = reversed;
iter->group = group;
if (group != NULL) {
Py_INCREF(group);
PyObject_GC_Track(iter);
iter->cur = (reversed ? group->prop->data.group.last : group->prop->data.group.first);
iter->len_init = group->prop->len;
}
else {
iter->cur = NULL;
iter->len_init = 0;
}
return (PyObject *)iter;
}
static PyObject *BPy_IDGroup_IterKeys_CreatePyObject(BPy_IDProperty *group, const bool reversed)
{
return IDGroup_Iter_New_WithType(group, reversed, &BPy_IDGroup_IterKeys_Type);
}
static PyObject *BPy_IDGroup_IterValues_CreatePyObject(BPy_IDProperty *group, const bool reversed)
{
return IDGroup_Iter_New_WithType(group, reversed, &BPy_IDGroup_IterValues_Type);
}
static PyObject *BPy_IDGroup_IterItems_CreatePyObject(BPy_IDProperty *group, const bool reversed)
{
return IDGroup_Iter_New_WithType(group, reversed, &BPy_IDGroup_IterItems_Type);
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name ID-Property Group View Types (Keys/Values/Items)
*
* This view types is a thin wrapper on keys/values/items, this matches Python's `dict_view` type.
* The is returned by `property.keys()` and is separate from the iterator that loops over keys.
*
* There are some less common features this type could support (matching Python's `dict_view`)
*
* TODO:
* - Efficient contains checks for values and items which currently convert to a list first.
* - Missing `dict_views.isdisjoint`.
* - Missing `tp_as_number` (`nb_subtract`, `nb_and`, `nb_xor`, `nb_or`).
* \{ */
static PyObject *BPy_IDGroup_View_repr(BPy_IDGroup_View *self)
{
if (self->group == NULL) {
return PyUnicode_FromFormat("<%s>", Py_TYPE(self)->tp_name);
}
return PyUnicode_FromFormat("<%s \"%s\">", Py_TYPE(self)->tp_name, self->group->prop->name);
}
static void BPy_IDGroup_View_dealloc(BPy_IDGroup_View *self)
{
if (self->group != NULL) {
PyObject_GC_UnTrack(self);
}
Py_CLEAR(self->group);
PyObject_GC_Del(self);
}
static int BPy_IDGroup_View_traverse(BPy_IDGroup_View *self, visitproc visit, void *arg)
{
Py_VISIT(self->group);
return 0;
}
static int BPy_IDGroup_View_clear(BPy_IDGroup_View *self)
{
Py_CLEAR(self->group);
return 0;
}
/* View Specific API's (Key/Value/Items). */
static PyObject *BPy_Group_ViewKeys_iter(BPy_IDGroup_View *self)
{
return BPy_IDGroup_IterKeys_CreatePyObject(self->group, self->reversed);
}
static PyObject *BPy_Group_ViewValues_iter(BPy_IDGroup_View *self)
{
return BPy_IDGroup_IterValues_CreatePyObject(self->group, self->reversed);
}
static PyObject *BPy_Group_ViewItems_iter(BPy_IDGroup_View *self)
{
return BPy_IDGroup_IterItems_CreatePyObject(self->group, self->reversed);
}
static Py_ssize_t BPy_Group_View_len(BPy_IDGroup_View *self)
{
if (self->group == NULL) {
return 0;
}
return self->group->prop->len;
}
static int BPy_Group_ViewKeys_Contains(BPy_IDGroup_View *self, PyObject *value)
{
if (self->group == NULL) {
return 0;
}
return BPy_IDGroup_Contains(self->group, value);
}
static int BPy_Group_ViewValues_Contains(BPy_IDGroup_View *self, PyObject *value)
{
if (self->group == NULL) {
return 0;
}
/* TODO: implement this without first converting to a list. */
PyObject *list = PySequence_List((PyObject *)self);
const int result = PySequence_Contains(list, value);
Py_DECREF(list);
return result;
}
static int BPy_Group_ViewItems_Contains(BPy_IDGroup_View *self, PyObject *value)
{
if (self->group == NULL) {
return 0;
}
/* TODO: implement this without first converting to a list. */
PyObject *list = PySequence_List((PyObject *)self);
const int result = PySequence_Contains(list, value);
Py_DECREF(list);
return result;
}
static PySequenceMethods BPy_IDGroup_ViewKeys_as_sequence = {
(lenfunc)BPy_Group_View_len, /* sq_length */
0, /* sq_concat */
0, /* sq_repeat */
0, /* sq_item */
0, /* sq_slice */
0, /* sq_ass_item */
0, /* sq_ass_slice */
(objobjproc)BPy_Group_ViewKeys_Contains, /* sq_contains */
};
static PySequenceMethods BPy_IDGroup_ViewValues_as_sequence = {
(lenfunc)BPy_Group_View_len, /* sq_length */
0, /* sq_concat */
0, /* sq_repeat */
0, /* sq_item */
0, /* sq_slice */
0, /* sq_ass_item */
0, /* sq_ass_slice */
(objobjproc)BPy_Group_ViewValues_Contains, /* sq_contains */
};
static PySequenceMethods BPy_IDGroup_ViewItems_as_sequence = {
(lenfunc)BPy_Group_View_len, /* sq_length */
0, /* sq_concat */
0, /* sq_repeat */
0, /* sq_item */
0, /* sq_slice */
0, /* sq_ass_item */
0, /* sq_ass_slice */
(objobjproc)BPy_Group_ViewItems_Contains, /* sq_contains */
};
/* Methods. */
PyDoc_STRVAR(BPy_IDGroup_View_reversed_doc,
"Return a reverse iterator over the ID Property keys values or items.");
static PyObject *BPy_IDGroup_View_reversed(BPy_IDGroup_View *self, PyObject *UNUSED(ignored))
{
BPy_IDGroup_View *result = IDGroup_View_New_WithType(self->group, Py_TYPE(self));
result->reversed = !self->reversed;
return (PyObject *)result;
}
static PyMethodDef BPy_IDGroup_View_methods[] = {
{"__reversed__",
(PyCFunction)(void (*)(void))BPy_IDGroup_View_reversed,
METH_NOARGS,
BPy_IDGroup_View_reversed_doc},
{NULL, NULL},
};
PyTypeObject BPy_IDGroup_ViewKeys_Type = {PyVarObject_HEAD_INIT(NULL, 0)};
PyTypeObject BPy_IDGroup_ViewValues_Type = {PyVarObject_HEAD_INIT(NULL, 0)};
PyTypeObject BPy_IDGroup_ViewItems_Type = {PyVarObject_HEAD_INIT(NULL, 0)};
/* ID Property Group View. */
static void IDGroup_View_init_type(void)
{
PyTypeObject *k_ty = &BPy_IDGroup_ViewKeys_Type;
PyTypeObject *v_ty = &BPy_IDGroup_ViewValues_Type;
PyTypeObject *i_ty = &BPy_IDGroup_ViewItems_Type;
/* Unique members. */
k_ty->tp_name = "IDPropertyGroupViewKeys";
v_ty->tp_name = "IDPropertyGroupViewValues";
i_ty->tp_name = "IDPropertyGroupViewItems";
k_ty->tp_iter = (getiterfunc)BPy_Group_ViewKeys_iter;
v_ty->tp_iter = (getiterfunc)BPy_Group_ViewValues_iter;
i_ty->tp_iter = (getiterfunc)BPy_Group_ViewItems_iter;
k_ty->tp_as_sequence = &BPy_IDGroup_ViewKeys_as_sequence;
v_ty->tp_as_sequence = &BPy_IDGroup_ViewValues_as_sequence;
i_ty->tp_as_sequence = &BPy_IDGroup_ViewItems_as_sequence;
/* Shared members. */
#define SHARED_MEMBER_SET(member, value) \
{ \
k_ty->member = v_ty->member = i_ty->member = value; \
} \
((void)0)
SHARED_MEMBER_SET(tp_basicsize, sizeof(BPy_IDGroup_View));
SHARED_MEMBER_SET(tp_dealloc, (destructor)BPy_IDGroup_View_dealloc);
SHARED_MEMBER_SET(tp_repr, (reprfunc)BPy_IDGroup_View_repr);
SHARED_MEMBER_SET(tp_flags, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC);
SHARED_MEMBER_SET(tp_traverse, (traverseproc)BPy_IDGroup_View_traverse);
SHARED_MEMBER_SET(tp_clear, (inquiry)BPy_IDGroup_View_clear);
SHARED_MEMBER_SET(tp_methods, BPy_IDGroup_View_methods);
#undef SHARED_MEMBER_SET
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name ID-Property Group Methods
* \{ */
@ -919,26 +1289,10 @@ static PyObject *BPy_IDGroup_pop(BPy_IDProperty *self, PyObject *args)
return NULL;
}
IDP_RemoveFromGroup(self->prop, idprop);
IDP_FreeFromGroup(self->prop, idprop);
return pyform;
}
PyDoc_STRVAR(
BPy_IDGroup_iter_items_doc,
".. method:: iteritems()\n"
"\n"
" Iterate through the items in the dict; behaves like dictionary method iteritems.\n");
static PyObject *BPy_IDGroup_iter_items(BPy_IDProperty *self)
{
BPy_IDGroup_Iter *iter = PyObject_GC_New(BPy_IDGroup_Iter, &BPy_IDGroup_Iter_Type);
iter->group = self;
Py_INCREF(self);
iter->mode = IDPROP_ITER_ITEMS;
iter->cur = self->prop->data.group.first;
PyObject_GC_Track(iter);
return (PyObject *)iter;
}
/* utility function */
static void BPy_IDGroup_CorrectListLen(IDProperty *prop, PyObject *seq, int len, const char *func)
{
@ -1023,13 +1377,37 @@ PyObject *BPy_Wrap_GetItems(ID *id, IDProperty *prop)
return seq;
}
PyObject *BPy_Wrap_GetKeys_View_WithID(ID *id, IDProperty *prop)
{
PyObject *self = prop ? idprop_py_from_idp_group(id, prop, NULL) : NULL;
PyObject *ret = BPy_IDGroup_ViewKeys_CreatePyObject((BPy_IDProperty *)self);
Py_XDECREF(self); /* Owned by `ret`. */
return ret;
}
PyObject *BPy_Wrap_GetValues_View_WithID(ID *id, IDProperty *prop)
{
PyObject *self = prop ? idprop_py_from_idp_group(id, prop, NULL) : NULL;
PyObject *ret = BPy_IDGroup_ViewValues_CreatePyObject((BPy_IDProperty *)self);
Py_XDECREF(self); /* Owned by `ret`. */
return ret;
}
PyObject *BPy_Wrap_GetItems_View_WithID(ID *id, IDProperty *prop)
{
PyObject *self = prop ? idprop_py_from_idp_group(id, prop, NULL) : NULL;
PyObject *ret = BPy_IDGroup_ViewItems_CreatePyObject((BPy_IDProperty *)self);
Py_XDECREF(self); /* Owned by `ret`. */
return ret;
}
PyDoc_STRVAR(BPy_IDGroup_keys_doc,
".. method:: keys()\n"
"\n"
" Return the keys associated with this group as a list of strings.\n");
static PyObject *BPy_IDGroup_keys(BPy_IDProperty *self)
{
return BPy_Wrap_GetKeys(self->prop);
return BPy_IDGroup_ViewKeys_CreatePyObject(self);
}
PyDoc_STRVAR(BPy_IDGroup_values_doc,
@ -1038,16 +1416,16 @@ PyDoc_STRVAR(BPy_IDGroup_values_doc,
" Return the values associated with this group.\n");
static PyObject *BPy_IDGroup_values(BPy_IDProperty *self)
{
return BPy_Wrap_GetValues(self->id, self->prop);
return BPy_IDGroup_ViewValues_CreatePyObject(self);
}
PyDoc_STRVAR(BPy_IDGroup_items_doc,
".. method:: items()\n"
"\n"
" Return the items associated with this group.\n");
" Iterate through the items in the dict; behaves like dictionary method items.\n");
static PyObject *BPy_IDGroup_items(BPy_IDProperty *self)
{
return BPy_Wrap_GetItems(self->id, self->prop);
return BPy_IDGroup_ViewItems_CreatePyObject(self);
}
static int BPy_IDGroup_Contains(BPy_IDProperty *self, PyObject *value)
@ -1148,7 +1526,6 @@ static PyObject *BPy_IDGroup_get(BPy_IDProperty *self, PyObject *args)
static struct PyMethodDef BPy_IDGroup_methods[] = {
{"pop", (PyCFunction)BPy_IDGroup_pop, METH_VARARGS, BPy_IDGroup_pop_doc},
{"iteritems", (PyCFunction)BPy_IDGroup_iter_items, METH_NOARGS, BPy_IDGroup_iter_items_doc},
{"keys", (PyCFunction)BPy_IDGroup_keys, METH_NOARGS, BPy_IDGroup_keys_doc},
{"values", (PyCFunction)BPy_IDGroup_values, METH_NOARGS, BPy_IDGroup_values_doc},
{"items", (PyCFunction)BPy_IDGroup_items, METH_NOARGS, BPy_IDGroup_items_doc},
@ -1678,120 +2055,59 @@ PyTypeObject BPy_IDArray_Type = {
/** \} */
/* -------------------------------------------------------------------- */
/** \name ID-Property Group Iterator Type
/** \name Initialize Types
* \{ */
static PyObject *IDGroup_Iter_repr(BPy_IDGroup_Iter *self)
{
return PyUnicode_FromFormat("(ID Property Group Iter \"%s\")", self->group->prop->name);
}
static void BPy_IDGroup_Iter_dealloc(BPy_IDGroup_Iter *self)
{
PyObject_GC_UnTrack(self);
Py_CLEAR(self->group);
PyObject_GC_Del(self);
}
static int BPy_IDGroup_Iter_traverse(BPy_IDGroup_Iter *self, visitproc visit, void *arg)
{
Py_VISIT(self->group);
return 0;
}
static int BPy_IDGroup_Iter_clear(BPy_IDGroup_Iter *self)
{
Py_CLEAR(self->group);
return 0;
}
static PyObject *BPy_Group_Iter_Next(BPy_IDGroup_Iter *self)
{
if (self->cur) {
PyObject *ret;
IDProperty *cur;
cur = self->cur;
self->cur = self->cur->next;
if (self->mode == IDPROP_ITER_ITEMS) {
ret = PyTuple_New(2);
PyTuple_SET_ITEMS(ret,
PyUnicode_FromString(cur->name),
BPy_IDGroup_WrapData(self->group->id, cur, self->group->prop));
return ret;
}
return PyUnicode_FromString(cur->name);
}
PyErr_SetNone(PyExc_StopIteration);
return NULL;
}
PyTypeObject BPy_IDGroup_Iter_Type = {
PyVarObject_HEAD_INIT(NULL, 0)
/* For printing, in format "<module>.<name>" */
"IDPropertyGroupIter", /* char *tp_name; */
sizeof(BPy_IDGroup_Iter), /* int tp_basicsize; */
0, /* tp_itemsize; For allocation */
/* Methods to implement standard operations */
(destructor)BPy_IDGroup_Iter_dealloc, /* tp_dealloc */
0, /* tp_vectorcall_offset */
NULL, /* getattrfunc tp_getattr; */
NULL, /* setattrfunc tp_setattr; */
NULL, /* cmpfunc tp_compare; */
(reprfunc)IDGroup_Iter_repr, /* reprfunc tp_repr; */
/* Method suites for standard classes */
NULL, /* PyNumberMethods *tp_as_number; */
NULL, /* PySequenceMethods *tp_as_sequence; */
NULL, /* PyMappingMethods *tp_as_mapping; */
/* More standard operations (here for binary compatibility) */
NULL, /* hashfunc tp_hash; */
NULL, /* ternaryfunc tp_call; */
NULL, /* reprfunc tp_str; */
NULL, /* getattrofunc tp_getattro; */
NULL, /* setattrofunc tp_setattro; */
/* Functions to access object as input/output buffer */
NULL, /* PyBufferProcs *tp_as_buffer; */
/*** Flags to define presence of optional/expanded features ***/
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* long tp_flags; */
NULL, /* char *tp_doc; Documentation string */
/*** Assigned meaning in release 2.0 ***/
/* call function for all accessible objects */
(traverseproc)BPy_IDGroup_Iter_traverse, /* traverseproc tp_traverse; */
/* delete references to contained objects */
(inquiry)BPy_IDGroup_Iter_clear, /* inquiry tp_clear; */
/*** Assigned meaning in release 2.1 ***/
/*** rich comparisons ***/
NULL, /* richcmpfunc tp_richcompare; */
/*** weak reference enabler ***/
0, /* long tp_weaklistoffset; */
/*** Added in release 2.2 ***/
/* Iterators */
PyObject_SelfIter, /* getiterfunc tp_iter; */
(iternextfunc)BPy_Group_Iter_Next, /* iternextfunc tp_iternext; */
};
void IDProp_Init_Types(void)
{
IDGroup_Iter_init_type();
IDGroup_View_init_type();
PyType_Ready(&BPy_IDGroup_Type);
PyType_Ready(&BPy_IDGroup_Iter_Type);
PyType_Ready(&BPy_IDArray_Type);
PyType_Ready(&BPy_IDGroup_IterKeys_Type);
PyType_Ready(&BPy_IDGroup_IterValues_Type);
PyType_Ready(&BPy_IDGroup_IterItems_Type);
PyType_Ready(&BPy_IDGroup_ViewKeys_Type);
PyType_Ready(&BPy_IDGroup_ViewValues_Type);
PyType_Ready(&BPy_IDGroup_ViewItems_Type);
}
/**
* \note `group` may be NULL, unlike most other uses of this argument.
* This is supported so RNA keys/values/items methods returns an iterator with the expected type:
* - Without having ID-properties.
* - Without supporting #BPy_IDProperty.prop being NULL, which would incur many more checks.
* Python's own dictionary-views also works this way too.
*/
static BPy_IDGroup_View *IDGroup_View_New_WithType(BPy_IDProperty *group, PyTypeObject *type)
{
BLI_assert(group ? group->prop->type == IDP_GROUP : true);
BPy_IDGroup_View *iter = PyObject_GC_New(BPy_IDGroup_View, type);
iter->reversed = false;
iter->group = group;
if (group != NULL) {
Py_INCREF(group);
PyObject_GC_Track(iter);
}
return iter;
}
static PyObject *BPy_IDGroup_ViewKeys_CreatePyObject(BPy_IDProperty *group)
{
return (PyObject *)IDGroup_View_New_WithType(group, &BPy_IDGroup_ViewKeys_Type);
}
static PyObject *BPy_IDGroup_ViewValues_CreatePyObject(BPy_IDProperty *group)
{
return (PyObject *)IDGroup_View_New_WithType(group, &BPy_IDGroup_ViewValues_Type);
}
static PyObject *BPy_IDGroup_ViewItems_CreatePyObject(BPy_IDProperty *group)
{
return (PyObject *)IDGroup_View_New_WithType(group, &BPy_IDGroup_ViewItems_Type);
}
/** \} */
@ -1822,7 +2138,15 @@ static PyObject *BPyInit_idprop_types(void)
/* bmesh_py_types.c */
PyModule_AddType(submodule, &BPy_IDGroup_Type);
PyModule_AddType(submodule, &BPy_IDGroup_Iter_Type);
PyModule_AddType(submodule, &BPy_IDGroup_ViewKeys_Type);
PyModule_AddType(submodule, &BPy_IDGroup_ViewValues_Type);
PyModule_AddType(submodule, &BPy_IDGroup_ViewItems_Type);
PyModule_AddType(submodule, &BPy_IDGroup_IterKeys_Type);
PyModule_AddType(submodule, &BPy_IDGroup_IterValues_Type);
PyModule_AddType(submodule, &BPy_IDGroup_IterItems_Type);
PyModule_AddType(submodule, &BPy_IDArray_Type);
return submodule;

View File

@ -25,16 +25,35 @@ struct ID;
struct IDProperty;
extern PyTypeObject BPy_IDArray_Type;
extern PyTypeObject BPy_IDGroup_Iter_Type;
extern PyTypeObject BPy_IDGroup_Type;
extern PyTypeObject BPy_IDGroup_ViewKeys_Type;
extern PyTypeObject BPy_IDGroup_ViewValues_Type;
extern PyTypeObject BPy_IDGroup_ViewItems_Type;
extern PyTypeObject BPy_IDGroup_IterKeys_Type;
extern PyTypeObject BPy_IDGroup_IterValues_Type;
extern PyTypeObject BPy_IDGroup_IterItems_Type;
#define BPy_IDArray_Check(v) (PyObject_TypeCheck(v, &BPy_IDArray_Type))
#define BPy_IDArray_CheckExact(v) (Py_TYPE(v) == &BPy_IDArray_Type)
#define BPy_IDGroup_Iter_Check(v) (PyObject_TypeCheck(v, &BPy_IDGroup_Iter_Type))
#define BPy_IDGroup_Iter_CheckExact(v) (Py_TYPE(v) == &BPy_IDGroup_Iter_Type)
#define BPy_IDGroup_Check(v) (PyObject_TypeCheck(v, &BPy_IDGroup_Type))
#define BPy_IDGroup_CheckExact(v) (Py_TYPE(v) == &BPy_IDGroup_Type)
#define BPy_IDGroup_ViewKeys_Check(v) (PyObject_TypeCheck(v, &BPy_IDGroup_ViewKeys_Type))
#define BPy_IDGroup_ViewKeys_CheckExact(v) (Py_TYPE(v) == &BPy_IDGroup_ViewKeys_Type)
#define BPy_IDGroup_ViewValues_Check(v) (PyObject_TypeCheck(v, &BPy_IDGroup_ViewValues_Type))
#define BPy_IDGroup_ViewValues_CheckExact(v) (Py_TYPE(v) == &BPy_IDGroup_ViewValues_Type)
#define BPy_IDGroup_ViewItems_Check(v) (PyObject_TypeCheck(v, &BPy_IDGroup_ViewItems_Type))
#define BPy_IDGroup_ViewItems_CheckExact(v) (Py_TYPE(v) == &BPy_IDGroup_ViewItems_Type)
#define BPy_IDGroup_IterKeys_Check(v) (PyObject_TypeCheck(v, &BPy_IDGroup_IterKeys_Type))
#define BPy_IDGroup_IterKeys_CheckExact(v) (Py_TYPE(v) == &BPy_IDGroup_IterKeys_Type)
#define BPy_IDGroup_IterValues_Check(v) (PyObject_TypeCheck(v, &BPy_IDGroup_IterValues_Type))
#define BPy_IDGroup_IterValues_CheckExact(v) (Py_TYPE(v) == &BPy_IDGroup_IterValues_Type)
#define BPy_IDGroup_IterItems_Check(v) (PyObject_TypeCheck(v, &BPy_IDGroup_IterItems_Type))
#define BPy_IDGroup_IterItems_CheckExact(v) (Py_TYPE(v) == &BPy_IDGroup_IterItems_Type)
typedef struct BPy_IDProperty {
PyObject_VAR_HEAD
struct ID *id; /* can be NULL */
@ -52,20 +71,34 @@ typedef struct BPy_IDGroup_Iter {
PyObject_VAR_HEAD
BPy_IDProperty *group;
struct IDProperty *cur;
int mode;
/** Use for detecting manipulation during iteration (which is not allowed). */
int len_init;
/** Iterate in the reverse direction. */
bool reversed;
} BPy_IDGroup_Iter;
/** Use to implement `IDPropertyGroup.keys/values/items` */
typedef struct BPy_IDGroup_View {
PyObject_VAR_HEAD
/** This will be NULL when accessing keys on data that has no ID properties. */
BPy_IDProperty *group;
bool reversed;
} BPy_IDGroup_View;
PyObject *BPy_Wrap_GetKeys(struct IDProperty *prop);
PyObject *BPy_Wrap_GetValues(struct ID *id, struct IDProperty *prop);
PyObject *BPy_Wrap_GetItems(struct ID *id, struct IDProperty *prop);
PyObject *BPy_Wrap_GetKeys_View_WithID(struct ID *id, struct IDProperty *prop);
PyObject *BPy_Wrap_GetValues_View_WithID(struct ID *id, struct IDProperty *prop);
PyObject *BPy_Wrap_GetItems_View_WithID(struct ID *id, struct IDProperty *prop);
int BPy_Wrap_SetMapItem(struct IDProperty *prop, PyObject *key, PyObject *val);
PyObject *BPy_IDGroup_MapDataToPy(struct IDProperty *prop);
PyObject *BPy_IDGroup_WrapData(struct ID *id, struct IDProperty *prop, struct IDProperty *parent);
bool BPy_IDProperty_Map_ValidateAndCreate(PyObject *key, struct IDProperty *group, PyObject *ob);
void IDProp_Init_Types(void);
PyObject *BPyInit_idprop(void);
#define IDPROP_ITER_KEYS 0
#define IDPROP_ITER_ITEMS 1

View File

@ -37,10 +37,12 @@ set(SRC
gpu_py_api.c
gpu_py_batch.c
gpu_py_buffer.c
gpu_py_capabilities.c
gpu_py_element.c
gpu_py_framebuffer.c
gpu_py_matrix.c
gpu_py_offscreen.c
gpu_py_platform.c
gpu_py_select.c
gpu_py_shader.c
gpu_py_state.c
@ -54,10 +56,12 @@ set(SRC
gpu_py_api.h
gpu_py_batch.h
gpu_py_buffer.h
gpu_py_capabilities.h
gpu_py_element.h
gpu_py_framebuffer.h
gpu_py_matrix.h
gpu_py_offscreen.h
gpu_py_platform.h
gpu_py_select.h
gpu_py_shader.h
gpu_py_state.h

View File

@ -30,7 +30,9 @@
#include "../generic/python_utildefines.h"
#include "gpu_py_capabilities.h"
#include "gpu_py_matrix.h"
#include "gpu_py_platform.h"
#include "gpu_py_select.h"
#include "gpu_py_state.h"
#include "gpu_py_types.h"
@ -61,9 +63,15 @@ PyObject *BPyInit_gpu(void)
PyModule_AddObject(mod, "types", (submodule = bpygpu_types_init()));
PyDict_SetItem(sys_modules, PyModule_GetNameObject(submodule), submodule);
PyModule_AddObject(mod, "capabilities", (submodule = bpygpu_capabilities_init()));
PyDict_SetItem(sys_modules, PyModule_GetNameObject(submodule), submodule);
PyModule_AddObject(mod, "matrix", (submodule = bpygpu_matrix_init()));
PyDict_SetItem(sys_modules, PyModule_GetNameObject(submodule), submodule);
PyModule_AddObject(mod, "platform", (submodule = bpygpu_platform_init()));
PyDict_SetItem(sys_modules, PyModule_GetNameObject(submodule), submodule);
PyModule_AddObject(mod, "select", (submodule = bpygpu_select_init()));
PyDict_SetItem(sys_modules, PyModule_GetNameObject(submodule), submodule);

View File

@ -0,0 +1,148 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/** \file
* \ingroup bpygpu
*
* - Use ``bpygpu_`` for local API.
* - Use ``BPyGPU`` for public API.
*/
#include <Python.h>
#include "BLI_utildefines.h"
#include "GPU_capabilities.h"
#include "gpu_py_capabilities.h" /* own include */
/* -------------------------------------------------------------------- */
/** \name Functions
* \{ */
static PyObject *pygpu_max_texture_size_get(PyObject *UNUSED(self))
{
return PyLong_FromLong(GPU_max_texture_size());
}
static PyObject *pygpu_max_texture_layers_get(PyObject *UNUSED(self))
{
return PyLong_FromLong(GPU_max_texture_layers());
}
static PyObject *pygpu_max_textures_get(PyObject *UNUSED(self))
{
return PyLong_FromLong(GPU_max_textures());
}
static PyObject *pygpu_max_textures_vert_get(PyObject *UNUSED(self))
{
return PyLong_FromLong(GPU_max_textures_vert());
}
static PyObject *pygpu_max_textures_geom_get(PyObject *UNUSED(self))
{
return PyLong_FromLong(GPU_max_textures_geom());
}
static PyObject *pygpu_max_textures_frag_get(PyObject *UNUSED(self))
{
return PyLong_FromLong(GPU_max_textures_frag());
}
static PyObject *pygpu_max_uniforms_vert_get(PyObject *UNUSED(self))
{
return PyLong_FromLong(GPU_max_uniforms_vert());
}
static PyObject *pygpu_max_uniforms_frag_get(PyObject *UNUSED(self))
{
return PyLong_FromLong(GPU_max_uniforms_frag());
}
static PyObject *pygpu_max_batch_indices_get(PyObject *UNUSED(self))
{
return PyLong_FromLong(GPU_max_batch_indices());
}
static PyObject *pygpu_max_batch_vertices_get(PyObject *UNUSED(self))
{
return PyLong_FromLong(GPU_max_batch_vertices());
}
static PyObject *pygpu_max_vertex_attribs_get(PyObject *UNUSED(self))
{
return PyLong_FromLong(GPU_max_vertex_attribs());
}
static PyObject *pygpu_max_varying_floats_get(PyObject *UNUSED(self))
{
return PyLong_FromLong(GPU_max_varying_floats());
}
static PyObject *pygpu_extensions_get(PyObject *UNUSED(self))
{
int extensions_len = GPU_extensions_len();
PyObject *ret = PyTuple_New(extensions_len);
PyObject **ob_items = ((PyTupleObject *)ret)->ob_item;
for (int i = 0; i < extensions_len; i++) {
ob_items[i] = PyUnicode_FromString(GPU_extension_get(i));
}
return ret;
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Module
* \{ */
static struct PyMethodDef pygpu_capabilities__tp_methods[] = {
{"max_texture_size_get", (PyCFunction)pygpu_max_texture_size_get, METH_NOARGS, NULL},
{"max_texture_layers_get", (PyCFunction)pygpu_max_texture_layers_get, METH_NOARGS, NULL},
{"max_textures_get", (PyCFunction)pygpu_max_textures_get, METH_NOARGS, NULL},
{"max_textures_vert_get", (PyCFunction)pygpu_max_textures_vert_get, METH_NOARGS, NULL},
{"max_textures_geom_get", (PyCFunction)pygpu_max_textures_geom_get, METH_NOARGS, NULL},
{"max_textures_frag_get", (PyCFunction)pygpu_max_textures_frag_get, METH_NOARGS, NULL},
{"max_uniforms_vert_get", (PyCFunction)pygpu_max_uniforms_vert_get, METH_NOARGS, NULL},
{"max_uniforms_frag_get", (PyCFunction)pygpu_max_uniforms_frag_get, METH_NOARGS, NULL},
{"max_batch_indices_get", (PyCFunction)pygpu_max_batch_indices_get, METH_NOARGS, NULL},
{"max_batch_vertices_get", (PyCFunction)pygpu_max_batch_vertices_get, METH_NOARGS, NULL},
{"max_vertex_attribs_get", (PyCFunction)pygpu_max_vertex_attribs_get, METH_NOARGS, NULL},
{"max_varying_floats_get", (PyCFunction)pygpu_max_varying_floats_get, METH_NOARGS, NULL},
{"extensions_get", (PyCFunction)pygpu_extensions_get, METH_NOARGS, NULL},
{NULL, NULL, 0, NULL},
};
PyDoc_STRVAR(pygpu_capabilities__tp_doc, "This module provides access to the GPU capabilities.");
static PyModuleDef pygpu_capabilities_module_def = {
PyModuleDef_HEAD_INIT,
.m_name = "gpu.capabilities",
.m_doc = pygpu_capabilities__tp_doc,
.m_methods = pygpu_capabilities__tp_methods,
};
PyObject *bpygpu_capabilities_init(void)
{
PyObject *submodule;
submodule = PyModule_Create(&pygpu_capabilities_module_def);
return submodule;
}
/** \} */

View File

@ -0,0 +1,23 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/** \file
* \ingroup bpygpu
*/
#pragma once
PyObject *bpygpu_capabilities_init(void);

View File

@ -0,0 +1,81 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/** \file
* \ingroup bpygpu
*
* - Use ``bpygpu_`` for local API.
* - Use ``BPyGPU`` for public API.
*/
#include <Python.h>
#include "BLI_utildefines.h"
#include "GPU_platform.h"
#include "gpu_py_platform.h" /* own include */
/* -------------------------------------------------------------------- */
/** \name Functions
* \{ */
static PyObject *pygpu_platform_vendor_get(PyObject *UNUSED(self), PyObject *value)
{
return PyUnicode_FromString(GPU_platform_vendor());
}
static PyObject *pygpu_platform_renderer_get(PyObject *UNUSED(self), PyObject *value)
{
return PyUnicode_FromString(GPU_platform_renderer());
}
static PyObject *pygpu_platform_version_get(PyObject *UNUSED(self), PyObject *value)
{
return PyUnicode_FromString(GPU_platform_version());
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Module
* \{ */
static struct PyMethodDef pygpu_platform__tp_methods[] = {
{"vendor_get", (PyCFunction)pygpu_platform_vendor_get, METH_NOARGS, NULL},
{"renderer_get", (PyCFunction)pygpu_platform_renderer_get, METH_NOARGS, NULL},
{"version_get", (PyCFunction)pygpu_platform_version_get, METH_NOARGS, NULL},
{NULL, NULL, 0, NULL},
};
PyDoc_STRVAR(pygpu_platform__tp_doc, "This module provides access to GPU Platform definitions.");
static PyModuleDef pygpu_platform_module_def = {
PyModuleDef_HEAD_INIT,
.m_name = "gpu.platform",
.m_doc = pygpu_platform__tp_doc,
.m_methods = pygpu_platform__tp_methods,
};
PyObject *bpygpu_platform_init(void)
{
PyObject *submodule;
submodule = PyModule_Create(&pygpu_platform_module_def);
return submodule;
}
/** \} */

View File

@ -0,0 +1,23 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/** \file
* \ingroup bpygpu
*/
#pragma once
PyObject *bpygpu_platform_init(void);

View File

@ -3562,7 +3562,7 @@ PyDoc_STRVAR(pyrna_struct_keys_doc,
" dictionary function of the same name).\n"
"\n"
" :return: custom property keys.\n"
" :rtype: list of strings\n"
" :rtype: :class:`idprop.type.IDPropertyGroupViewKeys`\n"
"\n" BPY_DOC_ID_PROP_TYPE_NOTE);
static PyObject *pyrna_struct_keys(BPy_PropertyRNA *self)
{
@ -3573,13 +3573,9 @@ static PyObject *pyrna_struct_keys(BPy_PropertyRNA *self)
return NULL;
}
/* `group` may be NULL. */
group = RNA_struct_idprops(&self->ptr, 0);
if (group == NULL) {
return PyList_New(0);
}
return BPy_Wrap_GetKeys(group);
return BPy_Wrap_GetKeys_View_WithID(self->ptr.owner_id, group);
}
PyDoc_STRVAR(pyrna_struct_items_doc,
@ -3589,7 +3585,7 @@ PyDoc_STRVAR(pyrna_struct_items_doc,
" dictionary function of the same name).\n"
"\n"
" :return: custom property key, value pairs.\n"
" :rtype: list of key, value tuples\n"
" :rtype: :class:`idprop.type.IDPropertyGroupViewItems`\n"
"\n" BPY_DOC_ID_PROP_TYPE_NOTE);
static PyObject *pyrna_struct_items(BPy_PropertyRNA *self)
{
@ -3600,13 +3596,9 @@ static PyObject *pyrna_struct_items(BPy_PropertyRNA *self)
return NULL;
}
/* `group` may be NULL. */
group = RNA_struct_idprops(&self->ptr, 0);
if (group == NULL) {
return PyList_New(0);
}
return BPy_Wrap_GetItems(self->ptr.owner_id, group);
return BPy_Wrap_GetItems_View_WithID(self->ptr.owner_id, group);
}
PyDoc_STRVAR(pyrna_struct_values_doc,
@ -3616,7 +3608,7 @@ PyDoc_STRVAR(pyrna_struct_values_doc,
" dictionary function of the same name).\n"
"\n"
" :return: custom property values.\n"
" :rtype: list\n"
" :rtype: :class:`idprop.type.IDPropertyGroupViewValues`\n"
"\n" BPY_DOC_ID_PROP_TYPE_NOTE);
static PyObject *pyrna_struct_values(BPy_PropertyRNA *self)
{
@ -3628,13 +3620,9 @@ static PyObject *pyrna_struct_values(BPy_PropertyRNA *self)
return NULL;
}
/* `group` may be NULL. */
group = RNA_struct_idprops(&self->ptr, 0);
if (group == NULL) {
return PyList_New(0);
}
return BPy_Wrap_GetValues(self->ptr.owner_id, group);
return BPy_Wrap_GetValues_View_WithID(self->ptr.owner_id, group);
}
PyDoc_STRVAR(pyrna_struct_is_property_set_doc,
@ -5006,8 +4994,13 @@ static PyObject *pyrna_struct_pop(BPy_StructRNA *self, PyObject *args)
idprop = IDP_GetPropertyFromGroup(group, key);
if (idprop) {
PyObject *ret = BPy_IDGroup_WrapData(self->ptr.owner_id, idprop, group);
IDP_RemoveFromGroup(group, idprop);
/* Don't use #BPy_IDGroup_WrapData as the id-property is being removed from the ID. */
PyObject *ret = BPy_IDGroup_MapDataToPy(idprop);
/* Internal error. */
if (UNLIKELY(ret == NULL)) {
return NULL;
}
IDP_FreeFromGroup(group, idprop);
return ret;
}
}

View File

@ -3033,10 +3033,9 @@ static ImBuf *do_adjustment_impl(const SeqRenderData *context, Sequence *seq, fl
i = seq_render_give_ibuf_seqbase(context, timeline_frame, seq->machine - 1, seqbasep);
}
/* found nothing? so let's work the way up the metastrip stack, so
/* Found nothing? so let's work the way up the meta-strip stack, so
* that it is possible to group a bunch of adjustment strips into
* a metastrip and have that work on everything below the metastrip
*/
* a meta-strip and have that work on everything below the meta-strip. */
if (!i) {
Sequence *meta;

View File

@ -448,8 +448,8 @@ static Sequence *seq_dupli(const Scene *scene_src,
seqn->strip->stripdata = NULL;
BLI_listbase_clear(&seqn->seqbase);
/* WATCH OUT!!! - This metastrip is not recursively duplicated here - do this after!!! */
/* - seq_dupli_recursive(&seq->seqbase, &seqn->seqbase);*/
/* WARNING: This meta-strip is not recursively duplicated here - do this after! */
// seq_dupli_recursive(&seq->seqbase, &seqn->seqbase);
}
else if (seq->type == SEQ_TYPE_SCENE) {
seqn->strip->stripdata = NULL;

View File

@ -149,7 +149,7 @@ void SEQ_edit_update_muting(Editing *ed)
static void sequencer_flag_users_for_removal(Scene *scene, ListBase *seqbase, Sequence *seq)
{
LISTBASE_FOREACH (Sequence *, user_seq, seqbase) {
/* Look in metas for usage of seq. */
/* Look in meta-strips for usage of seq. */
if (user_seq->type == SEQ_TYPE_META) {
sequencer_flag_users_for_removal(scene, &user_seq->seqbase, seq);
}

View File

@ -187,7 +187,7 @@ static void seq_time_update_meta_strip_range(Scene *scene, Sequence *seq_meta)
{
seq_time_update_meta_strip(scene, seq_meta);
/* Prevent metastrip to move in timeline. */
/* Prevent meta-strip to move in timeline. */
SEQ_transform_set_left_handle_frame(seq_meta, seq_meta->startdisp);
SEQ_transform_set_right_handle_frame(seq_meta, seq_meta->enddisp);
}
@ -196,7 +196,7 @@ void SEQ_time_update_sequence(Scene *scene, Sequence *seq)
{
Sequence *seqm;
/* check all metas recursively */
/* Check all meta-strips recursively. */
seqm = seq->seqbase.first;
while (seqm) {
if (seqm->seqbase.first) {

@ -1 +1 @@
Subproject commit 2afbb8ec472cac5102eb239f57b006f8c9387685
Subproject commit f99d29ae3e6ad44d45d79309454c45f8088781a4

View File

@ -75,7 +75,7 @@ class TestLibraryOverrides(TestHelper, unittest.TestCase):
assert(override_operation.operation == 'REPLACE')
# Setting location.y overridded all elements in the location array. -1 is a wildcard.
assert(override_operation.subitem_local_index == -1)
def test_link_permissive(self):
"""
Linked assets with a permissive template.

View File

@ -2,6 +2,7 @@
# ./blender.bin --background -noaudio --python tests/python/bl_pyapi_idprop.py -- --verbose
import bpy
import idprop
import unittest
import numpy as np
from array import array
@ -15,12 +16,12 @@ class TestHelper:
def setUp(self):
self._id = bpy.context.scene
assert(len(self._id.keys()) == 0 or self._id.keys() == ["cycles"])
self._id.pop("cycles", None)
assert(len(self._id.keys()) == 0)
def tearDown(self):
for key in list(self._id.keys()):
if key != "cycles":
del self._id[key]
del self._id[key]
def assertAlmostEqualSeq(self, list1, list2):
self.assertEqual(len(list1), len(list2))
@ -139,6 +140,51 @@ class TestIdPropertyCreation(TestHelper, unittest.TestCase):
with self.assertRaises(TypeError):
self.id["a"] = self
class TestIdPropertyGroupView(TestHelper, unittest.TestCase):
def test_type(self):
self.assertEqual(type(self.id.keys()), idprop.types.IDPropertyGroupViewKeys)
self.assertEqual(type(self.id.values()), idprop.types.IDPropertyGroupViewValues)
self.assertEqual(type(self.id.items()), idprop.types.IDPropertyGroupViewItems)
self.assertEqual(type(iter(self.id.keys())), idprop.types.IDPropertyGroupIterKeys)
self.assertEqual(type(iter(self.id.values())), idprop.types.IDPropertyGroupIterValues)
self.assertEqual(type(iter(self.id.items())), idprop.types.IDPropertyGroupIterItems)
def test_basic(self):
text = ["A", "B", "C"]
for i, ch in enumerate(text):
self.id[ch] = i
self.assertEqual(len(self.id.keys()), len(text))
self.assertEqual(list(self.id.keys()), text)
self.assertEqual(list(reversed(self.id.keys())), list(reversed(text)))
self.assertEqual(len(self.id.values()), len(text))
self.assertEqual(list(self.id.values()), list(range(len(text))))
self.assertEqual(list(reversed(self.id.values())), list(reversed(range(len(text)))))
self.assertEqual(len(self.id.items()), len(text))
self.assertEqual(list(self.id.items()), [(k, v) for v, k in enumerate(text)])
self.assertEqual(list(reversed(self.id.items())), list(reversed([(k, v) for v, k in enumerate(text)])))
def test_contains(self):
# Check `idprop.types.IDPropertyGroupView{Keys/Values/Items}.__contains__`
text = ["A", "B", "C"]
for i, ch in enumerate(text):
self.id[ch] = i
self.assertIn("A", self.id)
self.assertNotIn("D", self.id)
self.assertIn("A", self.id.keys())
self.assertNotIn("D", self.id.keys())
self.assertIn(2, self.id.values())
self.assertNotIn(3, self.id.values())
self.assertIn(("A", 0), self.id.items())
self.assertNotIn(("D", 3), self.id.items())
class TestBufferProtocol(TestHelper, unittest.TestCase):

View File

@ -61,4 +61,3 @@ def main():
if not inside_blender and __name__ == "__main__":
main()

View File

@ -316,13 +316,13 @@ def main():
# normal case
MeshTest("CubeFaceUnsubdivide", "testCubeUnsubdivide", "expectedCubeUnsubdivide",
[OperatorSpecEditMode("unsubdivide", {}, "FACE", {i for i in range(6)})]),
# T87259 - test cases
MeshTest("CubeEdgeUnsubdivide", "testCubeEdgeUnsubdivide", "expectedCubeEdgeUnsubdivide",
[OperatorSpecEditMode("unsubdivide", {}, "EDGE", {i for i in range(6)})]),
MeshTest("UVSphereUnsubdivide", "testUVSphereUnsubdivide", "expectedUVSphereUnsubdivide",
[OperatorSpecEditMode("unsubdivide", {'iterations': 9}, "FACE", {i for i in range(512)})]),
# vert connect path
# Tip: It works only if there is an already existing face or more than 2 vertices.
MeshTest("CubeVertConnectPath", "testCubeVertConnectPath", "expectedCubeVertConnectPath",