UI: Asset Shelf (Experimental Feature) #104831

Closed
Julian Eisel wants to merge 399 commits from asset-shelf into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
82 changed files with 1478 additions and 494 deletions
Showing only changes of commit 5c15bcac30 - Show all commits

View File

@ -152,10 +152,12 @@ LightTreeBucket operator+(const LightTreeBucket &a, const LightTreeBucket &b);
struct LightTreeNode {
LightTreeMeasure measure;
uint bit_trail;
int num_emitters = -1; /* The number of emitters a leaf node stores. A negative number indicates
it is an inner node. */
int first_emitter_index; /* Leaf nodes contain an index to first emitter. */
unique_ptr<LightTreeNode> children[2]; /* Inner node has two children. */
/* The number of emitters a leaf node stores. A negative number indicates it is an inner node. */
int num_emitters = -1;
/* Leaf nodes contain an index to first emitter. */
int first_emitter_index;
/* Inner node has two children. */
unique_ptr<LightTreeNode> children[2];
LightTreeNode() = default;

View File

@ -703,8 +703,11 @@ string OSLCompiler::id(ShaderNode *node)
{
/* assign layer unique name based on pointer address + bump mode */
stringstream stream;
stream.imbue(std::locale("C")); /* Ensure that no grouping characters (e.g. commas with en_US
locale) are added to the pointer string */
/* Ensure that no grouping characters (e.g. commas with en_US locale)
* are added to the pointer string. */
stream.imbue(std::locale("C"));
stream << "node_" << node->type->name << "_" << node;
return stream.str();

View File

@ -214,8 +214,8 @@ void deinterlace_line_inplace(
}
/* deinterlacing : 2 temporal taps, 3 spatial taps linear filter. The
top field is copied as is, but the bottom field is deinterlaced
against the top field. */
* top field is copied as is, but the bottom field is deinterlaced
* against the top field. */
FFMPEG_INLINE
void deinterlace_bottom_field(
uint8_t *dst, int dst_wrap, const uint8_t *src1, int src_wrap, int width, int height)

View File

@ -911,6 +911,27 @@ extern char *GHOST_getClipboard(bool selection);
*/
extern void GHOST_putClipboard(const char *buffer, bool selection);
/**
* Returns GHOST_kSuccess if the clipboard contains an image.
*/
extern GHOST_TSuccess GHOST_hasClipboardImage(void);
/**
* Get image data from the Clipboard
* \param r_width: the returned image width in pixels.
* \param r_height: the returned image height in pixels.
* \return pointer uint array in RGBA byte order. Caller must free.
*/
extern uint *GHOST_getClipboardImage(int *r_width, int *r_height);
/**
* Put image data to the Clipboard
* \param rgba: uint array in RGBA byte order.
* \param width: the image width in pixels.
* \param height: the image height in pixels.
*/
extern GHOST_TSuccess GHOST_putClipboardImage(uint *rgba, int width, int height);
/**
* Set the Console State
* \param action: console state

View File

@ -471,6 +471,27 @@ class GHOST_ISystem {
*/
virtual void putClipboard(const char *buffer, bool selection) const = 0;
/**
* Returns GHOST_kSuccess if the clipboard contains an image.
*/
virtual GHOST_TSuccess hasClipboardImage(void) const = 0;
/**
* Get image data from the Clipboard
* \param r_width: the returned image width in pixels.
* \param r_height: the returned image height in pixels.
* \return pointer uint array in RGBA byte order. Caller must free.
*/
virtual uint *getClipboardImage(int *r_width, int *r_height) const = 0;
/**
* Put image data to the Clipboard
* \param rgba: uint array in RGBA byte order.
* \param width: the image width in pixels.
* \param height: the image height in pixels.
*/
virtual GHOST_TSuccess putClipboardImage(uint *rgba, int width, int height) const = 0;
/***************************************************************************************
* System Message Box.
***************************************************************************************/

View File

@ -883,6 +883,24 @@ void GHOST_putClipboard(const char *buffer, bool selection)
system->putClipboard(buffer, selection);
}
GHOST_TSuccess GHOST_hasClipboardImage(void)
{
GHOST_ISystem *system = GHOST_ISystem::getSystem();
return system->hasClipboardImage();
}
uint *GHOST_getClipboardImage(int *r_width, int *r_height)
{
GHOST_ISystem *system = GHOST_ISystem::getSystem();
return system->getClipboardImage(r_width, r_height);
}
GHOST_TSuccess GHOST_putClipboardImage(uint *rgba, int width, int height)
{
GHOST_ISystem *system = GHOST_ISystem::getSystem();
return system->putClipboardImage(rgba, width, height);
}
bool GHOST_setConsoleWindowState(GHOST_TConsoleWindowState action)
{
GHOST_ISystem *system = GHOST_ISystem::getSystem();

View File

@ -42,6 +42,23 @@ GHOST_System::~GHOST_System()
exit();
}
GHOST_TSuccess GHOST_System::hasClipboardImage(void) const
{
return GHOST_kFailure;
}
uint *GHOST_System::getClipboardImage(int * /*r_width*/, int * /*r_height*/) const
{
return nullptr;
}
GHOST_TSuccess GHOST_System::putClipboardImage(uint * /*rgba*/,
int /*width*/,
int /*height*/) const
{
return GHOST_kFailure;
}
uint64_t GHOST_System::getMilliSeconds() const
{
return std::chrono::duration_cast<std::chrono::milliseconds>(

View File

@ -330,6 +330,27 @@ class GHOST_System : public GHOST_ISystem {
*/
virtual void putClipboard(const char *buffer, bool selection) const = 0;
/**
* Returns GHOST_kSuccess if the clipboard contains an image.
*/
GHOST_TSuccess hasClipboardImage(void) const;
/**
* Get image data from the Clipboard
* \param r_width: the returned image width in pixels.
* \param r_height: the returned image height in pixels.
* \return pointer uint array in RGBA byte order. Caller must free.
*/
uint *getClipboardImage(int *r_width, int *r_height) const;
/**
* Put image data to the Clipboard
* \param rgba: uint array in RGBA byte order.
* \param width: the image width in pixels.
* \param height: the image height in pixels.
*/
GHOST_TSuccess putClipboardImage(uint *rgba, int width, int height) const;
/**
* Show a system message box
* \param title: The title of the message box.

View File

@ -26,6 +26,9 @@
#include "utf_winfunc.h"
#include "utfconv.h"
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
#include "GHOST_DisplayManagerWin32.hh"
#include "GHOST_EventButton.hh"
#include "GHOST_EventCursor.hh"
@ -2305,6 +2308,257 @@ void GHOST_SystemWin32::putClipboard(const char *buffer, bool selection) const
}
}
GHOST_TSuccess GHOST_SystemWin32::hasClipboardImage(void) const
{
if (IsClipboardFormatAvailable(CF_DIBV5) ||
IsClipboardFormatAvailable(RegisterClipboardFormat("PNG"))) {
return GHOST_kSuccess;
}
return GHOST_kFailure;
}
static uint *getClipboardImageDibV5(int *r_width, int *r_height)
{
HANDLE hGlobal = GetClipboardData(CF_DIBV5);
if (hGlobal == nullptr) {
return nullptr;
}
BITMAPV5HEADER *bitmapV5Header = (BITMAPV5HEADER *)GlobalLock(hGlobal);
if (bitmapV5Header == nullptr) {
return nullptr;
}
int offset = bitmapV5Header->bV5Size + bitmapV5Header->bV5ClrUsed * sizeof(RGBQUAD);
if (bitmapV5Header->bV5Compression == BI_BITFIELDS) {
offset += 12;
}
BYTE *buffer = (BYTE *)bitmapV5Header + offset;
int bitcount = bitmapV5Header->bV5BitCount;
int width = bitmapV5Header->bV5Width;
int height = bitmapV5Header->bV5Height;
*r_width = width;
*r_height = height;
DWORD ColorMasks[4];
ColorMasks[0] = bitmapV5Header->bV5RedMask ? bitmapV5Header->bV5RedMask : 0xff;
ColorMasks[1] = bitmapV5Header->bV5GreenMask ? bitmapV5Header->bV5GreenMask : 0xff00;
ColorMasks[2] = bitmapV5Header->bV5BlueMask ? bitmapV5Header->bV5BlueMask : 0xff0000;
ColorMasks[3] = bitmapV5Header->bV5AlphaMask ? bitmapV5Header->bV5AlphaMask : 0xff000000;
/* Bit shifts needed for the ColorMasks. */
DWORD ColorShifts[4];
for (int i = 0; i < 4; i++) {
_BitScanForward(&ColorShifts[i], ColorMasks[i]);
}
uchar *source = (uchar *)buffer;
uint *rgba = (uint *)malloc(width * height * 4);
uint8_t *target = (uint8_t *)rgba;
if (bitmapV5Header->bV5Compression == BI_BITFIELDS && bitcount == 32) {
for (int h = 0; h < height; h++) {
for (int w = 0; w < width; w++, target += 4, source += 4) {
DWORD *pix = (DWORD *)source;
target[0] = uint8_t((*pix & ColorMasks[0]) >> ColorShifts[0]);
target[1] = uint8_t((*pix & ColorMasks[1]) >> ColorShifts[1]);
target[2] = uint8_t((*pix & ColorMasks[2]) >> ColorShifts[2]);
target[3] = uint8_t((*pix & ColorMasks[3]) >> ColorShifts[3]);
}
}
}
else if (bitmapV5Header->bV5Compression == BI_RGB && bitcount == 32) {
for (int h = 0; h < height; h++) {
for (int w = 0; w < width; w++, target += 4, source += 4) {
RGBQUAD *quad = (RGBQUAD *)source;
target[0] = uint8_t(quad->rgbRed);
target[1] = uint8_t(quad->rgbGreen);
target[2] = uint8_t(quad->rgbBlue);
target[3] = (bitmapV5Header->bV5AlphaMask) ? uint8_t(quad->rgbReserved) : 255;
}
}
}
else if (bitmapV5Header->bV5Compression == BI_RGB && bitcount == 24) {
int bytes_per_row = ((((width * bitcount) + 31) & ~31) >> 3);
int slack = bytes_per_row - (width * 3);
for (int h = 0; h < height; h++, source += slack) {
for (int w = 0; w < width; w++, target += 4, source += 3) {
RGBTRIPLE *triple = (RGBTRIPLE *)source;
target[0] = uint8_t(triple->rgbtRed);
target[1] = uint8_t(triple->rgbtGreen);
target[2] = uint8_t(triple->rgbtBlue);
target[3] = 255;
}
}
}
GlobalUnlock(hGlobal);
return rgba;
}
/* Works with any image format that ImBuf can load. */
static uint *getClipboardImageImBuf(int *r_width, int *r_height, UINT format)
{
HANDLE hGlobal = GetClipboardData(format);
if (hGlobal == nullptr) {
return nullptr;
}
LPVOID pMem = GlobalLock(hGlobal);
if (!pMem) {
return nullptr;
}
uint *rgba = nullptr;
ImBuf *ibuf = IMB_ibImageFromMemory(
(uchar *)pMem, GlobalSize(hGlobal), IB_rect, nullptr, "<clipboard>");
if (ibuf) {
*r_width = ibuf->x;
*r_height = ibuf->y;
rgba = (uint *)malloc(4 * ibuf->x * ibuf->y);
memcpy(rgba, ibuf->rect, 4 * ibuf->x * ibuf->y);
IMB_freeImBuf(ibuf);
}
GlobalUnlock(hGlobal);
return rgba;
}
uint *GHOST_SystemWin32::getClipboardImage(int *r_width, int *r_height) const
{
if (!OpenClipboard(nullptr)) {
return nullptr;
}
/* Synthesized formats are placed after posted formats. */
UINT cfPNG = RegisterClipboardFormat("PNG");
UINT format = 0;
for (int cf = EnumClipboardFormats(0); cf; cf = EnumClipboardFormats(cf)) {
if (ELEM(cf, CF_DIBV5, cfPNG)) {
format = cf;
}
if (cf == CF_DIBV5 || (cf == CF_BITMAP && format == cfPNG)) {
break; /* Favor CF_DIBV5, but not if synthesized. */
}
}
uint *rgba = nullptr;
if (format == CF_DIBV5) {
rgba = getClipboardImageDibV5(r_width, r_height);
}
else if (format == cfPNG) {
rgba = getClipboardImageImBuf(r_width, r_height, cfPNG);
}
else {
*r_width = 0;
*r_height = 0;
}
CloseClipboard();
return rgba;
}
static bool putClipboardImageDibV5(uint *rgba, int width, int height)
{
DWORD size_pixels = width * height * 4;
/* Pixel data is 12 bytes after the header. */
HGLOBAL hMem = GlobalAlloc(GHND, sizeof(BITMAPV5HEADER) + 12 + size_pixels);
if (!hMem) {
return false;
}
BITMAPV5HEADER *hdr = (BITMAPV5HEADER *)GlobalLock(hMem);
if (!hdr) {
GlobalFree(hMem);
return false;
}
hdr->bV5Size = sizeof(BITMAPV5HEADER);
hdr->bV5Width = width;
hdr->bV5Height = height;
hdr->bV5Planes = 1;
hdr->bV5BitCount = 32;
hdr->bV5SizeImage = size_pixels;
hdr->bV5Compression = BI_BITFIELDS;
hdr->bV5RedMask = 0x000000ff;
hdr->bV5GreenMask = 0x0000ff00;
hdr->bV5BlueMask = 0x00ff0000;
hdr->bV5AlphaMask = 0xff000000;
hdr->bV5CSType = LCS_sRGB;
hdr->bV5Intent = LCS_GM_IMAGES;
hdr->bV5ClrUsed = 0;
memcpy((char *)hdr + sizeof(BITMAPV5HEADER) + 12, rgba, size_pixels);
GlobalUnlock(hMem);
if (!SetClipboardData(CF_DIBV5, hMem)) {
GlobalFree(hMem);
return false;
}
return true;
}
static bool putClipboardImagePNG(uint *rgba, int width, int height)
{
UINT cf = RegisterClipboardFormat("PNG");
/* Load buffer into ImBuf, convert to PNG. */
ImBuf *ibuf = IMB_allocFromBuffer(rgba, nullptr, width, height, 32);
ibuf->ftype = IMB_FTYPE_PNG;
ibuf->foptions.quality = 15;
if (!IMB_saveiff(ibuf, "<memory>", IB_rect | IB_mem)) {
IMB_freeImBuf(ibuf);
return false;
}
HGLOBAL hMem = GlobalAlloc(GHND, ibuf->encodedbuffersize);
if (!hMem) {
IMB_freeImBuf(ibuf);
return false;
}
LPVOID pMem = GlobalLock(hMem);
if (!pMem) {
IMB_freeImBuf(ibuf);
GlobalFree(hMem);
return false;
}
memcpy(pMem, ibuf->encodedbuffer, ibuf->encodedbuffersize);
GlobalUnlock(hMem);
IMB_freeImBuf(ibuf);
if (!SetClipboardData(cf, hMem)) {
GlobalFree(hMem);
return false;
}
return true;
}
GHOST_TSuccess GHOST_SystemWin32::putClipboardImage(uint *rgba, int width, int height) const
{
if (!OpenClipboard(nullptr) || !EmptyClipboard()) {
return GHOST_kFailure;
}
bool ok = putClipboardImageDibV5(rgba, width, height) &&
putClipboardImagePNG(rgba, width, height);
CloseClipboard();
return (ok) ? GHOST_kSuccess : GHOST_kFailure;
}
/* -------------------------------------------------------------------- */
/** \name Message Box
* \{ */

View File

@ -215,6 +215,27 @@ class GHOST_SystemWin32 : public GHOST_System {
*/
void putClipboard(const char *buffer, bool selection) const;
/**
* Returns GHOST_kSuccess if the clipboard contains an image.
*/
GHOST_TSuccess hasClipboardImage(void) const;
/**
* Get image data from the Clipboard
* \param r_width: the returned image width in pixels.
* \param r_height: the returned image height in pixels.
* \return pointer uint array in RGBA byte order. Caller must free.
*/
uint *getClipboardImage(int *r_width, int *r_height) const;
/**
* Put image data to the Clipboard
* \param rgba: uint array in RGBA byte order.
* \param width: the image width in pixels.
* \param height: the image height in pixels.
*/
GHOST_TSuccess putClipboardImage(uint *rgba, int width, int height) const;
/**
* Show a system message box
* \param title: The title of the message box.

View File

@ -93,7 +93,7 @@ def write_sysinfo(filepath):
output.write("\t%r\n" % p)
output.write("datafiles: %r\n" % (bpy.utils.user_resource('DATAFILES')))
output.write("config: %r\n" % (bpy.utils.user_resource('CONFIG')))
output.write("scripts : %r\n" % (bpy.utils.user_resource('SCRIPTS')))
output.write("scripts: %r\n" % (bpy.utils.user_resource('SCRIPTS')))
output.write("autosave: %r\n" % (bpy.utils.user_resource('AUTOSAVE')))
output.write("tempdir: %r\n" % (bpy.app.tempdir))
@ -123,7 +123,7 @@ def write_sysinfo(filepath):
output.write("OpenColorIO: ")
if ocio.supported:
if ocio.version_string == "fallback":
output.write("Blender was built with OpenColorIO, " +
output.write("Blender was built with OpenColorIO, "
"but it currently uses fallback color management.\n")
else:
output.write("%s\n" % (ocio.version_string))

View File

@ -7,8 +7,7 @@ class CONSOLE_HT_header(Header):
bl_space_type = 'CONSOLE'
def draw(self, context):
layout = self.layout.row()
layout = self.layout
layout.template_header()
CONSOLE_MT_editor_menus.draw_collapsible(context, layout)

View File

@ -184,6 +184,8 @@ class IMAGE_MT_image(Menu):
bl_label = "Image"
def draw(self, context):
import sys
layout = self.layout
sima = context.space_data
@ -207,6 +209,11 @@ class IMAGE_MT_image(Menu):
layout.separator()
if sys.platform[:3] == "win":
layout.operator("image.clipboard_copy", text="Copy")
layout.operator("image.clipboard_paste", text="Paste")
layout.separator()
if ima:
layout.operator("image.save", text="Save", icon='FILE_TICK')
layout.operator("image.save_as", text="Save As...")

View File

@ -562,8 +562,6 @@ void BKE_pbvh_update_hide_attributes_from_mesh(PBVH *pbvh);
void BKE_pbvh_face_sets_color_set(PBVH *pbvh, int seed, int color_default);
void BKE_pbvh_respect_hide_set(PBVH *pbvh, bool respect_hide);
/* Vertex Deformer. */
float (*BKE_pbvh_vert_coords_alloc(struct PBVH *pbvh))[3];
@ -591,7 +589,6 @@ typedef struct PBVHVertexIter {
int i;
int index;
PBVHVertRef vertex;
bool respect_hide;
/* grid */
struct CCGKey key;
@ -664,14 +661,9 @@ void pbvh_vertex_iter_init(PBVH *pbvh, PBVHNode *node, PBVHVertexIter *vi, int m
} \
} \
else if (vi.vert_positions) { \
if (vi.respect_hide) { \
vi.visible = !(vi.hide_vert && vi.hide_vert[vi.vert_indices[vi.gx]]); \
if (mode == PBVH_ITER_UNIQUE && !vi.visible) { \
continue; \
} \
} \
else { \
BLI_assert(vi.visible); \
vi.visible = !(vi.hide_vert && vi.hide_vert[vi.vert_indices[vi.gx]]); \
if (mode == PBVH_ITER_UNIQUE && !vi.visible) { \
continue; \
} \
vi.co = vi.vert_positions[vi.vert_indices[vi.gx]]; \
vi.no = vi.vert_normals[vi.vert_indices[vi.gx]]; \

View File

@ -13,6 +13,10 @@
# include "BLI_bounds_types.hh"
# include "BLI_math_vector_types.hh"
# include "BLI_shared_cache.hh"
# include "DNA_pointcloud_types.h"
# include "BKE_customdata.h"
#endif
#ifdef __cplusplus
@ -45,6 +49,21 @@ struct PointCloudRuntime {
};
} // namespace blender::bke
inline blender::Span<blender::float3> PointCloud::positions() const
{
return {static_cast<const blender::float3 *>(
CustomData_get_layer_named(&this->pdata, CD_PROP_FLOAT3, "position")),
this->totpoint};
}
inline blender::MutableSpan<blender::float3> PointCloud::positions_for_write()
{
return {static_cast<blender::float3 *>(CustomData_get_layer_named_for_write(
&this->pdata, CD_PROP_FLOAT3, "position", this->totpoint)),
this->totpoint};
}
#endif
void *BKE_pointcloud_add(struct Main *bmain, const char *name);

View File

@ -26,6 +26,7 @@
#include "BKE_editmesh.h"
#include "BKE_mesh.hh"
#include "BKE_mesh_runtime.h"
#include "BKE_pointcloud.h"
#include "MEM_guardedalloc.h"
@ -1425,10 +1426,7 @@ BVHTree *BKE_bvhtree_from_pointcloud_get(BVHTreeFromPointCloud *data,
return nullptr;
}
blender::bke::AttributeAccessor attributes = pointcloud->attributes();
blender::VArraySpan<blender::float3> positions = attributes.lookup_or_default<blender::float3>(
"position", ATTR_DOMAIN_POINT, blender::float3(0));
const Span<float3> positions = pointcloud->positions();
for (const int i : positions.index_range()) {
BLI_bvhtree_insert(tree, i, positions[i], 1);
}

View File

@ -1952,9 +1952,11 @@ static void BKE_nlastrip_validate_autoblends(NlaTrack *nlt, NlaStrip *nls)
}
}
/* Ensure every transition's start/end properly set.
/**
* Ensure every transition's start/end properly set.
* Strip will be removed / freed if it doesn't fit (invalid).
* Return value indicates if passed strip is valid/fixed or invalid/removed. */
* Return value indicates if passed strip is valid/fixed or invalid/removed.
*/
static bool nlastrip_validate_transition_start_end(NlaStrip *strip)
{

View File

@ -132,7 +132,8 @@ struct DupliContext {
};
struct DupliGenerator {
short type; /* Dupli Type, see members of #OB_DUPLI. */
/** Duplicator Type, see members of #OB_DUPLI. */
short type;
void (*make_duplis)(const DupliContext *ctx);
};
@ -1325,8 +1326,10 @@ static void make_duplis_faces(const DupliContext *ctx)
}
}
static const DupliGenerator gen_dupli_faces = {/*type*/ OB_DUPLIFACES,
/*make_duplis*/ make_duplis_faces};
static const DupliGenerator gen_dupli_faces = {
/*type*/ OB_DUPLIFACES,
/*make_duplis*/ make_duplis_faces,
};
/** \} */
@ -1673,8 +1676,10 @@ static void make_duplis_particles(const DupliContext *ctx)
}
}
static const DupliGenerator gen_dupli_particles = {/*type*/ OB_DUPLIPARTS,
/*make_duplis*/ make_duplis_particles};
static const DupliGenerator gen_dupli_particles = {
/*type*/ OB_DUPLIPARTS,
/*make_duplis*/ make_duplis_particles,
};
/** \} */

