Merge branch 'master' into sculpt-dev
This commit is contained in:
commit
13bdc4a7e6
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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,
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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]]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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(
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -30,4 +30,4 @@ double ChunkOrderHotspot::calc_distance(int x, int y)
|
|||
return result;
|
||||
}
|
||||
|
||||
} // namespace blender::compositor
|
||||
} // namespace blender::compositor
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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];
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
set(INC
|
||||
../include
|
||||
../../blenfont
|
||||
../../blenkernel
|
||||
../../blenlib
|
||||
../../blentranslation
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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()));
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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", "")
|
||||
|
|
|
@ -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 ¶ms)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
/** \} */
|
|
@ -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);
|
|
@ -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;
|
||||
}
|
||||
|
||||
/** \} */
|
|
@ -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);
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
|
@ -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.
|
||||
|
|
|
@ -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):
|
||||
|
||||
|
|
|
@ -61,4 +61,3 @@ def main():
|
|||
|
||||
if not inside_blender and __name__ == "__main__":
|
||||
main()
|
||||
|
||||
|
|
|
@ -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",
|
||||
|
|
Loading…
Reference in New Issue