Initial Grease Pencil 3.0 stage #106848

Merged
Falk David merged 224 commits from filedescriptor/blender:grease-pencil-v3 into main 2023-05-30 11:14:22 +02:00
83 changed files with 1549 additions and 505 deletions
Showing only changes of commit 4e36522acb - Show all commits

View File

@ -1390,19 +1390,128 @@ ccl_device_extern void osl_noiseparams_set_impulses(ccl_private OSLNoiseOptions
res->y = n; \
res->z = n; \
} \
ccl_device_extern void name##_vv(ccl_private float3 *res, const float3 *v) \
ccl_device_extern void name##_vv(ccl_private float3 *res, ccl_private const float3 *v) \
{ \
const float n = name##_fv(v); \
res->x = n; \
res->y = n; \
res->z = n; \
} \
ccl_device_extern void name##_vvf(ccl_private float3 *res, const float3 *v, float w) \
ccl_device_extern void name##_vvf( \
ccl_private float3 *res, ccl_private const float3 *v, float w) \
{ \
const float n = name##_fvf(v, w); \
res->x = n; \
res->y = n; \
res->z = n; \
} \
ccl_device_extern void name##_dfdf(ccl_private float *res, ccl_private const float *x) \
{ \
res[0] = name##_ff(x[0]); \
res[1] = name##_ff(x[1]); \
res[2] = name##_ff(x[2]); \
} \
ccl_device_extern void name##_dfdff( \
ccl_private float *res, ccl_private const float *x, float y) \
{ \
res[0] = name##_fff(x[0], y); \
res[1] = name##_fff(x[1], y); \
res[2] = name##_fff(x[2], y); \
} \
ccl_device_extern void name##_dffdf( \
ccl_private float *res, float x, ccl_private const float *y) \
{ \
res[0] = name##_fff(x, y[0]); \
res[1] = name##_fff(x, y[1]); \
res[2] = name##_fff(x, y[2]); \
} \
ccl_device_extern void name##_dfdfdf( \
ccl_private float *res, ccl_private const float *x, ccl_private const float *y) \
{ \
res[0] = name##_fff(x[0], y[0]); \
res[1] = name##_fff(x[1], y[1]); \
res[2] = name##_fff(x[2], y[2]); \
} \
ccl_device_extern void name##_dfdv(ccl_private float *res, ccl_private const float3 *v) \
{ \
res[0] = name##_fv(&v[0]); \
res[1] = name##_fv(&v[1]); \
res[2] = name##_fv(&v[2]); \
} \
ccl_device_extern void name##_dfdvf( \
ccl_private float *res, ccl_private const float3 *v, float w) \
{ \
res[0] = name##_fvf(&v[0], w); \
res[1] = name##_fvf(&v[1], w); \
res[2] = name##_fvf(&v[2], w); \
} \
ccl_device_extern void name##_dfvdf( \
ccl_private float *res, ccl_private const float3 *v, ccl_private const float *w) \
{ \
res[0] = name##_fvf(v, w[0]); \
res[1] = name##_fvf(v, w[1]); \
res[2] = name##_fvf(v, w[2]); \
} \
ccl_device_extern void name##_dfdvdf( \
ccl_private float *res, ccl_private const float3 *v, ccl_private const float *w) \
{ \
res[0] = name##_fvf(&v[0], w[0]); \
res[1] = name##_fvf(&v[1], w[1]); \
res[2] = name##_fvf(&v[2], w[2]); \
} \
ccl_device_extern void name##_dvdf(ccl_private float3 *res, ccl_private const float *x) \
{ \
name##_vf(&res[0], x[0]); \
name##_vf(&res[1], x[1]); \
name##_vf(&res[2], x[2]); \
} \
ccl_device_extern void name##_dvdff( \
ccl_private float3 *res, ccl_private const float *x, float y) \
{ \
name##_vff(&res[0], x[0], y); \
name##_vff(&res[1], x[1], y); \
name##_vff(&res[2], x[2], y); \
} \
ccl_device_extern void name##_dvfdf( \
ccl_private float3 *res, float x, ccl_private const float *y) \
{ \
name##_vff(&res[0], x, y[0]); \
name##_vff(&res[1], x, y[1]); \
name##_vff(&res[2], x, y[2]); \
} \
ccl_device_extern void name##_dvdfdf( \
ccl_private float3 *res, ccl_private const float *x, ccl_private const float *y) \
{ \
name##_vff(&res[0], x[0], y[0]); \
name##_vff(&res[1], x[1], y[1]); \
name##_vff(&res[2], x[2], y[2]); \
} \
ccl_device_extern void name##_dvdv(ccl_private float3 *res, ccl_private const float3 *v) \
{ \
name##_vv(&res[0], &v[0]); \
name##_vv(&res[1], &v[1]); \
name##_vv(&res[2], &v[2]); \
} \
ccl_device_extern void name##_dvdvf( \
ccl_private float3 *res, ccl_private const float3 *v, float w) \
{ \
name##_vvf(&res[0], &v[0], w); \
name##_vvf(&res[1], &v[1], w); \
name##_vvf(&res[2], &v[2], w); \
} \
ccl_device_extern void name##_dvvdf( \
ccl_private float3 *res, ccl_private const float3 *v, ccl_private const float *w) \
{ \
name##_vvf(&res[0], v, w[0]); \
name##_vvf(&res[1], v, w[1]); \
name##_vvf(&res[2], v, w[2]); \
} \
ccl_device_extern void name##_dvdvdf( \
ccl_private float3 *res, ccl_private const float3 *v, ccl_private const float *w) \
{ \
name##_vvf(&res[0], &v[0], w[0]); \
name##_vvf(&res[1], &v[1], w[1]); \
name##_vvf(&res[2], &v[2], w[2]); \
}
ccl_device_forceinline float hashnoise_1d(float p)

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