View File

@ -2171,11 +2171,10 @@ static PBVH *build_pbvh_for_dynamic_topology(Object *ob)
return pbvh;
}
static PBVH *build_pbvh_from_regular_mesh(Object *ob, Mesh *me_eval_deform, bool respect_hide)
static PBVH *build_pbvh_from_regular_mesh(Object *ob, Mesh *me_eval_deform)
{
Mesh *me = BKE_object_get_original_mesh(ob);
PBVH *pbvh = BKE_pbvh_new(PBVH_FACES);
BKE_pbvh_respect_hide_set(pbvh, respect_hide);
BKE_pbvh_build_mesh(pbvh, me);
@ -2188,12 +2187,11 @@ static PBVH *build_pbvh_from_regular_mesh(Object *ob, Mesh *me_eval_deform, bool
return pbvh;
}
static PBVH *build_pbvh_from_ccg(Object *ob, SubdivCCG *subdiv_ccg, bool respect_hide)
static PBVH *build_pbvh_from_ccg(Object *ob, SubdivCCG *subdiv_ccg)
{
CCGKey key;
BKE_subdiv_ccg_key_top_level(&key, subdiv_ccg);
PBVH *pbvh = BKE_pbvh_new(PBVH_GRIDS);
BKE_pbvh_respect_hide_set(pbvh, respect_hide);
Mesh *base_mesh = BKE_mesh_from_object(ob);
BKE_sculpt_sync_face_visibility_to_grids(base_mesh, subdiv_ccg);
@ -2216,8 +2214,6 @@ PBVH *BKE_sculpt_object_pbvh_ensure(Depsgraph *depsgraph, Object *ob)
return nullptr;
}
const bool respect_hide = true;
PBVH *pbvh = ob->sculpt->pbvh;
if (pbvh != nullptr) {
/* NOTE: It is possible that pointers to grids or other geometry data changed. Need to update
@ -2258,11 +2254,11 @@ PBVH *BKE_sculpt_object_pbvh_ensure(Depsgraph *depsgraph, Object *ob)
Object *object_eval = DEG_get_evaluated_object(depsgraph, ob);
Mesh *mesh_eval = static_cast<Mesh *>(object_eval->data);
if (mesh_eval->runtime->subdiv_ccg != nullptr) {
pbvh = build_pbvh_from_ccg(ob, mesh_eval->runtime->subdiv_ccg, respect_hide);
pbvh = build_pbvh_from_ccg(ob, mesh_eval->runtime->subdiv_ccg);
}
else if (ob->type == OB_MESH) {
Mesh *me_eval_deform = object_eval->runtime.mesh_deform_eval;
pbvh = build_pbvh_from_regular_mesh(ob, me_eval_deform, respect_hide);
pbvh = build_pbvh_from_regular_mesh(ob, me_eval_deform);
}
}

View File

@ -335,10 +335,6 @@ static void build_mesh_leaf_node(PBVH *pbvh, PBVHNode *node)
node->face_vert_indices = (const int(*)[3])face_vert_indices;
if (pbvh->respect_hide == false) {
has_visible = true;
}
for (int i = 0; i < totface; i++) {
const MLoopTri *lt = &pbvh->looptri[node->prim_indices[i]];
for (int j = 0; j < 3; j++) {
@ -1042,7 +1038,6 @@ void BKE_pbvh_build_grids(PBVH *pbvh,
PBVH *BKE_pbvh_new(PBVHType type)
{
PBVH *pbvh = MEM_new<PBVH>(__func__);
pbvh->respect_hide = true;
pbvh->draw_cache_invalid = true;
pbvh->header.type = type;
@ -2600,7 +2595,7 @@ static bool pbvh_faces_node_raycast(PBVH *pbvh,
const MLoopTri *lt = &pbvh->looptri[faces[i]];
const int *face_verts = node->face_vert_indices[i];
if (pbvh->respect_hide && paint_is_face_hidden(lt, pbvh->hide_poly)) {
if (paint_is_face_hidden(lt, pbvh->hide_poly)) {
continue;
}
@ -2909,7 +2904,7 @@ static bool pbvh_faces_node_nearest_to_ray(PBVH *pbvh,
const MLoopTri *lt = &pbvh->looptri[faces[i]];
const int *face_verts = node->face_vert_indices[i];
if (pbvh->respect_hide && paint_is_face_hidden(lt, pbvh->hide_poly)) {
if (paint_is_face_hidden(lt, pbvh->hide_poly)) {
continue;
}
@ -3425,12 +3420,6 @@ void pbvh_vertex_iter_init(PBVH *pbvh, PBVHNode *node, PBVHVertexIter *vi, int m
vi->vert_positions = nullptr;
vi->vertex.i = 0LL;
vi->respect_hide = pbvh->respect_hide;
if (pbvh->respect_hide == false) {
/* The same value for all vertices. */
vi->visible = true;
}
BKE_pbvh_node_get_grids(pbvh, node, &grid_indices, &totgrid, nullptr, &gridsize, &grids);
BKE_pbvh_node_num_verts(pbvh, node, &uniq_verts, &totvert);
const int *vert_indices = BKE_pbvh_node_get_vert_indices(node);
@ -3586,11 +3575,6 @@ void BKE_pbvh_update_hide_attributes_from_mesh(PBVH *pbvh)
}
}
void BKE_pbvh_respect_hide_set(PBVH *pbvh, bool respect_hide)
{
pbvh->respect_hide = respect_hide;
}
bool BKE_pbvh_is_drawing(const PBVH *pbvh)
{
return pbvh->is_drawing;

View File

@ -187,7 +187,6 @@ struct PBVH {
/* flag are verts/faces deformed */
bool deformed;
bool respect_hide;
/* Dynamic topology */
float bm_max_edge_len;

View File

@ -64,7 +64,7 @@ static void pointcloud_init_data(ID *id)
CustomData_reset(&pointcloud->pdata);
CustomData_add_layer_named(&pointcloud->pdata,
CD_PROP_FLOAT3,
CD_SET_DEFAULT,
CD_CONSTRUCT,
pointcloud->totpoint,
POINTCLOUD_ATTR_POSITION);
@ -202,21 +202,18 @@ static void pointcloud_random(PointCloud *pointcloud)
RNG *rng = BLI_rng_new(0);
blender::bke::MutableAttributeAccessor attributes = pointcloud->attributes_for_write();
blender::bke::SpanAttributeWriter positions =
attributes.lookup_or_add_for_write_only_span<float3>(POINTCLOUD_ATTR_POSITION,
ATTR_DOMAIN_POINT);
blender::MutableSpan<float3> positions = pointcloud->positions_for_write();
blender::bke::SpanAttributeWriter<float> radii =
attributes.lookup_or_add_for_write_only_span<float>(POINTCLOUD_ATTR_RADIUS,
ATTR_DOMAIN_POINT);
for (const int i : positions.span.index_range()) {
positions.span[i] =
float3(BLI_rng_get_float(rng), BLI_rng_get_float(rng), BLI_rng_get_float(rng)) * 2.0f -
1.0f;
for (const int i : positions.index_range()) {
positions[i] = float3(BLI_rng_get_float(rng), BLI_rng_get_float(rng), BLI_rng_get_float(rng)) *
2.0f -
1.0f;
radii.span[i] = 0.05f * BLI_rng_get_float(rng);
}
positions.finish();
radii.finish();
BLI_rng_free(rng);

View File

@ -73,7 +73,7 @@ inline void gather(const VArray<T> &src,
{
BLI_assert(indices.size() == dst.size());
threading::parallel_for(indices.index_range(), grain_size, [&](const IndexRange range) {
src.materialize_compressed_to_uninitialized(indices.slice(range), dst.slice(range).data());
src.materialize_compressed_to_uninitialized(indices.slice(range), dst.slice(range));
});
}

View File

@ -20,7 +20,7 @@
#include "bmesh.h"
#include "intern/bmesh_private.h"
BMUVOffsets BM_uv_map_get_offsets_n(const BMesh *bm, const int layer)
BMUVOffsets BM_uv_map_get_offsets_from_layer(const BMesh *bm, const int layer)
{
using namespace blender;
using namespace blender::bke;
@ -46,7 +46,8 @@ BMUVOffsets BM_uv_map_get_offsets_n(const BMesh *bm, const int layer)
BMUVOffsets BM_uv_map_get_offsets(const BMesh *bm)
{
return BM_uv_map_get_offsets_n(bm, CustomData_get_active_layer(&bm->ldata, CD_PROP_FLOAT2));
const int layer = CustomData_get_active_layer(&bm->ldata, CD_PROP_FLOAT2);
return BM_uv_map_get_offsets_from_layer(bm, layer);
}
static void uv_aspect(const BMLoop *l,

View File

@ -11,11 +11,17 @@ extern "C" {
#endif
/**
* Retrieve the custom data offsets for layers used for user interaction with a UV map, returns the
* active uv map if layer is -1.
* Retrieve the custom data offsets for the UV map.
* \param layer: The layer index (where 0 is the first UV map).
* \return The layer offsets or -1 when not found.
*/
BMUVOffsets BM_uv_map_get_offsets_from_layer(const BMesh *bm, int layer);
/**
* Retrieve the custom data offsets for layers used for user interaction with the active UV map.
* \return The layer offsets or -1 when not found.
*/
BMUVOffsets BM_uv_map_get_offsets(const BMesh *bm);
BMUVOffsets BM_uv_map_get_offsets_n(const BMesh *bm, int layer);
float BM_loop_uv_calc_edge_length_squared(const BMLoop *l,
int cd_loop_uv_offset) ATTR_WARN_UNUSED_RESULT

View File

@ -77,8 +77,8 @@ GPU_SHADER_CREATE_INFO(workbench_next_resolve_curvature)
GPU_SHADER_CREATE_INFO(workbench_next_resolve_cavity)
.define("WORKBENCH_CAVITY")
/* TODO(@pragma37): GPU_SAMPLER_EXTEND_MODE_REPEAT is set in CavityEffect, it doesn't work
here? */
/* TODO(@pragma37): GPU_SAMPLER_EXTEND_MODE_REPEAT is set in CavityEffect,
* it doesn't work here? */
.sampler(8, ImageType::FLOAT_2D, "jitter_tx")
.uniform_buf(5, "vec4", "cavity_samples[512]");

View File

@ -250,7 +250,7 @@ static void pointcloud_extract_position_and_radius(const PointCloud &pointcloud,
using namespace blender;
const bke::AttributeAccessor attributes = pointcloud.attributes();
const VArraySpan<float3> positions = attributes.lookup<float3>("position", ATTR_DOMAIN_POINT);
const Span<float3> positions = pointcloud.positions();
const VArray<float> radii = attributes.lookup<float>("radius", ATTR_DOMAIN_POINT);
static GPUVertFormat format = {0};
if (format.attr_len == 0) {

View File

@ -7,6 +7,8 @@
#pragma once
#define DIAL_RESOLUTION 48
/**
* Data for common interactions. Used in gizmo_library_utils.c functions.
*/
@ -73,6 +75,13 @@ bool gizmo_window_project_2d(bContext *C,
bool gizmo_window_project_3d(
bContext *C, const struct wmGizmo *gz, const float mval[2], bool use_offset, float r_co[3]);
/* -------------------------------------------------------------------- */
/* Gizmo RNA Utils. */
struct wmGizmo *gizmo_find_from_properties(const struct IDProperty *properties,
const int spacetype,
const int regionid);
/* -------------------------------------------------------------------- */
/* Gizmo drawing */

View File

@ -15,12 +15,15 @@
#include "DNA_view3d_types.h"
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_main.h"
#include "RNA_access.h"
#include "WM_api.h"
#include "WM_types.h"
#include "ED_screen.h"
#include "ED_view3d.h"
#include "CLG_log.h"
@ -245,3 +248,38 @@ bool gizmo_window_project_3d(
copy_v2_v2(r_co, co);
return true;
}
/* -------------------------------------------------------------------- */
/** \name RNA Utils
* \{ */
/* Based on 'rna_GizmoProperties_find_operator'. */
wmGizmo *gizmo_find_from_properties(const struct IDProperty *properties,
const int spacetype,
const int regionid)
{
for (bScreen *screen = G_MAIN->screens.first; screen; screen = screen->id.next) {
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
if (!ELEM(spacetype, SPACE_TYPE_ANY, area->spacetype)) {
continue;
}
LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
if (region->gizmo_map == NULL) {
continue;
}
if (!ELEM(regionid, RGN_TYPE_ANY, region->regiontype)) {
continue;
}
LISTBASE_FOREACH (wmGizmoGroup *, gzgroup, WM_gizmomap_group_list(region->gizmo_map)) {
LISTBASE_FOREACH (wmGizmo *, gz, &gzgroup->gizmos) {
if (gz->properties == properties) {
return gz;
}
}
}
}
}
}
return NULL;
}

View File

@ -48,7 +48,7 @@
#include "../gizmo_library_intern.h"
/* to use custom arrows exported to geom_arrow_gizmo.c */
//#define USE_GIZMO_CUSTOM_ARROWS
// #define USE_GIZMO_CUSTOM_ARROWS
/* Margin to add when selecting the arrow. */
#define ARROW_SELECT_THRESHOLD_PX (5)
@ -115,6 +115,29 @@ static void arrow_draw_geom(const ArrowGizmo3D *arrow,
immUniform1f("lineWidth", arrow->gizmo.line_width * U.pixelsize);
wm_gizmo_vec_draw(color, vec, ARRAY_SIZE(vec), pos, GPU_PRIM_LINE_LOOP);
}
else if (draw_style == ED_GIZMO_ARROW_STYLE_PLANE) {
const float scale = 0.1f;
const float verts[4][3] = {
{0, 0, 0},
{scale, 0, scale},
{0, 0, 2 * scale},
{-scale, 0, scale},
};
const float color_inner[4] = {UNPACK3(color), color[3] * 0.5f};
/* Translate to line end. */
GPU_matrix_push();
GPU_matrix_translate_3f(0.0f, 0.0f, arrow_length);
immUniform1f("lineWidth", arrow->gizmo.line_width * U.pixelsize);
wm_gizmo_vec_draw(color, verts, ARRAY_SIZE(verts), pos, GPU_PRIM_LINE_LOOP);
immUnbindProgram();
immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
wm_gizmo_vec_draw(color_inner, verts, ARRAY_SIZE(verts), pos, GPU_PRIM_TRI_FAN);
GPU_matrix_pop();
}
else {
#ifdef USE_GIZMO_CUSTOM_ARROWS
wm_gizmo_geometryinfo_draw(&wm_gizmo_geom_data_arrow, select, color);
@ -177,6 +200,19 @@ static void arrow_draw_geom(const ArrowGizmo3D *arrow,
if (unbind_shader) {
immUnbindProgram();
}
if (draw_options & ED_GIZMO_ARROW_DRAW_FLAG_ORIGIN) {
const float point_size = 10 * U.pixelsize;
GPU_program_point_size(true);
immBindBuiltinProgram(GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA);
immUniform1f("size", point_size);
immUniformColor4fv(color);
immBegin(GPU_PRIM_POINTS, 1);
immVertex3f(pos, 0.0f, 0.0f, 0.0f);
immEnd();
immUnbindProgram();
GPU_program_point_size(false);
}
}
static void arrow_draw_intern(ArrowGizmo3D *arrow, const bool select, const bool highlight)
@ -504,10 +540,12 @@ static void GIZMO_GT_arrow_3d(wmGizmoType *gzt)
{ED_GIZMO_ARROW_STYLE_CROSS, "CROSS", 0, "Cross", ""},
{ED_GIZMO_ARROW_STYLE_BOX, "BOX", 0, "Box", ""},
{ED_GIZMO_ARROW_STYLE_CONE, "CONE", 0, "Cone", ""},
{ED_GIZMO_ARROW_STYLE_PLANE, "PLANE", 0, "Plane", ""},
{0, NULL, 0, NULL, NULL},
};
static EnumPropertyItem rna_enum_draw_options_items[] = {
{ED_GIZMO_ARROW_DRAW_FLAG_STEM, "STEM", 0, "Stem", ""},
{ED_GIZMO_ARROW_DRAW_FLAG_ORIGIN, "ORIGIN", 0, "Origin", ""},
{0, NULL, 0, NULL, NULL},
};
static EnumPropertyItem rna_enum_transform_items[] = {

View File

@ -71,7 +71,6 @@ typedef struct DialInteraction {
} DialInteraction;
#define DIAL_WIDTH 1.0f
#define DIAL_RESOLUTION 48
/* Could make option, negative to clip more (don't show when view aligned). */
#define DIAL_CLIP_BIAS 0.02

View File

@ -42,6 +42,7 @@
#include "../gizmo_library_intern.h"
#define MVAL_MAX_PX_DIST 12.0f
#define RING_2D_RESOLUTION 32
typedef struct MoveGizmo3D {
wmGizmo gizmo;
@ -78,8 +79,6 @@ typedef struct MoveInteraction {
} MoveInteraction;
#define DIAL_RESOLUTION 32
/* -------------------------------------------------------------------- */
static void move_geom_draw(const wmGizmo *gz,
@ -116,10 +115,10 @@ static void move_geom_draw(const wmGizmo *gz,
if (draw_style == ED_GIZMO_MOVE_STYLE_RING_2D) {
if (filled) {
imm_draw_circle_fill_3d(pos, 0.0f, 0.0f, radius, DIAL_RESOLUTION);
imm_draw_circle_fill_3d(pos, 0.0f, 0.0f, radius, RING_2D_RESOLUTION);
}
else {
imm_draw_circle_wire_3d(pos, 0.0f, 0.0f, radius, DIAL_RESOLUTION);
imm_draw_circle_wire_3d(pos, 0.0f, 0.0f, radius, RING_2D_RESOLUTION);
}
}
else if (draw_style == ED_GIZMO_MOVE_STYLE_CROSS_2D) {

View File

@ -15,6 +15,8 @@
#include "BLI_math.h"
#include "DNA_screen_types.h"
#include "DNA_space_types.h"
#include "DNA_view3d_types.h"
#include "BKE_context.h"
@ -42,36 +44,135 @@ static float verts_plane[4][3] = {
{-1, 1, 0},
};
typedef struct PrimitiveGizmo3D {
wmGizmo gizmo;
int draw_style;
float arc_inner_factor;
bool draw_inner;
} PrimitiveGizmo3D;
/* -------------------------------------------------------------------- */
/** \name RNA callbacks */
static void gizmo_primitive_draw_geom(const float col_inner[4],
const float col_outer[4],
const int draw_style)
static PrimitiveGizmo3D *gizmo_primitive_rna_find_operator(PointerRNA *ptr)
{
float(*verts)[3];
uint vert_count = 0;
if (draw_style == ED_GIZMO_PRIMITIVE_STYLE_PLANE) {
verts = verts_plane;
vert_count = ARRAY_SIZE(verts_plane);
}
if (vert_count > 0) {
uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
wm_gizmo_vec_draw(col_inner, verts, vert_count, pos, GPU_PRIM_TRI_FAN);
wm_gizmo_vec_draw(col_outer, verts, vert_count, pos, GPU_PRIM_LINE_LOOP);
immUnbindProgram();
}
return (PrimitiveGizmo3D *)gizmo_find_from_properties(ptr->data, SPACE_TYPE_ANY, RGN_TYPE_ANY);
}
static void gizmo_primitive_draw_intern(wmGizmo *gz,
const bool UNUSED(select),
const bool highlight)
static int gizmo_primitive_rna__draw_style_get_fn(struct PointerRNA *ptr,
struct PropertyRNA *UNUSED(prop))
{
PrimitiveGizmo3D *gz_prim = gizmo_primitive_rna_find_operator(ptr);
return gz_prim->draw_style;
}
static void gizmo_primitive_rna__draw_style_set_fn(struct PointerRNA *ptr,
struct PropertyRNA *UNUSED(prop),
int value)
{
PrimitiveGizmo3D *gz_prim = gizmo_primitive_rna_find_operator(ptr);
gz_prim->draw_style = value;
}
static float gizmo_primitive_rna__arc_inner_factor_get_fn(struct PointerRNA *ptr,
struct PropertyRNA *UNUSED(prop))
{
PrimitiveGizmo3D *gz_prim = gizmo_primitive_rna_find_operator(ptr);
return gz_prim->arc_inner_factor;
}
static void gizmo_primitive_rna__arc_inner_factor_set_fn(struct PointerRNA *ptr,
struct PropertyRNA *UNUSED(prop),
float value)
{
PrimitiveGizmo3D *gz_prim = gizmo_primitive_rna_find_operator(ptr);
gz_prim->arc_inner_factor = value;
}
static bool gizmo_primitive_rna__draw_inner_get_fn(struct PointerRNA *ptr,
struct PropertyRNA *UNUSED(prop))
{
PrimitiveGizmo3D *gz_prim = gizmo_primitive_rna_find_operator(ptr);
return gz_prim->draw_inner;
}
static void gizmo_primitive_rna__draw_inner_set_fn(struct PointerRNA *ptr,
struct PropertyRNA *UNUSED(prop),
bool value)
{
PrimitiveGizmo3D *gz_prim = gizmo_primitive_rna_find_operator(ptr);
gz_prim->draw_inner = value;
}
/* -------------------------------------------------------------------- */
static void gizmo_primitive_draw_geom(PrimitiveGizmo3D *gz_prim,
const float col_inner[4],
const float col_outer[4],
const int nsegments,
const bool draw_inner)
{
uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
const bool use_polyline_shader = gz_prim->gizmo.line_width > 1.0f;
if (draw_inner || !use_polyline_shader) {
immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
}
if (draw_inner) {
if (gz_prim->draw_style == ED_GIZMO_PRIMITIVE_STYLE_PLANE) {
wm_gizmo_vec_draw(col_inner, verts_plane, ARRAY_SIZE(verts_plane), pos, GPU_PRIM_TRI_FAN);
}
else {
immUniformColor4fv(col_inner);
if (gz_prim->draw_style == ED_GIZMO_PRIMITIVE_STYLE_CIRCLE) {
imm_draw_circle_fill_3d(pos, 0.0f, 0.0f, 1.0f, nsegments);
}
else {
BLI_assert(gz_prim->draw_style == ED_GIZMO_PRIMITIVE_STYLE_ANNULUS);
imm_draw_disk_partial_fill_3d(
pos, 0.0f, 0.0f, 0.0f, gz_prim->arc_inner_factor, 1.0f, nsegments, 0.0f, 360.0f);
}
}
}
/* Draw outline. */
if (use_polyline_shader) {
if (draw_inner) {
immUnbindProgram();
}
immBindBuiltinProgram(GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR);
float viewport[4];
GPU_viewport_size_get_f(viewport);
immUniform2fv("viewportSize", &viewport[2]);
immUniform1f("lineWidth", gz_prim->gizmo.line_width * U.pixelsize);
}
if (gz_prim->draw_style == ED_GIZMO_PRIMITIVE_STYLE_PLANE) {
wm_gizmo_vec_draw(col_outer, verts_plane, ARRAY_SIZE(verts_plane), pos, GPU_PRIM_LINE_LOOP);
}
else {
immUniformColor4fv(col_outer);
if (gz_prim->draw_style == ED_GIZMO_PRIMITIVE_STYLE_CIRCLE) {
imm_draw_circle_wire_3d(pos, 0.0f, 0.0f, 1.0f, nsegments);
}
else {
imm_draw_circle_wire_3d(pos, 0.0f, 0.0f, gz_prim->arc_inner_factor, nsegments);
imm_draw_circle_wire_3d(pos, 0.0f, 0.0f, 1.0f, nsegments);
}
}
immUnbindProgram();
}
static void gizmo_primitive_draw_intern(wmGizmo *gz, const bool select, const bool highlight)
{
PrimitiveGizmo3D *gz_prim = (PrimitiveGizmo3D *)gz;
float color_inner[4], color_outer[4];
float matrix_final[4][4];
const int draw_style = RNA_enum_get(gz->ptr, "draw_style");
gizmo_color_get(gz, highlight, color_outer);
copy_v4_v4(color_inner, color_outer);
@ -79,12 +180,15 @@ static void gizmo_primitive_draw_intern(wmGizmo *gz,
WM_gizmo_calc_matrix_final(gz, matrix_final);
GPU_blend(GPU_BLEND_ALPHA);
GPU_matrix_push();
GPU_matrix_mul(matrix_final);
GPU_blend(GPU_BLEND_ALPHA);
gizmo_primitive_draw_geom(color_inner, color_outer, draw_style);
GPU_blend(GPU_BLEND_NONE);
gizmo_primitive_draw_geom(gz_prim,
color_inner,
color_outer,
select ? 24 : DIAL_RESOLUTION,
gz_prim->draw_inner || select);
GPU_matrix_pop();
@ -98,12 +202,12 @@ static void gizmo_primitive_draw_intern(wmGizmo *gz,
GPU_matrix_push();
GPU_matrix_mul(inter->init_matrix_final);
GPU_blend(GPU_BLEND_ALPHA);
gizmo_primitive_draw_geom(color_inner, color_outer, draw_style);
GPU_blend(GPU_BLEND_NONE);
gizmo_primitive_draw_geom(
gz_prim, color_inner, color_outer, DIAL_RESOLUTION, gz_prim->draw_inner);
GPU_matrix_pop();
}
GPU_blend(GPU_BLEND_NONE);
}
static void gizmo_primitive_draw_select(const bContext *UNUSED(C), wmGizmo *gz, int select_id)
@ -120,6 +224,12 @@ static void gizmo_primitive_draw(const bContext *UNUSED(C), wmGizmo *gz)
static void gizmo_primitive_setup(wmGizmo *gz)
{
gz->flag |= WM_GIZMO_DRAW_MODAL;
/* Default Values. */
PrimitiveGizmo3D *gz_prim = (PrimitiveGizmo3D *)gz;
gz_prim->draw_style = ED_GIZMO_PRIMITIVE_STYLE_PLANE;
gz_prim->arc_inner_factor = true;
gz_prim->draw_inner = true;
}
static int gizmo_primitive_invoke(bContext *UNUSED(C), wmGizmo *gz, const wmEvent *UNUSED(event))
@ -148,18 +258,35 @@ static void GIZMO_GT_primitive_3d(wmGizmoType *gzt)
gzt->setup = gizmo_primitive_setup;
gzt->invoke = gizmo_primitive_invoke;
gzt->struct_size = sizeof(wmGizmo);
gzt->struct_size = sizeof(PrimitiveGizmo3D);
static EnumPropertyItem rna_enum_draw_style[] = {
{ED_GIZMO_PRIMITIVE_STYLE_PLANE, "PLANE", 0, "Plane", ""},
{ED_GIZMO_PRIMITIVE_STYLE_CIRCLE, "CIRCLE", 0, "Circle", ""},
{ED_GIZMO_PRIMITIVE_STYLE_ANNULUS, "ANNULUS", 0, "Annulus", ""},
{0, NULL, 0, NULL, NULL},
};
RNA_def_enum(gzt->srna,
"draw_style",
rna_enum_draw_style,
ED_GIZMO_PRIMITIVE_STYLE_PLANE,
"Draw Style",
"");
PropertyRNA *prop;
prop = RNA_def_enum(gzt->srna,
"draw_style",
rna_enum_draw_style,
ED_GIZMO_PRIMITIVE_STYLE_PLANE,
"Draw Style",
"");
RNA_def_property_enum_funcs_runtime(
prop, gizmo_primitive_rna__draw_style_get_fn, gizmo_primitive_rna__draw_style_set_fn, NULL);
prop = RNA_def_float_factor(
gzt->srna, "arc_inner_factor", 0.0f, 0.0f, FLT_MAX, "Arc Inner Factor", "", 0.0f, 1.0f);
RNA_def_property_float_funcs_runtime(prop,
gizmo_primitive_rna__arc_inner_factor_get_fn,
gizmo_primitive_rna__arc_inner_factor_set_fn,
NULL);
prop = RNA_def_boolean(gzt->srna, "draw_inner", true, "Draw Inner", "");
RNA_def_property_boolean_funcs_runtime(
prop, gizmo_primitive_rna__draw_inner_get_fn, gizmo_primitive_rna__draw_inner_set_fn);
}
void ED_gizmotypes_primitive_3d(void)

View File

@ -123,30 +123,9 @@ void ED_gizmotypes_snap_3d_data_get(const struct bContext *C,
/** \name RNA callbacks
* \{ */
/* Based on 'rna_GizmoProperties_find_operator'. */
static SnapGizmo3D *gizmo_snap_rna_find_operator(PointerRNA *ptr)
{
IDProperty *properties = ptr->data;
for (bScreen *screen = G_MAIN->screens.first; screen; screen = screen->id.next) {
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
if (area->spacetype != SPACE_VIEW3D) {
continue;
}
LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
if (region->regiontype == RGN_TYPE_WINDOW && region->gizmo_map) {
wmGizmoMap *gzmap = region->gizmo_map;
LISTBASE_FOREACH (wmGizmoGroup *, gzgroup, WM_gizmomap_group_list(gzmap)) {
LISTBASE_FOREACH (wmGizmo *, gz, &gzgroup->gizmos) {
if (gz->properties == properties) {
return (SnapGizmo3D *)gz;
}
}
}
}
}
}
}
return NULL;
return (SnapGizmo3D *)gizmo_find_from_properties(ptr->data, SPACE_VIEW3D, RGN_TYPE_WINDOW);
}
static V3DSnapCursorState *gizmo_snap_state_from_rna_get(struct PointerRNA *ptr)

View File

@ -64,6 +64,7 @@ enum {
ED_GIZMO_ARROW_STYLE_CROSS = 1,
ED_GIZMO_ARROW_STYLE_BOX = 2,
ED_GIZMO_ARROW_STYLE_CONE = 3,
ED_GIZMO_ARROW_STYLE_PLANE = 4,
};
/* transform */
@ -78,6 +79,7 @@ enum {
enum {
/* Show arrow stem. */
ED_GIZMO_ARROW_DRAW_FLAG_STEM = (1 << 0),
ED_GIZMO_ARROW_DRAW_FLAG_ORIGIN = (1 << 1),
};
/**
@ -233,6 +235,8 @@ enum {
enum {
ED_GIZMO_PRIMITIVE_STYLE_PLANE = 0,
ED_GIZMO_PRIMITIVE_STYLE_CIRCLE,
ED_GIZMO_PRIMITIVE_STYLE_ANNULUS,
};
/* -------------------------------------------------------------------- */

View File

@ -155,10 +155,16 @@ bool UI_but_is_tool(const uiBut *but)
bool UI_but_has_tooltip_label(const uiBut *but)
{
if ((but->drawstr[0] == '\0') && !ui_block_is_popover(but->block)) {
return UI_but_is_tool(but);
/* No tooltip label if the button itself shows a label already. */
if (but->drawstr[0] != '\0') {
return false;
}
return false;
if (UI_but_is_tool(but)) {
return !ui_block_is_popover(but->block);
}
return ELEM(but->type, UI_BTYPE_TAB);
}
int ui_but_icon(const uiBut *but)

View File

@ -116,18 +116,18 @@ static void ui_popup_block_position(wmWindow *window,
const int center_x = (block->direction & UI_DIR_CENTER_X) ? size_x / 2 : 0;
const int center_y = (block->direction & UI_DIR_CENTER_Y) ? size_y / 2 : 0;
const int win_x = WM_window_pixels_x(window);
const int win_y = WM_window_pixels_y(window);
/* Take into account maximum size so we don't have to flip on refresh. */
const float max_size_x = max_ff(size_x, handle->max_size_x);
const float max_size_y = max_ff(size_y, handle->max_size_y);
short dir1 = 0, dir2 = 0;
if (!handle->refresh) {
bool left = false, right = false, top = false, down = false;
const int win_x = WM_window_pixels_x(window);
const int win_y = WM_window_pixels_y(window);
/* Take into account maximum size so we don't have to flip on refresh. */
const float max_size_x = max_ff(size_x, handle->max_size_x);
const float max_size_y = max_ff(size_y, handle->max_size_y);
/* check if there's space at all */
if (butrct.xmin - max_size_x + center_x > 0.0f) {
left = true;
@ -237,6 +237,15 @@ static void ui_popup_block_position(wmWindow *window,
}
else if (dir1 == UI_DIR_UP) {
offset_y = (butrct.ymax - block->rect.ymin) - offset_overlap;
if (but->type == UI_BTYPE_COLOR && block->rect.ymax + offset_y > win_y - UI_POPUP_MENU_TOP) {
/* Shift this down, aligning the top edge close to the window top. */
offset_y = win_y - block->rect.ymax - UI_POPUP_MENU_TOP;
/* All four corners should be rounded since this no longer button-aligned. */
block->direction = UI_DIR_CENTER_Y;
dir1 = UI_DIR_CENTER_Y;
}
if (dir2 == UI_DIR_RIGHT) {
offset_x = butrct.xmax - block->rect.xmax + center_x;
}
@ -251,6 +260,15 @@ static void ui_popup_block_position(wmWindow *window,
}
else if (dir1 == UI_DIR_DOWN) {
offset_y = (butrct.ymin - block->rect.ymax) + offset_overlap;
if (but->type == UI_BTYPE_COLOR && block->rect.ymin + offset_y < UI_SCREEN_MARGIN) {
/* Shift this up, aligning the bottom edge close to the window bottom. */
offset_y = -block->rect.ymin + UI_SCREEN_MARGIN;
/* All four corners should be rounded since this no longer button-aligned. */
block->direction = UI_DIR_CENTER_Y;
dir1 = UI_DIR_CENTER_Y;
}
if (dir2 == UI_DIR_RIGHT) {
offset_x = butrct.xmax - block->rect.xmax + center_x;
}

View File

@ -742,7 +742,8 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is
static uiTooltipData *ui_tooltip_data_from_button_or_extra_icon(bContext *C,
uiBut *but,
uiButExtraOpIcon *extra_icon)
uiButExtraOpIcon *extra_icon,
const bool is_label)
{
uiStringInfo but_label = {BUT_GET_LABEL, nullptr};
uiStringInfo but_tip = {BUT_GET_TIP, nullptr};
@ -763,20 +764,30 @@ static uiTooltipData *ui_tooltip_data_from_button_or_extra_icon(bContext *C,
uiTooltipData *data = MEM_cnew<uiTooltipData>(__func__);
if (extra_icon) {
UI_but_extra_icon_string_info_get(C, extra_icon, &but_label, &but_tip, &op_keymap, nullptr);
if (is_label) {
UI_but_extra_icon_string_info_get(C, extra_icon, &but_label, &enum_label, nullptr);
}
else {
UI_but_extra_icon_string_info_get(C, extra_icon, &but_label, &but_tip, &op_keymap, nullptr);
}
}
else {
UI_but_string_info_get(C,
but,
&but_label,
&but_tip,
&enum_label,
&enum_tip,
&op_keymap,
&prop_keymap,
&rna_struct,
&rna_prop,
nullptr);
if (is_label) {
UI_but_string_info_get(C, but, &but_label, &enum_label, nullptr);
}
else {
UI_but_string_info_get(C,
but,
&but_label,
&but_tip,
&enum_label,
&enum_tip,
&op_keymap,
&prop_keymap,
&rna_struct,
&rna_prop,
nullptr);
}
}
/* Tip Label (only for buttons not already showing the label).
@ -811,6 +822,13 @@ static uiTooltipData *ui_tooltip_data_from_button_or_extra_icon(bContext *C,
field->text = BLI_strdup(TIP_("(Shift-Click/Drag to select multiple)"));
}
}
/* When there is only an enum label (no button label or tip), draw that as header. */
else if (enum_label.strinfo && !(but_label.strinfo && but_label.strinfo[0])) {
uiTooltipField *field = text_field_add(
data, uiTooltipFormat::Style::Header, uiTooltipFormat::ColorID::Normal);
field->text = BLI_strdup(enum_label.strinfo);
}
/* Enum field label & tip. */
if (enum_tip.strinfo) {
uiTooltipField *field = text_field_add(
@ -1346,11 +1364,11 @@ ARegion *UI_tooltip_create_from_button_or_extra_icon(
}
if (data == nullptr) {
data = ui_tooltip_data_from_button_or_extra_icon(C, but, extra_icon);
data = ui_tooltip_data_from_button_or_extra_icon(C, but, extra_icon, is_label);
}
if (data == nullptr) {
data = ui_tooltip_data_from_button_or_extra_icon(C, but, nullptr);
data = ui_tooltip_data_from_button_or_extra_icon(C, but, nullptr, is_label);
}
if (data == nullptr) {

View File

@ -326,7 +326,7 @@ void WM_OT_usd_export(struct wmOperatorType *ot)
"overwrite_textures",
false,
"Overwrite Textures",
"Allow overwriting existing texture files when exporting textures");
"Overwrite existing files when exporting textures");
RNA_def_boolean(ot->srna,
"relative_paths",
@ -612,7 +612,7 @@ void WM_OT_usd_import(struct wmOperatorType *ot)
RNA_def_boolean(ot->srna, "read_mesh_uvs", true, "UV Coordinates", "Read mesh UV coordinates");
RNA_def_boolean(
ot->srna, "read_mesh_colors", false, "Color Attributes", "Read mesh color attributes");
ot->srna, "read_mesh_colors", true, "Color Attributes", "Read mesh color attributes");
RNA_def_string(ot->srna,
"prim_path_mask",

View File

@ -62,6 +62,8 @@ void IMAGE_OT_save_sequence(struct wmOperatorType *ot);
void IMAGE_OT_save_all_modified(struct wmOperatorType *ot);
void IMAGE_OT_pack(struct wmOperatorType *ot);
void IMAGE_OT_unpack(struct wmOperatorType *ot);
void IMAGE_OT_clipboard_copy(struct wmOperatorType *ot);
void IMAGE_OT_clipboard_paste(struct wmOperatorType *ot);
void IMAGE_OT_flip(struct wmOperatorType *ot);
void IMAGE_OT_invert(struct wmOperatorType *ot);

View File

@ -71,6 +71,7 @@
#include "ED_screen.h"
#include "ED_space_api.h"
#include "ED_util.h"
#include "ED_undo.h"
#include "ED_util_imbuf.h"
#include "ED_uvedit.h"
@ -2834,6 +2835,125 @@ void IMAGE_OT_flip(wmOperatorType *ot)
/** \} */
/* -------------------------------------------------------------------- */
/** \name Clipboard Copy Operator
* \{ */
static int image_clipboard_copy_exec(bContext *C, wmOperator *op)
{
Image *ima = image_from_context(C);
if (ima == NULL) {
return false;
}
if (G.is_rendering && ima->source == IMA_SRC_VIEWER) {
BKE_report(op->reports, RPT_ERROR, "Images cannot be copied while rendering");
return false;
}
ImageUser *iuser = image_user_from_context(C);
WM_cursor_set(CTX_wm_window(C), WM_CURSOR_WAIT);
void *lock;
ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, &lock);
if (ibuf == NULL) {
BKE_image_release_ibuf(ima, ibuf, lock);
WM_cursor_set(CTX_wm_window(C), WM_CURSOR_DEFAULT);
return OPERATOR_CANCELLED;
}
WM_clipboard_image_set(ibuf);
BKE_image_release_ibuf(ima, ibuf, lock);
WM_cursor_set(CTX_wm_window(C), WM_CURSOR_DEFAULT);
return OPERATOR_FINISHED;
}
static bool image_clipboard_copy_poll(bContext *C)
{
if (!image_from_context_has_data_poll(C)) {
CTX_wm_operator_poll_msg_set(C, "No images available");
return false;
}
return true;
}
void IMAGE_OT_clipboard_copy(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Copy Image";
ot->idname = "IMAGE_OT_clipboard_copy";
ot->description = "Copy the image to the clipboard";
/* api callbacks */
ot->exec = image_clipboard_copy_exec;
ot->poll = image_clipboard_copy_poll;
/* flags */
ot->flag = OPTYPE_REGISTER;
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Clipboard Paste Operator
* \{ */
static int image_clipboard_paste_exec(bContext *C, wmOperator *op)
{
WM_cursor_set(CTX_wm_window(C), WM_CURSOR_WAIT);
ImBuf *ibuf = WM_clipboard_image_get();
if (!ibuf) {
WM_cursor_set(CTX_wm_window(C), WM_CURSOR_DEFAULT);
return OPERATOR_CANCELLED;
}
ED_undo_push_op(C, op);
Main *bmain = CTX_data_main(C);
SpaceImage *sima = CTX_wm_space_image(C);
Image *ima = BKE_image_add_from_imbuf(bmain, ibuf, "Clipboard");
IMB_freeImBuf(ibuf);
ED_space_image_set(bmain, sima, ima, false);
BKE_image_signal(bmain, ima, (sima) ? &sima->iuser : NULL, IMA_SIGNAL_USER_NEW_IMAGE);
WM_event_add_notifier(C, NC_IMAGE | NA_ADDED, ima);
WM_cursor_set(CTX_wm_window(C), WM_CURSOR_DEFAULT);
return OPERATOR_FINISHED;
}
static bool image_clipboard_paste_poll(bContext *C)
{
if (!WM_clipboard_image_available()) {
CTX_wm_operator_poll_msg_set(C, "No compatible images are on the clipboard");
return false;
}
return true;
}
void IMAGE_OT_clipboard_paste(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Paste Image";
ot->idname = "IMAGE_OT_clipboard_paste";
ot->description = "Paste new image from the clipboard";
/* api callbacks */
ot->exec = image_clipboard_paste_exec;
ot->poll = image_clipboard_paste_poll;
/* flags */
ot->flag = OPTYPE_REGISTER;
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Invert Operators
* \{ */

View File

@ -216,6 +216,8 @@ static void image_operatortypes(void)
WM_operatortype_append(IMAGE_OT_save_all_modified);
WM_operatortype_append(IMAGE_OT_pack);
WM_operatortype_append(IMAGE_OT_unpack);
WM_operatortype_append(IMAGE_OT_clipboard_copy);
WM_operatortype_append(IMAGE_OT_clipboard_paste);
WM_operatortype_append(IMAGE_OT_flip);
WM_operatortype_append(IMAGE_OT_invert);

View File

@ -194,7 +194,8 @@ static void nlastrip_flag_overlaps(NlaStrip *strip)
}
}
/** Check the Transformation data for the given Strip, and fix any overlap. Then
/**
* Check the Transformation data for the given Strip, and fix any overlap. Then
* apply the Transformation.
*/
static void nlastrip_fix_overlapping(TransInfo *t, TransDataNla *tdn, NlaStrip *strip)
@ -202,8 +203,7 @@ static void nlastrip_fix_overlapping(TransInfo *t, TransDataNla *tdn, NlaStrip *
/* firstly, check if the proposed transform locations would overlap with any neighboring
* strips (barring transitions) which are absolute barriers since they are not being moved
*
* this is done as a iterative procedure (done 5 times max for now)
*/
* this is done as a iterative procedure (done 5 times max for now). */
short iter_max = 4;
NlaStrip *prev = BKE_nlastrip_prev_in_track(strip, true);
NlaStrip *next = BKE_nlastrip_next_in_track(strip, true);
@ -215,9 +215,8 @@ static void nlastrip_fix_overlapping(TransInfo *t, TransDataNla *tdn, NlaStrip *
const bool n_exceeded = (next != NULL) && (tdn->h2[0] > next->start);
if ((p_exceeded && n_exceeded) || (iter == iter_max)) {
/* both endpoints exceeded (or iteration ping-pong'd meaning that we need a
* compromise)
* - Simply crop strip to fit within the bounds of the strips bounding it
/* Both endpoints exceeded (or iteration ping-pong'd meaning that we need a compromise).
* - Simply crop strip to fit within the bounds of the strips bounding it.
* - If there were no neighbors, clear the transforms
* (make it default to the strip's current values).
*/
@ -250,16 +249,14 @@ static void nlastrip_fix_overlapping(TransInfo *t, TransDataNla *tdn, NlaStrip *
}
/* Use RNA to write the values to ensure that constraints on these are obeyed
* (e.g. for transition strips, the values are taken from the neighbors)
*/
* (e.g. for transition strips, the values are taken from the neighbors). */
RNA_pointer_create(NULL, &RNA_NlaStrip, strip, &strip_ptr);
switch (t->mode) {
case TFM_TIME_EXTEND:
case TFM_TIME_SCALE: {
/* The final scale is the product of the original strip scale (from before the
* transform operation started) and the current scale value of this transform
* operation. */
* transform operation started) and the current scale value of this transform operation. */
const float originalStripScale = tdn->h1[2];
const float newStripScale = originalStripScale * t->values_final[0];
applyTransformNLA_timeScale(&strip_ptr, newStripScale);
@ -380,18 +377,18 @@ static void createTransNlaData(bContext *C, TransInfo *t)
/* transition strips can't get directly transformed */
if (strip->type != NLASTRIP_TYPE_TRANSITION) {
if (strip->flag & NLASTRIP_FLAG_SELECT) {
/* our transform data is constructed as follows:
* - only the handles on the right side of the current-frame get included
* - td structs are transform-elements operated on by the transform system
* and represent a single handle. The storage/pointer used (val or loc) depends
* on whether we're scaling or transforming. Ultimately though, the handles the td
* writes to will simply be a dummy in tdn
* - for each strip being transformed, a single tdn struct is used, so in some
* cases, there will need to be 1 of these tdn elements in the array skipped...
/* Our transform data is constructed as follows:
* - Only the handles on the right side of the current-frame get included.
* - `td` structs are transform-elements operated on by the transform system and
* represent a single handle. The storage/pointer used (`val` or `loc`) depends
* on whether we're scaling or transforming. Ultimately though, the handles the `td`
* writes to will simply be a dummy in `tdn`.
* - For each strip being transformed, a single `tdn` struct is used, so in some
* cases, there will need to be 1 of these `tdn` elements in the array skipped.
*/
float center[3], yval;
/* firstly, init tdn settings */
/* Firstly, initialize `tdn` settings. */
tdn->id = ale->id;
tdn->oldTrack = tdn->nlt = nlt;
tdn->strip = strip;
@ -648,14 +645,12 @@ typedef struct IDGroupedTransData {
/** horizontally translate (shuffle) the transformed strip to a non-overlapping state. */
static void nlastrip_shuffle_transformed(TransDataContainer *tc, TransDataNla *first_trans_data)
{
/* Element: (IDGroupedTransData*) */
/* Element: #IDGroupedTransData. */
ListBase grouped_trans_datas = {NULL, NULL};
/* Flag all non-library-override transformed strips so we can distinguish them when
* shuffling.
/* Flag all non-library-override transformed strips so we can distinguish them when shuffling.
*
* Group trans_datas by ID so shuffling is unique per ID.
*/
* Group trans_datas by ID so shuffling is unique per ID. */
{
TransDataNla *tdn = first_trans_data;
for (int i = 0; i < tc->data_len; i++, tdn++) {

View File

@ -1227,9 +1227,7 @@ static void gizmo_3d_dial_matrixbasis_calc(const ARegion *region,
* \{ */
/** Scale of the two-axis planes. */
#define MAN_AXIS_SCALE_PLANE_SCALE 0.07f
/** Offset of the two-axis planes, depends on the gizmos scale. Define to avoid repeating. */
#define MAN_AXIS_SCALE_PLANE_OFFSET 7.0f
#define MAN_AXIS_SCALE_PLANE_SCALE 0.7f
static void rotation_get_fn(const wmGizmo * /*gz*/, wmGizmoProperty *gz_prop, void *value)
{
@ -1273,21 +1271,21 @@ static void gizmo_3d_setup_default_matrix(wmGizmo *axis, const int axis_idx)
case MAN_AXIS_TRANS_XY:
case MAN_AXIS_SCALE_XY:
copy_v3_fl3(matrix[0], MAN_AXIS_SCALE_PLANE_SCALE, 0.0f, 0.0f);
copy_v3_fl3(matrix[1], 0.0f, MAN_AXIS_SCALE_PLANE_SCALE, 0.0f);
copy_v3_fl3(matrix[2], 0.0f, 0.0f, MAN_AXIS_SCALE_PLANE_SCALE);
copy_v3_fl3(matrix[0], -M_SQRT1_2, M_SQRT1_2, 0.0f);
copy_v3_fl3(matrix[1], 0.0f, 0.0f, 1.0f);
copy_v3_fl3(matrix[2], M_SQRT1_2, M_SQRT1_2, 0.0f);
break;
case MAN_AXIS_TRANS_YZ:
case MAN_AXIS_SCALE_YZ:
copy_v3_fl3(matrix[0], 0.0f, 0.0f, MAN_AXIS_SCALE_PLANE_SCALE);
copy_v3_fl3(matrix[1], 0.0f, MAN_AXIS_SCALE_PLANE_SCALE, 0.0f);
copy_v3_fl3(matrix[2], -MAN_AXIS_SCALE_PLANE_SCALE, 0.0f, 0.0f);
copy_v3_fl3(matrix[0], 0.0f, -M_SQRT1_2, M_SQRT1_2);
copy_v3_fl3(matrix[1], 1.0f, 0.0f, 0.0f);
copy_v3_fl3(matrix[2], 0, M_SQRT1_2, M_SQRT1_2);
break;
case MAN_AXIS_TRANS_ZX:
case MAN_AXIS_SCALE_ZX:
copy_v3_fl3(matrix[0], MAN_AXIS_SCALE_PLANE_SCALE, 0.0f, 0.0f);
copy_v3_fl3(matrix[1], 0.0f, 0.0f, MAN_AXIS_SCALE_PLANE_SCALE);
copy_v3_fl3(matrix[2], 0.0f, -MAN_AXIS_SCALE_PLANE_SCALE, 0.0f);
case MAN_AXIS_TRANS_ZX:
copy_v3_fl3(matrix[0], M_SQRT1_2, 0.0f, -M_SQRT1_2);
copy_v3_fl3(matrix[1], 0.0f, 1.0f, 0.0f);
copy_v3_fl3(matrix[2], M_SQRT1_2, 0.0f, M_SQRT1_2);
break;
case MAN_AXIS_TRANS_C:
@ -1299,22 +1297,6 @@ static void gizmo_3d_setup_default_matrix(wmGizmo *axis, const int axis_idx)
}
copy_m4_m3(axis->matrix_offset, matrix);
switch (axis_idx) {
case MAN_AXIS_TRANS_XY:
case MAN_AXIS_TRANS_YZ:
case MAN_AXIS_TRANS_ZX:
case MAN_AXIS_SCALE_XY:
case MAN_AXIS_SCALE_YZ:
case MAN_AXIS_SCALE_ZX: {
float offs[3];
add_v3_v3v3(offs, axis->matrix_offset[0], axis->matrix_offset[1]);
mul_v3_fl(offs, MAN_AXIS_SCALE_PLANE_OFFSET);
WM_gizmo_set_matrix_offset_location(axis, offs);
} break;
default:
return;
}
}
static void gizmo_3d_setup_draw_default(wmGizmo *axis, const int axis_idx)
@ -1334,38 +1316,39 @@ static void gizmo_3d_setup_draw_default(wmGizmo *axis, const int axis_idx)
RNA_enum_set(axis->ptr, "draw_style", ED_GIZMO_ARROW_STYLE_BOX);
RNA_enum_set(axis->ptr, "draw_options", ED_GIZMO_ARROW_DRAW_FLAG_STEM);
break;
/* Primitive. */
case MAN_AXIS_TRANS_XY:
case MAN_AXIS_TRANS_YZ:
case MAN_AXIS_TRANS_ZX:
case MAN_AXIS_SCALE_XY:
case MAN_AXIS_SCALE_YZ:
case MAN_AXIS_SCALE_ZX:
RNA_enum_set(axis->ptr, "draw_style", ED_GIZMO_PRIMITIVE_STYLE_PLANE);
WM_gizmo_set_flag(axis, WM_GIZMO_DRAW_OFFSET_SCALE, true);
RNA_enum_set(axis->ptr, "draw_style", ED_GIZMO_ARROW_STYLE_PLANE);
RNA_enum_set(axis->ptr, "draw_options", 0);
RNA_float_set(axis->ptr, "length", MAN_AXIS_SCALE_PLANE_SCALE);
break;
/* Dial. */
/* Primitive. */
case MAN_AXIS_TRANS_C:
RNA_enum_set(axis->ptr, "draw_options", ED_GIZMO_DIAL_DRAW_FLAG_FILL_SELECT);
WM_gizmo_set_flag(axis, WM_GIZMO_DRAW_MODAL, true);
RNA_enum_set(axis->ptr, "draw_style", ED_GIZMO_PRIMITIVE_STYLE_CIRCLE);
RNA_boolean_set(axis->ptr, "draw_inner", false);
WM_gizmo_set_scale(axis, 0.2f);
/* Prevent axis gizmos overlapping the center point, see: #63744. */
axis->select_bias = 2.0f;
break;
case MAN_AXIS_SCALE_C:
RNA_enum_set(axis->ptr, "draw_options", ED_GIZMO_DIAL_DRAW_FLAG_FILL_SELECT);
RNA_enum_set(axis->ptr, "draw_style", ED_GIZMO_PRIMITIVE_STYLE_ANNULUS);
RNA_boolean_set(axis->ptr, "draw_inner", false);
/* Use 1/6 since this is '0.2' if the main scale is 1.2. */
RNA_float_set(axis->ptr, "arc_inner_factor", 1.0 / 6.0);
WM_gizmo_set_scale(axis, 1.2f);
/* Use 6 since this is '1.2' if the main scale is 0.2. */
RNA_float_set(axis->ptr, "arc_inner_factor", 6.0f);
WM_gizmo_set_scale(axis, 0.2f);
/* Prevent axis gizmos overlapping the center point, see: #63744. */
axis->select_bias = -2.0f;
break;
/* Dial. */
case MAN_AXIS_ROT_X:
case MAN_AXIS_ROT_Y:
case MAN_AXIS_ROT_Z:
@ -1385,11 +1368,12 @@ static void gizmo_3d_setup_draw_default(wmGizmo *axis, const int axis_idx)
}
switch (axis_idx) {
case MAN_AXIS_ROT_X:
case MAN_AXIS_ROT_Y:
case MAN_AXIS_ROT_Z:
/* Increased line width for better display. */
WM_gizmo_set_line_width(axis, GIZMO_AXIS_LINE_WIDTH + 1.0f);
case MAN_AXIS_TRANS_X:
case MAN_AXIS_TRANS_Y:
case MAN_AXIS_TRANS_Z:
case MAN_AXIS_SCALE_X:
case MAN_AXIS_SCALE_Y:
WM_gizmo_set_line_width(axis, GIZMO_AXIS_LINE_WIDTH);
break;
case MAN_AXIS_TRANS_XY:
case MAN_AXIS_TRANS_YZ:
@ -1399,6 +1383,12 @@ static void gizmo_3d_setup_draw_default(wmGizmo *axis, const int axis_idx)
case MAN_AXIS_SCALE_ZX:
WM_gizmo_set_line_width(axis, 1.0f);
break;
case MAN_AXIS_ROT_X:
case MAN_AXIS_ROT_Y:
case MAN_AXIS_ROT_Z:
/* Increased line width for better display. */
WM_gizmo_set_line_width(axis, GIZMO_AXIS_LINE_WIDTH + 1.0f);
break;
default:
WM_gizmo_set_line_width(axis, GIZMO_AXIS_LINE_WIDTH);
break;
@ -1462,9 +1452,42 @@ static void gizmo_3d_setup_draw_from_twtype(wmGizmo *axis, const int axis_idx, c
}
}
static void gizmo_3d_setup_draw_modal(wmGizmo *axis, const int axis_idx)
static void gizmo_3d_setup_draw_modal(wmGizmo *axis, const int axis_idx, const int twtype)
{
const short axis_type = gizmo_get_axis_type(axis_idx);
switch (axis_idx) {
case MAN_AXIS_TRANS_X:
case MAN_AXIS_TRANS_Y:
case MAN_AXIS_TRANS_Z:
case MAN_AXIS_SCALE_X:
case MAN_AXIS_SCALE_Y:
case MAN_AXIS_SCALE_Z: {
float end, start_co[3] = {0.0f, 0.0f, 0.0f};
gizmo_line_range(twtype, axis_type, NULL, &end);
RNA_float_set(axis->ptr, "length", end);
RNA_enum_set(axis->ptr,
"draw_options",
ED_GIZMO_ARROW_DRAW_FLAG_STEM | ED_GIZMO_ARROW_DRAW_FLAG_ORIGIN);
WM_gizmo_set_matrix_offset_location(axis, start_co);
WM_gizmo_set_flag(axis, WM_GIZMO_DRAW_OFFSET_SCALE, false);
break;
}
case MAN_AXIS_TRANS_XY:
case MAN_AXIS_TRANS_YZ:
case MAN_AXIS_TRANS_ZX:
case MAN_AXIS_SCALE_XY:
case MAN_AXIS_SCALE_YZ:
case MAN_AXIS_SCALE_ZX:
RNA_enum_set(axis->ptr, "draw_options", ED_GIZMO_ARROW_DRAW_FLAG_ORIGIN);
break;
case MAN_AXIS_SCALE_C:
RNA_enum_set(axis->ptr, "draw_style", ED_GIZMO_PRIMITIVE_STYLE_CIRCLE);
break;
default:
break;
}
switch (axis_type) {
case MAN_AXES_ROTATE: {
PropertyRNA *prop = RNA_struct_find_property(axis->ptr, "draw_options");
@ -1510,15 +1533,15 @@ static GizmoGroup *gizmogroup_init(wmGizmoGroup *gzgroup)
/* add/init widgets - order matters! */
GIZMO_NEW_DIAL(MAN_AXIS_ROT_T);
GIZMO_NEW_DIAL(MAN_AXIS_SCALE_C);
GIZMO_NEW_PRIM(MAN_AXIS_SCALE_C);
GIZMO_NEW_ARROW(MAN_AXIS_SCALE_X);
GIZMO_NEW_ARROW(MAN_AXIS_SCALE_Y);
GIZMO_NEW_ARROW(MAN_AXIS_SCALE_Z);
GIZMO_NEW_PRIM(MAN_AXIS_SCALE_XY);
GIZMO_NEW_PRIM(MAN_AXIS_SCALE_YZ);
GIZMO_NEW_PRIM(MAN_AXIS_SCALE_ZX);
GIZMO_NEW_ARROW(MAN_AXIS_SCALE_XY);
GIZMO_NEW_ARROW(MAN_AXIS_SCALE_YZ);
GIZMO_NEW_ARROW(MAN_AXIS_SCALE_ZX);
GIZMO_NEW_DIAL(MAN_AXIS_ROT_X);
GIZMO_NEW_DIAL(MAN_AXIS_ROT_Y);
@ -1527,15 +1550,15 @@ static GizmoGroup *gizmogroup_init(wmGizmoGroup *gzgroup)
/* init screen aligned widget last here, looks better, behaves better */
GIZMO_NEW_DIAL(MAN_AXIS_ROT_C);
GIZMO_NEW_DIAL(MAN_AXIS_TRANS_C);
GIZMO_NEW_PRIM(MAN_AXIS_TRANS_C);
GIZMO_NEW_ARROW(MAN_AXIS_TRANS_X);
GIZMO_NEW_ARROW(MAN_AXIS_TRANS_Y);
GIZMO_NEW_ARROW(MAN_AXIS_TRANS_Z);
GIZMO_NEW_PRIM(MAN_AXIS_TRANS_XY);
GIZMO_NEW_PRIM(MAN_AXIS_TRANS_YZ);
GIZMO_NEW_PRIM(MAN_AXIS_TRANS_ZX);
GIZMO_NEW_ARROW(MAN_AXIS_TRANS_XY);
GIZMO_NEW_ARROW(MAN_AXIS_TRANS_YZ);
GIZMO_NEW_ARROW(MAN_AXIS_TRANS_ZX);
MAN_ITER_AXES_BEGIN (axis, axis_idx) {
gizmo_3d_setup_draw_default(axis, axis_idx);
@ -1763,11 +1786,9 @@ static void gizmo_refresh_from_matrix(wmGizmo *axis,
case MAN_AXIS_SCALE_ZX:
copy_m4_m4(axis->matrix_basis, twmat);
if (scale) {
float offs[3];
add_v3_v3v3(offs, axis->matrix_offset[0], axis->matrix_offset[1]);
mul_v3_fl(offs, MAN_AXIS_SCALE_PLANE_OFFSET);
mul_v3_v3(offs, scale);
WM_gizmo_set_matrix_offset_location(axis, offs);
RNA_float_set(axis->ptr,
"length",
MAN_AXIS_SCALE_PLANE_SCALE * scale[aidx_norm == 2 ? 0 : aidx_norm + 1]);
}
break;
case MAN_AXIS_SCALE_X:
@ -1775,23 +1796,29 @@ static void gizmo_refresh_from_matrix(wmGizmo *axis,
case MAN_AXIS_SCALE_Z:
copy_m4_m4(axis->matrix_basis, twmat);
if (scale) {
float start, end;
gizmo_line_range(twtype, axis_type, &start, &end);
RNA_float_set(axis->ptr, "length", (end - start) * scale[aidx_norm]);
float end;
gizmo_line_range(twtype, axis_type, NULL, &end);
RNA_float_set(axis->ptr, "length", end * scale[aidx_norm]);
}
break;
case MAN_AXIS_TRANS_X:
case MAN_AXIS_TRANS_Y:
case MAN_AXIS_TRANS_Z:
copy_m4_m4(axis->matrix_basis, twmat);
break;
case MAN_AXIS_SCALE_C:
WM_gizmo_set_matrix_location(axis, twmat[3]);
if (scale) {
WM_gizmo_set_scale(axis, 0.2f * scale[0]);
}
break;
case MAN_AXIS_ROT_X:
case MAN_AXIS_ROT_Y:
case MAN_AXIS_ROT_Z:
copy_m4_m4(axis->matrix_basis, twmat);
orthogonalize_m4(axis->matrix_basis, aidx_norm);
break;
case MAN_AXIS_SCALE_C:
case MAN_AXIS_ROT_C:
case MAN_AXIS_ROT_T:
default:
@ -1971,66 +1998,43 @@ static void gizmo_3d_draw_invoke(wmGizmoGroup *gzgroup,
wmGizmo *axis_active = ggd->gizmos[axis_idx_active];
const short axis_active_type = gizmo_get_axis_type(axis_idx_active);
if (axis_active_type == MAN_AXES_ROTATE) {
/* Hide other gizmos except the active one and #MAN_AXIS_ROT_C.
* #MAN_AXIS_ROT_C was displayed before and remains visible by convention. */
gizmogroup_hide_all(ggd);
WM_gizmo_set_flag(axis_active, WM_GIZMO_HIDDEN, false);
WM_gizmo_set_flag(ggd->gizmos[MAN_AXIS_ROT_C], WM_GIZMO_HIDDEN, false);
}
else {
/* We switch from a modal gizmo to another. So make sure the gizmos are visible and have the
* default properties. */
const int twtype_expected = (axis_active_type == MAN_AXES_TRANSLATE ?
V3D_GIZMO_SHOW_OBJECT_TRANSLATE :
V3D_GIZMO_SHOW_OBJECT_SCALE);
/* Display only the active gizmo. */
gizmogroup_hide_all(ggd);
WM_gizmo_set_flag(axis_active, WM_GIZMO_HIDDEN, false);
gizmo_refresh_from_matrix(axis_active, axis_idx_active, ggd->twtype, rv3d->twmat, nullptr);
const int twtype = (ggd->twtype & twtype_expected) ? ggd->twtype : twtype_expected;
float idot[3];
gizmo_get_idot(rv3d, idot);
MAN_ITER_AXES_BEGIN (axis, axis_idx) {
const short axis_type = gizmo_get_axis_type(axis_idx);
if (gizmo_is_axis_visible(rv3d, twtype, idot, axis_type, axis_idx)) {
WM_gizmo_set_flag(axis, WM_GIZMO_HIDDEN, false);
gizmo_3d_setup_draw_default(axis, axis_idx);
gizmo_3d_setup_draw_from_twtype(axis, axis_idx, twtype);
}
else {
WM_gizmo_set_flag(axis, WM_GIZMO_HIDDEN, true);
}
}
MAN_ITER_AXES_END;
if (ELEM(axis_idx_active, MAN_AXIS_TRANS_C, MAN_AXIS_SCALE_C, MAN_AXIS_ROT_C, MAN_AXIS_ROT_T)) {
WM_gizmo_set_matrix_rotation_from_z_axis(axis_active, rv3d->viewinv[2]);
}
MAN_ITER_AXES_BEGIN (axis, axis_idx) {
if (axis->flag & WM_GIZMO_HIDDEN) {
continue;
}
gizmo_refresh_from_matrix(axis, axis_idx, ggd->twtype, rv3d->twmat, nullptr);
gizmo_3d_setup_draw_modal(axis_active, axis_idx_active, ggd->twtype);
if (ELEM(axis_idx, MAN_AXIS_TRANS_C, MAN_AXIS_SCALE_C, MAN_AXIS_ROT_C, MAN_AXIS_ROT_T)) {
WM_gizmo_set_matrix_rotation_from_z_axis(axis, rv3d->viewinv[2]);
}
if (axis == axis_active) {
if (axis_active_type == MAN_AXES_ROTATE && axis_idx_active != MAN_AXIS_ROT_T) {
float mat[3][3];
mul_m3_m4m4(mat, axis_active->matrix_basis, axis_active->matrix_offset);
gizmo_3d_dial_matrixbasis_calc(
region, mat[2], axis_active->matrix_basis[3], mval, axis_active->matrix_offset);
copy_m3_m4(mat, axis_active->matrix_basis);
invert_m3(mat);
mul_m4_m3m4(axis_active->matrix_offset, mat, axis_active->matrix_offset);
zero_v3(axis_active->matrix_offset[3]);
if (axis_active_type == MAN_AXES_TRANSLATE) {
/* Arrows are used for visual reference, so keep all visible. */
for (int axis_idx = MAN_AXIS_TRANS_X; axis_idx <= MAN_AXIS_TRANS_Z; axis_idx++) {
if (axis_idx == axis_idx_active) {
continue;
}
gizmo_3d_setup_draw_modal(axis_active, axis_idx);
wmGizmo *axis = ggd->gizmos[axis_idx];
WM_gizmo_set_flag(axis, WM_GIZMO_HIDDEN, false);
gizmo_refresh_from_matrix(axis, axis_idx, ggd->twtype, rv3d->twmat, nullptr);
gizmo_3d_setup_draw_default(axis, axis_idx);
gizmo_3d_setup_draw_from_twtype(axis, axis_idx, ggd->twtype);
RNA_enum_set(axis->ptr, "draw_options", ED_GIZMO_ARROW_DRAW_FLAG_STEM);
}
}
MAN_ITER_AXES_END;
else if (axis_active_type == MAN_AXES_ROTATE && axis_idx_active != MAN_AXIS_ROT_T) {
float mat[3][3];
mul_m3_m4m4(mat, axis_active->matrix_basis, axis_active->matrix_offset);
gizmo_3d_dial_matrixbasis_calc(
region, mat[2], axis_active->matrix_basis[3], mval, axis_active->matrix_offset);
copy_m3_m4(mat, axis_active->matrix_basis);
invert_m3(mat);
mul_m4_m3m4(axis_active->matrix_offset, mat, axis_active->matrix_offset);
zero_v3(axis_active->matrix_offset[3]);
}
}
static void WIDGETGROUP_gizmo_invoke_prepare(const bContext *C,

View File

@ -44,10 +44,13 @@ class UV_ClipboardBuffer {
~UV_ClipboardBuffer();
void append(UvElementMap *element_map, const int cd_loop_uv_offset);
/**
* \return True when found.
*/
bool find_isomorphism(UvElementMap *dest_element_map,
int island_index,
blender::Vector<int> &r_label,
int cd_loop_uv_offset,
blender::Vector<int> &r_label,
bool *r_search_abandoned);
void write_uvs(UvElementMap *element_map,
@ -196,12 +199,15 @@ void UV_ClipboardBuffer::write_uvs(UvElementMap *element_map,
BLI_assert(unique_uv == label.size());
}
/* Call the external isomorphism solver. */
/**
* Call the external isomorphism solver.
* \return True when found.
*/
static bool find_isomorphism(UvElementMap *dest,
const int dest_island_index,
GraphISO *graph_source,
const int cd_loop_uv_offset,
blender::Vector<int> &r_label,
int cd_loop_uv_offset,
bool *r_search_abandoned)
{
@ -215,12 +221,12 @@ static bool find_isomorphism(UvElementMap *dest,
int(*solution)[2] = (int(*)[2])MEM_mallocN(graph_source->n * sizeof(*solution), __func__);
int solution_length = 0;
const bool result = ED_uvedit_clipboard_maximum_common_subgraph(
const bool found = ED_uvedit_clipboard_maximum_common_subgraph(
graph_source, graph_dest, solution, &solution_length, r_search_abandoned);
/* Todo: Implement "Best Effort" / "Nearest Match" paste functionality here. */
if (result) {
if (found) {
BLI_assert(solution_length == dest->island_total_unique_uvs[dest_island_index]);
for (int i = 0; i < solution_length; i++) {
int index_s = solution[i][0];
@ -233,21 +239,21 @@ static bool find_isomorphism(UvElementMap *dest,
MEM_SAFE_FREE(solution);
delete graph_dest;
return result;
return found;
}
bool UV_ClipboardBuffer::find_isomorphism(UvElementMap *dest_element_map,
int dest_island_index,
const int dest_island_index,
const int cd_loop_uv_offset,
blender::Vector<int> &r_label,
int cd_loop_uv_offset,
bool *r_search_abandoned)
{
for (const int64_t source_island_index : graph.index_range()) {
if (::find_isomorphism(dest_element_map,
dest_island_index,
graph[source_island_index],
r_label,
cd_loop_uv_offset,
r_label,
r_search_abandoned)) {
const int island_total_unique_uvs =
dest_element_map->island_total_unique_uvs[dest_island_index];
@ -311,7 +317,7 @@ static int uv_paste_exec(bContext *C, wmOperator *op)
Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
scene, view_layer, ((View3D *)nullptr), &objects_len);
int result = OPERATOR_CANCELLED; /* Assume no changes. */
bool changed_multi = false;
int complicated_search = 0;
int total_search = 0;
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
@ -328,12 +334,14 @@ static int uv_paste_exec(bContext *C, wmOperator *op)
continue;
}
bool changed = false;
for (int i = 0; i < dest_element_map->total_islands; i++) {
total_search++;
blender::Vector<int> label;
bool search_abandoned = false;
const bool found = uv_clipboard->find_isomorphism(
dest_element_map, i, label, cd_loop_uv_offset, &search_abandoned);
dest_element_map, i, cd_loop_uv_offset, label, &search_abandoned);
if (!found) {
if (search_abandoned) {
complicated_search++;
@ -342,12 +350,17 @@ static int uv_paste_exec(bContext *C, wmOperator *op)
}
uv_clipboard->write_uvs(dest_element_map, i, cd_loop_uv_offset, label);
result = OPERATOR_FINISHED; /* UVs were moved. */
changed = true; /* UVs were moved. */
}
BM_uv_element_map_free(dest_element_map);
DEG_id_tag_update(static_cast<ID *>(ob->data), 0);
WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
if (changed) {
changed_multi = true;
DEG_id_tag_update(static_cast<ID *>(ob->data), 0);
WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
}
}
if (complicated_search) {
@ -360,7 +373,7 @@ static int uv_paste_exec(bContext *C, wmOperator *op)
MEM_freeN(objects);
return result;
return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
}
void UV_OT_copy(wmOperatorType *ot)

View File

@ -31,8 +31,10 @@ class GraphISO {
void calculate_degrees() const;
};
/* Find the maximum common subgraph between two graphs.
/**
* Find the maximum common subgraph between two graphs.
* (Can be used to find graph ismorphism.)
* \return True when found.
*/
bool ED_uvedit_clipboard_maximum_common_subgraph(
GraphISO *, GraphISO *, int solution[][2], int *solution_length, bool *r_search_abandoned);

View File

@ -19,8 +19,7 @@ PointCloud *point_merge_by_distance(const PointCloud &src_points,
const bke::AnonymousAttributePropagationInfo &propagation_info)
{
const bke::AttributeAccessor src_attributes = src_points.attributes();
VArraySpan<float3> positions = src_attributes.lookup_or_default<float3>(
"position", ATTR_DOMAIN_POINT, float3(0));
const Span<float3> positions = src_points.positions();
const int src_size = positions.size();
/* Create the KD tree based on only the selected points, to speed up merge detection and

View File

@ -1185,12 +1185,12 @@ void PackIsland::build_transformation(const float scale,
r_matrix[0][1] = -sin_angle * scale * aspect_y;
r_matrix[1][0] = sin_angle * scale / aspect_y;
r_matrix[1][1] = cos_angle * scale;
/*
#if 0
if (reflect) {
r_matrix[0][0] *= -1.0f;
r_matrix[0][1] *= -1.0f;
}
*/
#endif
}
void PackIsland::build_inverse_transformation(const float scale,
@ -1204,12 +1204,12 @@ void PackIsland::build_inverse_transformation(const float scale,
r_matrix[0][1] = sin_angle / scale * aspect_y;
r_matrix[1][0] = -sin_angle / scale / aspect_y;
r_matrix[1][1] = cos_angle / scale;
/*
#if 0
if (reflect) {
r_matrix[0][0] *= -1.0f;
r_matrix[1][0] *= -1.0f;
}
*/
#endif
}
} // namespace blender::geometry

View File

@ -337,7 +337,13 @@ if(WITH_VULKAN_BACKEND)
${MOLTENVK_LIBRARIES}
extern_vulkan_memory_allocator
)
add_definitions(-DWITH_VULKAN_BACKEND)
if(WIN32)
if(EXISTS ${LIBDIR}/imath/bin/imath.dll)
add_definitions(-DIMATH_DLL)
endif()
endif()
endif()
if(WITH_VULKAN_GUARDEDALLOC)

View File

@ -497,7 +497,7 @@ id<MTLBuffer> MTLContext::get_null_buffer()
null_buffer_ = [this->device newBufferWithLength:null_buffer_size
options:MTLResourceStorageModeManaged];
[null_buffer_ retain];
uint32_t *null_data = (uint32_t *)calloc(0, null_buffer_size);
uint32_t *null_data = (uint32_t *)calloc(1, null_buffer_size);
memcpy([null_buffer_ contents], null_data, null_buffer_size);
[null_buffer_ didModifyRange:NSMakeRange(0, null_buffer_size)];
free(null_data);
@ -2191,16 +2191,6 @@ void present(MTLRenderPassDescriptor *blit_descriptor,
id<MTLCommandBuffer> cmdbuf = [ctx->queue commandBuffer];
MTLCommandBufferManager::num_active_cmd_bufs++;
if (MTLCommandBufferManager::sync_event != nil) {
/* Release synchronization primitive for current frame to avoid cross-frame dependencies.
* We require MTLEvents to ensure correct ordering of workload submissions within a frame,
* however, we should not create long chains of dependencies spanning several drawables as any
* temporary stalls can then trigger erroneous GPU timeouts in non-dependent submissions. */
[MTLCommandBufferManager::sync_event release];
MTLCommandBufferManager::sync_event = nil;
MTLCommandBufferManager::event_signal_val = 0;
}
/* Do Present Call and final Blit to MTLDrawable. */
id<MTLRenderCommandEncoder> enc = [cmdbuf renderCommandEncoderWithDescriptor:blit_descriptor];
[enc setRenderPipelineState:blit_pso];

View File

@ -607,6 +607,19 @@ void MTLFence::wait()
return;
}
/* Note(#106431 #106704): `sync_event` is a global cross-context synchronization primitive used
* to ensure GPU workloads execute in the correct order across contexts.
*
* To prevent unexpected GPU stalls, this needs to be reset when used along side explicit
* synchronization. Previously this was handled during frame boundaries, however, to eliminate
* situational flickering (#106704), only reset this during the cases where we are waiting on
* synchronization primitives. */
if (MTLCommandBufferManager::sync_event != nil) {
[MTLCommandBufferManager::sync_event release];
MTLCommandBufferManager::sync_event = nil;
MTLCommandBufferManager::event_signal_val = 0;
}
if (signalled_) {
MTLContext *ctx = MTLContext::get();
BLI_assert(ctx);

View File

@ -247,9 +247,10 @@ void VKFrameBuffer::render_pass_create()
std::array<VkAttachmentDescription, GPU_FB_MAX_ATTACHMENT> attachment_descriptions;
std::array<VkImageView, GPU_FB_MAX_ATTACHMENT> image_views;
std::array<VkAttachmentReference, GPU_FB_MAX_ATTACHMENT> attachment_references;
/*Vector<VkAttachmentReference> color_attachments;
#if 0
Vector<VkAttachmentReference> color_attachments;
VkAttachmentReference depth_attachment = {};
*/
#endif
bool has_depth_attachment = false;
bool found_attachment = false;
int depth_location = -1;

View File

@ -225,8 +225,6 @@ typedef struct ImBuf {
char name[IMB_FILENAME_SIZE];
/* memory cache limiter */
/** handle for cache limiter */
struct MEM_CacheLimiterHandle_s *c_handle;
/** reference counter for multiple users */
int refcounter;

View File

@ -585,7 +585,6 @@ ImBuf *IMB_dupImBuf(const ImBuf *ibuf1)
/* set malloc flag */
tbuf.mall = ibuf2->mall;
tbuf.c_handle = NULL;
tbuf.refcounter = 0;
/* for now don't duplicate metadata */
@ -631,31 +630,3 @@ size_t IMB_get_size_in_memory(ImBuf *ibuf)
return size;
}
#if 0 /* remove? - campbell */
/* support for cache limiting */
static void imbuf_cache_destructor(void *data)
{
ImBuf *ibuf = (ImBuf *)data;
imb_freerectImBuf(ibuf);
imb_freerectfloatImBuf(ibuf);
IMB_freezbufImBuf(ibuf);
IMB_freezbuffloatImBuf(ibuf);
freeencodedbufferImBuf(ibuf);
ibuf->c_handle = NULL;
}
static MEM_CacheLimiterC **get_imbuf_cache_limiter(void)
{
static MEM_CacheLimiterC *c = NULL;
if (!c) {
c = new_MEM_CacheLimiter(imbuf_cache_destructor, NULL);
}
return &c;
}
#endif

View File

@ -25,6 +25,9 @@
#include "DNA_meshdata_types.h"
#include "DNA_modifier_types.h"
#include "DNA_object_types.h"
#include "DNA_windowmanager_types.h"
#include "WM_api.h"
#include "MEM_guardedalloc.h"
@ -408,102 +411,191 @@ void USDMeshReader::read_uvs(Mesh *mesh, const double motionSampleTime, const bo
}
}
void USDMeshReader::read_colors(Mesh *mesh, const double motionSampleTime)
void USDMeshReader::read_color_data_all_primvars(Mesh *mesh, const double motionSampleTime)
{
if (!(mesh && mesh_prim_ && mesh->totloop > 0)) {
return;
}
/* Early out if we read the display color before and if this attribute isn't animated. */
if (primvar_varying_map_.find(usdtokens::displayColor) != primvar_varying_map_.end() &&
!primvar_varying_map_.at(usdtokens::displayColor)) {
pxr::UsdGeomPrimvarsAPI pv_api = pxr::UsdGeomPrimvarsAPI(mesh_prim_);
std::vector<pxr::UsdGeomPrimvar> primvars = pv_api.GetPrimvarsWithValues();
pxr::TfToken active_color_name;
/* Convert color primvars to custom layer data. */
for (pxr::UsdGeomPrimvar &pv : primvars) {
if (!pv.HasValue()) {
continue;
}
pxr::SdfValueTypeName type = pv.GetTypeName();
if (!ELEM(type,
pxr::SdfValueTypeNames->Color3hArray,
pxr::SdfValueTypeNames->Color3fArray,
pxr::SdfValueTypeNames->Color3dArray)) {
continue;
}
pxr::TfToken name = pv.GetPrimvarName();
/* Set the active color name to 'displayColor', if a color primvar
* with this name exists. Otherwise, use the name of the first
* color primvar we find for the active color. */
if (active_color_name.IsEmpty() || name == usdtokens::displayColor) {
active_color_name = name;
}
/* Skip if we read this primvar before and it isn't animated. */
const std::map<const pxr::TfToken, bool>::const_iterator is_animated_iter =
primvar_varying_map_.find(name);
if (is_animated_iter != primvar_varying_map_.end() && !is_animated_iter->second) {
continue;
}
read_color_data_primvar(mesh, pv, motionSampleTime);
}
if (!active_color_name.IsEmpty()) {
BKE_id_attributes_default_color_set(&mesh->id, active_color_name.GetText());
BKE_id_attributes_active_color_set(&mesh->id, active_color_name.GetText());
}
}
void USDMeshReader::read_color_data_primvar(Mesh *mesh,
const pxr::UsdGeomPrimvar &color_primvar,
const double motionSampleTime)
{
if (!(mesh && color_primvar && color_primvar.HasValue())) {
return;
}
pxr::UsdGeomPrimvar color_primvar = mesh_prim_.GetDisplayColorPrimvar();
if (!color_primvar.HasValue()) {
return;
}
pxr::TfToken interp = color_primvar.GetInterpolation();
if (interp == pxr::UsdGeomTokens->varying) {
std::cerr << "WARNING: Unsupported varying interpolation for display colors\n" << std::endl;
return;
}
if (primvar_varying_map_.find(usdtokens::displayColor) == primvar_varying_map_.end()) {
if (primvar_varying_map_.find(color_primvar.GetPrimvarName()) == primvar_varying_map_.end()) {
bool might_be_time_varying = color_primvar.ValueMightBeTimeVarying();
primvar_varying_map_.insert(std::make_pair(usdtokens::displayColor, might_be_time_varying));
primvar_varying_map_.insert(
std::make_pair(color_primvar.GetPrimvarName(), might_be_time_varying));
if (might_be_time_varying) {
is_time_varying_ = true;
}
}
pxr::VtArray<pxr::GfVec3f> display_colors;
pxr::VtArray<pxr::GfVec3f> usd_colors;
if (!color_primvar.ComputeFlattened(&display_colors, motionSampleTime)) {
std::cerr << "WARNING: Couldn't compute display colors\n" << std::endl;
if (!color_primvar.ComputeFlattened(&usd_colors, motionSampleTime)) {
WM_reportf(RPT_WARNING,
"USD Import: couldn't compute values for color attribute '%s'",
color_primvar.GetName().GetText());
return;
}
if ((interp == pxr::UsdGeomTokens->faceVarying && display_colors.size() != mesh->totloop) ||
(interp == pxr::UsdGeomTokens->vertex && display_colors.size() != mesh->totvert) ||
(interp == pxr::UsdGeomTokens->constant && display_colors.size() != 1) ||
(interp == pxr::UsdGeomTokens->uniform && display_colors.size() != mesh->totpoly)) {
std::cerr << "WARNING: display colors count mismatch\n" << std::endl;
pxr::TfToken interp = color_primvar.GetInterpolation();
if ((interp == pxr::UsdGeomTokens->faceVarying && usd_colors.size() != mesh->totloop) ||
(interp == pxr::UsdGeomTokens->varying && usd_colors.size() != mesh->totloop) ||
(interp == pxr::UsdGeomTokens->vertex && usd_colors.size() != mesh->totvert) ||
(interp == pxr::UsdGeomTokens->constant && usd_colors.size() != 1) ||
(interp == pxr::UsdGeomTokens->uniform && usd_colors.size() != mesh->totpoly)) {
WM_reportf(RPT_WARNING,
"USD Import: color attribute value '%s' count inconsistent with interpolation type",
color_primvar.GetName().GetText());
return;
}
void *cd_ptr = add_customdata_cb(mesh, "displayColor", CD_PROP_BYTE_COLOR);
const StringRef color_primvar_name(color_primvar.GetBaseName().GetString());
bke::MutableAttributeAccessor attributes = mesh->attributes_for_write();
if (!cd_ptr) {
std::cerr << "WARNING: Couldn't add displayColor custom data.\n";
eAttrDomain color_domain = ATTR_DOMAIN_POINT;
if (ELEM(interp,
pxr::UsdGeomTokens->varying,
pxr::UsdGeomTokens->faceVarying,
pxr::UsdGeomTokens->uniform)) {
color_domain = ATTR_DOMAIN_CORNER;
}
bke::SpanAttributeWriter<ColorGeometry4f> color_data;
color_data = attributes.lookup_or_add_for_write_only_span<ColorGeometry4f>(color_primvar_name,
color_domain);
if (!color_data) {
WM_reportf(RPT_WARNING,
"USD Import: couldn't add color attribute '%s'",
color_primvar.GetBaseName().GetText());
return;
}
MLoopCol *colors = static_cast<MLoopCol *>(cd_ptr);
const OffsetIndices polys = mesh->polys();
const Span<int> corner_verts = mesh->corner_verts();
for (const int i : polys.index_range()) {
const IndexRange poly = polys[i];
for (int j = 0; j < poly.size(); ++j) {
int loop_index = poly[j];
/* Default for constant varying interpolation. */
int usd_index = 0;
if (interp == pxr::UsdGeomTokens->vertex) {
usd_index = corner_verts[loop_index];
if (ELEM(interp, pxr::UsdGeomTokens->constant, pxr::UsdGeomTokens->uniform)) {
/* For situations where there's only a single item, flood fill the object. */
color_data.span.fill(
ColorGeometry4f(usd_colors[0][0], usd_colors[0][1], usd_colors[0][2], 1.0f));
}
else {
/* Check for situations that allow for a straight-forward copy by index. */
if ((ELEM(interp, pxr::UsdGeomTokens->vertex)) ||
(color_domain == ATTR_DOMAIN_CORNER && !is_left_handed_)) {
for (int i = 0; i < usd_colors.size(); i++) {
ColorGeometry4f color = ColorGeometry4f(
usd_colors[i][0], usd_colors[i][1], usd_colors[i][2], 1.0f);
color_data.span[i] = color;
}
else if (interp == pxr::UsdGeomTokens->faceVarying) {
usd_index = poly.start();
if (is_left_handed_) {
usd_index += poly.size() - 1 - j;
}
else {
usd_index += j;
}
/* Special case: expand uniform color into corner color.
* Uniforms in USD come through as single colors, face-varying. Since Blender does not
* support this particular combination for paintable color attributes, we convert the type
* here to make sure that the user gets the same visual result.
* */
else if (ELEM(interp, pxr::UsdGeomTokens->uniform)) {
for (int i = 0; i < usd_colors.size(); i++) {
const ColorGeometry4f color = ColorGeometry4f(
usd_colors[i][0], usd_colors[i][1], usd_colors[i][2], 1.0f);
color_data.span[i * 4] = color;
color_data.span[i * 4 + 1] = color;
color_data.span[i * 4 + 2] = color;
color_data.span[i * 4 + 3] = color;
}
}
else {
const OffsetIndices polys = mesh->polys();
const Span<int> corner_verts = mesh->corner_verts();
for (const int i : polys.index_range()) {
const IndexRange &poly = polys[i];
for (int j = 0; j < poly.size(); ++j) {
int loop_index = poly[j];
/* Default for constant varying interpolation. */
int usd_index = 0;
if (interp == pxr::UsdGeomTokens->vertex) {
usd_index = corner_verts[loop_index];
}
else if (interp == pxr::UsdGeomTokens->faceVarying) {
usd_index = poly.start();
if (is_left_handed_) {
usd_index += poly.size() - 1 - j;
}
else {
usd_index += j;
}
}
else if (interp == pxr::UsdGeomTokens->uniform) {
/* Uniform varying uses the poly index. */
usd_index = i;
}
if (usd_index >= usd_colors.size()) {
continue;
}
ColorGeometry4f color = ColorGeometry4f(
usd_colors[usd_index][0], usd_colors[usd_index][1], usd_colors[usd_index][2], 1.0f);
color_data.span[usd_index] = color;
}
}
else if (interp == pxr::UsdGeomTokens->uniform) {
/* Uniform varying uses the poly index. */
usd_index = i;
}
if (usd_index >= display_colors.size()) {
continue;
}
colors[loop_index].r = unit_float_to_uchar_clamp(display_colors[usd_index][0]);
colors[loop_index].g = unit_float_to_uchar_clamp(display_colors[usd_index][1]);
colors[loop_index].b = unit_float_to_uchar_clamp(display_colors[usd_index][2]);
colors[loop_index].a = unit_float_to_uchar_clamp(1.0);
}
}
BKE_id_attributes_active_color_set(&mesh->id, "displayColor");
color_data.finish();
}
void USDMeshReader::read_vertex_creases(Mesh *mesh, const double motionSampleTime)
@ -672,9 +764,19 @@ void USDMeshReader::read_mesh_sample(ImportSettings *settings,
read_uvs(mesh, motionSampleTime, new_mesh);
}
/* Custom Data layers. */
read_custom_data(settings, mesh, motionSampleTime);
}
void USDMeshReader::read_custom_data(const ImportSettings *settings,
Mesh *mesh,
const double motionSampleTime)
{
if ((settings->read_flag & MOD_MESHSEQ_READ_COLOR) != 0) {
read_colors(mesh, motionSampleTime);
read_color_data_all_primvars(mesh, motionSampleTime);
}
/* TODO: Generic readers for custom data layers not listed above. */
}
void USDMeshReader::assign_facesets_to_material_indices(double motionSampleTime,

View File

@ -66,13 +66,20 @@ class USDMeshReader : public USDGeomReader {
void read_mpolys(Mesh *mesh);
void read_uvs(Mesh *mesh, double motionSampleTime, bool load_uvs = false);
void read_colors(Mesh *mesh, double motionSampleTime);
void read_vertex_creases(Mesh *mesh, double motionSampleTime);
void read_mesh_sample(ImportSettings *settings,
Mesh *mesh,
double motionSampleTime,
bool new_mesh);
void read_custom_data(const ImportSettings *settings,
Mesh *mesh,
double motionSampleTime);
void read_color_data_all_primvars(Mesh *mesh, const double motionSampleTime);
void read_color_data_primvar(Mesh *mesh, const pxr::UsdGeomPrimvar &color_primvar,
const double motionSampleTime);
};
} // namespace blender::io::usd

View File

@ -14,7 +14,6 @@
#include "BLI_math_vector_types.hh"
#include "BKE_attribute.h"
#include "BKE_attribute.hh"
#include "BKE_customdata.h"
#include "BKE_lib_id.h"
#include "BKE_material.h"
@ -32,6 +31,8 @@
#include "DNA_object_fluidsim_types.h"
#include "DNA_particle_types.h"
#include "WM_api.h"
#include <iostream>
namespace blender::io::usd {
@ -73,6 +74,72 @@ void USDGenericMeshWriter::do_write(HierarchyContext &context)
}
}
void USDGenericMeshWriter::write_custom_data(const Mesh *mesh, pxr::UsdGeomMesh usd_mesh)
{
const bke::AttributeAccessor attributes = mesh->attributes();
attributes.for_all(
[&](const bke::AttributeIDRef &attribute_id, const bke::AttributeMetaData &meta_data) {
/* Color data. */
if (ELEM(meta_data.domain, ATTR_DOMAIN_CORNER, ATTR_DOMAIN_POINT) &&
ELEM(meta_data.data_type, CD_PROP_BYTE_COLOR, CD_PROP_COLOR)) {
write_color_data(mesh, usd_mesh, attribute_id, meta_data);
}
return true;
});
}
void USDGenericMeshWriter::write_color_data(const Mesh *mesh,
pxr::UsdGeomMesh usd_mesh,
const bke::AttributeIDRef &attribute_id,
const bke::AttributeMetaData &meta_data)
{
pxr::UsdTimeCode timecode = get_export_time_code();
const std::string name = attribute_id.name();
pxr::TfToken primvar_name(pxr::TfMakeValidIdentifier(name));
const pxr::UsdGeomPrimvarsAPI pvApi = pxr::UsdGeomPrimvarsAPI(usd_mesh);
/* Varying type depends on original domain. */
const pxr::TfToken prim_varying = meta_data.domain == ATTR_DOMAIN_CORNER ?
pxr::UsdGeomTokens->faceVarying :
pxr::UsdGeomTokens->vertex;
pxr::UsdGeomPrimvar colors_pv = pvApi.CreatePrimvar(
primvar_name, pxr::SdfValueTypeNames->Color3fArray, prim_varying);
const VArray<ColorGeometry4f> attribute = mesh->attributes().lookup_or_default<ColorGeometry4f>(
attribute_id, meta_data.domain, {0.0f, 0.0f, 0.0f, 1.0f});
pxr::VtArray<pxr::GfVec3f> colors_data;
/* TODO: Thread the copy, like the obj exporter. */
switch (meta_data.domain) {
case ATTR_DOMAIN_CORNER:
for (size_t loop_idx = 0; loop_idx < mesh->totloop; loop_idx++) {
const ColorGeometry4f color = attribute.get(loop_idx);
colors_data.push_back(pxr::GfVec3f(color.r, color.g, color.b));
}
break;
case ATTR_DOMAIN_POINT:
for (const int point_index : attribute.index_range()) {
const ColorGeometry4f color = attribute.get(point_index);
colors_data.push_back(pxr::GfVec3f(color.r, color.g, color.b));
}
break;
default:
BLI_assert_msg(0, "Invalid domain for mesh color data.");
return;
}
colors_pv.Set(colors_data, timecode);
const pxr::UsdAttribute &prim_colors_attr = colors_pv.GetAttr();
usd_value_writer_.SetAttribute(prim_colors_attr, pxr::VtValue(colors_data), timecode);
}
void USDGenericMeshWriter::free_export_mesh(Mesh *mesh)
{
BKE_id_free(nullptr, mesh);
@ -233,6 +300,9 @@ void USDGenericMeshWriter::write_mesh(HierarchyContext &context, Mesh *mesh)
if (usd_export_context_.export_params.export_uvmaps) {
write_uv_maps(mesh, usd_mesh);
}
write_custom_data(mesh, usd_mesh);
if (usd_export_context_.export_params.export_normals) {
write_normals(mesh, usd_mesh);
}

View File

@ -4,6 +4,8 @@
#include "usd_writer_abstract.h"
#include "BKE_attribute.hh"
#include <pxr/usd/usdGeom/mesh.h>
namespace blender::io::usd {
@ -34,6 +36,12 @@ class USDGenericMeshWriter : public USDAbstractWriter {
void write_uv_maps(const Mesh *mesh, pxr::UsdGeomMesh usd_mesh);
void write_normals(const Mesh *mesh, pxr::UsdGeomMesh usd_mesh);
void write_surface_velocity(const Mesh *mesh, pxr::UsdGeomMesh usd_mesh);
void write_custom_data(const Mesh *mesh, pxr::UsdGeomMesh usd_mesh);
void write_color_data(const Mesh *mesh,
pxr::UsdGeomMesh usd_mesh,
const bke::AttributeIDRef &attribute_id,
const bke::AttributeMetaData &meta_data);
};
class USDMeshWriter : public USDGenericMeshWriter {

View File

@ -808,8 +808,10 @@ typedef enum eNlaStrip_Flag {
// NLASTRIP_FLAG_SELECT_L = (1 << 2), /* left handle selected. */
// NLASTRIP_FLAG_SELECT_R = (1 << 3), /* right handle selected. */
/** NLA strip uses the same action that the action being tweaked uses
* (not set for the tweaking one though). */
/**
* NLA strip uses the same action that the action being tweaked uses
* (not set for the tweaking one though).
*/
NLASTRIP_FLAG_TWEAKUSER = (1 << 4),
/* controls driven by local F-Curves */
@ -833,9 +835,11 @@ typedef enum eNlaStrip_Flag {
/* temporary editing flags */
/** When transforming strips, this flag is set when the strip is placed in an invalid location
/**
* When transforming strips, this flag is set when the strip is placed in an invalid location
* such as overlapping another strip or moved to a locked track. In such cases, the strip's
* location must be corrected after the transform operator is done. */
* location must be corrected after the transform operator is done.
*/
NLASTRIP_FLAG_INVALID_LOCATION = (1 << 28),
/** NLA strip should ignore frame range and hold settings, and evaluate at global time. */
NLASTRIP_FLAG_NO_TIME_MAP = (1 << 29),
@ -1031,9 +1035,11 @@ typedef enum eInsertKeyFlags {
INSERTKEY_XYZ2RGB = (1 << 5),
/** ignore user-prefs (needed for predictable API use) */
INSERTKEY_NO_USERPREF = (1 << 6),
/** Allow to make a full copy of new key into existing one, if any,
/**
* Allow to make a full copy of new key into existing one, if any,
* instead of 'reusing' existing handles.
* Used by copy/paste code. */
* Used by copy/paste code.
*/
INSERTKEY_OVERWRITE_FULL = (1 << 7),
/** for driver FCurves, use driver's "input" value - for easier corrective driver setup */
INSERTKEY_DRIVER = (1 << 8),
@ -1089,11 +1095,13 @@ typedef struct AnimOverride {
typedef struct AnimData {
/**
* Active action - acts as the 'tweaking track' for the NLA.
* Either use BKE_animdata_set_action() to set this, or call BKE_animdata_action_ensure_idroot()
* after setting. */
* Either use BKE_animdata_set_action() to set this, or call
* #BKE_animdata_action_ensure_idroot() after setting.
*/
bAction *action;
/** temp-storage for the 'real' active action (i.e. the one used before the tweaking-action
/**
* Temp-storage for the 'real' active action (i.e. the one used before the tweaking-action
* took over to be edited in the Animation Editors)
*/
bAction *tmpact;

View File

@ -11,6 +11,7 @@
#ifdef __cplusplus
# include "BLI_math_vector_types.hh"
# include "BLI_span.hh"
#endif
#ifdef __cplusplus
@ -51,6 +52,9 @@ typedef struct PointCloud {
short _pad3[3];
#ifdef __cplusplus
blender::Span<blender::float3> positions() const;
blender::MutableSpan<blender::float3> positions_for_write();
blender::bke::AttributeAccessor attributes() const;
blender::bke::MutableAttributeAccessor attributes_for_write();

View File

@ -696,7 +696,7 @@ ModifierTypeInfo modifierType_Ocean = {
/*icon*/ ICON_MOD_OCEAN,
/*copyData*/ copyData,
/*deformMatrices*/ nullptr,
/*deformVerts*/ nullptr,
/*deformMatrices*/ nullptr,
/*deformVertsEM*/ nullptr,

View File

@ -243,14 +243,11 @@ static void node_geo_exec(GeoNodeExecParams params)
PointCloud *pointcloud = BKE_pointcloud_new_nomain(positions.size());
bke::MutableAttributeAccessor point_attributes = pointcloud->attributes_for_write();
bke::SpanAttributeWriter<float3> point_positions =
point_attributes.lookup_or_add_for_write_only_span<float3>("position", ATTR_DOMAIN_POINT);
pointcloud->positions_for_write().copy_from(positions);
bke::SpanAttributeWriter<float> point_radii =
point_attributes.lookup_or_add_for_write_only_span<float>("radius", ATTR_DOMAIN_POINT);
point_positions.span.copy_from(positions);
point_radii.span.fill(0.05f);
point_positions.finish();
point_radii.finish();
geometry_set.replace_pointcloud(pointcloud);

View File

@ -539,13 +539,10 @@ static void point_distribution_calculate(GeometrySet &geometry_set,
PointCloud *pointcloud = BKE_pointcloud_new_nomain(positions.size());
bke::MutableAttributeAccessor point_attributes = pointcloud->attributes_for_write();
bke::SpanAttributeWriter<float3> point_positions =
point_attributes.lookup_or_add_for_write_only_span<float3>("position", ATTR_DOMAIN_POINT);
bke::SpanAttributeWriter<float> point_radii =
point_attributes.lookup_or_add_for_write_only_span<float>("radius", ATTR_DOMAIN_POINT);
point_positions.span.copy_from(positions);
pointcloud->positions_for_write().copy_from(positions);
point_radii.span.fill(0.05f);
point_positions.finish();
point_radii.finish();
geometry_set.replace_pointcloud(pointcloud);

View File

@ -119,7 +119,7 @@ static void expand_mesh(Mesh &mesh,
}
}
static CustomData &get_customdata(Mesh &mesh, const eAttrDomain domain)
static CustomData &mesh_custom_data_for_domain(Mesh &mesh, const eAttrDomain domain)
{
switch (domain) {
case ATTR_DOMAIN_POINT:
@ -142,7 +142,7 @@ static CustomData &get_customdata(Mesh &mesh, const eAttrDomain domain)
static MutableSpan<int> get_orig_index_layer(Mesh &mesh, const eAttrDomain domain)
{
const bke::AttributeAccessor attributes = mesh.attributes();
CustomData &custom_data = get_customdata(mesh, domain);
CustomData &custom_data = mesh_custom_data_for_domain(mesh, domain);
if (int *orig_indices = static_cast<int *>(CustomData_get_layer_for_write(
&custom_data, CD_ORIGINDEX, attributes.domain_size(domain)))) {
return {orig_indices, attributes.domain_size(domain)};

View File

@ -1,5 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#include "BLI_array_utils.hh"
#include "DNA_pointcloud_types.h"
#include "BKE_attribute_math.hh"
@ -26,7 +28,7 @@ static void node_declare(NodeDeclarationBuilder &b)
static void convert_instances_to_points(GeometrySet &geometry_set,
Field<float3> position_field,
Field<float> radius_field,
const Field<bool> selection_field,
Field<bool> selection_field,
const AnonymousAttributePropagationInfo &propagation_info)
{
const bke::Instances &instances = *geometry_set.get_instances_for_read();
@ -41,22 +43,17 @@ static void convert_instances_to_points(GeometrySet &geometry_set,
if (selection.is_empty()) {
return;
}
const VArray<float3> &positions = evaluator.get_evaluated<float3>(0);
const VArray<float3> positions = evaluator.get_evaluated<float3>(0);
const VArray<float> radii = evaluator.get_evaluated<float>(1);
PointCloud *pointcloud = BKE_pointcloud_new_nomain(selection.size());
geometry_set.replace_pointcloud(pointcloud);
array_utils::gather(positions, selection, pointcloud->positions_for_write());
bke::MutableAttributeAccessor point_attributes = pointcloud->attributes_for_write();
bke::SpanAttributeWriter<float3> point_positions =
point_attributes.lookup_or_add_for_write_only_span<float3>("position", ATTR_DOMAIN_POINT);
bke::SpanAttributeWriter<float> point_radii =
point_attributes.lookup_or_add_for_write_only_span<float>("radius", ATTR_DOMAIN_POINT);
positions.materialize_compressed_to_uninitialized(selection, point_positions.span);
radii.materialize_compressed_to_uninitialized(selection, point_radii.span);
point_positions.finish();
array_utils::gather(radii, selection, point_radii.span);
point_radii.finish();
Map<AttributeIDRef, AttributeKind> attributes_to_propagate;

View File

@ -71,18 +71,15 @@ static void node_geo_exec(GeoNodeExecParams params)
PointCloud *points = BKE_pointcloud_new_nomain(count);
MutableAttributeAccessor attributes = points->attributes_for_write();
AttributeWriter<float3> output_position = attributes.lookup_or_add_for_write<float3>(
"position", ATTR_DOMAIN_POINT);
AttributeWriter<float> output_radii = attributes.lookup_or_add_for_write<float>(
"radius", ATTR_DOMAIN_POINT);
PointsFieldContext context{count};
fn::FieldEvaluator evaluator{context, count};
evaluator.add_with_destination(position_field, output_position.varray);
evaluator.add_with_destination(position_field, points->positions_for_write());
evaluator.add_with_destination(radius_field, output_radii.varray);
evaluator.evaluate();
output_position.finish();
output_radii.finish();
params.set_output("Geometry", GeometrySet::create_with_pointcloud(points));
}

View File

@ -3332,14 +3332,14 @@ static PySequenceMethods bpy_bmelemseq_as_sequence = {
};
static PyMappingMethods bpy_bmelemseq_as_mapping = {
/*mp_len*/ (lenfunc)bpy_bmelemseq_length,
/*mp_length*/ (lenfunc)bpy_bmelemseq_length,
/*mp_subscript*/ (binaryfunc)bpy_bmelemseq_subscript,
/*mp_ass_subscript*/ (objobjargproc)NULL,
};
/* for customdata access */
static PyMappingMethods bpy_bm_elem_as_mapping = {
/*mp_len*/ (lenfunc)NULL, /* Keep this empty, messes up `if elem: ...` test. */
/*mp_length*/ (lenfunc)NULL, /* Keep this empty, messes up `if elem: ...` test. */
/*mp_subscript*/ (binaryfunc)bpy_bmelem_subscript,
/*mp_ass_subscript*/ (objobjargproc)bpy_bmelem_ass_subscript,
};

View File

@ -899,7 +899,7 @@ static PySequenceMethods bpy_bmlayercollection_as_sequence = {
};
static PyMappingMethods bpy_bmlayercollection_as_mapping = {
/*mp_len*/ (lenfunc)bpy_bmlayercollection_length,
/*mp_length*/ (lenfunc)bpy_bmlayercollection_length,
/*mp_subscript*/ (binaryfunc)bpy_bmlayercollection_subscript,
/*mp_ass_subscript*/ (objobjargproc)NULL,
};

View File

@ -213,7 +213,7 @@ PyObject *BPy_BMLoopUV_CreatePyObject(struct BMesh *bm, BMLoop *loop, int layer)
{
BPy_BMLoopUV *self = PyObject_New(BPy_BMLoopUV, &BPy_BMLoopUV_Type);
const BMUVOffsets offsets = BM_uv_map_get_offsets_n(bm, layer);
const BMUVOffsets offsets = BM_uv_map_get_offsets_from_layer(bm, layer);
self->uv = BM_ELEM_CD_GET_FLOAT_P(loop, offsets.uv);
self->vert_select = offsets.select_vert >= 0 ? BM_ELEM_CD_GET_BOOL_P(loop, offsets.select_vert) :
@ -588,7 +588,7 @@ static PySequenceMethods bpy_bmdeformvert_as_sequence = {
};
static PyMappingMethods bpy_bmdeformvert_as_mapping = {
/*mp_len*/ (lenfunc)bpy_bmdeformvert_len,
/*mp_length*/ (lenfunc)bpy_bmdeformvert_len,
/*mp_subscript*/ (binaryfunc)bpy_bmdeformvert_subscript,
/*mp_ass_subscript*/ (objobjargproc)bpy_bmdeformvert_ass_subscript,
};

View File

@ -305,7 +305,7 @@ static PySequenceMethods bpy_bmeditselseq_as_sequence = {
};
static PyMappingMethods bpy_bmeditselseq_as_mapping = {
/*mp_len*/ (lenfunc)bpy_bmeditselseq_length,
/*mp_length*/ (lenfunc)bpy_bmeditselseq_length,
/*mp_subscript*/ (binaryfunc)bpy_bmeditselseq_subscript,
/*mp_ass_subscript*/ (objobjargproc)NULL,
};

View File

@ -557,7 +557,7 @@ static PySequenceMethods Buffer_SeqMethods = {
};
static PyMappingMethods Buffer_AsMapping = {
/*mp_len*/ (lenfunc)Buffer_len,
/*mp_length*/ (lenfunc)Buffer_len,
/*mp_subscript*/ (binaryfunc)Buffer_subscript,
/*mp_ass_subscript*/ (objobjargproc)Buffer_ass_subscript,
};

View File

@ -1620,7 +1620,7 @@ static PySequenceMethods BPy_IDGroup_Seq = {
};
static PyMappingMethods BPy_IDGroup_Mapping = {
/*mp_len*/ (lenfunc)BPy_IDGroup_Map_Len,
/*mp_length*/ (lenfunc)BPy_IDGroup_Map_Len,
/*mp_subscript*/ (binaryfunc)BPy_IDGroup_Map_GetItem,
/*mp_ass_subscript*/ (objobjargproc)BPy_IDGroup_Map_SetItem,
};
@ -1994,7 +1994,7 @@ static int BPy_IDArray_ass_subscript(BPy_IDArray *self, PyObject *item, PyObject
}
static PyMappingMethods BPy_IDArray_AsMapping = {
/*mp_len*/ (lenfunc)BPy_IDArray_Len,
/*mp_length*/ (lenfunc)BPy_IDArray_Len,
/*mp_subscript*/ (binaryfunc)BPy_IDArray_subscript,
/*mp_ass_subscript*/ (objobjargproc)BPy_IDArray_ass_subscript,
};

View File

@ -592,7 +592,7 @@ static PySequenceMethods pygpu_buffer__tp_as_sequence = {
};
static PyMappingMethods pygpu_buffer__tp_as_mapping = {
/*mp_len*/ (lenfunc)pygpu_buffer__sq_length,
/*mp_length*/ (lenfunc)pygpu_buffer__sq_length,
/*mp_subscript*/ (binaryfunc)pygpu_buffer__mp_subscript,
/*mp_ass_subscript*/ (objobjargproc)pygpu_buffer__mp_ass_subscript,
};

View File

@ -3252,13 +3252,13 @@ static int pyrna_prop_array_ass_subscript(BPy_PropertyArrayRNA *self,
/* For slice only. */
static PyMappingMethods pyrna_prop_array_as_mapping = {
/*mp_len*/ (lenfunc)pyrna_prop_array_length,
/*mp_length*/ (lenfunc)pyrna_prop_array_length,
/*mp_subscript*/ (binaryfunc)pyrna_prop_array_subscript,
/*mp_ass_subscript*/ (objobjargproc)pyrna_prop_array_ass_subscript,
};
static PyMappingMethods pyrna_prop_collection_as_mapping = {
/*mp_len*/ (lenfunc)pyrna_prop_collection_length,
/*mp_length*/ (lenfunc)pyrna_prop_collection_length,
/*mp_subscript*/ (binaryfunc)pyrna_prop_collection_subscript,
/*mp_ass_subscript*/ (objobjargproc)pyrna_prop_collection_ass_subscript,
};

View File

@ -838,7 +838,7 @@ static PySequenceMethods Color_SeqMethods = {
};
static PyMappingMethods Color_AsMapping = {
/*mp_len*/ (lenfunc)Color_len,
/*mp_length*/ (lenfunc)Color_len,
/*mp_subscript*/ (binaryfunc)Color_subscript,
/*mp_ass_subscript*/ (objobjargproc)Color_ass_subscript,
};

View File

@ -649,7 +649,7 @@ static PySequenceMethods Euler_SeqMethods = {
};
static PyMappingMethods Euler_AsMapping = {
/*mp_len*/ (lenfunc)Euler_len,
/*mp_length*/ (lenfunc)Euler_len,
/*mp_subscript*/ (binaryfunc)Euler_subscript,
/*mp_ass_subscript*/ (objobjargproc)Euler_ass_subscript,
};

View File

@ -2977,7 +2977,7 @@ static PySequenceMethods Matrix_SeqMethods = {
};
static PyMappingMethods Matrix_AsMapping = {
/*mp_len*/ (lenfunc)Matrix_len,
/*mp_length*/ (lenfunc)Matrix_len,
/*mp_subscript*/ (binaryfunc)Matrix_subscript,
/*mp_ass_subscript*/ (objobjargproc)Matrix_ass_subscript,
};
@ -3760,7 +3760,7 @@ static PyObject *MatrixAccess_iter(MatrixAccessObject *self)
}
static PyMappingMethods MatrixAccess_AsMapping = {
/*mp_len*/ (lenfunc)MatrixAccess_len,
/*mp_length*/ (lenfunc)MatrixAccess_len,
/*mp_subscript*/ (binaryfunc)MatrixAccess_subscript,
/*mp_ass_subscript*/ (objobjargproc)MatrixAccess_ass_subscript,
};

View File

@ -1355,7 +1355,7 @@ static PySequenceMethods Quaternion_SeqMethods = {
};
static PyMappingMethods Quaternion_AsMapping = {
/*mp_len*/ (lenfunc)Quaternion_len,
/*mp_length*/ (lenfunc)Quaternion_len,
/*mp_subscript*/ (binaryfunc)Quaternion_subscript,
/*mp_ass_subscript*/ (objobjargproc)Quaternion_ass_subscript,
};

View File

@ -2400,7 +2400,7 @@ static PySequenceMethods Vector_SeqMethods = {
};
static PyMappingMethods Vector_AsMapping = {
/*mp_len*/ (lenfunc)Vector_len,
/*mp_length*/ (lenfunc)Vector_len,
/*mp_subscript*/ (binaryfunc)Vector_subscript,
/*mp_ass_subscript*/ (objobjargproc)Vector_ass_subscript,
};

View File

@ -1286,7 +1286,7 @@ PyTypeObject PyBVHTree_Type = {
/*tp_init*/ nullptr,
/*tp_alloc*/ (allocfunc)PyType_GenericAlloc,
/*tp_new*/ (newfunc)PyType_GenericNew,
/*tp_free*/ (freefunc)0,
/*tp_free*/ (freefunc) nullptr,
/*tp_is_gc*/ nullptr,
/*tp_bases*/ nullptr,
/*tp_mro*/ nullptr,

View File

@ -1572,6 +1572,27 @@ char *WM_clipboard_text_get(bool selection, int *r_len);
char *WM_clipboard_text_get_firstline(bool selection, int *r_len);
void WM_clipboard_text_set(const char *buf, bool selection);
/**
* Returns true if the clipboard contains an image.
*/
bool WM_clipboard_image_available(void);
/**
* Get image data from the Clipboard
* \param r_width: the returned image width in pixels.
* \param r_height: the returned image height in pixels.
* \return pointer uint array in RGBA byte order. Caller must free.
*/
struct ImBuf *WM_clipboard_image_get(void);
/**
* Put image data to the Clipboard
* \param rgba: uint array in RGBA byte order.
* \param width: the image width in pixels.
* \param height: the image height in pixels.
*/
bool WM_clipboard_image_set(struct ImBuf *ibuf);
/* progress */
void WM_progress_set(struct wmWindow *win, float progress);

View File

@ -60,6 +60,9 @@
#include "ED_scene.h"
#include "ED_screen.h"
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
#include "UI_interface.h"
#include "UI_interface_icons.h"
@ -2062,6 +2065,45 @@ void WM_clipboard_text_set(const char *buf, bool selection)
}
}
bool WM_clipboard_image_available(void)
{
return (bool)GHOST_hasClipboardImage();
}
ImBuf *WM_clipboard_image_get(void)
{
int width, height;
uint *rgba = GHOST_getClipboardImage(&width, &height);
if (!rgba) {
return NULL;
}
ImBuf *ibuf = IMB_allocFromBuffer(rgba, NULL, width, height, 4);
free(rgba);
return ibuf;
}
bool WM_clipboard_image_set(ImBuf *ibuf)
{
bool free_byte_buffer = false;
if (ibuf->rect == NULL) {
/* Add a byte buffer if it does not have one. */
IMB_rect_from_float(ibuf);
free_byte_buffer = true;
}
bool success = (bool)GHOST_putClipboardImage(ibuf->rect, ibuf->x, ibuf->y);
if (free_byte_buffer) {
/* Remove the byte buffer if we added it. */
imb_freerectImBuf(ibuf);
}
return success;
}
/** \} */
/* -------------------------------------------------------------------- */