Initial Grease Pencil 3.0 stage #106848
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
***************************************************************************************/
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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>(
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
* \{ */
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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...")
|
||||
|
|
|
@ -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]]; \
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
||||
/** \} */
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -187,7 +187,6 @@ struct PBVH {
|
|||
|
||||
/* flag are verts/faces deformed */
|
||||
bool deformed;
|
||||
bool respect_hide;
|
||||
|
||||
/* Dynamic topology */
|
||||
float bm_max_edge_len;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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));
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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]");
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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[] = {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
* \{ */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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++) {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -696,7 +696,7 @@ ModifierTypeInfo modifierType_Ocean = {
|
|||
/*icon*/ ICON_MOD_OCEAN,
|
||||
|
||||
/*copyData*/ copyData,
|
||||
/*deformMatrices*/ nullptr,
|
||||
/*deformVerts*/ nullptr,
|
||||
|
||||
/*deformMatrices*/ nullptr,
|
||||
/*deformVertsEM*/ nullptr,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)};
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
|
Loading…
Reference in New Issue