@ -64,42 +64,16 @@ static void curves_init_data(ID *id)
static void curves_copy_data(Main * /*bmain*/, ID *id_dst, const ID *id_src, const int /*flag*/)
{
using namespace blender;
Curves *curves_dst = (Curves *)id_dst;
const Curves *curves_src = (const Curves *)id_src;
curves_dst->mat = static_cast<Material **>(MEM_dupallocN(curves_src->mat));
const bke::CurvesGeometry &src = curves_src->geometry.wrap();
bke::CurvesGeometry &dst = curves_dst->geometry.wrap();
/* We need special handling here because the generic ID management code has already done a
* shallow copy from the source to the destination, and because the copy-on-write functionality
* isn't supported more generically yet. */
dst.point_num = src.point_num;
dst.curve_num = src.curve_num;
CustomData_copy(&src.point_data, &dst.point_data, CD_MASK_ALL, dst.point_num);
CustomData_copy(&src.curve_data, &dst.curve_data, CD_MASK_ALL, dst.curve_num);
dst.curve_offsets = static_cast<int *>(MEM_dupallocN(src.curve_offsets));
new (&curves_dst->geometry) blender::bke::CurvesGeometry(curves_src->geometry.wrap());
if (curves_src->surface_uv_map != nullptr) {
curves_dst->surface_uv_map = BLI_strdup(curves_src->surface_uv_map);
}
dst.runtime = MEM_new<bke::CurvesGeometryRuntime>(__func__);
dst.runtime->type_counts = src.runtime->type_counts;
dst.runtime->evaluated_offsets_cache = src.runtime->evaluated_offsets_cache;
dst.runtime->nurbs_basis_cache = src.runtime->nurbs_basis_cache;
dst.runtime->evaluated_position_cache = src.runtime->evaluated_position_cache;
dst.runtime->bounds_cache = src.runtime->bounds_cache;
dst.runtime->evaluated_length_cache = src.runtime->evaluated_length_cache;
dst.runtime->evaluated_tangent_cache = src.runtime->evaluated_tangent_cache;
dst.runtime->evaluated_normal_cache = src.runtime->evaluated_normal_cache;
curves_dst->batch_cache = nullptr;
}

View File

@ -224,6 +224,7 @@ void BKE_mesh_runtime_clear_geometry(Mesh *mesh)
mesh->runtime->subsurf_optimal_display_edges.clear_and_shrink();
if (mesh->runtime->shrinkwrap_data) {
BKE_shrinkwrap_boundary_data_free(mesh->runtime->shrinkwrap_data);
mesh->runtime->shrinkwrap_data = nullptr;
}
}

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

@ -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

@ -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

@ -338,7 +338,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;
}
/** \} */
/* -------------------------------------------------------------------- */