Nodes: Panel declarations for grouping sockets #108649
|
@ -155,12 +155,15 @@ ccl_device_inline void shader_setup_from_sample(KernelGlobals kg,
|
|||
sd->Ng = Ng;
|
||||
sd->wi = I;
|
||||
sd->shader = shader;
|
||||
if (prim != PRIM_NONE)
|
||||
sd->type = PRIMITIVE_TRIANGLE;
|
||||
else if (lamp != LAMP_NONE)
|
||||
if (lamp != LAMP_NONE) {
|
||||
sd->type = PRIMITIVE_LAMP;
|
||||
else
|
||||
}
|
||||
else if (prim != PRIM_NONE) {
|
||||
sd->type = PRIMITIVE_TRIANGLE;
|
||||
}
|
||||
else {
|
||||
sd->type = PRIMITIVE_NONE;
|
||||
}
|
||||
|
||||
/* primitive */
|
||||
sd->object = object;
|
||||
|
|
|
@ -162,7 +162,7 @@ extern void GHOST_GetAllDisplayDimensions(GHOST_SystemHandle systemhandle,
|
|||
* \param height: The height the window.
|
||||
* \param state: The state of the window when opened.
|
||||
* \param is_dialog: Stay on top of parent window, no icon in taskbar, can't be minimized.
|
||||
* \param glSettings: Misc OpenGL options.
|
||||
* \param gpuSettings: Misc GPU options.
|
||||
* \return A handle to the new window ( == NULL if creation failed).
|
||||
*/
|
||||
extern GHOST_WindowHandle GHOST_CreateWindow(GHOST_SystemHandle systemhandle,
|
||||
|
@ -174,17 +174,17 @@ extern GHOST_WindowHandle GHOST_CreateWindow(GHOST_SystemHandle systemhandle,
|
|||
uint32_t height,
|
||||
GHOST_TWindowState state,
|
||||
bool is_dialog,
|
||||
GHOST_GLSettings glSettings);
|
||||
GHOST_GPUSettings gpuSettings);
|
||||
|
||||
/**
|
||||
* Create a new off-screen context.
|
||||
* Never explicitly delete the context, use #disposeContext() instead.
|
||||
* \param systemhandle: The handle to the system.
|
||||
* \param glSettings: Misc OpenGL options.
|
||||
* \param gpuSettings: Misc GPU options.
|
||||
* \return A handle to the new context ( == NULL if creation failed).
|
||||
*/
|
||||
extern GHOST_ContextHandle GHOST_CreateOpenGLContext(GHOST_SystemHandle systemhandle,
|
||||
GHOST_GLSettings glSettings);
|
||||
extern GHOST_ContextHandle GHOST_CreateGPUContext(GHOST_SystemHandle systemhandle,
|
||||
GHOST_GPUSettings gpuSettings);
|
||||
|
||||
/**
|
||||
* Dispose of a context.
|
||||
|
@ -192,8 +192,8 @@ extern GHOST_ContextHandle GHOST_CreateOpenGLContext(GHOST_SystemHandle systemha
|
|||
* \param contexthandle: Handle to the context to be disposed.
|
||||
* \return Indication of success.
|
||||
*/
|
||||
extern GHOST_TSuccess GHOST_DisposeOpenGLContext(GHOST_SystemHandle systemhandle,
|
||||
GHOST_ContextHandle contexthandle);
|
||||
extern GHOST_TSuccess GHOST_DisposeGPUContext(GHOST_SystemHandle systemhandle,
|
||||
GHOST_ContextHandle contexthandle);
|
||||
|
||||
/**
|
||||
* Returns the window user data.
|
||||
|
@ -730,24 +730,24 @@ extern GHOST_TSuccess GHOST_InvalidateWindow(GHOST_WindowHandle windowhandle);
|
|||
* \param contexthandle: The handle to the context.
|
||||
* \return A success indicator.
|
||||
*/
|
||||
extern GHOST_TSuccess GHOST_ActivateOpenGLContext(GHOST_ContextHandle contexthandle);
|
||||
extern GHOST_TSuccess GHOST_ActivateGPUContext(GHOST_ContextHandle contexthandle);
|
||||
|
||||
/**
|
||||
* Release the drawing context bound to this thread.
|
||||
* \param contexthandle: The handle to the context.
|
||||
* \return A success indicator.
|
||||
*/
|
||||
extern GHOST_TSuccess GHOST_ReleaseOpenGLContext(GHOST_ContextHandle contexthandle);
|
||||
extern GHOST_TSuccess GHOST_ReleaseGPUContext(GHOST_ContextHandle contexthandle);
|
||||
|
||||
/**
|
||||
* Get the OpenGL frame-buffer handle that serves as a default frame-buffer.
|
||||
* Get the GPU frame-buffer handle that serves as a default frame-buffer.
|
||||
*/
|
||||
extern unsigned int GHOST_GetContextDefaultOpenGLFramebuffer(GHOST_ContextHandle contexthandle);
|
||||
extern unsigned int GHOST_GetContextDefaultGPUFramebuffer(GHOST_ContextHandle contexthandle);
|
||||
|
||||
/**
|
||||
* Get the OpenGL frame-buffer handle that serves as a default frame-buffer.
|
||||
* Get the GPU frame-buffer handle that serves as a default frame-buffer.
|
||||
*/
|
||||
extern unsigned int GHOST_GetDefaultOpenGLFramebuffer(GHOST_WindowHandle windowhandle);
|
||||
extern unsigned int GHOST_GetDefaultGPUFramebuffer(GHOST_WindowHandle windowhandle);
|
||||
|
||||
/**
|
||||
* Use multi-touch gestures if supported.
|
||||
|
@ -1072,7 +1072,7 @@ int GHOST_XrSessionIsRunning(const GHOST_XrContextHandle xr_context);
|
|||
|
||||
/**
|
||||
* Check if \a xr_context has a session that requires an upside-down frame-buffer (compared to
|
||||
* OpenGL). If true, the render result should be flipped vertically for correct output.
|
||||
* GPU). If true, the render result should be flipped vertically for correct output.
|
||||
* \note Only to be called after session start, may otherwise result in a false negative.
|
||||
*/
|
||||
int GHOST_XrSessionNeedsUpsideDownDrawing(const GHOST_XrContextHandle xr_context);
|
||||
|
|
|
@ -230,7 +230,7 @@ class GHOST_ISystem {
|
|||
* \param width: The width the window.
|
||||
* \param height: The height the window.
|
||||
* \param state: The state of the window when opened.
|
||||
* \param glSettings: Misc OpenGL settings.
|
||||
* \param gpuSettings: Misc GPU settings.
|
||||
* \param exclusive: Use to show the window on top and ignore others (used full-screen).
|
||||
* \param is_dialog: Stay on top of parent window, no icon in taskbar, can't be minimized.
|
||||
* \param parentWindow: Parent (embedder) window
|
||||
|
@ -242,7 +242,7 @@ class GHOST_ISystem {
|
|||
uint32_t width,
|
||||
uint32_t height,
|
||||
GHOST_TWindowState state,
|
||||
GHOST_GLSettings glSettings,
|
||||
GHOST_GPUSettings gpuSettings,
|
||||
const bool exclusive = false,
|
||||
const bool is_dialog = false,
|
||||
const GHOST_IWindow *parentWindow = NULL) = 0;
|
||||
|
@ -259,7 +259,7 @@ class GHOST_ISystem {
|
|||
* Never explicitly delete the context, use #disposeContext() instead.
|
||||
* \return The new context (or 0 if creation failed).
|
||||
*/
|
||||
virtual GHOST_IContext *createOffscreenContext(GHOST_GLSettings glSettings) = 0;
|
||||
virtual GHOST_IContext *createOffscreenContext(GHOST_GPUSettings gpuSettings) = 0;
|
||||
|
||||
/**
|
||||
* Dispose of a context.
|
||||
|
|
|
@ -64,9 +64,9 @@ typedef struct {
|
|||
} GHOST_CursorBitmapRef;
|
||||
|
||||
typedef enum {
|
||||
GHOST_glStereoVisual = (1 << 0),
|
||||
GHOST_glDebugContext = (1 << 1),
|
||||
} GHOST_GLFlags;
|
||||
GHOST_gpuStereoVisual = (1 << 0),
|
||||
GHOST_gpuDebugContext = (1 << 1),
|
||||
} GHOST_GPUFlags;
|
||||
|
||||
typedef enum GHOST_DialogOptions {
|
||||
GHOST_DialogWarning = (1 << 0),
|
||||
|
@ -681,7 +681,7 @@ typedef struct {
|
|||
typedef struct {
|
||||
int flags;
|
||||
GHOST_TDrawingContextType context_type;
|
||||
} GHOST_GLSettings;
|
||||
} GHOST_GPUSettings;
|
||||
|
||||
typedef enum {
|
||||
/** Axis that cursor grab will wrap. */
|
||||
|
|
|
@ -135,16 +135,16 @@ void GHOST_GetAllDisplayDimensions(GHOST_SystemHandle systemhandle,
|
|||
system->getAllDisplayDimensions(*width, *height);
|
||||
}
|
||||
|
||||
GHOST_ContextHandle GHOST_CreateOpenGLContext(GHOST_SystemHandle systemhandle,
|
||||
GHOST_GLSettings glSettings)
|
||||
GHOST_ContextHandle GHOST_CreateGPUContext(GHOST_SystemHandle systemhandle,
|
||||
GHOST_GPUSettings gpuSettings)
|
||||
{
|
||||
GHOST_ISystem *system = (GHOST_ISystem *)systemhandle;
|
||||
|
||||
return (GHOST_ContextHandle)system->createOffscreenContext(glSettings);
|
||||
return (GHOST_ContextHandle)system->createOffscreenContext(gpuSettings);
|
||||
}
|
||||
|
||||
GHOST_TSuccess GHOST_DisposeOpenGLContext(GHOST_SystemHandle systemhandle,
|
||||
GHOST_ContextHandle contexthandle)
|
||||
GHOST_TSuccess GHOST_DisposeGPUContext(GHOST_SystemHandle systemhandle,
|
||||
GHOST_ContextHandle contexthandle)
|
||||
{
|
||||
GHOST_ISystem *system = (GHOST_ISystem *)systemhandle;
|
||||
GHOST_IContext *context = (GHOST_IContext *)contexthandle;
|
||||
|
@ -161,7 +161,7 @@ GHOST_WindowHandle GHOST_CreateWindow(GHOST_SystemHandle systemhandle,
|
|||
uint32_t height,
|
||||
GHOST_TWindowState state,
|
||||
bool is_dialog,
|
||||
GHOST_GLSettings glSettings)
|
||||
GHOST_GPUSettings gpuSettings)
|
||||
{
|
||||
GHOST_ISystem *system = (GHOST_ISystem *)systemhandle;
|
||||
|
||||
|
@ -171,7 +171,7 @@ GHOST_WindowHandle GHOST_CreateWindow(GHOST_SystemHandle systemhandle,
|
|||
width,
|
||||
height,
|
||||
state,
|
||||
glSettings,
|
||||
gpuSettings,
|
||||
false,
|
||||
is_dialog,
|
||||
(GHOST_IWindow *)parent_windowhandle);
|
||||
|
@ -716,7 +716,7 @@ GHOST_TSuccess GHOST_ActivateWindowDrawingContext(GHOST_WindowHandle windowhandl
|
|||
return window->activateDrawingContext();
|
||||
}
|
||||
|
||||
GHOST_TSuccess GHOST_ActivateOpenGLContext(GHOST_ContextHandle contexthandle)
|
||||
GHOST_TSuccess GHOST_ActivateGPUContext(GHOST_ContextHandle contexthandle)
|
||||
{
|
||||
GHOST_IContext *context = (GHOST_IContext *)contexthandle;
|
||||
if (context) {
|
||||
|
@ -726,21 +726,21 @@ GHOST_TSuccess GHOST_ActivateOpenGLContext(GHOST_ContextHandle contexthandle)
|
|||
return GHOST_kFailure;
|
||||
}
|
||||
|
||||
GHOST_TSuccess GHOST_ReleaseOpenGLContext(GHOST_ContextHandle contexthandle)
|
||||
GHOST_TSuccess GHOST_ReleaseGPUContext(GHOST_ContextHandle contexthandle)
|
||||
{
|
||||
GHOST_IContext *context = (GHOST_IContext *)contexthandle;
|
||||
|
||||
return context->releaseDrawingContext();
|
||||
}
|
||||
|
||||
uint GHOST_GetContextDefaultOpenGLFramebuffer(GHOST_ContextHandle contexthandle)
|
||||
uint GHOST_GetContextDefaultGPUFramebuffer(GHOST_ContextHandle contexthandle)
|
||||
{
|
||||
GHOST_IContext *context = (GHOST_IContext *)contexthandle;
|
||||
|
||||
return context->getDefaultFramebuffer();
|
||||
}
|
||||
|
||||
uint GHOST_GetDefaultOpenGLFramebuffer(GHOST_WindowHandle windowhandle)
|
||||
uint GHOST_GetDefaultGPUFramebuffer(GHOST_WindowHandle windowhandle)
|
||||
{
|
||||
GHOST_IWindow *window = (GHOST_IWindow *)windowhandle;
|
||||
|
||||
|
|
|
@ -397,12 +397,12 @@ GHOST_TSuccess GHOST_System::createFullScreenWindow(GHOST_Window **window,
|
|||
const GHOST_DisplaySetting &settings,
|
||||
const bool stereoVisual)
|
||||
{
|
||||
GHOST_GLSettings glSettings = {0};
|
||||
GHOST_GPUSettings gpuSettings = {0};
|
||||
|
||||
if (stereoVisual) {
|
||||
glSettings.flags |= GHOST_glStereoVisual;
|
||||
gpuSettings.flags |= GHOST_gpuStereoVisual;
|
||||
}
|
||||
glSettings.context_type = GHOST_kDrawingContextTypeOpenGL;
|
||||
gpuSettings.context_type = GHOST_kDrawingContextTypeOpenGL;
|
||||
/* NOTE: don't use #getCurrentDisplaySetting() because on X11 we may
|
||||
* be zoomed in and the desktop may be bigger than the viewport. */
|
||||
GHOST_ASSERT(m_displayManager,
|
||||
|
@ -414,7 +414,7 @@ GHOST_TSuccess GHOST_System::createFullScreenWindow(GHOST_Window **window,
|
|||
settings.xPixels,
|
||||
settings.yPixels,
|
||||
GHOST_kWindowStateNormal,
|
||||
glSettings,
|
||||
gpuSettings,
|
||||
true /* exclusive */);
|
||||
return (*window == nullptr) ? GHOST_kFailure : GHOST_kSuccess;
|
||||
}
|
||||
|
|
|
@ -101,7 +101,7 @@ class GHOST_System : public GHOST_ISystem {
|
|||
* Never explicitly delete the context, use #disposeContext() instead.
|
||||
* \return The new context (or 0 if creation failed).
|
||||
*/
|
||||
virtual GHOST_IContext *createOffscreenContext(GHOST_GLSettings glSettings) = 0;
|
||||
virtual GHOST_IContext *createOffscreenContext(GHOST_GPUSettings gpuSettings) = 0;
|
||||
|
||||
/**
|
||||
* Returns whether a window is valid.
|
||||
|
|
|
@ -77,7 +77,7 @@ class GHOST_SystemCocoa : public GHOST_System {
|
|||
* \param width: The width the window.
|
||||
* \param height: The height the window.
|
||||
* \param state: The state of the window when opened.
|
||||
* \param glSettings: Misc OpenGL settings.
|
||||
* \param gpuSettings: Misc GPU settings.
|
||||
* \param exclusive: Use to show the window on top and ignore others (used full-screen).
|
||||
* \param parentWindow: Parent (embedder) window.
|
||||
* \return The new window (or 0 if creation failed).
|
||||
|
@ -88,7 +88,7 @@ class GHOST_SystemCocoa : public GHOST_System {
|
|||
uint32_t width,
|
||||
uint32_t height,
|
||||
GHOST_TWindowState state,
|
||||
GHOST_GLSettings glSettings,
|
||||
GHOST_GPUSettings gpuSettings,
|
||||
const bool exclusive = false,
|
||||
const bool is_dialog = false,
|
||||
const GHOST_IWindow *parentWindow = NULL);
|
||||
|
@ -98,7 +98,7 @@ class GHOST_SystemCocoa : public GHOST_System {
|
|||
* Never explicitly delete the context, use #disposeContext() instead.
|
||||
* \return The new context (or 0 if creation failed).
|
||||
*/
|
||||
GHOST_IContext *createOffscreenContext(GHOST_GLSettings glSettings);
|
||||
GHOST_IContext *createOffscreenContext(GHOST_GPUSettings gpuSettings);
|
||||
|
||||
/**
|
||||
* Dispose of a context.
|
||||
|
|
|
@ -696,7 +696,7 @@ GHOST_IWindow *GHOST_SystemCocoa::createWindow(const char *title,
|
|||
uint32_t width,
|
||||
uint32_t height,
|
||||
GHOST_TWindowState state,
|
||||
GHOST_GLSettings glSettings,
|
||||
GHOST_GPUSettings gpuSettings,
|
||||
const bool exclusive,
|
||||
const bool is_dialog,
|
||||
const GHOST_IWindow *parentWindow)
|
||||
|
@ -725,9 +725,9 @@ GHOST_IWindow *GHOST_SystemCocoa::createWindow(const char *title,
|
|||
width,
|
||||
height,
|
||||
state,
|
||||
glSettings.context_type,
|
||||
glSettings.flags & GHOST_glStereoVisual,
|
||||
glSettings.flags & GHOST_glDebugContext,
|
||||
gpuSettings.context_type,
|
||||
gpuSettings.flags & GHOST_gpuStereoVisual,
|
||||
gpuSettings.flags & GHOST_gpuDebugContext,
|
||||
is_dialog,
|
||||
(GHOST_WindowCocoa *)parentWindow);
|
||||
|
||||
|
@ -755,11 +755,11 @@ GHOST_IWindow *GHOST_SystemCocoa::createWindow(const char *title,
|
|||
* Never explicitly delete the context, use #disposeContext() instead.
|
||||
* \return The new context (or 0 if creation failed).
|
||||
*/
|
||||
GHOST_IContext *GHOST_SystemCocoa::createOffscreenContext(GHOST_GLSettings glSettings)
|
||||
GHOST_IContext *GHOST_SystemCocoa::createOffscreenContext(GHOST_GPUSettings gpuSettings)
|
||||
{
|
||||
#ifdef WITH_VULKAN_BACKEND
|
||||
if (glSettings.context_type == GHOST_kDrawingContextTypeVulkan) {
|
||||
const bool debug_context = (glSettings.flags & GHOST_glDebugContext) != 0;
|
||||
if (gpuSettings.context_type == GHOST_kDrawingContextTypeVulkan) {
|
||||
const bool debug_context = (gpuSettings.flags & GHOST_gpuDebugContext) != 0;
|
||||
GHOST_Context *context = new GHOST_ContextVK(false, NULL, 1, 2, debug_context);
|
||||
if (!context->initializeDrawingContext()) {
|
||||
delete context;
|
||||
|
@ -769,7 +769,7 @@ GHOST_IContext *GHOST_SystemCocoa::createOffscreenContext(GHOST_GLSettings glSet
|
|||
}
|
||||
#endif
|
||||
|
||||
GHOST_Context *context = new GHOST_ContextCGL(false, NULL, NULL, NULL, glSettings.context_type);
|
||||
GHOST_Context *context = new GHOST_ContextCGL(false, NULL, NULL, NULL, gpuSettings.context_type);
|
||||
if (context->initializeDrawingContext())
|
||||
return context;
|
||||
else
|
||||
|
|
|
@ -79,7 +79,7 @@ class GHOST_SystemHeadless : public GHOST_System {
|
|||
void getAllDisplayDimensions(uint32_t & /*width*/, uint32_t & /*height*/) const override
|
||||
{ /* nop */
|
||||
}
|
||||
GHOST_IContext *createOffscreenContext(GHOST_GLSettings /*glSettings*/) override
|
||||
GHOST_IContext *createOffscreenContext(GHOST_GPUSettings /*gpuSettings*/) override
|
||||
{
|
||||
#ifdef __linux__
|
||||
GHOST_Context *context;
|
||||
|
@ -150,7 +150,7 @@ class GHOST_SystemHeadless : public GHOST_System {
|
|||
uint32_t width,
|
||||
uint32_t height,
|
||||
GHOST_TWindowState state,
|
||||
GHOST_GLSettings glSettings,
|
||||
GHOST_GPUSettings gpuSettings,
|
||||
const bool /*exclusive*/,
|
||||
const bool /*is_dialog*/,
|
||||
const GHOST_IWindow *parentWindow) override
|
||||
|
@ -162,8 +162,8 @@ class GHOST_SystemHeadless : public GHOST_System {
|
|||
height,
|
||||
state,
|
||||
parentWindow,
|
||||
glSettings.context_type,
|
||||
((glSettings.flags & GHOST_glStereoVisual) != 0));
|
||||
gpuSettings.context_type,
|
||||
((gpuSettings.flags & GHOST_gpuStereoVisual) != 0));
|
||||
}
|
||||
|
||||
GHOST_IWindow *getWindowUnderCursor(int32_t /*x*/, int32_t /*y*/) override
|
||||
|
|
|
@ -42,7 +42,7 @@ GHOST_IWindow *GHOST_SystemSDL::createWindow(const char *title,
|
|||
uint32_t width,
|
||||
uint32_t height,
|
||||
GHOST_TWindowState state,
|
||||
GHOST_GLSettings glSettings,
|
||||
GHOST_GPUSettings gpuSettings,
|
||||
const bool exclusive,
|
||||
const bool /* is_dialog */,
|
||||
const GHOST_IWindow *parentWindow)
|
||||
|
@ -56,8 +56,8 @@ GHOST_IWindow *GHOST_SystemSDL::createWindow(const char *title,
|
|||
width,
|
||||
height,
|
||||
state,
|
||||
glSettings.context_type,
|
||||
((glSettings.flags & GHOST_glStereoVisual) != 0),
|
||||
gpuSettings.context_type,
|
||||
((gpuSettings.flags & GHOST_gpuStereoVisual) != 0),
|
||||
exclusive,
|
||||
parentWindow);
|
||||
|
||||
|
@ -125,7 +125,7 @@ uint8_t GHOST_SystemSDL::getNumDisplays() const
|
|||
return SDL_GetNumVideoDisplays();
|
||||
}
|
||||
|
||||
GHOST_IContext *GHOST_SystemSDL::createOffscreenContext(GHOST_GLSettings /*glSettings*/)
|
||||
GHOST_IContext *GHOST_SystemSDL::createOffscreenContext(GHOST_GPUSettings /*gpuSettings*/)
|
||||
{
|
||||
GHOST_Context *context = new GHOST_ContextSDL(false,
|
||||
nullptr,
|
||||
|
|
|
@ -60,7 +60,7 @@ class GHOST_SystemSDL : public GHOST_System {
|
|||
|
||||
void getMainDisplayDimensions(uint32_t &width, uint32_t &height) const override;
|
||||
|
||||
GHOST_IContext *createOffscreenContext(GHOST_GLSettings glSettings) override;
|
||||
GHOST_IContext *createOffscreenContext(GHOST_GPUSettings gpuSettings) override;
|
||||
|
||||
GHOST_TSuccess disposeContext(GHOST_IContext *context) override;
|
||||
|
||||
|
@ -73,7 +73,7 @@ class GHOST_SystemSDL : public GHOST_System {
|
|||
uint32_t width,
|
||||
uint32_t height,
|
||||
GHOST_TWindowState state,
|
||||
GHOST_GLSettings glSettings,
|
||||
GHOST_GPUSettings gpuSettings,
|
||||
const bool exclusive = false,
|
||||
const bool is_dialog = false,
|
||||
const GHOST_IWindow *parentWindow = nullptr) override;
|
||||
|
|
|
@ -6279,7 +6279,7 @@ static GHOST_Context *createOffscreenContext_impl(GHOST_SystemWayland *system,
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
GHOST_IContext *GHOST_SystemWayland::createOffscreenContext(GHOST_GLSettings glSettings)
|
||||
GHOST_IContext *GHOST_SystemWayland::createOffscreenContext(GHOST_GPUSettings gpuSettings)
|
||||
{
|
||||
#ifdef USE_EVENT_BACKGROUND_THREAD
|
||||
std::lock_guard lock_server_guard{*server_mutex};
|
||||
|
@ -6289,9 +6289,9 @@ GHOST_IContext *GHOST_SystemWayland::createOffscreenContext(GHOST_GLSettings glS
|
|||
wl_surface *wl_surface = wl_compositor_create_surface(wl_compositor());
|
||||
|
||||
#ifdef WITH_VULKAN_BACKEND
|
||||
const bool debug_context = (glSettings.flags & GHOST_glDebugContext) != 0;
|
||||
const bool debug_context = (gpuSettings.flags & GHOST_gpuDebugContext) != 0;
|
||||
|
||||
if (glSettings.context_type == GHOST_kDrawingContextTypeVulkan) {
|
||||
if (gpuSettings.context_type == GHOST_kDrawingContextTypeVulkan) {
|
||||
GHOST_Context *context = new GHOST_ContextVK(false,
|
||||
GHOST_kVulkanPlatformWayland,
|
||||
0,
|
||||
|
@ -6310,7 +6310,7 @@ GHOST_IContext *GHOST_SystemWayland::createOffscreenContext(GHOST_GLSettings glS
|
|||
return context;
|
||||
}
|
||||
#else
|
||||
(void)glSettings;
|
||||
(void)gpuSettings;
|
||||
#endif
|
||||
|
||||
wl_egl_window *egl_window = wl_surface ? wl_egl_window_create(wl_surface, 1, 1) : nullptr;
|
||||
|
@ -6359,7 +6359,7 @@ GHOST_IWindow *GHOST_SystemWayland::createWindow(const char *title,
|
|||
const uint32_t width,
|
||||
const uint32_t height,
|
||||
const GHOST_TWindowState state,
|
||||
const GHOST_GLSettings glSettings,
|
||||
const GHOST_GPUSettings gpuSettings,
|
||||
const bool exclusive,
|
||||
const bool is_dialog,
|
||||
const GHOST_IWindow *parentWindow)
|
||||
|
@ -6374,9 +6374,9 @@ GHOST_IWindow *GHOST_SystemWayland::createWindow(const char *title,
|
|||
height,
|
||||
state,
|
||||
parentWindow,
|
||||
glSettings.context_type,
|
||||
gpuSettings.context_type,
|
||||
is_dialog,
|
||||
((glSettings.flags & GHOST_glStereoVisual) != 0),
|
||||
((gpuSettings.flags & GHOST_gpuStereoVisual) != 0),
|
||||
exclusive);
|
||||
|
||||
if (window) {
|
||||
|
|
|
@ -157,7 +157,7 @@ class GHOST_SystemWayland : public GHOST_System {
|
|||
|
||||
void getAllDisplayDimensions(uint32_t &width, uint32_t &height) const override;
|
||||
|
||||
GHOST_IContext *createOffscreenContext(GHOST_GLSettings glSettings) override;
|
||||
GHOST_IContext *createOffscreenContext(GHOST_GPUSettings gpuSettings) override;
|
||||
|
||||
GHOST_TSuccess disposeContext(GHOST_IContext *context) override;
|
||||
|
||||
|
@ -167,7 +167,7 @@ class GHOST_SystemWayland : public GHOST_System {
|
|||
uint32_t width,
|
||||
uint32_t height,
|
||||
GHOST_TWindowState state,
|
||||
GHOST_GLSettings glSettings,
|
||||
GHOST_GPUSettings gpuSettings,
|
||||
const bool exclusive,
|
||||
const bool is_dialog,
|
||||
const GHOST_IWindow *parentWindow) override;
|
||||
|
|
|
@ -224,7 +224,7 @@ GHOST_IWindow *GHOST_SystemWin32::createWindow(const char *title,
|
|||
uint32_t width,
|
||||
uint32_t height,
|
||||
GHOST_TWindowState state,
|
||||
GHOST_GLSettings glSettings,
|
||||
GHOST_GPUSettings gpuSettings,
|
||||
const bool /*exclusive*/,
|
||||
const bool is_dialog,
|
||||
const GHOST_IWindow *parentWindow)
|
||||
|
@ -237,11 +237,11 @@ GHOST_IWindow *GHOST_SystemWin32::createWindow(const char *title,
|
|||
width,
|
||||
height,
|
||||
state,
|
||||
glSettings.context_type,
|
||||
((glSettings.flags & GHOST_glStereoVisual) != 0),
|
||||
gpuSettings.context_type,
|
||||
((gpuSettings.flags & GHOST_gpuStereoVisual) != 0),
|
||||
false,
|
||||
(GHOST_WindowWin32 *)parentWindow,
|
||||
((glSettings.flags & GHOST_glDebugContext) != 0),
|
||||
((gpuSettings.flags & GHOST_gpuDebugContext) != 0),
|
||||
is_dialog);
|
||||
|
||||
if (window->getValid()) {
|
||||
|
@ -263,15 +263,15 @@ GHOST_IWindow *GHOST_SystemWin32::createWindow(const char *title,
|
|||
* Never explicitly delete the window, use #disposeContext() instead.
|
||||
* \return The new context (or 0 if creation failed).
|
||||
*/
|
||||
GHOST_IContext *GHOST_SystemWin32::createOffscreenContext(GHOST_GLSettings glSettings)
|
||||
GHOST_IContext *GHOST_SystemWin32::createOffscreenContext(GHOST_GPUSettings gpuSettings)
|
||||
{
|
||||
const bool debug_context = (glSettings.flags & GHOST_glDebugContext) != 0;
|
||||
const bool debug_context = (gpuSettings.flags & GHOST_gpuDebugContext) != 0;
|
||||
|
||||
GHOST_Context *context = nullptr;
|
||||
|
||||
#ifdef WITH_VULKAN_BACKEND
|
||||
/* Vulkan does not need a window. */
|
||||
if (glSettings.context_type == GHOST_kDrawingContextTypeVulkan) {
|
||||
if (gpuSettings.context_type == GHOST_kDrawingContextTypeVulkan) {
|
||||
context = new GHOST_ContextVK(false, (HWND)0, 1, 2, debug_context);
|
||||
|
||||
if (!context->initializeDrawingContext()) {
|
||||
|
|
|
@ -103,7 +103,7 @@ class GHOST_SystemWin32 : public GHOST_System {
|
|||
* \param width: The width the window.
|
||||
* \param height: The height the window.
|
||||
* \param state: The state of the window when opened.
|
||||
* \param glSettings: Misc OpenGL settings.
|
||||
* \param gpuSettings: Misc GPU settings.
|
||||
* \param exclusive: Use to show the window on top and ignore others (used full-screen).
|
||||
* \param parentWindow: Parent window.
|
||||
* \return The new window (or 0 if creation failed).
|
||||
|
@ -114,7 +114,7 @@ class GHOST_SystemWin32 : public GHOST_System {
|
|||
uint32_t width,
|
||||
uint32_t height,
|
||||
GHOST_TWindowState state,
|
||||
GHOST_GLSettings glSettings,
|
||||
GHOST_GPUSettings gpuSettings,
|
||||
const bool exclusive = false,
|
||||
const bool is_dialog = false,
|
||||
const GHOST_IWindow *parentWindow = 0);
|
||||
|
@ -124,7 +124,7 @@ class GHOST_SystemWin32 : public GHOST_System {
|
|||
* Never explicitly delete the window, use #disposeContext() instead.
|
||||
* \return The new context (or 0 if creation failed).
|
||||
*/
|
||||
GHOST_IContext *createOffscreenContext(GHOST_GLSettings glSettings);
|
||||
GHOST_IContext *createOffscreenContext(GHOST_GPUSettings gpuSettings);
|
||||
|
||||
/**
|
||||
* Dispose of a context.
|
||||
|
|
|
@ -304,7 +304,7 @@ GHOST_IWindow *GHOST_SystemX11::createWindow(const char *title,
|
|||
uint32_t width,
|
||||
uint32_t height,
|
||||
GHOST_TWindowState state,
|
||||
GHOST_GLSettings glSettings,
|
||||
GHOST_GPUSettings gpuSettings,
|
||||
const bool exclusive,
|
||||
const bool is_dialog,
|
||||
const GHOST_IWindow *parentWindow)
|
||||
|
@ -324,11 +324,11 @@ GHOST_IWindow *GHOST_SystemX11::createWindow(const char *title,
|
|||
height,
|
||||
state,
|
||||
(GHOST_WindowX11 *)parentWindow,
|
||||
glSettings.context_type,
|
||||
gpuSettings.context_type,
|
||||
is_dialog,
|
||||
((glSettings.flags & GHOST_glStereoVisual) != 0),
|
||||
((gpuSettings.flags & GHOST_gpuStereoVisual) != 0),
|
||||
exclusive,
|
||||
(glSettings.flags & GHOST_glDebugContext) != 0);
|
||||
(gpuSettings.flags & GHOST_gpuDebugContext) != 0);
|
||||
|
||||
if (window) {
|
||||
/* Both are now handle in GHOST_WindowX11.cc
|
||||
|
@ -399,7 +399,7 @@ static GHOST_Context *create_glx_context(Display *display,
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
GHOST_IContext *GHOST_SystemX11::createOffscreenContext(GHOST_GLSettings glSettings)
|
||||
GHOST_IContext *GHOST_SystemX11::createOffscreenContext(GHOST_GPUSettings gpuSettings)
|
||||
{
|
||||
/* During development:
|
||||
* try 4.x compatibility profile
|
||||
|
@ -411,11 +411,11 @@ GHOST_IContext *GHOST_SystemX11::createOffscreenContext(GHOST_GLSettings glSetti
|
|||
* try 3.3 core profile
|
||||
* no fall-backs. */
|
||||
|
||||
const bool debug_context = (glSettings.flags & GHOST_glDebugContext) != 0;
|
||||
const bool debug_context = (gpuSettings.flags & GHOST_gpuDebugContext) != 0;
|
||||
GHOST_Context *context = nullptr;
|
||||
|
||||
#ifdef WITH_VULKAN_BACKEND
|
||||
if (glSettings.context_type == GHOST_kDrawingContextTypeVulkan) {
|
||||
if (gpuSettings.context_type == GHOST_kDrawingContextTypeVulkan) {
|
||||
context = new GHOST_ContextVK(
|
||||
false, GHOST_kVulkanPlatformX11, 0, m_display, NULL, NULL, 1, 2, debug_context);
|
||||
|
||||
|
|
|
@ -124,7 +124,7 @@ class GHOST_SystemX11 : public GHOST_System {
|
|||
uint32_t width,
|
||||
uint32_t height,
|
||||
GHOST_TWindowState state,
|
||||
GHOST_GLSettings glSettings,
|
||||
GHOST_GPUSettings gpuSettings,
|
||||
const bool exclusive = false,
|
||||
const bool is_dialog = false,
|
||||
const GHOST_IWindow *parentWindow = nullptr) override;
|
||||
|
@ -134,7 +134,7 @@ class GHOST_SystemX11 : public GHOST_System {
|
|||
* Never explicitly delete the context, use #disposeContext() instead.
|
||||
* \return The new context (or 0 if creation failed).
|
||||
*/
|
||||
GHOST_IContext *createOffscreenContext(GHOST_GLSettings glSettings) override;
|
||||
GHOST_IContext *createOffscreenContext(GHOST_GPUSettings gpuSettings) override;
|
||||
|
||||
/**
|
||||
* Dispose of a context.
|
||||
|
|
|
@ -412,7 +412,7 @@ bool processEvent(GHOST_EventHandle hEvent, GHOST_TUserDataPtr userData)
|
|||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
GHOST_GLSettings glSettings = {0};
|
||||
GHOST_GPUSettings gpuSettings = {0};
|
||||
char *title1 = "gears - main window";
|
||||
char *title2 = "gears - secondary window";
|
||||
GHOST_EventConsumerHandle consumer = GHOST_CreateEventConsumer(processEvent, NULL);
|
||||
|
@ -433,7 +433,7 @@ int main(int argc, char **argv)
|
|||
GHOST_kWindowStateNormal,
|
||||
false,
|
||||
GHOST_kDrawingContextTypeOpenGL,
|
||||
glSettings);
|
||||
gpuSettings);
|
||||
if (!sMainWindow) {
|
||||
printf("could not create main window\n");
|
||||
exit(-1);
|
||||
|
@ -450,7 +450,7 @@ int main(int argc, char **argv)
|
|||
GHOST_kWindowStateNormal,
|
||||
false,
|
||||
GHOST_kDrawingContextTypeOpenGL,
|
||||
glSettings);
|
||||
gpuSettings);
|
||||
if (!sSecondaryWindow) {
|
||||
printf("could not create secondary window\n");
|
||||
exit(-1);
|
||||
|
|
|
@ -406,13 +406,13 @@ Application::Application(GHOST_ISystem *system)
|
|||
m_exitRequested(false),
|
||||
stereo(false)
|
||||
{
|
||||
GHOST_GLSettings glSettings = {0};
|
||||
glSettings.context_type = GHOST_kDrawingContextTypeOpenGL;
|
||||
GHOST_GPUSettings gpuSettings = {0};
|
||||
gpuSettings.context_type = GHOST_kDrawingContextTypeOpenGL;
|
||||
fApp = this;
|
||||
|
||||
// Create the main window
|
||||
m_mainWindow = system->createWindow(
|
||||
"gears - main window", 10, 64, 320, 200, GHOST_kWindowStateNormal, glSettings);
|
||||
"gears - main window", 10, 64, 320, 200, GHOST_kWindowStateNormal, gpuSettings);
|
||||
|
||||
if (!m_mainWindow) {
|
||||
std::cout << "could not create main window\n";
|
||||
|
@ -421,7 +421,7 @@ Application::Application(GHOST_ISystem *system)
|
|||
|
||||
// Create a secondary window
|
||||
m_secondaryWindow = system->createWindow(
|
||||
"gears - secondary window", 340, 64, 320, 200, GHOST_kWindowStateNormal, glSettings);
|
||||
"gears - secondary window", 340, 64, 320, 200, GHOST_kWindowStateNormal, gpuSettings);
|
||||
if (!m_secondaryWindow) {
|
||||
std::cout << "could not create secondary window\n";
|
||||
exit(-1);
|
||||
|
|
|
@ -306,7 +306,7 @@ MainWindow *mainwindow_new(MultiTestApp *app)
|
|||
{
|
||||
GHOST_SystemHandle sys = multitestapp_get_system(app);
|
||||
GHOST_WindowHandle win;
|
||||
GHOST_GLSettings glSettings = {0};
|
||||
GHOST_GPUSettings gpuSettings = {0};
|
||||
|
||||
win = GHOST_CreateWindow(sys,
|
||||
NULL,
|
||||
|
@ -318,7 +318,7 @@ MainWindow *mainwindow_new(MultiTestApp *app)
|
|||
GHOST_kWindowStateNormal,
|
||||
false,
|
||||
GHOST_kDrawingContextTypeOpenGL,
|
||||
glSettings);
|
||||
gpuSettings);
|
||||
|
||||
if (win) {
|
||||
MainWindow *mw = MEM_callocN(sizeof(*mw), "mainwindow_new");
|
||||
|
@ -557,7 +557,7 @@ static void loggerwindow_handle(void *priv, GHOST_EventHandle evt)
|
|||
|
||||
LoggerWindow *loggerwindow_new(MultiTestApp *app)
|
||||
{
|
||||
GHOST_GLSettings glSettings = {0};
|
||||
GHOST_GPUSettings gpuSettings = {0};
|
||||
GHOST_SystemHandle sys = multitestapp_get_system(app);
|
||||
uint32_t screensize[2];
|
||||
GHOST_WindowHandle win;
|
||||
|
@ -573,7 +573,7 @@ LoggerWindow *loggerwindow_new(MultiTestApp *app)
|
|||
GHOST_kWindowStateNormal,
|
||||
false,
|
||||
GHOST_kDrawingContextTypeOpenGL,
|
||||
glSettings);
|
||||
gpuSettings);
|
||||
|
||||
if (win) {
|
||||
LoggerWindow *lw = MEM_callocN(sizeof(*lw), "loggerwindow_new");
|
||||
|
@ -761,7 +761,7 @@ static void extrawindow_handle(void *priv, GHOST_EventHandle evt)
|
|||
|
||||
ExtraWindow *extrawindow_new(MultiTestApp *app)
|
||||
{
|
||||
GHOST_GLSettings glSettings = {0};
|
||||
GHOST_GPUSettings gpuSettings = {0};
|
||||
GHOST_SystemHandle sys = multitestapp_get_system(app);
|
||||
GHOST_WindowHandle win;
|
||||
|
||||
|
@ -775,7 +775,7 @@ ExtraWindow *extrawindow_new(MultiTestApp *app)
|
|||
GHOST_kWindowStateNormal,
|
||||
false,
|
||||
GHOST_kDrawingContextTypeOpenGL,
|
||||
glSettings);
|
||||
gpuSettings);
|
||||
|
||||
if (win) {
|
||||
ExtraWindow *ew = MEM_callocN(sizeof(*ew), "mainwindow_new");
|
||||
|
|
|
@ -571,8 +571,6 @@ class KeyframesCo:
|
|||
keyframe_points.foreach_set("co", co_buffer)
|
||||
keyframe_points.foreach_set("interpolation", ipo_buffer)
|
||||
|
||||
# TODO: in Blender 4.0 the next lines can be replaced with one call to `fcurve.update()`.
|
||||
# See https://projects.blender.org/blender/blender/issues/107126 for more info.
|
||||
keyframe_points.sort()
|
||||
keyframe_points.deduplicate()
|
||||
keyframe_points.handles_recalc()
|
||||
# This also deduplicates keys where baked keys were inserted on the
|
||||
# same frame as existing ones.
|
||||
fcurve.update()
|
||||
|
|
|
@ -44,8 +44,8 @@ def geometry_modifier_poll(context):
|
|||
|
||||
|
||||
def get_context_modifier(context):
|
||||
area = context.area
|
||||
if (area is not None) and (area.type == 'PROPERTIES'):
|
||||
# Context only has a 'modifier' attribute in the modifier extra operators dropdown.
|
||||
if hasattr(context, 'modifier'):
|
||||
modifier = context.modifier
|
||||
else:
|
||||
ob = context.object
|
||||
|
|
|
@ -109,15 +109,7 @@ class MESH_UL_vgroups(UIList):
|
|||
layout.label(text="", icon_value=icon)
|
||||
|
||||
|
||||
class MESH_UL_fmaps(UIList):
|
||||
def draw_item(self, _context, layout, _data, item, icon, _active_data, _active_propname, _index):
|
||||
# assert(isinstance(item, bpy.types.FaceMap))
|
||||
fmap = item
|
||||
if self.layout_type in {'DEFAULT', 'COMPACT'}:
|
||||
layout.prop(fmap, "name", text="", emboss=False, icon='FACE_MAPS')
|
||||
elif self.layout_type == 'GRID':
|
||||
layout.alignment = 'CENTER'
|
||||
layout.label(text="", icon_value=icon)
|
||||
|
||||
|
||||
|
||||
class MESH_UL_shape_keys(UIList):
|
||||
|
@ -285,50 +277,6 @@ class DATA_PT_vertex_groups(MeshButtonsPanel, Panel):
|
|||
layout.prop(context.tool_settings, "vertex_group_weight", text="Weight")
|
||||
|
||||
|
||||
class DATA_PT_face_maps(MeshButtonsPanel, Panel):
|
||||
bl_label = "Face Maps"
|
||||
bl_options = {'DEFAULT_CLOSED'}
|
||||
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH', 'BLENDER_WORKBENCH_NEXT'}
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
obj = context.object
|
||||
return (obj and obj.type == 'MESH')
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
ob = context.object
|
||||
facemap = ob.face_maps.active
|
||||
|
||||
rows = 2
|
||||
if facemap:
|
||||
rows = 4
|
||||
|
||||
row = layout.row()
|
||||
row.template_list("MESH_UL_fmaps", "", ob, "face_maps", ob.face_maps, "active_index", rows=rows)
|
||||
|
||||
col = row.column(align=True)
|
||||
col.operator("object.face_map_add", icon='ADD', text="")
|
||||
col.operator("object.face_map_remove", icon='REMOVE', text="")
|
||||
|
||||
if facemap:
|
||||
col.separator()
|
||||
col.operator("object.face_map_move", icon='TRIA_UP', text="").direction = 'UP'
|
||||
col.operator("object.face_map_move", icon='TRIA_DOWN', text="").direction = 'DOWN'
|
||||
|
||||
if ob.face_maps and (ob.mode == 'EDIT' and ob.type == 'MESH'):
|
||||
row = layout.row()
|
||||
|
||||
sub = row.row(align=True)
|
||||
sub.operator("object.face_map_assign", text="Assign")
|
||||
sub.operator("object.face_map_remove_from", text="Remove")
|
||||
|
||||
sub = row.row(align=True)
|
||||
sub.operator("object.face_map_select", text="Select")
|
||||
sub.operator("object.face_map_deselect", text="Deselect")
|
||||
|
||||
|
||||
class DATA_PT_shape_keys(MeshButtonsPanel, Panel):
|
||||
bl_label = "Shape Keys"
|
||||
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH', 'BLENDER_WORKBENCH_NEXT'}
|
||||
|
@ -717,7 +665,6 @@ classes = (
|
|||
MESH_MT_color_attribute_context_menu,
|
||||
MESH_MT_attribute_context_menu,
|
||||
MESH_UL_vgroups,
|
||||
MESH_UL_fmaps,
|
||||
MESH_UL_shape_keys,
|
||||
MESH_UL_uvmaps,
|
||||
MESH_UL_attributes,
|
||||
|
@ -726,7 +673,6 @@ classes = (
|
|||
DATA_PT_shape_keys,
|
||||
DATA_PT_uv_texture,
|
||||
DATA_PT_vertex_colors,
|
||||
DATA_PT_face_maps,
|
||||
DATA_PT_mesh_attributes,
|
||||
DATA_PT_normals,
|
||||
DATA_PT_texture_space,
|
||||
|
|
|
@ -1221,7 +1221,7 @@ class IMAGE_PT_tools_brush_display(Panel, BrushButtonsPanel, DisplayPanel):
|
|||
bl_context = ".paint_common_2d"
|
||||
bl_parent_id = "IMAGE_PT_paint_settings"
|
||||
bl_category = "Tool"
|
||||
bl_label = "Brush Tip"
|
||||
bl_label = "Cursor"
|
||||
bl_options = {'DEFAULT_CLOSED'}
|
||||
bl_ui_units_x = 15
|
||||
|
||||
|
|
|
@ -335,6 +335,7 @@ compositor_node_categories = [
|
|||
NodeItem("CompositorNodeSunBeams"),
|
||||
NodeItem("CompositorNodeDenoise"),
|
||||
NodeItem("CompositorNodeAntiAliasing"),
|
||||
NodeItem("CompositorNodeKuwahara"),
|
||||
]),
|
||||
CompositorNodeCategory("CMP_OP_VECTOR", "Vector", items=[
|
||||
NodeItem("CompositorNodeNormal"),
|
||||
|
|
|
@ -124,6 +124,7 @@ class AssetLibrary {
|
|||
*/
|
||||
AssetRepresentation &add_external_asset(StringRef relative_asset_path,
|
||||
StringRef name,
|
||||
int id_type,
|
||||
std::unique_ptr<AssetMetaData> metadata);
|
||||
/** See #AssetLibrary::add_external_asset(). */
|
||||
AssetRepresentation &add_local_id_asset(StringRef relative_asset_path, ID &id);
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
|
||||
#include "BLI_compiler_attrs.h"
|
||||
|
||||
#include "DNA_ID_enums.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
@ -22,6 +24,8 @@ typedef struct AssetRepresentation AssetRepresentation;
|
|||
|
||||
const char *AS_asset_representation_name_get(const AssetRepresentation *asset)
|
||||
ATTR_WARN_UNUSED_RESULT;
|
||||
ID_Type AS_asset_representation_id_type_get(const AssetRepresentation *asset)
|
||||
ATTR_WARN_UNUSED_RESULT;
|
||||
AssetMetaData *AS_asset_representation_metadata_get(const AssetRepresentation *asset)
|
||||
ATTR_WARN_UNUSED_RESULT;
|
||||
struct ID *AS_asset_representation_local_id_get(const AssetRepresentation *asset)
|
||||
|
@ -30,6 +34,9 @@ bool AS_asset_representation_is_local_id(const AssetRepresentation *asset) ATTR_
|
|||
bool AS_asset_representation_is_never_link(const AssetRepresentation *asset)
|
||||
ATTR_WARN_UNUSED_RESULT;
|
||||
|
||||
bool AS_asset_representation_may_override_import_method(const AssetRepresentation *asset);
|
||||
bool AS_asset_representation_use_relative_path_get(const AssetRepresentation *asset);
|
||||
|
||||
/**
|
||||
* C version of #AssetRepresentation::make_weak_reference. Returned pointer needs freeing with
|
||||
* #MEM_delete() or #BKE_asset_weak_reference_free().
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
#include "BLI_string_ref.hh"
|
||||
|
||||
#include "DNA_ID_enums.h"
|
||||
#include "DNA_asset_types.h"
|
||||
|
||||
#include "AS_asset_identifier.hh"
|
||||
|
@ -42,6 +43,7 @@ class AssetRepresentation {
|
|||
|
||||
struct ExternalAsset {
|
||||
std::string name;
|
||||
int id_type = 0;
|
||||
std::unique_ptr<AssetMetaData> metadata_ = nullptr;
|
||||
};
|
||||
union {
|
||||
|
@ -55,6 +57,7 @@ class AssetRepresentation {
|
|||
/** Constructs an asset representation for an external ID. The asset will not be editable. */
|
||||
AssetRepresentation(AssetIdentifier &&identifier,
|
||||
StringRef name,
|
||||
int id_type,
|
||||
std::unique_ptr<AssetMetaData> metadata,
|
||||
const AssetLibrary &owner_asset_library);
|
||||
/**
|
||||
|
@ -85,6 +88,7 @@ class AssetRepresentation {
|
|||
std::unique_ptr<AssetWeakReference> make_weak_reference() const;
|
||||
|
||||
StringRefNull get_name() const;
|
||||
ID_Type get_id_type() const;
|
||||
AssetMetaData &get_metadata() const;
|
||||
/**
|
||||
* Get the import method to use for this asset. A different one may be used if
|
||||
|
@ -114,6 +118,9 @@ class AssetRepresentation {
|
|||
/* C-Handle */
|
||||
struct AssetRepresentation;
|
||||
|
||||
const blender::StringRefNull AS_asset_representation_library_relative_identifier_get(
|
||||
const AssetRepresentation *asset_handle);
|
||||
|
||||
std::string AS_asset_representation_full_path_get(const ::AssetRepresentation *asset);
|
||||
/**
|
||||
* Get the absolute path to the .blend file containing the given asset. String will be empty if
|
||||
|
@ -123,5 +130,3 @@ std::string AS_asset_representation_full_path_get(const ::AssetRepresentation *a
|
|||
std::string AS_asset_representation_full_library_path_get(const ::AssetRepresentation *asset);
|
||||
std::optional<eAssetImportMethod> AS_asset_representation_import_method_get(
|
||||
const ::AssetRepresentation *asset_handle);
|
||||
bool AS_asset_representation_may_override_import_method(const ::AssetRepresentation *asset_handle);
|
||||
bool AS_asset_representation_use_relative_path_get(const ::AssetRepresentation *asset_handle);
|
||||
|
|
|
@ -230,11 +230,12 @@ void AssetLibrary::refresh()
|
|||
|
||||
AssetRepresentation &AssetLibrary::add_external_asset(StringRef relative_asset_path,
|
||||
StringRef name,
|
||||
const int id_type,
|
||||
std::unique_ptr<AssetMetaData> metadata)
|
||||
{
|
||||
AssetIdentifier identifier = asset_identifier_from_library(relative_asset_path);
|
||||
return asset_storage_->add_external_asset(
|
||||
std::move(identifier), name, std::move(metadata), *this);
|
||||
std::move(identifier), name, id_type, std::move(metadata), *this);
|
||||
}
|
||||
|
||||
AssetRepresentation &AssetLibrary::add_local_id_asset(StringRef relative_asset_path, ID &id)
|
||||
|
|
|
@ -21,6 +21,7 @@ namespace blender::asset_system {
|
|||
|
||||
AssetRepresentation::AssetRepresentation(AssetIdentifier &&identifier,
|
||||
StringRef name,
|
||||
const int id_type,
|
||||
std::unique_ptr<AssetMetaData> metadata,
|
||||
const AssetLibrary &owner_asset_library)
|
||||
: identifier_(identifier),
|
||||
|
@ -29,6 +30,7 @@ AssetRepresentation::AssetRepresentation(AssetIdentifier &&identifier,
|
|||
external_asset_()
|
||||
{
|
||||
external_asset_.name = name;
|
||||
external_asset_.id_type = id_type;
|
||||
external_asset_.metadata_ = std::move(metadata);
|
||||
}
|
||||
|
||||
|
@ -87,6 +89,15 @@ StringRefNull AssetRepresentation::get_name() const
|
|||
return external_asset_.name;
|
||||
}
|
||||
|
||||
ID_Type AssetRepresentation::get_id_type() const
|
||||
{
|
||||
if (is_local_id_) {
|
||||
return GS(local_asset_id_->name);
|
||||
}
|
||||
|
||||
return ID_Type(external_asset_.id_type);
|
||||
}
|
||||
|
||||
AssetMetaData &AssetRepresentation::get_metadata() const
|
||||
{
|
||||
return is_local_id_ ? *local_asset_id_->asset_data : *external_asset_.metadata_;
|
||||
|
@ -135,6 +146,15 @@ const AssetLibrary &AssetRepresentation::owner_asset_library() const
|
|||
|
||||
using namespace blender;
|
||||
|
||||
const StringRefNull AS_asset_representation_library_relative_identifier_get(
|
||||
const AssetRepresentation *asset_handle)
|
||||
{
|
||||
const asset_system::AssetRepresentation *asset =
|
||||
reinterpret_cast<const asset_system::AssetRepresentation *>(asset_handle);
|
||||
const asset_system::AssetIdentifier &identifier = asset->get_identifier();
|
||||
return identifier.library_relative_identifier();
|
||||
}
|
||||
|
||||
std::string AS_asset_representation_full_path_get(const AssetRepresentation *asset_handle)
|
||||
{
|
||||
const asset_system::AssetRepresentation *asset =
|
||||
|
@ -183,6 +203,13 @@ const char *AS_asset_representation_name_get(const AssetRepresentation *asset_ha
|
|||
return asset->get_name().c_str();
|
||||
}
|
||||
|
||||
ID_Type AS_asset_representation_id_type_get(const AssetRepresentation *asset_handle)
|
||||
{
|
||||
const asset_system::AssetRepresentation *asset =
|
||||
reinterpret_cast<const asset_system::AssetRepresentation *>(asset_handle);
|
||||
return asset->get_id_type();
|
||||
}
|
||||
|
||||
AssetMetaData *AS_asset_representation_metadata_get(const AssetRepresentation *asset_handle)
|
||||
{
|
||||
const asset_system::AssetRepresentation *asset =
|
||||
|
|
|
@ -27,11 +27,12 @@ AssetRepresentation &AssetStorage::add_local_id_asset(AssetIdentifier &&identifi
|
|||
|
||||
AssetRepresentation &AssetStorage::add_external_asset(AssetIdentifier &&identifier,
|
||||
StringRef name,
|
||||
const int id_type,
|
||||
std::unique_ptr<AssetMetaData> metadata,
|
||||
const AssetLibrary &owner_asset_library)
|
||||
{
|
||||
return *external_assets_.lookup_key_or_add(std::make_unique<AssetRepresentation>(
|
||||
std::move(identifier), name, std::move(metadata), owner_asset_library));
|
||||
std::move(identifier), name, id_type, std::move(metadata), owner_asset_library));
|
||||
}
|
||||
|
||||
bool AssetStorage::remove_asset(AssetRepresentation &asset)
|
||||
|
|
|
@ -37,6 +37,7 @@ class AssetStorage {
|
|||
/** See #AssetLibrary::add_external_asset(). */
|
||||
AssetRepresentation &add_external_asset(AssetIdentifier &&identifier,
|
||||
StringRef name,
|
||||
int id_type,
|
||||
std::unique_ptr<AssetMetaData> metadata,
|
||||
const AssetLibrary &owner_asset_library);
|
||||
/** See #AssetLibrary::add_external_asset(). */
|
||||
|
|
|
@ -32,7 +32,8 @@ class AssetRepresentationTest : public AssetLibraryTestBase {
|
|||
AssetRepresentation &add_dummy_asset(AssetLibrary &library, StringRef relative_path)
|
||||
{
|
||||
std::unique_ptr<AssetMetaData> dummy_metadata = std::make_unique<AssetMetaData>();
|
||||
return library.add_external_asset(relative_path, "Some asset name", std::move(dummy_metadata));
|
||||
return library.add_external_asset(
|
||||
relative_path, "Some asset name", 0, std::move(dummy_metadata));
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -27,13 +27,13 @@ extern "C" {
|
|||
|
||||
/* Blender file format version. */
|
||||
#define BLENDER_FILE_VERSION BLENDER_VERSION
|
||||
#define BLENDER_FILE_SUBVERSION 5
|
||||
#define BLENDER_FILE_SUBVERSION 6
|
||||
|
||||
/* Minimum Blender version that supports reading file written with the current
|
||||
* version. Older Blender versions will test this and show a warning if the file
|
||||
* was written with too new a version. */
|
||||
#define BLENDER_FILE_MIN_VERSION 400
|
||||
#define BLENDER_FILE_MIN_SUBVERSION 2
|
||||
#define BLENDER_FILE_MIN_SUBVERSION 3
|
||||
|
||||
/** User readable version string. */
|
||||
const char *BKE_blender_version_string(void);
|
||||
|
|
|
@ -180,8 +180,6 @@ struct Mesh *BKE_mesh_new_nomain_from_curve_displist(const struct Object *ob,
|
|||
|
||||
bool BKE_mesh_attribute_required(const char *name);
|
||||
|
||||
bool BKE_mesh_ensure_facemap_customdata(struct Mesh *me);
|
||||
bool BKE_mesh_clear_facemap_customdata(struct Mesh *me);
|
||||
|
||||
float (*BKE_mesh_orco_verts_get(struct Object *ob))[3];
|
||||
void BKE_mesh_orco_verts_transform(struct Mesh *me, float (*orco)[3], int totvert, int invert);
|
||||
|
|
|
@ -84,6 +84,8 @@ void BKE_mesh_legacy_convert_polys_to_offsets(Mesh *mesh);
|
|||
|
||||
void BKE_mesh_legacy_convert_loops_to_corners(struct Mesh *mesh);
|
||||
|
||||
void BKE_mesh_legacy_face_map_to_generic(struct Mesh *mesh);
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
|
@ -1112,6 +1112,7 @@ void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree, struct Scene *scene, i
|
|||
#define CMP_NODE_INPAINT 272
|
||||
#define CMP_NODE_DESPECKLE 273
|
||||
#define CMP_NODE_ANTIALIASING 274
|
||||
#define CMP_NODE_KUWAHARA 275
|
||||
|
||||
#define CMP_NODE_GLARE 301
|
||||
#define CMP_NODE_TONEMAP 302
|
||||
|
|
|
@ -1,37 +0,0 @@
|
|||
/* SPDX-FileCopyrightText: 2023 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma once
|
||||
|
||||
/** \file
|
||||
* \ingroup bke
|
||||
* \brief Functions for dealing with object face-maps.
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct ListBase;
|
||||
struct Object;
|
||||
struct bFaceMap;
|
||||
|
||||
struct bFaceMap *BKE_object_facemap_add(struct Object *ob);
|
||||
struct bFaceMap *BKE_object_facemap_add_name(struct Object *ob, const char *name);
|
||||
void BKE_object_facemap_remove(struct Object *ob, struct bFaceMap *fmap);
|
||||
void BKE_object_facemap_clear(struct Object *ob);
|
||||
|
||||
int BKE_object_facemap_name_index(struct Object *ob, const char *name);
|
||||
void BKE_object_facemap_unique_name(struct Object *ob, struct bFaceMap *fmap);
|
||||
struct bFaceMap *BKE_object_facemap_find_name(struct Object *ob, const char *name);
|
||||
void BKE_object_facemap_copy_list(struct ListBase *outbase, const struct ListBase *inbase);
|
||||
|
||||
int *BKE_object_facemap_index_map_create(struct Object *ob_src,
|
||||
struct Object *ob_dst,
|
||||
int *r_map_len);
|
||||
void BKE_object_facemap_index_map_apply(int *fmap, int fmap_len, const int *map, int map_len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
|
@ -241,7 +241,6 @@ set(SRC
|
|||
intern/object.cc
|
||||
intern/object_deform.c
|
||||
intern/object_dupli.cc
|
||||
intern/object_facemap.c
|
||||
intern/object_update.cc
|
||||
intern/ocean.c
|
||||
intern/ocean_spectrum.c
|
||||
|
@ -457,7 +456,6 @@ set(SRC
|
|||
BKE_node_tree_zones.hh
|
||||
BKE_object.h
|
||||
BKE_object_deform.h
|
||||
BKE_object_facemap.h
|
||||
BKE_ocean.h
|
||||
BKE_outliner_treehash.hh
|
||||
BKE_packedFile.h
|
||||
|
|
|
@ -1257,20 +1257,6 @@ static void layerSwap_flnor(void *data, const int *corner_indices)
|
|||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Callbacks for (`int`, #CD_FACEMAP)
|
||||
* \{ */
|
||||
|
||||
static void layerDefault_fmap(void *data, const int count)
|
||||
{
|
||||
int *fmap_num = (int *)data;
|
||||
for (int i = 0; i < count; i++) {
|
||||
fmap_num[i] = -1;
|
||||
}
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Callbacks for (#MPropCol, #CD_PROP_COLOR)
|
||||
* \{ */
|
||||
|
@ -1628,8 +1614,8 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
|
|||
nullptr,
|
||||
nullptr,
|
||||
layerCopyValue_normal},
|
||||
/* 9: CD_FACEMAP */
|
||||
{sizeof(int), "", 0, nullptr, nullptr, nullptr, nullptr, nullptr, layerDefault_fmap, nullptr},
|
||||
/* 9: CD_FACEMAP */ /* DEPRECATED */
|
||||
{sizeof(int), ""},
|
||||
/* 10: CD_PROP_FLOAT */
|
||||
{sizeof(MFloatProperty),
|
||||
"MFloatProperty",
|
||||
|
@ -1865,7 +1851,7 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
|
|||
/* 41: CD_CUSTOMLOOPNORMAL */
|
||||
{sizeof(short[2]), "vec2s", 1, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 42: CD_SCULPT_FACE_SETS */ /* DEPRECATED */
|
||||
{sizeof(int), "", 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
{sizeof(int), ""},
|
||||
/* 43: CD_LOCATION */
|
||||
{sizeof(float[3]), "vec3f", 1, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 44: CD_RADIUS */
|
||||
|
@ -2010,14 +1996,14 @@ const CustomData_MeshMasks CD_MASK_BAREMESH = {
|
|||
/*vmask*/ CD_MASK_PROP_FLOAT3,
|
||||
/*emask*/ CD_MASK_PROP_INT32_2D,
|
||||
/*fmask*/ 0,
|
||||
/*pmask*/ CD_MASK_FACEMAP,
|
||||
/*pmask*/ 0,
|
||||
/*lmask*/ CD_MASK_PROP_INT32,
|
||||
};
|
||||
const CustomData_MeshMasks CD_MASK_BAREMESH_ORIGINDEX = {
|
||||
/*vmask*/ CD_MASK_PROP_FLOAT3 | CD_MASK_ORIGINDEX,
|
||||
/*emask*/ CD_MASK_PROP_INT32_2D | CD_MASK_ORIGINDEX,
|
||||
/*fmask*/ 0,
|
||||
/*pmask*/ CD_MASK_FACEMAP | CD_MASK_ORIGINDEX,
|
||||
/*pmask*/ CD_MASK_ORIGINDEX,
|
||||
/*lmask*/ CD_MASK_PROP_INT32,
|
||||
};
|
||||
const CustomData_MeshMasks CD_MASK_MESH = {
|
||||
|
@ -2027,7 +2013,7 @@ const CustomData_MeshMasks CD_MASK_MESH = {
|
|||
(CD_MASK_FREESTYLE_EDGE | CD_MASK_PROP_ALL | CD_MASK_CREASE),
|
||||
/*fmask*/ 0,
|
||||
/*pmask*/
|
||||
(CD_MASK_FACEMAP | CD_MASK_FREESTYLE_FACE | CD_MASK_PROP_ALL),
|
||||
(CD_MASK_FREESTYLE_FACE | CD_MASK_PROP_ALL),
|
||||
/*lmask*/
|
||||
(CD_MASK_MDISPS | CD_MASK_CUSTOMLOOPNORMAL | CD_MASK_GRID_PAINT_MASK | CD_MASK_PROP_ALL),
|
||||
};
|
||||
|
@ -2039,7 +2025,7 @@ const CustomData_MeshMasks CD_MASK_DERIVEDMESH = {
|
|||
(CD_MASK_ORIGINDEX | CD_MASK_FREESTYLE_EDGE | CD_MASK_PROP_ALL | CD_MASK_CREASE),
|
||||
/*fmask*/ (CD_MASK_ORIGINDEX | CD_MASK_ORIGSPACE | CD_MASK_PREVIEW_MCOL | CD_MASK_TANGENT),
|
||||
/*pmask*/
|
||||
(CD_MASK_ORIGINDEX | CD_MASK_FREESTYLE_FACE | CD_MASK_FACEMAP | CD_MASK_PROP_ALL),
|
||||
(CD_MASK_ORIGINDEX | CD_MASK_FREESTYLE_FACE | CD_MASK_PROP_ALL),
|
||||
/*lmask*/
|
||||
(CD_MASK_CUSTOMLOOPNORMAL | CD_MASK_PREVIEW_MLOOPCOL | CD_MASK_ORIGSPACE_MLOOP |
|
||||
CD_MASK_PROP_ALL), /* XXX: MISSING #CD_MASK_MLOOPTANGENT ? */
|
||||
|
@ -2050,7 +2036,7 @@ const CustomData_MeshMasks CD_MASK_BMESH = {
|
|||
/*emask*/ (CD_MASK_CREASE | CD_MASK_FREESTYLE_EDGE | CD_MASK_PROP_ALL),
|
||||
/*fmask*/ 0,
|
||||
/*pmask*/
|
||||
(CD_MASK_FREESTYLE_FACE | CD_MASK_FACEMAP | CD_MASK_PROP_ALL),
|
||||
(CD_MASK_FREESTYLE_FACE | CD_MASK_PROP_ALL),
|
||||
/*lmask*/
|
||||
(CD_MASK_MDISPS | CD_MASK_CUSTOMLOOPNORMAL | CD_MASK_GRID_PAINT_MASK | CD_MASK_PROP_ALL),
|
||||
};
|
||||
|
@ -2066,8 +2052,7 @@ const CustomData_MeshMasks CD_MASK_EVERYTHING = {
|
|||
CD_MASK_ORIGSPACE | CD_MASK_TANGENT | CD_MASK_TESSLOOPNORMAL | CD_MASK_PREVIEW_MCOL |
|
||||
CD_MASK_PROP_ALL),
|
||||
/*pmask*/
|
||||
(CD_MASK_BM_ELEM_PYPTR | CD_MASK_ORIGINDEX | CD_MASK_FACEMAP | CD_MASK_FREESTYLE_FACE |
|
||||
CD_MASK_PROP_ALL),
|
||||
(CD_MASK_BM_ELEM_PYPTR | CD_MASK_ORIGINDEX | CD_MASK_FREESTYLE_FACE | CD_MASK_PROP_ALL),
|
||||
/*lmask*/
|
||||
(CD_MASK_BM_ELEM_PYPTR | CD_MASK_MDISPS | CD_MASK_NORMAL | CD_MASK_CUSTOMLOOPNORMAL |
|
||||
CD_MASK_MLOOPTANGENT | CD_MASK_PREVIEW_MLOOPCOL | CD_MASK_ORIGSPACE_MLOOP |
|
||||
|
@ -5169,9 +5154,6 @@ void CustomData_blend_write(BlendWriter *writer,
|
|||
case CD_GRID_PAINT_MASK:
|
||||
write_grid_paint_mask(writer, count, static_cast<const GridPaintMask *>(layer.data));
|
||||
break;
|
||||
case CD_FACEMAP:
|
||||
BLO_write_raw(writer, sizeof(int) * count, static_cast<const int *>(layer.data));
|
||||
break;
|
||||
case CD_PROP_BOOL:
|
||||
BLO_write_raw(writer, sizeof(bool) * count, static_cast<const bool *>(layer.data));
|
||||
break;
|
||||
|
|
|
@ -18,8 +18,6 @@
|
|||
|
||||
#include "attribute_access_intern.hh"
|
||||
|
||||
using blender::GVArray;
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Geometry Component Implementation
|
||||
* \{ */
|
||||
|
@ -292,47 +290,43 @@ std::optional<eAttrDomain> CurveLengthFieldInput::preferred_domain(
|
|||
|
||||
/** \} */
|
||||
|
||||
} // namespace blender::bke
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Attribute Access Helper Functions
|
||||
* \{ */
|
||||
|
||||
static void tag_component_topology_changed(void *owner)
|
||||
{
|
||||
blender::bke::CurvesGeometry &curves = *static_cast<blender::bke::CurvesGeometry *>(owner);
|
||||
CurvesGeometry &curves = *static_cast<CurvesGeometry *>(owner);
|
||||
curves.tag_topology_changed();
|
||||
}
|
||||
|
||||
static void tag_component_curve_types_changed(void *owner)
|
||||
{
|
||||
blender::bke::CurvesGeometry &curves = *static_cast<blender::bke::CurvesGeometry *>(owner);
|
||||
CurvesGeometry &curves = *static_cast<CurvesGeometry *>(owner);
|
||||
curves.update_curve_types();
|
||||
curves.tag_topology_changed();
|
||||
}
|
||||
|
||||
static void tag_component_positions_changed(void *owner)
|
||||
{
|
||||
blender::bke::CurvesGeometry &curves = *static_cast<blender::bke::CurvesGeometry *>(owner);
|
||||
CurvesGeometry &curves = *static_cast<CurvesGeometry *>(owner);
|
||||
curves.tag_positions_changed();
|
||||
}
|
||||
|
||||
static void tag_component_radii_changed(void *owner)
|
||||
{
|
||||
blender::bke::CurvesGeometry &curves = *static_cast<blender::bke::CurvesGeometry *>(owner);
|
||||
CurvesGeometry &curves = *static_cast<CurvesGeometry *>(owner);
|
||||
curves.tag_radii_changed();
|
||||
}
|
||||
|
||||
static void tag_component_normals_changed(void *owner)
|
||||
{
|
||||
blender::bke::CurvesGeometry &curves = *static_cast<blender::bke::CurvesGeometry *>(owner);
|
||||
CurvesGeometry &curves = *static_cast<CurvesGeometry *>(owner);
|
||||
curves.tag_normals_changed();
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
namespace blender::bke {
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Attribute Provider Declaration
|
||||
* \{ */
|
||||
|
@ -590,7 +584,7 @@ static AttributeAccessorFunctions get_curves_accessor_functions()
|
|||
return ELEM(domain, ATTR_DOMAIN_POINT, ATTR_DOMAIN_CURVE);
|
||||
};
|
||||
fn.adapt_domain = [](const void *owner,
|
||||
const blender::GVArray &varray,
|
||||
const GVArray &varray,
|
||||
const eAttrDomain from_domain,
|
||||
const eAttrDomain to_domain) -> GVArray {
|
||||
if (owner == nullptr) {
|
||||
|
|
|
@ -24,17 +24,6 @@
|
|||
|
||||
#include "BLI_cpp_type_make.hh"
|
||||
|
||||
using blender::float4x4;
|
||||
using blender::GSpan;
|
||||
using blender::IndexMask;
|
||||
using blender::Map;
|
||||
using blender::MutableSpan;
|
||||
using blender::Set;
|
||||
using blender::Span;
|
||||
using blender::VectorSet;
|
||||
using blender::bke::InstanceReference;
|
||||
using blender::bke::Instances;
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Geometry Component Implementation
|
||||
* \{ */
|
||||
|
@ -50,7 +39,7 @@ GeometryComponent *InstancesComponent::copy() const
|
|||
{
|
||||
InstancesComponent *new_component = new InstancesComponent();
|
||||
if (instances_ != nullptr) {
|
||||
new_component->instances_ = new Instances(*instances_);
|
||||
new_component->instances_ = new blender::bke::Instances(*instances_);
|
||||
new_component->ownership_ = GeometryOwnershipType::Owned;
|
||||
}
|
||||
return new_component;
|
||||
|
@ -99,13 +88,14 @@ blender::bke::Instances *InstancesComponent::get_for_write()
|
|||
{
|
||||
BLI_assert(this->is_mutable());
|
||||
if (ownership_ == GeometryOwnershipType::ReadOnly) {
|
||||
instances_ = new Instances(*instances_);
|
||||
instances_ = new blender::bke::Instances(*instances_);
|
||||
ownership_ = GeometryOwnershipType::Owned;
|
||||
}
|
||||
return instances_;
|
||||
}
|
||||
|
||||
void InstancesComponent::replace(Instances *instances, GeometryOwnershipType ownership)
|
||||
void InstancesComponent::replace(blender::bke::Instances *instances,
|
||||
GeometryOwnershipType ownership)
|
||||
{
|
||||
BLI_assert(this->is_mutable());
|
||||
this->clear();
|
||||
|
@ -233,13 +223,13 @@ static AttributeAccessorFunctions get_instances_accessor_functions()
|
|||
return domain == ATTR_DOMAIN_INSTANCE;
|
||||
};
|
||||
fn.adapt_domain = [](const void * /*owner*/,
|
||||
const blender::GVArray &varray,
|
||||
const GVArray &varray,
|
||||
const eAttrDomain from_domain,
|
||||
const eAttrDomain to_domain) {
|
||||
if (from_domain == to_domain && from_domain == ATTR_DOMAIN_INSTANCE) {
|
||||
return varray;
|
||||
}
|
||||
return blender::GVArray{};
|
||||
return GVArray{};
|
||||
};
|
||||
return fn;
|
||||
}
|
||||
|
|
|
@ -21,8 +21,6 @@
|
|||
|
||||
#include "attribute_access_intern.hh"
|
||||
|
||||
extern "C" MDeformVert *BKE_object_defgroup_data_create(ID *id);
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Geometry Component Implementation
|
||||
* \{ */
|
||||
|
@ -158,16 +156,12 @@ VArray<float3> mesh_normals_varray(const Mesh &mesh,
|
|||
}
|
||||
}
|
||||
|
||||
} // namespace blender::bke
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Attribute Access
|
||||
* \{ */
|
||||
|
||||
namespace blender::bke {
|
||||
|
||||
template<typename T>
|
||||
static void adapt_mesh_domain_corner_to_point_impl(const Mesh &mesh,
|
||||
const VArray<T> &old_values,
|
||||
|
@ -740,8 +734,6 @@ static GVArray adapt_mesh_domain_edge_to_face(const Mesh &mesh, const GVArray &v
|
|||
return new_varray;
|
||||
}
|
||||
|
||||
} // namespace blender::bke
|
||||
|
||||
static bool can_simple_adapt_for_single(const Mesh &mesh,
|
||||
const eAttrDomain from_domain,
|
||||
const eAttrDomain to_domain)
|
||||
|
@ -780,10 +772,10 @@ static bool can_simple_adapt_for_single(const Mesh &mesh,
|
|||
}
|
||||
}
|
||||
|
||||
static blender::GVArray adapt_mesh_attribute_domain(const Mesh &mesh,
|
||||
const blender::GVArray &varray,
|
||||
const eAttrDomain from_domain,
|
||||
const eAttrDomain to_domain)
|
||||
static GVArray adapt_mesh_attribute_domain(const Mesh &mesh,
|
||||
const GVArray &varray,
|
||||
const eAttrDomain from_domain,
|
||||
const eAttrDomain to_domain)
|
||||
{
|
||||
if (!varray) {
|
||||
return {};
|
||||
|
@ -798,8 +790,7 @@ static blender::GVArray adapt_mesh_attribute_domain(const Mesh &mesh,
|
|||
if (can_simple_adapt_for_single(mesh, from_domain, to_domain)) {
|
||||
BUFFER_FOR_CPP_TYPE_VALUE(varray.type(), value);
|
||||
varray.get_internal_single(value);
|
||||
return blender::GVArray::ForSingle(
|
||||
varray.type(), mesh.attributes().domain_size(to_domain), value);
|
||||
return GVArray::ForSingle(varray.type(), mesh.attributes().domain_size(to_domain), value);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -807,11 +798,11 @@ static blender::GVArray adapt_mesh_attribute_domain(const Mesh &mesh,
|
|||
case ATTR_DOMAIN_CORNER: {
|
||||
switch (to_domain) {
|
||||
case ATTR_DOMAIN_POINT:
|
||||
return blender::bke::adapt_mesh_domain_corner_to_point(mesh, varray);
|
||||
return adapt_mesh_domain_corner_to_point(mesh, varray);
|
||||
case ATTR_DOMAIN_FACE:
|
||||
return blender::bke::adapt_mesh_domain_corner_to_face(mesh, varray);
|
||||
return adapt_mesh_domain_corner_to_face(mesh, varray);
|
||||
case ATTR_DOMAIN_EDGE:
|
||||
return blender::bke::adapt_mesh_domain_corner_to_edge(mesh, varray);
|
||||
return adapt_mesh_domain_corner_to_edge(mesh, varray);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -820,11 +811,11 @@ static blender::GVArray adapt_mesh_attribute_domain(const Mesh &mesh,
|
|||
case ATTR_DOMAIN_POINT: {
|
||||
switch (to_domain) {
|
||||
case ATTR_DOMAIN_CORNER:
|
||||
return blender::bke::adapt_mesh_domain_point_to_corner(mesh, varray);
|
||||
return adapt_mesh_domain_point_to_corner(mesh, varray);
|
||||
case ATTR_DOMAIN_FACE:
|
||||
return blender::bke::adapt_mesh_domain_point_to_face(mesh, varray);
|
||||
return adapt_mesh_domain_point_to_face(mesh, varray);
|
||||
case ATTR_DOMAIN_EDGE:
|
||||
return blender::bke::adapt_mesh_domain_point_to_edge(mesh, varray);
|
||||
return adapt_mesh_domain_point_to_edge(mesh, varray);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -833,11 +824,11 @@ static blender::GVArray adapt_mesh_attribute_domain(const Mesh &mesh,
|
|||
case ATTR_DOMAIN_FACE: {
|
||||
switch (to_domain) {
|
||||
case ATTR_DOMAIN_POINT:
|
||||
return blender::bke::adapt_mesh_domain_face_to_point(mesh, varray);
|
||||
return adapt_mesh_domain_face_to_point(mesh, varray);
|
||||
case ATTR_DOMAIN_CORNER:
|
||||
return blender::bke::adapt_mesh_domain_face_to_corner(mesh, varray);
|
||||
return adapt_mesh_domain_face_to_corner(mesh, varray);
|
||||
case ATTR_DOMAIN_EDGE:
|
||||
return blender::bke::adapt_mesh_domain_face_to_edge(mesh, varray);
|
||||
return adapt_mesh_domain_face_to_edge(mesh, varray);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -846,11 +837,11 @@ static blender::GVArray adapt_mesh_attribute_domain(const Mesh &mesh,
|
|||
case ATTR_DOMAIN_EDGE: {
|
||||
switch (to_domain) {
|
||||
case ATTR_DOMAIN_CORNER:
|
||||
return blender::bke::adapt_mesh_domain_edge_to_corner(mesh, varray);
|
||||
return adapt_mesh_domain_edge_to_corner(mesh, varray);
|
||||
case ATTR_DOMAIN_POINT:
|
||||
return blender::bke::adapt_mesh_domain_edge_to_point(mesh, varray);
|
||||
return adapt_mesh_domain_edge_to_point(mesh, varray);
|
||||
case ATTR_DOMAIN_FACE:
|
||||
return blender::bke::adapt_mesh_domain_edge_to_face(mesh, varray);
|
||||
return adapt_mesh_domain_edge_to_face(mesh, varray);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -863,8 +854,6 @@ static blender::GVArray adapt_mesh_attribute_domain(const Mesh &mesh,
|
|||
return {};
|
||||
}
|
||||
|
||||
namespace blender::bke {
|
||||
|
||||
static void tag_component_positions_changed(void *owner)
|
||||
{
|
||||
Mesh *mesh = static_cast<Mesh *>(owner);
|
||||
|
@ -1269,9 +1258,9 @@ static AttributeAccessorFunctions get_mesh_accessor_functions()
|
|||
return ELEM(domain, ATTR_DOMAIN_POINT, ATTR_DOMAIN_EDGE, ATTR_DOMAIN_FACE, ATTR_DOMAIN_CORNER);
|
||||
};
|
||||
fn.adapt_domain = [](const void *owner,
|
||||
const blender::GVArray &varray,
|
||||
const GVArray &varray,
|
||||
const eAttrDomain from_domain,
|
||||
const eAttrDomain to_domain) -> blender::GVArray {
|
||||
const eAttrDomain to_domain) -> GVArray {
|
||||
if (owner == nullptr) {
|
||||
return {};
|
||||
}
|
||||
|
|
|
@ -808,44 +808,6 @@ void BKE_mesh_ensure_skin_customdata(Mesh *me)
|
|||
}
|
||||
}
|
||||
|
||||
bool BKE_mesh_ensure_facemap_customdata(Mesh *me)
|
||||
{
|
||||
BMesh *bm = me->edit_mesh ? me->edit_mesh->bm : nullptr;
|
||||
bool changed = false;
|
||||
if (bm) {
|
||||
if (!CustomData_has_layer(&bm->pdata, CD_FACEMAP)) {
|
||||
BM_data_layer_add(bm, &bm->pdata, CD_FACEMAP);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!CustomData_has_layer(&me->pdata, CD_FACEMAP)) {
|
||||
CustomData_add_layer(&me->pdata, CD_FACEMAP, CD_SET_DEFAULT, me->totpoly);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
bool BKE_mesh_clear_facemap_customdata(Mesh *me)
|
||||
{
|
||||
BMesh *bm = me->edit_mesh ? me->edit_mesh->bm : nullptr;
|
||||
bool changed = false;
|
||||
if (bm) {
|
||||
if (CustomData_has_layer(&bm->pdata, CD_FACEMAP)) {
|
||||
BM_data_layer_free(bm, &bm->pdata, CD_FACEMAP);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (CustomData_has_layer(&me->pdata, CD_FACEMAP)) {
|
||||
CustomData_free_layers(&me->pdata, CD_FACEMAP, me->totpoly);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
bool BKE_mesh_has_custom_loop_normals(Mesh *me)
|
||||
{
|
||||
if (me->edit_mesh) {
|
||||
|
|
|
@ -1305,6 +1305,40 @@ void BKE_mesh_legacy_face_set_to_generic(Mesh *mesh)
|
|||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Face Map Conversion
|
||||
* \{ */
|
||||
|
||||
void BKE_mesh_legacy_face_map_to_generic(Mesh *mesh)
|
||||
{
|
||||
using namespace blender;
|
||||
if (mesh->attributes().contains("face_maps")) {
|
||||
return;
|
||||
}
|
||||
void *data = nullptr;
|
||||
const ImplicitSharingInfo *sharing_info = nullptr;
|
||||
for (const int i : IndexRange(mesh->pdata.totlayer)) {
|
||||
CustomDataLayer &layer = mesh->pdata.layers[i];
|
||||
if (layer.type == CD_FACEMAP) {
|
||||
data = layer.data;
|
||||
sharing_info = layer.sharing_info;
|
||||
layer.data = nullptr;
|
||||
layer.sharing_info = nullptr;
|
||||
CustomData_free_layer(&mesh->pdata, CD_FACEMAP, mesh->totpoly, i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (data != nullptr) {
|
||||
CustomData_add_layer_named_with_data(
|
||||
&mesh->pdata, CD_PROP_INT32, data, mesh->totpoly, "face_maps", sharing_info);
|
||||
}
|
||||
if (sharing_info != nullptr) {
|
||||
sharing_info->remove_user_and_delete_if_last();
|
||||
}
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Bevel Weight Conversion
|
||||
* \{ */
|
||||
|
|
|
@ -16,9 +16,9 @@
|
|||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "BLI_array.hh"
|
||||
#include "BLI_array_utils.hh"
|
||||
#include "BLI_index_range.hh"
|
||||
#include "BLI_math_vector.h"
|
||||
#include "BLI_math_vector_types.hh"
|
||||
#include "BLI_span.hh"
|
||||
#include "BLI_task.hh"
|
||||
|
||||
|
@ -27,6 +27,7 @@
|
|||
|
||||
#include "BKE_attribute.h"
|
||||
#include "BKE_attribute.hh"
|
||||
#include "BKE_attribute_math.hh"
|
||||
#include "BKE_bvhutils.h"
|
||||
#include "BKE_customdata.h"
|
||||
#include "BKE_editmesh.h"
|
||||
|
@ -35,6 +36,7 @@
|
|||
#include "BKE_mesh_mapping.h"
|
||||
#include "BKE_mesh_remesh_voxel.h" /* own include */
|
||||
#include "BKE_mesh_runtime.h"
|
||||
#include "BKE_mesh_sample.hh"
|
||||
|
||||
#include "bmesh_tools.h"
|
||||
|
||||
|
@ -360,116 +362,104 @@ void BKE_remesh_reproject_sculpt_face_sets(Mesh *target, const Mesh *source)
|
|||
|
||||
void BKE_remesh_reproject_vertex_paint(Mesh *target, const Mesh *source)
|
||||
{
|
||||
BVHTreeFromMesh bvhtree = {nullptr};
|
||||
BKE_bvhtree_from_mesh_get(&bvhtree, source, BVHTREE_FROM_VERTS, 2);
|
||||
using namespace blender;
|
||||
using namespace blender::bke;
|
||||
const AttributeAccessor src_attributes = source->attributes();
|
||||
MutableAttributeAccessor dst_attributes = target->attributes_for_write();
|
||||
|
||||
int i = 0;
|
||||
const CustomDataLayer *layer;
|
||||
Vector<AttributeIDRef> point_ids;
|
||||
Vector<AttributeIDRef> corner_ids;
|
||||
source->attributes().for_all([&](const AttributeIDRef &id, const AttributeMetaData &meta_data) {
|
||||
if (CD_TYPE_AS_MASK(meta_data.data_type) & CD_MASK_COLOR_ALL) {
|
||||
if (meta_data.domain == ATTR_DOMAIN_POINT) {
|
||||
point_ids.append(id);
|
||||
}
|
||||
else if (meta_data.domain == ATTR_DOMAIN_CORNER) {
|
||||
corner_ids.append(id);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
if (point_ids.is_empty() && corner_ids.is_empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Array<int> source_vert_to_loop_offsets;
|
||||
Array<int> source_vert_to_loop_indices;
|
||||
blender::GroupedSpan<int> source_lmap;
|
||||
|
||||
GroupedSpan<int> source_lmap;
|
||||
Array<int> target_vert_to_loop_offsets;
|
||||
Array<int> target_vert_to_loop_indices;
|
||||
blender::GroupedSpan<int> target_lmap;
|
||||
GroupedSpan<int> target_lmap;
|
||||
BVHTreeFromMesh bvhtree = {nullptr};
|
||||
threading::parallel_invoke(
|
||||
[&]() { BKE_bvhtree_from_mesh_get(&bvhtree, source, BVHTREE_FROM_VERTS, 2); },
|
||||
[&]() {
|
||||
source_lmap = mesh::build_vert_to_loop_map(source->corner_verts(),
|
||||
source->totvert,
|
||||
source_vert_to_loop_offsets,
|
||||
source_vert_to_loop_indices);
|
||||
},
|
||||
[&]() {
|
||||
target_lmap = mesh::build_vert_to_loop_map(target->corner_verts(),
|
||||
target->totvert,
|
||||
target_vert_to_loop_offsets,
|
||||
target_vert_to_loop_indices);
|
||||
});
|
||||
|
||||
while ((layer = BKE_id_attribute_from_index(
|
||||
const_cast<ID *>(&source->id), i++, ATTR_DOMAIN_MASK_COLOR, CD_MASK_COLOR_ALL)))
|
||||
{
|
||||
eAttrDomain domain = BKE_id_attribute_domain(&source->id, layer);
|
||||
const eCustomDataType type = eCustomDataType(layer->type);
|
||||
|
||||
CustomData *target_cdata = domain == ATTR_DOMAIN_POINT ? &target->vdata : &target->ldata;
|
||||
const CustomData *source_cdata = domain == ATTR_DOMAIN_POINT ? &source->vdata : &source->ldata;
|
||||
|
||||
/* Check attribute exists in target. */
|
||||
int layer_i = CustomData_get_named_layer_index(target_cdata, type, layer->name);
|
||||
if (layer_i == -1) {
|
||||
int elem_num = domain == ATTR_DOMAIN_POINT ? target->totvert : target->totloop;
|
||||
|
||||
CustomData_add_layer_named(target_cdata, type, CD_SET_DEFAULT, elem_num, layer->name);
|
||||
layer_i = CustomData_get_named_layer_index(target_cdata, type, layer->name);
|
||||
const Span<float3> target_positions = target->vert_positions();
|
||||
Array<int> nearest_src_verts(target_positions.size());
|
||||
threading::parallel_for(target_positions.index_range(), 1024, [&](const IndexRange range) {
|
||||
for (const int i : range) {
|
||||
BVHTreeNearest nearest;
|
||||
nearest.index = -1;
|
||||
nearest.dist_sq = FLT_MAX;
|
||||
BLI_bvhtree_find_nearest(
|
||||
bvhtree.tree, target_positions[i], &nearest, bvhtree.nearest_callback, &bvhtree);
|
||||
nearest_src_verts[i] = nearest.index;
|
||||
}
|
||||
});
|
||||
|
||||
size_t data_size = CustomData_sizeof(type);
|
||||
void *target_data = target_cdata->layers[layer_i].data;
|
||||
void *source_data = layer->data;
|
||||
const Span<float3> target_positions = target->vert_positions();
|
||||
for (const AttributeIDRef &id : point_ids) {
|
||||
const GVArraySpan src = *src_attributes.lookup(id, ATTR_DOMAIN_POINT);
|
||||
GSpanAttributeWriter dst = dst_attributes.lookup_or_add_for_write_only_span(
|
||||
id, ATTR_DOMAIN_POINT, cpp_type_to_custom_data_type(src.type()));
|
||||
attribute_math::gather(src, nearest_src_verts, dst.span);
|
||||
dst.finish();
|
||||
}
|
||||
|
||||
if (domain == ATTR_DOMAIN_POINT) {
|
||||
blender::threading::parallel_for(
|
||||
IndexRange(target->totvert), 4096, [&](const IndexRange range) {
|
||||
for (const int i : range) {
|
||||
BVHTreeNearest nearest;
|
||||
nearest.index = -1;
|
||||
nearest.dist_sq = FLT_MAX;
|
||||
BLI_bvhtree_find_nearest(
|
||||
bvhtree.tree, target_positions[i], &nearest, bvhtree.nearest_callback, &bvhtree);
|
||||
if (nearest.index != -1) {
|
||||
memcpy(POINTER_OFFSET(target_data, size_t(i) * data_size),
|
||||
POINTER_OFFSET(source_data, size_t(nearest.index) * data_size),
|
||||
data_size);
|
||||
if (!corner_ids.is_empty()) {
|
||||
for (const AttributeIDRef &id : corner_ids) {
|
||||
const GVArraySpan src = *src_attributes.lookup(id, ATTR_DOMAIN_CORNER);
|
||||
GSpanAttributeWriter dst = dst_attributes.lookup_or_add_for_write_only_span(
|
||||
id, ATTR_DOMAIN_CORNER, cpp_type_to_custom_data_type(src.type()));
|
||||
|
||||
threading::parallel_for(target_positions.index_range(), 1024, [&](const IndexRange range) {
|
||||
src.type().to_static_type_tag<ColorGeometry4b, ColorGeometry4f>([&](auto type_tag) {
|
||||
using T = typename decltype(type_tag)::type;
|
||||
if constexpr (std::is_void_v<T>) {
|
||||
BLI_assert_unreachable();
|
||||
}
|
||||
else {
|
||||
const Span<T> src_typed = src.typed<T>();
|
||||
MutableSpan<T> dst_typed = dst.span.typed<T>();
|
||||
for (const int dst_vert : range) {
|
||||
/* Find the average value at the corners of the closest vertex on the
|
||||
* source mesh. */
|
||||
const int src_vert = nearest_src_verts[dst_vert];
|
||||
T value;
|
||||
typename blender::bke::attribute_math::DefaultMixer<T> mixer({&value, 1});
|
||||
for (const int corner : source_lmap[src_vert]) {
|
||||
mixer.mix_in(0, src_typed[corner]);
|
||||
}
|
||||
|
||||
dst_typed.fill_indices(target_lmap[dst_vert], value);
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
/* Lazily init vertex -> loop maps. */
|
||||
if (source_lmap.is_empty()) {
|
||||
source_lmap = blender::bke::mesh::build_vert_to_loop_map(source->corner_verts(),
|
||||
source->totvert,
|
||||
source_vert_to_loop_offsets,
|
||||
source_vert_to_loop_indices);
|
||||
target_lmap = blender::bke::mesh::build_vert_to_loop_map(target->corner_verts(),
|
||||
target->totvert,
|
||||
target_vert_to_loop_offsets,
|
||||
target_vert_to_loop_indices);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
blender::threading::parallel_for(
|
||||
IndexRange(target->totvert), 2048, [&](const IndexRange range) {
|
||||
for (const int i : range) {
|
||||
BVHTreeNearest nearest;
|
||||
nearest.index = -1;
|
||||
nearest.dist_sq = FLT_MAX;
|
||||
BLI_bvhtree_find_nearest(
|
||||
bvhtree.tree, target_positions[i], &nearest, bvhtree.nearest_callback, &bvhtree);
|
||||
|
||||
if (nearest.index == -1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const Span<int> source_loops = source_lmap[nearest.index];
|
||||
const Span<int> target_loops = target_lmap[i];
|
||||
|
||||
if (target_loops.size() == 0 || source_loops.size() == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Average color data for loops around the source vertex into
|
||||
* the first target loop around the target vertex
|
||||
*/
|
||||
|
||||
CustomData_interp(source_cdata,
|
||||
target_cdata,
|
||||
source_loops.data(),
|
||||
nullptr,
|
||||
nullptr,
|
||||
source_loops.size(),
|
||||
target_loops[0]);
|
||||
|
||||
void *elem = POINTER_OFFSET(target_data, size_t(target_loops[0]) * data_size);
|
||||
|
||||
/* Copy to rest of target loops. */
|
||||
for (int j = 1; j < target_loops.size(); j++) {
|
||||
memcpy(POINTER_OFFSET(target_data, size_t(target_loops[j]) * data_size),
|
||||
elem,
|
||||
data_size);
|
||||
}
|
||||
}
|
||||
});
|
||||
dst.finish();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -759,6 +759,10 @@ class NodeTreeMainUpdater {
|
|||
|
||||
LISTBASE_FOREACH (bNodeLink *, link, &ntree.links) {
|
||||
link->flag |= NODE_LINK_VALID;
|
||||
if (!link->fromsock->is_available() || !link->tosock->is_available()) {
|
||||
link->flag &= ~NODE_LINK_VALID;
|
||||
continue;
|
||||
}
|
||||
const bNode &from_node = *link->fromnode;
|
||||
const bNode &to_node = *link->tonode;
|
||||
if (toposort_indices[from_node.index()] > toposort_indices[to_node.index()]) {
|
||||
|
|
|
@ -114,7 +114,6 @@
|
|||
#include "BKE_multires.h"
|
||||
#include "BKE_node.hh"
|
||||
#include "BKE_object.h"
|
||||
#include "BKE_object_facemap.h"
|
||||
#include "BKE_paint.h"
|
||||
#include "BKE_particle.h"
|
||||
#include "BKE_pbvh.h"
|
||||
|
@ -233,7 +232,6 @@ static void object_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const in
|
|||
}
|
||||
}
|
||||
|
||||
BKE_object_facemap_copy_list(&ob_dst->fmaps, &ob_src->fmaps);
|
||||
BKE_constraints_copy_ex(&ob_dst->constraints, &ob_src->constraints, flag_subdata, true);
|
||||
|
||||
ob_dst->mode = ob_dst->type != OB_GPENCIL_LEGACY ? OB_MODE_OBJECT : ob_dst->mode;
|
||||
|
@ -302,7 +300,6 @@ static void object_free_data(ID *id)
|
|||
MEM_SAFE_FREE(ob->iuser);
|
||||
MEM_SAFE_FREE(ob->runtime.bb);
|
||||
|
||||
BLI_freelistN(&ob->fmaps);
|
||||
if (ob->pose) {
|
||||
BKE_pose_free_ex(ob->pose, false);
|
||||
ob->pose = nullptr;
|
||||
|
@ -546,13 +543,6 @@ static void object_foreach_path(ID *id, BPathForeachPathData *bpath_data)
|
|||
}
|
||||
}
|
||||
|
||||
static void write_fmaps(BlendWriter *writer, ListBase *fbase)
|
||||
{
|
||||
LISTBASE_FOREACH (bFaceMap *, fmap, fbase) {
|
||||
BLO_write_struct(writer, bFaceMap, fmap);
|
||||
}
|
||||
}
|
||||
|
||||
static void object_blend_write(BlendWriter *writer, ID *id, const void *id_address)
|
||||
{
|
||||
Object *ob = (Object *)id;
|
||||
|
@ -586,7 +576,6 @@ static void object_blend_write(BlendWriter *writer, ID *id, const void *id_addre
|
|||
}
|
||||
|
||||
BKE_pose_blend_write(writer, ob->pose, arm);
|
||||
write_fmaps(writer, &ob->fmaps);
|
||||
BKE_constraint_blend_write(writer, &ob->constraints);
|
||||
animviz_motionpath_blend_write(writer, ob->mpath);
|
||||
|
||||
|
@ -682,7 +671,6 @@ static void object_blend_read_data(BlendDataReader *reader, ID *id)
|
|||
/* Only for versioning, vertex group names are now stored on object data. */
|
||||
BLO_read_list(reader, &ob->defbase);
|
||||
|
||||
BLO_read_list(reader, &ob->fmaps);
|
||||
/* XXX deprecated - old animation system <<< */
|
||||
direct_link_nlastrips(reader, &ob->nlastrips);
|
||||
BLO_read_list(reader, &ob->constraintChannels);
|
||||
|
|
|
@ -1,286 +0,0 @@
|
|||
/* SPDX-FileCopyrightText: 2008 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup bke
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "DNA_mesh_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
|
||||
#include "BLI_listbase.h"
|
||||
#include "BLI_string.h"
|
||||
#include "BLI_string_utils.h"
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
#include "BKE_customdata.h"
|
||||
#include "BKE_editmesh.h"
|
||||
#include "BKE_object.h"
|
||||
#include "BKE_object_deform.h"
|
||||
#include "BKE_object_facemap.h" /* own include */
|
||||
|
||||
#include "BLT_translation.h"
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "RNA_access.h"
|
||||
#include "RNA_define.h"
|
||||
|
||||
static bool fmap_unique_check(void *arg, const char *name)
|
||||
{
|
||||
struct {
|
||||
Object *ob;
|
||||
void *fm;
|
||||
} *data = arg;
|
||||
|
||||
bFaceMap *fmap;
|
||||
|
||||
for (fmap = data->ob->fmaps.first; fmap; fmap = fmap->next) {
|
||||
if (data->fm != fmap) {
|
||||
if (STREQ(fmap->name, name)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bFaceMap *fmap_duplicate(bFaceMap *infmap)
|
||||
{
|
||||
bFaceMap *outfmap;
|
||||
|
||||
if (!infmap) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
outfmap = MEM_callocN(sizeof(bFaceMap), "copy facemap");
|
||||
|
||||
/* For now, just copy everything over. */
|
||||
memcpy(outfmap, infmap, sizeof(bFaceMap));
|
||||
|
||||
outfmap->next = outfmap->prev = NULL;
|
||||
|
||||
return outfmap;
|
||||
}
|
||||
|
||||
void BKE_object_facemap_copy_list(ListBase *outbase, const ListBase *inbase)
|
||||
{
|
||||
bFaceMap *fmap, *fmapn;
|
||||
|
||||
BLI_listbase_clear(outbase);
|
||||
|
||||
for (fmap = inbase->first; fmap; fmap = fmap->next) {
|
||||
fmapn = fmap_duplicate(fmap);
|
||||
BLI_addtail(outbase, fmapn);
|
||||
}
|
||||
}
|
||||
|
||||
void BKE_object_facemap_unique_name(Object *ob, bFaceMap *fmap)
|
||||
{
|
||||
struct {
|
||||
Object *ob;
|
||||
void *fmap;
|
||||
} data;
|
||||
data.ob = ob;
|
||||
data.fmap = fmap;
|
||||
|
||||
BLI_uniquename_cb(fmap_unique_check, &data, DATA_("Group"), '.', fmap->name, sizeof(fmap->name));
|
||||
}
|
||||
|
||||
bFaceMap *BKE_object_facemap_add_name(Object *ob, const char *name)
|
||||
{
|
||||
bFaceMap *fmap;
|
||||
|
||||
if (!ob || ob->type != OB_MESH) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fmap = MEM_callocN(sizeof(bFaceMap), __func__);
|
||||
|
||||
STRNCPY(fmap->name, name);
|
||||
|
||||
BLI_addtail(&ob->fmaps, fmap);
|
||||
|
||||
ob->actfmap = BLI_listbase_count(&ob->fmaps);
|
||||
|
||||
BKE_object_facemap_unique_name(ob, fmap);
|
||||
|
||||
return fmap;
|
||||
}
|
||||
|
||||
bFaceMap *BKE_object_facemap_add(Object *ob)
|
||||
{
|
||||
return BKE_object_facemap_add_name(ob, DATA_("FaceMap"));
|
||||
}
|
||||
|
||||
static void object_fmap_remove_edit_mode(Object *ob, bFaceMap *fmap, bool do_selected, bool purge)
|
||||
{
|
||||
const int fmap_nr = BLI_findindex(&ob->fmaps, fmap);
|
||||
|
||||
if (ob->type == OB_MESH) {
|
||||
Mesh *me = ob->data;
|
||||
|
||||
if (me->edit_mesh) {
|
||||
BMEditMesh *em = me->edit_mesh;
|
||||
const int cd_fmap_offset = CustomData_get_offset(&em->bm->pdata, CD_FACEMAP);
|
||||
|
||||
if (cd_fmap_offset != -1) {
|
||||
BMFace *efa;
|
||||
BMIter iter;
|
||||
int *map;
|
||||
|
||||
if (purge) {
|
||||
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
|
||||
map = BM_ELEM_CD_GET_VOID_P(efa, cd_fmap_offset);
|
||||
|
||||
if (map) {
|
||||
if (*map == fmap_nr) {
|
||||
*map = -1;
|
||||
}
|
||||
else if (*map > fmap_nr) {
|
||||
*map -= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
|
||||
map = BM_ELEM_CD_GET_VOID_P(efa, cd_fmap_offset);
|
||||
|
||||
if (map && *map == fmap_nr && (!do_selected || BM_elem_flag_test(efa, BM_ELEM_SELECT)))
|
||||
{
|
||||
*map = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ob->actfmap == BLI_listbase_count(&ob->fmaps)) {
|
||||
ob->actfmap--;
|
||||
}
|
||||
|
||||
BLI_remlink(&ob->fmaps, fmap);
|
||||
MEM_freeN(fmap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void object_fmap_remove_object_mode(Object *ob, bFaceMap *fmap, bool purge)
|
||||
{
|
||||
const int fmap_nr = BLI_findindex(&ob->fmaps, fmap);
|
||||
|
||||
if (ob->type == OB_MESH) {
|
||||
Mesh *me = ob->data;
|
||||
|
||||
if (CustomData_has_layer(&me->pdata, CD_FACEMAP)) {
|
||||
int *map = CustomData_get_layer_for_write(&me->pdata, CD_FACEMAP, me->totpoly);
|
||||
int i;
|
||||
|
||||
if (map) {
|
||||
for (i = 0; i < me->totpoly; i++) {
|
||||
if (map[i] == fmap_nr) {
|
||||
map[i] = -1;
|
||||
}
|
||||
else if (purge && map[i] > fmap_nr) {
|
||||
map[i]--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ob->actfmap == BLI_listbase_count(&ob->fmaps)) {
|
||||
ob->actfmap--;
|
||||
}
|
||||
|
||||
BLI_remlink(&ob->fmaps, fmap);
|
||||
MEM_freeN(fmap);
|
||||
}
|
||||
}
|
||||
|
||||
static void fmap_remove_exec(Object *ob, bFaceMap *fmap, const bool is_edit_mode, const bool purge)
|
||||
{
|
||||
if (is_edit_mode) {
|
||||
object_fmap_remove_edit_mode(ob, fmap, false, purge);
|
||||
}
|
||||
else {
|
||||
object_fmap_remove_object_mode(ob, fmap, purge);
|
||||
}
|
||||
}
|
||||
|
||||
void BKE_object_facemap_remove(Object *ob, bFaceMap *fmap)
|
||||
{
|
||||
fmap_remove_exec(ob, fmap, BKE_object_is_in_editmode(ob), true);
|
||||
}
|
||||
|
||||
void BKE_object_facemap_clear(Object *ob)
|
||||
{
|
||||
bFaceMap *fmap = (bFaceMap *)ob->fmaps.first;
|
||||
|
||||
if (fmap) {
|
||||
const bool edit_mode = BKE_object_is_in_editmode_vgroup(ob);
|
||||
|
||||
while (fmap) {
|
||||
bFaceMap *next_fmap = fmap->next;
|
||||
fmap_remove_exec(ob, fmap, edit_mode, false);
|
||||
fmap = next_fmap;
|
||||
}
|
||||
}
|
||||
/* remove all face-maps */
|
||||
if (ob->type == OB_MESH) {
|
||||
Mesh *me = ob->data;
|
||||
CustomData_free_layer(&me->pdata, CD_FACEMAP, me->totpoly, 0);
|
||||
}
|
||||
ob->actfmap = 0;
|
||||
}
|
||||
|
||||
int BKE_object_facemap_name_index(Object *ob, const char *name)
|
||||
{
|
||||
return (name) ? BLI_findstringindex(&ob->fmaps, name, offsetof(bFaceMap, name)) : -1;
|
||||
}
|
||||
|
||||
bFaceMap *BKE_object_facemap_find_name(Object *ob, const char *name)
|
||||
{
|
||||
return BLI_findstring(&ob->fmaps, name, offsetof(bFaceMap, name));
|
||||
}
|
||||
|
||||
int *BKE_object_facemap_index_map_create(Object *ob_src, Object *ob_dst, int *r_map_len)
|
||||
{
|
||||
/* Build src to merged mapping of facemap indices. */
|
||||
if (BLI_listbase_is_empty(&ob_src->fmaps) || BLI_listbase_is_empty(&ob_dst->fmaps)) {
|
||||
*r_map_len = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*r_map_len = BLI_listbase_count(&ob_src->fmaps);
|
||||
int *fmap_index_map = MEM_malloc_arrayN(
|
||||
*r_map_len, sizeof(*fmap_index_map), "defgroup index map create");
|
||||
bool is_fmap_remap_needed = false;
|
||||
|
||||
int i = 0;
|
||||
for (bFaceMap *fmap_src = ob_src->fmaps.first; fmap_src; fmap_src = fmap_src->next, i++) {
|
||||
fmap_index_map[i] = BKE_object_facemap_name_index(ob_dst, fmap_src->name);
|
||||
is_fmap_remap_needed = is_fmap_remap_needed || (fmap_index_map[i] != i);
|
||||
}
|
||||
|
||||
if (!is_fmap_remap_needed) {
|
||||
MEM_freeN(fmap_index_map);
|
||||
fmap_index_map = NULL;
|
||||
*r_map_len = 0;
|
||||
}
|
||||
|
||||
return fmap_index_map;
|
||||
}
|
||||
|
||||
void BKE_object_facemap_index_map_apply(int *fmap, int fmap_len, const int *map, int map_len)
|
||||
{
|
||||
if (map == NULL || map_len == 0) {
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < fmap_len; i++, fmap++) {
|
||||
*fmap = (*fmap < map_len && *fmap != -1) ? map[*fmap] : -1;
|
||||
}
|
||||
}
|
|
@ -1569,7 +1569,6 @@ static void set_ccgdm_all_geometry(CCGDerivedMesh *ccgdm,
|
|||
loopindex2);
|
||||
loopindex2++;
|
||||
|
||||
/* Copy over poly data, e.g. #CD_FACEMAP. */
|
||||
CustomData_copy_data(&dm->polyData, &ccgdm->dm.polyData, origIndex, faceNum, 1);
|
||||
|
||||
if (polyOrigIndex) {
|
||||
|
|
|
@ -179,94 +179,98 @@ static void libmv_frame_to_normalized_relative(const float frame_coord[2],
|
|||
/** \name Conversion of markers between Blender's DNA and Libmv.
|
||||
* \{ */
|
||||
|
||||
static void dna_marker_to_libmv_marker(/*const*/ MovieTrackingTrack *track,
|
||||
const MovieTrackingMarker *marker,
|
||||
int clip,
|
||||
int track_index,
|
||||
int frame_width,
|
||||
int frame_height,
|
||||
bool backwards,
|
||||
libmv_Marker *libmv_marker)
|
||||
static libmv_Marker dna_marker_to_libmv_marker(/*const*/ MovieTrackingTrack &track,
|
||||
const MovieTrackingMarker &marker,
|
||||
const int clip,
|
||||
const int track_index,
|
||||
const int frame_width,
|
||||
const int frame_height,
|
||||
const bool backwards)
|
||||
{
|
||||
const int frame_dimensions[2] = {frame_width, frame_height};
|
||||
libmv_marker->clip = clip;
|
||||
libmv_marker->frame = marker->framenr;
|
||||
libmv_marker->track = track_index;
|
||||
libmv_Marker libmv_marker{};
|
||||
|
||||
normalized_to_libmv_frame(marker->pos, frame_dimensions, libmv_marker->center);
|
||||
const int frame_dimensions[2] = {frame_width, frame_height};
|
||||
libmv_marker.clip = clip;
|
||||
libmv_marker.frame = marker.framenr;
|
||||
libmv_marker.track = track_index;
|
||||
|
||||
normalized_to_libmv_frame(marker.pos, frame_dimensions, libmv_marker.center);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
normalized_relative_to_libmv_frame(
|
||||
marker->pattern_corners[i], marker->pos, frame_dimensions, libmv_marker->patch[i]);
|
||||
marker.pattern_corners[i], marker.pos, frame_dimensions, libmv_marker.patch[i]);
|
||||
}
|
||||
|
||||
normalized_relative_to_libmv_frame(
|
||||
marker->search_min, marker->pos, frame_dimensions, libmv_marker->search_region_min);
|
||||
marker.search_min, marker.pos, frame_dimensions, libmv_marker.search_region_min);
|
||||
|
||||
normalized_relative_to_libmv_frame(
|
||||
marker->search_max, marker->pos, frame_dimensions, libmv_marker->search_region_max);
|
||||
marker.search_max, marker.pos, frame_dimensions, libmv_marker.search_region_max);
|
||||
|
||||
/* NOTE: All the markers does have 1.0 weight.
|
||||
* Might support in the future, but will require more elaborated process which will involve
|
||||
* F-Curve evaluation. */
|
||||
libmv_marker->weight = 1.0f;
|
||||
libmv_marker.weight = 1.0f;
|
||||
|
||||
if (marker->flag & MARKER_TRACKED) {
|
||||
libmv_marker->source = LIBMV_MARKER_SOURCE_TRACKED;
|
||||
if (marker.flag & MARKER_TRACKED) {
|
||||
libmv_marker.source = LIBMV_MARKER_SOURCE_TRACKED;
|
||||
}
|
||||
else {
|
||||
libmv_marker->source = LIBMV_MARKER_SOURCE_MANUAL;
|
||||
libmv_marker.source = LIBMV_MARKER_SOURCE_MANUAL;
|
||||
}
|
||||
libmv_marker->status = LIBMV_MARKER_STATUS_UNKNOWN;
|
||||
libmv_marker->model_type = LIBMV_MARKER_MODEL_TYPE_POINT;
|
||||
libmv_marker->model_id = 0;
|
||||
libmv_marker.status = LIBMV_MARKER_STATUS_UNKNOWN;
|
||||
libmv_marker.model_type = LIBMV_MARKER_MODEL_TYPE_POINT;
|
||||
libmv_marker.model_id = 0;
|
||||
|
||||
/* NOTE: We currently don't support reference marker from different clip. */
|
||||
libmv_marker->reference_clip = clip;
|
||||
libmv_marker.reference_clip = clip;
|
||||
|
||||
if (track->pattern_match == TRACK_MATCH_KEYFRAME) {
|
||||
if (track.pattern_match == TRACK_MATCH_KEYFRAME) {
|
||||
const MovieTrackingMarker *keyframe_marker = tracking_get_keyframed_marker(
|
||||
track, marker->framenr, backwards);
|
||||
libmv_marker->reference_frame = keyframe_marker->framenr;
|
||||
&track, marker.framenr, backwards);
|
||||
libmv_marker.reference_frame = keyframe_marker->framenr;
|
||||
}
|
||||
else {
|
||||
libmv_marker->reference_frame = backwards ? marker->framenr - 1 : marker->framenr;
|
||||
libmv_marker.reference_frame = backwards ? marker.framenr - 1 : marker.framenr;
|
||||
}
|
||||
|
||||
libmv_marker->disabled_channels =
|
||||
((track->flag & TRACK_DISABLE_RED) ? LIBMV_MARKER_CHANNEL_R : 0) |
|
||||
((track->flag & TRACK_DISABLE_GREEN) ? LIBMV_MARKER_CHANNEL_G : 0) |
|
||||
((track->flag & TRACK_DISABLE_BLUE) ? LIBMV_MARKER_CHANNEL_B : 0);
|
||||
libmv_marker.disabled_channels =
|
||||
((track.flag & TRACK_DISABLE_RED) ? LIBMV_MARKER_CHANNEL_R : 0) |
|
||||
((track.flag & TRACK_DISABLE_GREEN) ? LIBMV_MARKER_CHANNEL_G : 0) |
|
||||
((track.flag & TRACK_DISABLE_BLUE) ? LIBMV_MARKER_CHANNEL_B : 0);
|
||||
|
||||
return libmv_marker;
|
||||
}
|
||||
|
||||
static void libmv_marker_to_dna_marker(libmv_Marker *libmv_marker,
|
||||
int frame_width,
|
||||
int frame_height,
|
||||
MovieTrackingMarker *marker)
|
||||
static MovieTrackingMarker libmv_marker_to_dna_marker(const libmv_Marker &libmv_marker,
|
||||
const int frame_width,
|
||||
const int frame_height)
|
||||
{
|
||||
const int frame_dimensions[2] = {frame_width, frame_height};
|
||||
marker->framenr = libmv_marker->frame;
|
||||
MovieTrackingMarker marker{};
|
||||
|
||||
libmv_frame_to_normalized(libmv_marker->center, frame_dimensions, marker->pos);
|
||||
const int frame_dimensions[2] = {frame_width, frame_height};
|
||||
marker.framenr = libmv_marker.frame;
|
||||
|
||||
libmv_frame_to_normalized(libmv_marker.center, frame_dimensions, marker.pos);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
libmv_frame_to_normalized_relative(libmv_marker->patch[i],
|
||||
libmv_marker->center,
|
||||
frame_dimensions,
|
||||
marker->pattern_corners[i]);
|
||||
libmv_frame_to_normalized_relative(
|
||||
libmv_marker.patch[i], libmv_marker.center, frame_dimensions, marker.pattern_corners[i]);
|
||||
}
|
||||
|
||||
libmv_frame_to_normalized_relative(
|
||||
libmv_marker->search_region_min, libmv_marker->center, frame_dimensions, marker->search_min);
|
||||
libmv_marker.search_region_min, libmv_marker.center, frame_dimensions, marker.search_min);
|
||||
|
||||
libmv_frame_to_normalized_relative(
|
||||
libmv_marker->search_region_max, libmv_marker->center, frame_dimensions, marker->search_max);
|
||||
libmv_marker.search_region_max, libmv_marker.center, frame_dimensions, marker.search_max);
|
||||
|
||||
marker->flag = 0;
|
||||
if (libmv_marker->source == LIBMV_MARKER_SOURCE_TRACKED) {
|
||||
marker->flag |= MARKER_TRACKED;
|
||||
marker.flag = 0;
|
||||
if (libmv_marker.source == LIBMV_MARKER_SOURCE_TRACKED) {
|
||||
marker.flag |= MARKER_TRACKED;
|
||||
}
|
||||
else {
|
||||
marker->flag &= ~MARKER_TRACKED;
|
||||
marker.flag &= ~MARKER_TRACKED;
|
||||
}
|
||||
|
||||
return marker;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
@ -279,29 +283,28 @@ static void libmv_marker_to_dna_marker(libmv_Marker *libmv_marker,
|
|||
* \{ */
|
||||
|
||||
/* Returns false if marker crossed margin area from frame bounds. */
|
||||
static bool tracking_check_marker_margin(const libmv_Marker *libmv_marker,
|
||||
int margin,
|
||||
int frame_width,
|
||||
int frame_height)
|
||||
static bool tracking_check_marker_margin(const libmv_Marker &libmv_marker,
|
||||
const int margin,
|
||||
const int frame_width,
|
||||
const int frame_height)
|
||||
{
|
||||
float patch_min[2], patch_max[2];
|
||||
float margin_left, margin_top, margin_right, margin_bottom;
|
||||
|
||||
INIT_MINMAX2(patch_min, patch_max);
|
||||
minmax_v2v2_v2(patch_min, patch_max, libmv_marker->patch[0]);
|
||||
minmax_v2v2_v2(patch_min, patch_max, libmv_marker->patch[1]);
|
||||
minmax_v2v2_v2(patch_min, patch_max, libmv_marker->patch[2]);
|
||||
minmax_v2v2_v2(patch_min, patch_max, libmv_marker->patch[3]);
|
||||
minmax_v2v2_v2(patch_min, patch_max, libmv_marker.patch[0]);
|
||||
minmax_v2v2_v2(patch_min, patch_max, libmv_marker.patch[1]);
|
||||
minmax_v2v2_v2(patch_min, patch_max, libmv_marker.patch[2]);
|
||||
minmax_v2v2_v2(patch_min, patch_max, libmv_marker.patch[3]);
|
||||
|
||||
margin_left = max_ff(libmv_marker->center[0] - patch_min[0], margin);
|
||||
margin_top = max_ff(patch_max[1] - libmv_marker->center[1], margin);
|
||||
margin_right = max_ff(patch_max[0] - libmv_marker->center[0], margin);
|
||||
margin_bottom = max_ff(libmv_marker->center[1] - patch_min[1], margin);
|
||||
margin_left = max_ff(libmv_marker.center[0] - patch_min[0], margin);
|
||||
margin_top = max_ff(patch_max[1] - libmv_marker.center[1], margin);
|
||||
margin_right = max_ff(patch_max[0] - libmv_marker.center[0], margin);
|
||||
margin_bottom = max_ff(libmv_marker.center[1] - patch_min[1], margin);
|
||||
|
||||
if (libmv_marker->center[0] < margin_left ||
|
||||
libmv_marker->center[0] > frame_width - margin_right ||
|
||||
libmv_marker->center[1] < margin_bottom ||
|
||||
libmv_marker->center[1] > frame_height - margin_top)
|
||||
if (libmv_marker.center[0] < margin_left ||
|
||||
libmv_marker.center[0] > frame_width - margin_right ||
|
||||
libmv_marker.center[1] < margin_bottom || libmv_marker.center[1] > frame_height - margin_top)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -315,9 +318,9 @@ static bool tracking_check_marker_margin(const libmv_Marker *libmv_marker,
|
|||
/** \name Auto-Track Context Initialization
|
||||
* \{ */
|
||||
|
||||
static bool autotrack_is_marker_usable(const MovieTrackingMarker *marker)
|
||||
static bool autotrack_is_marker_usable(const MovieTrackingMarker &marker)
|
||||
{
|
||||
if (marker->flag & MARKER_DISABLED) {
|
||||
if (marker.flag & MARKER_DISABLED) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
@ -334,7 +337,7 @@ static bool autotrack_is_track_trackable(const AutoTrackContext *context,
|
|||
clip, context->start_scene_frame);
|
||||
|
||||
const MovieTrackingMarker *marker = BKE_tracking_marker_get(track, clip_frame_number);
|
||||
return autotrack_is_marker_usable(marker);
|
||||
return autotrack_is_marker_usable(*marker);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -430,7 +433,7 @@ static size_t autotrack_count_all_usable_markers(AutoTrackContext *context)
|
|||
for (int track_index = 0; track_index < context->num_all_tracks; ++track_index) {
|
||||
const MovieTrackingTrack *track = context->all_autotrack_tracks[track_index].track;
|
||||
for (int marker_index = 0; marker_index < track->markersnr; ++marker_index) {
|
||||
const MovieTrackingMarker *marker = &track->markers[marker_index];
|
||||
const MovieTrackingMarker &marker = track->markers[marker_index];
|
||||
if (!autotrack_is_marker_usable(marker)) {
|
||||
continue;
|
||||
}
|
||||
|
@ -475,21 +478,21 @@ static void autotrack_context_init_autotrack(AutoTrackContext *context)
|
|||
int num_filled_libmv_markers = 0;
|
||||
for (int track_index = 0; track_index < context->num_all_tracks; ++track_index) {
|
||||
const AutoTrackTrack *autotrack_track = &context->all_autotrack_tracks[track_index];
|
||||
/*const*/ MovieTrackingTrack *track = autotrack_track->track;
|
||||
for (int marker_index = 0; marker_index < track->markersnr; ++marker_index) {
|
||||
/*const*/ MovieTrackingMarker *marker = &track->markers[marker_index];
|
||||
/*const*/ MovieTrackingTrack &track = *autotrack_track->track;
|
||||
for (int marker_index = 0; marker_index < track.markersnr; ++marker_index) {
|
||||
/*const*/ MovieTrackingMarker &marker = track.markers[marker_index];
|
||||
if (!autotrack_is_marker_usable(marker)) {
|
||||
continue;
|
||||
}
|
||||
const AutoTrackClip *autotrack_clip = &context->autotrack_clips[autotrack_track->clip_index];
|
||||
dna_marker_to_libmv_marker(track,
|
||||
marker,
|
||||
autotrack_track->clip_index,
|
||||
track_index,
|
||||
autotrack_clip->width,
|
||||
autotrack_clip->height,
|
||||
context->is_backwards,
|
||||
&libmv_markers[num_filled_libmv_markers++]);
|
||||
libmv_markers[num_filled_libmv_markers++] = dna_marker_to_libmv_marker(
|
||||
track,
|
||||
marker,
|
||||
autotrack_track->clip_index,
|
||||
track_index,
|
||||
autotrack_clip->width,
|
||||
autotrack_clip->height,
|
||||
context->is_backwards);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -525,18 +528,17 @@ static void autotrack_context_init_markers(AutoTrackContext *context)
|
|||
const int clip_frame_number = BKE_movieclip_remap_scene_to_clip_frame(
|
||||
clip, context->start_scene_frame);
|
||||
|
||||
/*const*/ MovieTrackingTrack *track = context->all_autotrack_tracks[track_index].track;
|
||||
const MovieTrackingMarker *marker = BKE_tracking_marker_get(track, clip_frame_number);
|
||||
/*const*/ MovieTrackingTrack &track = *context->all_autotrack_tracks[track_index].track;
|
||||
const MovieTrackingMarker &marker = *BKE_tracking_marker_get(&track, clip_frame_number);
|
||||
|
||||
AutoTrackMarker *autotrack_marker = &context->autotrack_markers[autotrack_marker_index++];
|
||||
dna_marker_to_libmv_marker(track,
|
||||
marker,
|
||||
autotrack_track->clip_index,
|
||||
track_index,
|
||||
autotrack_clip->width,
|
||||
autotrack_clip->height,
|
||||
context->is_backwards,
|
||||
&autotrack_marker->libmv_marker);
|
||||
autotrack_marker->libmv_marker = dna_marker_to_libmv_marker(track,
|
||||
marker,
|
||||
autotrack_track->clip_index,
|
||||
track_index,
|
||||
autotrack_clip->width,
|
||||
autotrack_clip->height,
|
||||
context->is_backwards);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -633,35 +635,35 @@ static void autotrack_context_step_cb(void *__restrict userdata,
|
|||
AutoTrackContext *context = static_cast<AutoTrackContext *>(userdata);
|
||||
AutoTrackTLS *autotrack_tls = (AutoTrackTLS *)tls->userdata_chunk;
|
||||
|
||||
const AutoTrackMarker *autotrack_marker = &context->autotrack_markers[marker_index];
|
||||
const libmv_Marker *libmv_current_marker = &autotrack_marker->libmv_marker;
|
||||
const AutoTrackMarker &autotrack_marker = context->autotrack_markers[marker_index];
|
||||
const libmv_Marker &libmv_current_marker = autotrack_marker.libmv_marker;
|
||||
|
||||
const int frame_delta = context->is_backwards ? -1 : 1;
|
||||
const int clip_index = libmv_current_marker->clip;
|
||||
const int track_index = libmv_current_marker->track;
|
||||
const int clip_index = libmv_current_marker.clip;
|
||||
const int track_index = libmv_current_marker.track;
|
||||
|
||||
const AutoTrackClip *autotrack_clip = &context->autotrack_clips[clip_index];
|
||||
const AutoTrackTrack *autotrack_track = &context->all_autotrack_tracks[track_index];
|
||||
const MovieTrackingTrack *track = autotrack_track->track;
|
||||
const AutoTrackClip &autotrack_clip = context->autotrack_clips[clip_index];
|
||||
const AutoTrackTrack &autotrack_track = context->all_autotrack_tracks[track_index];
|
||||
const MovieTrackingTrack &track = *autotrack_track.track;
|
||||
|
||||
/* Check whether marker is going outside of allowed frame margin. */
|
||||
if (!tracking_check_marker_margin(
|
||||
libmv_current_marker, track->margin, autotrack_clip->width, autotrack_clip->height))
|
||||
libmv_current_marker, track.margin, autotrack_clip.width, autotrack_clip.height))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const int new_marker_frame = libmv_current_marker->frame + frame_delta;
|
||||
const int new_marker_frame = libmv_current_marker.frame + frame_delta;
|
||||
|
||||
AutoTrackTrackingResult *autotrack_result = MEM_cnew<AutoTrackTrackingResult>(
|
||||
"autotrack result");
|
||||
autotrack_result->libmv_marker = *libmv_current_marker;
|
||||
autotrack_result->libmv_marker = libmv_current_marker;
|
||||
autotrack_result->libmv_marker.frame = new_marker_frame;
|
||||
|
||||
/* Update reference frame. */
|
||||
libmv_Marker libmv_reference_marker;
|
||||
if (track->pattern_match == TRACK_MATCH_KEYFRAME) {
|
||||
autotrack_result->libmv_marker.reference_frame = libmv_current_marker->reference_frame;
|
||||
if (track.pattern_match == TRACK_MATCH_KEYFRAME) {
|
||||
autotrack_result->libmv_marker.reference_frame = libmv_current_marker.reference_frame;
|
||||
libmv_autoTrackGetMarker(context->autotrack,
|
||||
clip_index,
|
||||
autotrack_result->libmv_marker.reference_frame,
|
||||
|
@ -669,14 +671,14 @@ static void autotrack_context_step_cb(void *__restrict userdata,
|
|||
&libmv_reference_marker);
|
||||
}
|
||||
else {
|
||||
BLI_assert(track->pattern_match == TRACK_MATCH_PREVIOS_FRAME);
|
||||
autotrack_result->libmv_marker.reference_frame = libmv_current_marker->frame;
|
||||
libmv_reference_marker = *libmv_current_marker;
|
||||
BLI_assert(track.pattern_match == TRACK_MATCH_PREVIOUS_FRAME);
|
||||
autotrack_result->libmv_marker.reference_frame = libmv_current_marker.frame;
|
||||
libmv_reference_marker = libmv_current_marker;
|
||||
}
|
||||
|
||||
/* Perform actual tracking. */
|
||||
autotrack_result->success = libmv_autoTrackMarker(context->autotrack,
|
||||
&autotrack_track->track_region_options,
|
||||
&autotrack_track.track_region_options,
|
||||
&autotrack_result->libmv_marker,
|
||||
&autotrack_result->libmv_result);
|
||||
|
||||
|
@ -684,7 +686,7 @@ static void autotrack_context_step_cb(void *__restrict userdata,
|
|||
* This is how Blender side is currently expecting failed track to be handled. Without this the
|
||||
* marker is left in an arbitrary position which did not provide good correlation. */
|
||||
if (!autotrack_result->success) {
|
||||
autotrack_result->libmv_marker = *libmv_current_marker;
|
||||
autotrack_result->libmv_marker = libmv_current_marker;
|
||||
autotrack_result->libmv_marker.frame = new_marker_frame;
|
||||
}
|
||||
|
||||
|
@ -768,22 +770,21 @@ void BKE_autotrack_context_sync(AutoTrackContext *context)
|
|||
BLI_spin_unlock(&context->spin_lock);
|
||||
|
||||
LISTBASE_FOREACH_MUTABLE (AutoTrackTrackingResult *, autotrack_result, &results_to_sync) {
|
||||
const libmv_Marker *libmv_marker = &autotrack_result->libmv_marker;
|
||||
const int clip_index = libmv_marker->clip;
|
||||
const int track_index = libmv_marker->track;
|
||||
const AutoTrackClip *autotrack_clip = &context->autotrack_clips[clip_index];
|
||||
const MovieClip *clip = autotrack_clip->clip;
|
||||
const AutoTrackTrack *autotrack_track = &context->all_autotrack_tracks[track_index];
|
||||
MovieTrackingTrack *track = autotrack_track->track;
|
||||
const libmv_Marker &libmv_marker = autotrack_result->libmv_marker;
|
||||
const int clip_index = libmv_marker.clip;
|
||||
const int track_index = libmv_marker.track;
|
||||
const AutoTrackClip &autotrack_clip = context->autotrack_clips[clip_index];
|
||||
const MovieClip *clip = autotrack_clip.clip;
|
||||
const AutoTrackTrack &autotrack_track = context->all_autotrack_tracks[track_index];
|
||||
MovieTrackingTrack *track = autotrack_track.track;
|
||||
|
||||
const int start_clip_frame = BKE_movieclip_remap_scene_to_clip_frame(
|
||||
clip, context->start_scene_frame);
|
||||
const int first_result_frame = start_clip_frame + frame_delta;
|
||||
|
||||
/* Insert marker which corresponds to the tracking result. */
|
||||
MovieTrackingMarker marker;
|
||||
libmv_marker_to_dna_marker(
|
||||
&autotrack_result->libmv_marker, autotrack_clip->width, autotrack_clip->height, &marker);
|
||||
MovieTrackingMarker marker = libmv_marker_to_dna_marker(
|
||||
autotrack_result->libmv_marker, autotrack_clip.width, autotrack_clip.height);
|
||||
if (!autotrack_result->success) {
|
||||
marker.flag |= MARKER_DISABLED;
|
||||
}
|
||||
|
|
|
@ -186,7 +186,7 @@ bool BLI_is_file(const char *path) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
|
|||
*/
|
||||
bool BLI_dir_create_recursive(const char *dir) ATTR_NONNULL();
|
||||
/**
|
||||
* Returns the number of free bytes on the volume containing the specified pathname.
|
||||
* Returns the number of free bytes on the volume containing the specified path.
|
||||
*
|
||||
* \note Not actually used anywhere.
|
||||
*/
|
||||
|
|
|
@ -74,12 +74,6 @@ template<typename T> struct AngleRadianBase {
|
|||
|
||||
/** Methods. */
|
||||
|
||||
/* 'mod_inline(-3, 4)= 1', 'fmod(-3, 4)= -3' */
|
||||
static float mod_inline(float a, float b)
|
||||
{
|
||||
return a - (b * floorf(a / b));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the angle wrapped inside [-pi..pi] interval. Basically `(angle + pi) % 2pi - pi`.
|
||||
*/
|
||||
|
|
|
@ -171,6 +171,11 @@ template<typename T> inline T pow(const T &x, const T &power)
|
|||
return std::pow(x, power);
|
||||
}
|
||||
|
||||
template<typename T> inline T exp(const T &x)
|
||||
{
|
||||
return std::exp(x);
|
||||
}
|
||||
|
||||
template<typename T> inline T safe_acos(const T &a)
|
||||
{
|
||||
if (UNLIKELY(a <= T(-1))) {
|
||||
|
|
|
@ -680,7 +680,7 @@ template<typename T> QuaternionBase<T> QuaternionBase<T>::expmap(const VecBase<T
|
|||
T angle;
|
||||
const VecBase<T, 3> axis = normalize_and_get_length(expmap, angle);
|
||||
if (LIKELY(angle != T(0))) {
|
||||
return to_quaternion(AxisAngleT(axis, angle_wrap_rad(angle)));
|
||||
return to_quaternion(AxisAngleT(axis, AngleRadianBase<T>(angle).wrapped()));
|
||||
}
|
||||
return QuaternionBase<T>::identity();
|
||||
}
|
||||
|
|
|
@ -162,6 +162,11 @@ template<typename T> struct QuaternionBase {
|
|||
return (a.w == b.w) && (a.x == b.x) && (a.y == b.y) && (a.z == b.z);
|
||||
}
|
||||
|
||||
uint64_t hash() const
|
||||
{
|
||||
return VecBase<T, 4>(*this).hash();
|
||||
}
|
||||
|
||||
friend std::ostream &operator<<(std::ostream &stream, const QuaternionBase &rot)
|
||||
{
|
||||
return stream << "Quaternion" << static_cast<VecBase<T, 4>>(rot);
|
||||
|
|
|
@ -206,6 +206,16 @@ template<typename T, int Size>
|
|||
return result;
|
||||
}
|
||||
|
||||
/* Per-element exponent. */
|
||||
template<typename T, int Size> [[nodiscard]] inline VecBase<T, Size> exp(const VecBase<T, Size> &x)
|
||||
{
|
||||
VecBase<T, Size> result;
|
||||
for (int i = 0; i < Size; i++) {
|
||||
result[i] = math::exp(x[i]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns \a a if it is a multiple of \a b or the next multiple or \a b after \b a .
|
||||
* In other words, it is equivalent to `divide_ceil(a, b) * b`.
|
||||
|
|
|
@ -34,7 +34,7 @@ extern "C" {
|
|||
#define BLI_STR_FORMAT_INT32_INTEGER_UNIT_SIZE 5
|
||||
|
||||
/**
|
||||
* Duplicates the first \a len bytes of cstring \a str
|
||||
* Duplicates the first \a len bytes of the C-string \a str
|
||||
* into a newly mallocN'd string and returns it. \a str
|
||||
* is assumed to be at least len bytes long.
|
||||
*
|
||||
|
@ -45,7 +45,7 @@ extern "C" {
|
|||
char *BLI_strdupn(const char *str, size_t len) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
|
||||
|
||||
/**
|
||||
* Duplicates the cstring \a str into a newly mallocN'd
|
||||
* Duplicates the C-string \a str into a newly mallocN'd
|
||||
* string and returns it.
|
||||
*
|
||||
* \param str: The string to be duplicated
|
||||
|
|
|
@ -172,4 +172,13 @@ TEST(math_vector, safe_rcp)
|
|||
EXPECT_NEAR(result.z, 0.25f, 1e-6f);
|
||||
}
|
||||
|
||||
TEST(math_vector, exp)
|
||||
{
|
||||
const float3 a(1.0f, 2.0f, 3.0f);
|
||||
const float3 result = math::exp(a);
|
||||
EXPECT_NEAR(result.x, 2.718281828459045f, 1e-6f);
|
||||
EXPECT_NEAR(result.y, 7.38905609893065f, 1e-6f);
|
||||
EXPECT_NEAR(result.z, 20.085536923187668f, 1e-6f);
|
||||
}
|
||||
|
||||
} // namespace blender::tests
|
||||
|
|
|
@ -76,7 +76,10 @@ typedef struct BlendFileReadWMSetupData {
|
|||
/** The existing WM when filereading process is started. */
|
||||
struct wmWindowManager *old_wm;
|
||||
|
||||
/** The startup file is being read. */
|
||||
bool is_read_homefile;
|
||||
/** The factory startup file is being read. */
|
||||
bool is_factory_startup;
|
||||
} BlendFileReadWMSetupData;
|
||||
|
||||
struct BlendFileReadParams {
|
||||
|
|
|
@ -184,14 +184,30 @@ void blo_do_versions_400(FileData *fd, Library * /*lib*/, Main *bmain)
|
|||
|
||||
if (!MAIN_VERSION_ATLEAST(bmain, 400, 5)) {
|
||||
LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
|
||||
ToolSettings *ts = scene->toolsettings;
|
||||
if (ts->snap_mode_tools != SCE_SNAP_MODE_NONE) {
|
||||
ts->snap_mode_tools = SCE_SNAP_MODE_GEOM;
|
||||
}
|
||||
|
||||
#define SCE_SNAP_PROJECT (1 << 3)
|
||||
if (scene->toolsettings->snap_flag & SCE_SNAP_PROJECT) {
|
||||
scene->toolsettings->snap_mode |= SCE_SNAP_MODE_FACE_RAYCAST;
|
||||
if (ts->snap_flag & SCE_SNAP_PROJECT) {
|
||||
ts->snap_mode |= SCE_SNAP_MODE_FACE_RAYCAST;
|
||||
}
|
||||
#undef SCE_SNAP_PROJECT
|
||||
}
|
||||
}
|
||||
|
||||
if (!MAIN_VERSION_ATLEAST(bmain, 400, 6)) {
|
||||
LISTBASE_FOREACH (Mesh *, mesh, &bmain->meshes) {
|
||||
BKE_mesh_legacy_face_map_to_generic(mesh);
|
||||
}
|
||||
FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
|
||||
versioning_replace_legacy_glossy_node(ntree);
|
||||
versioning_remove_microfacet_sharp_distribution(ntree);
|
||||
}
|
||||
FOREACH_NODETREE_END;
|
||||
}
|
||||
|
||||
/**
|
||||
* Versioning code until next subversion bump goes here.
|
||||
*
|
||||
|
@ -206,11 +222,6 @@ void blo_do_versions_400(FileData *fd, Library * /*lib*/, Main *bmain)
|
|||
*/
|
||||
{
|
||||
/* Convert anisotropic BSDF node to glossy BSDF. */
|
||||
FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
|
||||
versioning_replace_legacy_glossy_node(ntree);
|
||||
versioning_remove_microfacet_sharp_distribution(ntree);
|
||||
}
|
||||
FOREACH_NODETREE_END;
|
||||
|
||||
/* Keep this block, even when empty. */
|
||||
}
|
||||
|
|
|
@ -72,7 +72,7 @@ set(SRC
|
|||
intern/bmesh_edgeloop.c
|
||||
intern/bmesh_edgeloop.h
|
||||
intern/bmesh_inline.h
|
||||
intern/bmesh_interp.c
|
||||
intern/bmesh_interp.cc
|
||||
intern/bmesh_interp.h
|
||||
intern/bmesh_iterators.cc
|
||||
intern/bmesh_iterators.h
|
||||
|
|
|
@ -35,7 +35,7 @@ typedef struct BMEdgeLoopStore {
|
|||
#define EDGELOOP_EPS 1e-10f
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/* BM_mesh_edgeloops_find & Util Functions. */
|
||||
/* BM_mesh_edgeloops_find & Utility Functions. */
|
||||
|
||||
static int bm_vert_other_tag(BMVert *v, BMVert *v_prev, BMEdge **r_e)
|
||||
{
|
||||
|
|
|
@ -63,7 +63,7 @@ static void bm_data_interp_from_elem(CustomData *data_layer,
|
|||
src[1] = ele_src_2->head.data;
|
||||
w[0] = 1.0f - fac;
|
||||
w[1] = fac;
|
||||
CustomData_bmesh_interp(data_layer, src, w, NULL, 2, ele_dst->head.data);
|
||||
CustomData_bmesh_interp(data_layer, src, w, nullptr, 2, ele_dst->head.data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -88,21 +88,21 @@ void BM_data_interp_from_edges(
|
|||
* Sets all the customdata (e.g. vert, loop) associated with a vert
|
||||
* to the average of the face regions surrounding it.
|
||||
*/
|
||||
static void UNUSED_FUNCTION(BM_Data_Vert_Average)(BMesh *UNUSED(bm), BMFace *UNUSED(f))
|
||||
static void UNUSED_FUNCTION(BM_Data_Vert_Average)(BMesh * /*bm*/, BMFace * /*f*/)
|
||||
{
|
||||
// BMIter iter;
|
||||
}
|
||||
|
||||
void BM_data_interp_face_vert_edge(BMesh *bm,
|
||||
const BMVert *v_src_1,
|
||||
const BMVert *UNUSED(v_src_2),
|
||||
const BMVert * /*v_src_2*/,
|
||||
BMVert *v,
|
||||
BMEdge *e,
|
||||
const float fac)
|
||||
{
|
||||
float w[2];
|
||||
BMLoop *l_v1 = NULL, *l_v = NULL, *l_v2 = NULL;
|
||||
BMLoop *l_iter = NULL;
|
||||
BMLoop *l_v1 = nullptr, *l_v = nullptr, *l_v2 = nullptr;
|
||||
BMLoop *l_iter = nullptr;
|
||||
|
||||
if (!e->l) {
|
||||
return;
|
||||
|
@ -132,7 +132,7 @@ void BM_data_interp_face_vert_edge(BMesh *bm,
|
|||
src[0] = l_v1->head.data;
|
||||
src[1] = l_v2->head.data;
|
||||
|
||||
CustomData_bmesh_interp(&bm->ldata, src, w, NULL, 2, l_v->head.data);
|
||||
CustomData_bmesh_interp(&bm->ldata, src, w, nullptr, 2, l_v->head.data);
|
||||
} while ((l_iter = l_iter->radial_next) != e->l);
|
||||
}
|
||||
|
||||
|
@ -148,7 +148,7 @@ void BM_face_interp_from_face_ex(BMesh *bm,
|
|||
BMLoop *l_iter;
|
||||
BMLoop *l_first;
|
||||
|
||||
float *w = BLI_array_alloca(w, f_src->len);
|
||||
float *w = static_cast<float *>(BLI_array_alloca(w, f_src->len));
|
||||
float co[2];
|
||||
|
||||
if (f_src != f_dst) {
|
||||
|
@ -160,9 +160,9 @@ void BM_face_interp_from_face_ex(BMesh *bm,
|
|||
do {
|
||||
mul_v2_m3v3(co, axis_mat, l_iter->v->co);
|
||||
interp_weights_poly_v2(w, cos_2d, f_src->len, co);
|
||||
CustomData_bmesh_interp(&bm->ldata, blocks_l, w, NULL, f_src->len, l_iter->head.data);
|
||||
CustomData_bmesh_interp(&bm->ldata, blocks_l, w, nullptr, f_src->len, l_iter->head.data);
|
||||
if (do_vertex) {
|
||||
CustomData_bmesh_interp(&bm->vdata, blocks_v, w, NULL, f_src->len, l_iter->v->head.data);
|
||||
CustomData_bmesh_interp(&bm->vdata, blocks_v, w, nullptr, f_src->len, l_iter->v->head.data);
|
||||
}
|
||||
} while ((l_iter = l_iter->next) != l_first);
|
||||
}
|
||||
|
@ -172,9 +172,11 @@ void BM_face_interp_from_face(BMesh *bm, BMFace *f_dst, const BMFace *f_src, con
|
|||
BMLoop *l_iter;
|
||||
BMLoop *l_first;
|
||||
|
||||
const void **blocks_l = BLI_array_alloca(blocks_l, f_src->len);
|
||||
const void **blocks_v = do_vertex ? BLI_array_alloca(blocks_v, f_src->len) : NULL;
|
||||
float(*cos_2d)[2] = BLI_array_alloca(cos_2d, f_src->len);
|
||||
const void **blocks_l = static_cast<const void **>(BLI_array_alloca(blocks_l, f_src->len));
|
||||
const void **blocks_v = do_vertex ?
|
||||
static_cast<const void **>(BLI_array_alloca(blocks_v, f_src->len)) :
|
||||
nullptr;
|
||||
float(*cos_2d)[2] = static_cast<float(*)[2]>(BLI_array_alloca(cos_2d, f_src->len));
|
||||
float axis_mat[3][3]; /* use normal to transform into 2d xy coords */
|
||||
int i;
|
||||
|
||||
|
@ -287,7 +289,7 @@ static bool quad_co(const float v1[3],
|
|||
|
||||
static void mdisp_axis_from_quad(const float v1[3],
|
||||
const float v2[3],
|
||||
float UNUSED(v3[3]),
|
||||
float[3] /*v3[3]*/,
|
||||
const float v4[3],
|
||||
float r_axis_x[3],
|
||||
float r_axis_y[3])
|
||||
|
@ -421,9 +423,9 @@ typedef struct BMLoopInterpMultiresData {
|
|||
|
||||
static void loop_interp_multires_cb(void *__restrict userdata,
|
||||
const int ix,
|
||||
const TaskParallelTLS *__restrict UNUSED(tls))
|
||||
const TaskParallelTLS *__restrict /*tls*/)
|
||||
{
|
||||
BMLoopInterpMultiresData *data = userdata;
|
||||
BMLoopInterpMultiresData *data = static_cast<BMLoopInterpMultiresData *>(userdata);
|
||||
|
||||
BMLoop *l_first = data->l_src_first;
|
||||
BMLoop *l_dst = data->l_dst;
|
||||
|
@ -458,7 +460,7 @@ static void loop_interp_multires_cb(void *__restrict userdata,
|
|||
float src_axis_x[3], src_axis_y[3];
|
||||
float uv[2];
|
||||
|
||||
md_src = BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_mdisp_offset);
|
||||
md_src = static_cast<MDisps *>(BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_mdisp_offset));
|
||||
|
||||
if (mdisp_in_mdispquad(l_dst, l_iter, f_src_center, co, res, src_axis_x, src_axis_y, uv)) {
|
||||
old_mdisps_bilinear(md_dst->disps[iy * res + ix], md_src->disps, res, uv[0], uv[1]);
|
||||
|
@ -470,7 +472,7 @@ static void loop_interp_multires_cb(void *__restrict userdata,
|
|||
}
|
||||
}
|
||||
|
||||
void BM_loop_interp_multires_ex(BMesh *UNUSED(bm),
|
||||
void BM_loop_interp_multires_ex(BMesh * /*bm*/,
|
||||
BMLoop *l_dst,
|
||||
const BMFace *f_src,
|
||||
const float f_dst_center[3],
|
||||
|
@ -486,17 +488,19 @@ void BM_loop_interp_multires_ex(BMesh *UNUSED(bm),
|
|||
return;
|
||||
}
|
||||
|
||||
md_dst = BM_ELEM_CD_GET_VOID_P(l_dst, cd_loop_mdisp_offset);
|
||||
md_dst = static_cast<MDisps *>(BM_ELEM_CD_GET_VOID_P(l_dst, cd_loop_mdisp_offset));
|
||||
compute_mdisp_quad(l_dst, f_dst_center, v1, v2, v3, v4, e1, e2);
|
||||
|
||||
/* if no disps data allocate a new grid, the size of the first grid in f_src. */
|
||||
if (!md_dst->totdisp) {
|
||||
const MDisps *md_src = BM_ELEM_CD_GET_VOID_P(BM_FACE_FIRST_LOOP(f_src), cd_loop_mdisp_offset);
|
||||
const MDisps *md_src = static_cast<const MDisps *>(
|
||||
BM_ELEM_CD_GET_VOID_P(BM_FACE_FIRST_LOOP(f_src), cd_loop_mdisp_offset));
|
||||
|
||||
md_dst->totdisp = md_src->totdisp;
|
||||
md_dst->level = md_src->level;
|
||||
if (md_dst->totdisp) {
|
||||
md_dst->disps = MEM_callocN(sizeof(float[3]) * md_dst->totdisp, __func__);
|
||||
md_dst->disps = static_cast<float(*)[3]>(
|
||||
MEM_callocN(sizeof(float[3]) * md_dst->totdisp, __func__));
|
||||
}
|
||||
else {
|
||||
return;
|
||||
|
@ -506,21 +510,21 @@ void BM_loop_interp_multires_ex(BMesh *UNUSED(bm),
|
|||
mdisp_axis_from_quad(v1, v2, v3, v4, axis_x, axis_y);
|
||||
|
||||
const int res = (int)sqrt(md_dst->totdisp);
|
||||
BMLoopInterpMultiresData data = {
|
||||
.l_dst = l_dst,
|
||||
.l_src_first = BM_FACE_FIRST_LOOP(f_src),
|
||||
.cd_loop_mdisp_offset = cd_loop_mdisp_offset,
|
||||
.md_dst = md_dst,
|
||||
.f_src_center = f_src_center,
|
||||
.axis_x = axis_x,
|
||||
.axis_y = axis_y,
|
||||
.v1 = v1,
|
||||
.v4 = v4,
|
||||
.e1 = e1,
|
||||
.e2 = e2,
|
||||
.res = res,
|
||||
.d = 1.0f / (float)(res - 1),
|
||||
};
|
||||
BMLoopInterpMultiresData data = {};
|
||||
data.l_dst = l_dst;
|
||||
data.l_src_first = BM_FACE_FIRST_LOOP(f_src);
|
||||
data.cd_loop_mdisp_offset = cd_loop_mdisp_offset;
|
||||
data.md_dst = md_dst;
|
||||
data.f_src_center = f_src_center;
|
||||
data.axis_x = axis_x;
|
||||
data.axis_y = axis_y;
|
||||
data.v1 = v1;
|
||||
data.v4 = v4;
|
||||
data.e1 = e1;
|
||||
data.e2 = e2;
|
||||
data.res = res;
|
||||
data.d = 1.0f / (float)(res - 1);
|
||||
|
||||
TaskParallelSettings settings;
|
||||
BLI_parallel_range_settings_defaults(&settings);
|
||||
settings.use_threading = (res > 5);
|
||||
|
@ -583,9 +587,9 @@ void BM_face_multires_bounds_smooth(BMesh *bm, BMFace *f)
|
|||
}
|
||||
|
||||
BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
|
||||
MDisps *mdp = BM_ELEM_CD_GET_VOID_P(l->prev, cd_loop_mdisp_offset);
|
||||
MDisps *mdl = BM_ELEM_CD_GET_VOID_P(l, cd_loop_mdisp_offset);
|
||||
MDisps *mdn = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_mdisp_offset);
|
||||
MDisps *mdp = static_cast<MDisps *>(BM_ELEM_CD_GET_VOID_P(l->prev, cd_loop_mdisp_offset));
|
||||
MDisps *mdl = static_cast<MDisps *>(BM_ELEM_CD_GET_VOID_P(l, cd_loop_mdisp_offset));
|
||||
MDisps *mdn = static_cast<MDisps *>(BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_mdisp_offset));
|
||||
float co1[3];
|
||||
int sides;
|
||||
int y;
|
||||
|
@ -615,7 +619,7 @@ void BM_face_multires_bounds_smooth(BMesh *bm, BMFace *f)
|
|||
}
|
||||
|
||||
BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
|
||||
MDisps *mdl1 = BM_ELEM_CD_GET_VOID_P(l, cd_loop_mdisp_offset);
|
||||
MDisps *mdl1 = static_cast<MDisps *>(BM_ELEM_CD_GET_VOID_P(l, cd_loop_mdisp_offset));
|
||||
MDisps *mdl2;
|
||||
float co1[3], co2[3], co[3];
|
||||
int sides;
|
||||
|
@ -641,10 +645,11 @@ void BM_face_multires_bounds_smooth(BMesh *bm, BMFace *f)
|
|||
}
|
||||
|
||||
if (l->radial_next->v == l->v) {
|
||||
mdl2 = BM_ELEM_CD_GET_VOID_P(l->radial_next, cd_loop_mdisp_offset);
|
||||
mdl2 = static_cast<MDisps *>(BM_ELEM_CD_GET_VOID_P(l->radial_next, cd_loop_mdisp_offset));
|
||||
}
|
||||
else {
|
||||
mdl2 = BM_ELEM_CD_GET_VOID_P(l->radial_next->next, cd_loop_mdisp_offset);
|
||||
mdl2 = static_cast<MDisps *>(
|
||||
BM_ELEM_CD_GET_VOID_P(l->radial_next->next, cd_loop_mdisp_offset));
|
||||
}
|
||||
|
||||
sides = (int)sqrt(mdl1->totdisp);
|
||||
|
@ -685,10 +690,12 @@ void BM_loop_interp_from_face(
|
|||
{
|
||||
BMLoop *l_iter;
|
||||
BMLoop *l_first;
|
||||
const void **vblocks = do_vertex ? BLI_array_alloca(vblocks, f_src->len) : NULL;
|
||||
const void **blocks = BLI_array_alloca(blocks, f_src->len);
|
||||
float(*cos_2d)[2] = BLI_array_alloca(cos_2d, f_src->len);
|
||||
float *w = BLI_array_alloca(w, f_src->len);
|
||||
const void **vblocks = do_vertex ?
|
||||
static_cast<const void **>(BLI_array_alloca(vblocks, f_src->len)) :
|
||||
nullptr;
|
||||
const void **blocks = static_cast<const void **>(BLI_array_alloca(blocks, f_src->len));
|
||||
float(*cos_2d)[2] = static_cast<float(*)[2]>(BLI_array_alloca(cos_2d, f_src->len));
|
||||
float *w = static_cast<float *>(BLI_array_alloca(w, f_src->len));
|
||||
float axis_mat[3][3]; /* use normal to transform into 2d xy coords */
|
||||
float co[2];
|
||||
|
||||
|
@ -723,9 +730,9 @@ void BM_loop_interp_from_face(
|
|||
|
||||
/* interpolate */
|
||||
interp_weights_poly_v2(w, cos_2d, f_src->len, co);
|
||||
CustomData_bmesh_interp(&bm->ldata, blocks, w, NULL, f_src->len, l_dst->head.data);
|
||||
CustomData_bmesh_interp(&bm->ldata, blocks, w, nullptr, f_src->len, l_dst->head.data);
|
||||
if (do_vertex) {
|
||||
CustomData_bmesh_interp(&bm->vdata, vblocks, w, NULL, f_src->len, l_dst->v->head.data);
|
||||
CustomData_bmesh_interp(&bm->vdata, vblocks, w, nullptr, f_src->len, l_dst->v->head.data);
|
||||
}
|
||||
|
||||
if (do_multires) {
|
||||
|
@ -737,9 +744,9 @@ void BM_vert_interp_from_face(BMesh *bm, BMVert *v_dst, const BMFace *f_src)
|
|||
{
|
||||
BMLoop *l_iter;
|
||||
BMLoop *l_first;
|
||||
const void **blocks = BLI_array_alloca(blocks, f_src->len);
|
||||
float(*cos_2d)[2] = BLI_array_alloca(cos_2d, f_src->len);
|
||||
float *w = BLI_array_alloca(w, f_src->len);
|
||||
const void **blocks = static_cast<const void **>(BLI_array_alloca(blocks, f_src->len));
|
||||
float(*cos_2d)[2] = static_cast<float(*)[2]>(BLI_array_alloca(cos_2d, f_src->len));
|
||||
float *w = static_cast<float *>(BLI_array_alloca(w, f_src->len));
|
||||
float axis_mat[3][3]; /* use normal to transform into 2d xy coords */
|
||||
float co[2];
|
||||
|
||||
|
@ -758,7 +765,7 @@ void BM_vert_interp_from_face(BMesh *bm, BMVert *v_dst, const BMFace *f_src)
|
|||
|
||||
/* interpolate */
|
||||
interp_weights_poly_v2(w, cos_2d, f_src->len, co);
|
||||
CustomData_bmesh_interp(&bm->vdata, blocks, w, NULL, f_src->len, v_dst->head.data);
|
||||
CustomData_bmesh_interp(&bm->vdata, blocks, w, nullptr, f_src->len, v_dst->head.data);
|
||||
}
|
||||
|
||||
static void update_data_blocks(BMesh *bm, CustomData *olddata, CustomData *data)
|
||||
|
@ -773,7 +780,7 @@ static void update_data_blocks(BMesh *bm, CustomData *olddata, CustomData *data)
|
|||
CustomData_bmesh_init_pool(data, bm->totvert, BM_VERT);
|
||||
|
||||
BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
|
||||
block = NULL;
|
||||
block = nullptr;
|
||||
CustomData_bmesh_set_default(data, &block);
|
||||
CustomData_bmesh_copy_data(olddata, data, eve->head.data, &block);
|
||||
CustomData_bmesh_free_block(olddata, &eve->head.data);
|
||||
|
@ -786,7 +793,7 @@ static void update_data_blocks(BMesh *bm, CustomData *olddata, CustomData *data)
|
|||
CustomData_bmesh_init_pool(data, bm->totedge, BM_EDGE);
|
||||
|
||||
BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
|
||||
block = NULL;
|
||||
block = nullptr;
|
||||
CustomData_bmesh_set_default(data, &block);
|
||||
CustomData_bmesh_copy_data(olddata, data, eed->head.data, &block);
|
||||
CustomData_bmesh_free_block(olddata, &eed->head.data);
|
||||
|
@ -801,7 +808,7 @@ static void update_data_blocks(BMesh *bm, CustomData *olddata, CustomData *data)
|
|||
CustomData_bmesh_init_pool(data, bm->totloop, BM_LOOP);
|
||||
BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
|
||||
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
|
||||
block = NULL;
|
||||
block = nullptr;
|
||||
CustomData_bmesh_set_default(data, &block);
|
||||
CustomData_bmesh_copy_data(olddata, data, l->head.data, &block);
|
||||
CustomData_bmesh_free_block(olddata, &l->head.data);
|
||||
|
@ -815,7 +822,7 @@ static void update_data_blocks(BMesh *bm, CustomData *olddata, CustomData *data)
|
|||
CustomData_bmesh_init_pool(data, bm->totface, BM_FACE);
|
||||
|
||||
BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
|
||||
block = NULL;
|
||||
block = nullptr;
|
||||
CustomData_bmesh_set_default(data, &block);
|
||||
CustomData_bmesh_copy_data(olddata, data, efa->head.data, &block);
|
||||
CustomData_bmesh_free_block(olddata, &efa->head.data);
|
||||
|
@ -838,11 +845,13 @@ static void update_data_blocks(BMesh *bm, CustomData *olddata, CustomData *data)
|
|||
void BM_data_layer_add(BMesh *bm, CustomData *data, int type)
|
||||
{
|
||||
CustomData olddata = *data;
|
||||
olddata.layers = (olddata.layers) ? MEM_dupallocN(olddata.layers) : NULL;
|
||||
olddata.layers = (olddata.layers) ?
|
||||
static_cast<CustomDataLayer *>(MEM_dupallocN(olddata.layers)) :
|
||||
nullptr;
|
||||
/* The pool is now owned by `olddata` and must not be shared. */
|
||||
data->pool = NULL;
|
||||
data->pool = nullptr;
|
||||
|
||||
CustomData_add_layer(data, type, CD_SET_DEFAULT, 0);
|
||||
CustomData_add_layer(data, eCustomDataType(type), CD_SET_DEFAULT, 0);
|
||||
|
||||
update_data_blocks(bm, &olddata, data);
|
||||
if (olddata.layers) {
|
||||
|
@ -853,11 +862,13 @@ void BM_data_layer_add(BMesh *bm, CustomData *data, int type)
|
|||
void BM_data_layer_add_named(BMesh *bm, CustomData *data, int type, const char *name)
|
||||
{
|
||||
CustomData olddata = *data;
|
||||
olddata.layers = (olddata.layers) ? MEM_dupallocN(olddata.layers) : NULL;
|
||||
olddata.layers = (olddata.layers) ?
|
||||
static_cast<CustomDataLayer *>(MEM_dupallocN(olddata.layers)) :
|
||||
nullptr;
|
||||
/* The pool is now owned by `olddata` and must not be shared. */
|
||||
data->pool = NULL;
|
||||
data->pool = nullptr;
|
||||
|
||||
CustomData_add_layer_named(data, type, CD_SET_DEFAULT, 0, name);
|
||||
CustomData_add_layer_named(data, eCustomDataType(type), CD_SET_DEFAULT, 0, name);
|
||||
|
||||
update_data_blocks(bm, &olddata, data);
|
||||
if (olddata.layers) {
|
||||
|
@ -867,7 +878,7 @@ void BM_data_layer_add_named(BMesh *bm, CustomData *data, int type, const char *
|
|||
|
||||
void BM_data_layer_ensure_named(BMesh *bm, CustomData *data, int type, const char *name)
|
||||
{
|
||||
if (CustomData_get_named_layer_index(data, type, name) == -1) {
|
||||
if (CustomData_get_named_layer_index(data, eCustomDataType(type), name) == -1) {
|
||||
BM_data_layer_add_named(bm, data, type, name);
|
||||
}
|
||||
}
|
||||
|
@ -923,11 +934,13 @@ void BM_uv_map_ensure_pin_attr(BMesh *bm, const char *uv_map_name)
|
|||
void BM_data_layer_free(BMesh *bm, CustomData *data, int type)
|
||||
{
|
||||
CustomData olddata = *data;
|
||||
olddata.layers = (olddata.layers) ? MEM_dupallocN(olddata.layers) : NULL;
|
||||
olddata.layers = (olddata.layers) ?
|
||||
static_cast<CustomDataLayer *>(MEM_dupallocN(olddata.layers)) :
|
||||
nullptr;
|
||||
/* The pool is now owned by `olddata` and must not be shared. */
|
||||
data->pool = NULL;
|
||||
data->pool = nullptr;
|
||||
|
||||
const bool had_layer = CustomData_free_layer_active(data, type, 0);
|
||||
const bool had_layer = CustomData_free_layer_active(data, eCustomDataType(type), 0);
|
||||
/* Assert because its expensive to realloc - better not do if layer isn't present. */
|
||||
BLI_assert(had_layer != false);
|
||||
UNUSED_VARS_NDEBUG(had_layer);
|
||||
|
@ -941,9 +954,11 @@ void BM_data_layer_free(BMesh *bm, CustomData *data, int type)
|
|||
bool BM_data_layer_free_named(BMesh *bm, CustomData *data, const char *name)
|
||||
{
|
||||
CustomData olddata = *data;
|
||||
olddata.layers = (olddata.layers) ? MEM_dupallocN(olddata.layers) : NULL;
|
||||
olddata.layers = (olddata.layers) ?
|
||||
static_cast<CustomDataLayer *>(MEM_dupallocN(olddata.layers)) :
|
||||
nullptr;
|
||||
/* The pool is now owned by `olddata` and must not be shared. */
|
||||
data->pool = NULL;
|
||||
data->pool = nullptr;
|
||||
|
||||
const bool had_layer = CustomData_free_layer_named(data, name, 0);
|
||||
|
||||
|
@ -965,12 +980,17 @@ bool BM_data_layer_free_named(BMesh *bm, CustomData *data, const char *name)
|
|||
void BM_data_layer_free_n(BMesh *bm, CustomData *data, int type, int n)
|
||||
{
|
||||
CustomData olddata = *data;
|
||||
olddata.layers = (olddata.layers) ? MEM_dupallocN(olddata.layers) : NULL;
|
||||
olddata.layers = (olddata.layers) ?
|
||||
static_cast<CustomDataLayer *>(MEM_dupallocN(olddata.layers)) :
|
||||
nullptr;
|
||||
/* The pool is now owned by `olddata` and must not be shared. */
|
||||
data->pool = NULL;
|
||||
data->pool = nullptr;
|
||||
|
||||
const bool had_layer = CustomData_free_layer(
|
||||
data, type, 0, CustomData_get_layer_index_n(data, type, n));
|
||||
data,
|
||||
eCustomDataType(type),
|
||||
0,
|
||||
CustomData_get_layer_index_n(data, eCustomDataType(type), n));
|
||||
/* Assert because its expensive to realloc - better not do if layer isn't present. */
|
||||
BLI_assert(had_layer != false);
|
||||
UNUSED_VARS_NDEBUG(had_layer);
|
||||
|
@ -989,24 +1009,24 @@ void BM_data_layer_copy(BMesh *bm, CustomData *data, int type, int src_n, int ds
|
|||
BMVert *eve;
|
||||
|
||||
BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
|
||||
void *ptr = CustomData_bmesh_get_n(data, eve->head.data, type, src_n);
|
||||
CustomData_bmesh_set_n(data, eve->head.data, type, dst_n, ptr);
|
||||
void *ptr = CustomData_bmesh_get_n(data, eve->head.data, eCustomDataType(type), src_n);
|
||||
CustomData_bmesh_set_n(data, eve->head.data, eCustomDataType(type), dst_n, ptr);
|
||||
}
|
||||
}
|
||||
else if (&bm->edata == data) {
|
||||
BMEdge *eed;
|
||||
|
||||
BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
|
||||
void *ptr = CustomData_bmesh_get_n(data, eed->head.data, type, src_n);
|
||||
CustomData_bmesh_set_n(data, eed->head.data, type, dst_n, ptr);
|
||||
void *ptr = CustomData_bmesh_get_n(data, eed->head.data, eCustomDataType(type), src_n);
|
||||
CustomData_bmesh_set_n(data, eed->head.data, eCustomDataType(type), dst_n, ptr);
|
||||
}
|
||||
}
|
||||
else if (&bm->pdata == data) {
|
||||
BMFace *efa;
|
||||
|
||||
BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
|
||||
void *ptr = CustomData_bmesh_get_n(data, efa->head.data, type, src_n);
|
||||
CustomData_bmesh_set_n(data, efa->head.data, type, dst_n, ptr);
|
||||
void *ptr = CustomData_bmesh_get_n(data, efa->head.data, eCustomDataType(type), src_n);
|
||||
CustomData_bmesh_set_n(data, efa->head.data, eCustomDataType(type), dst_n, ptr);
|
||||
}
|
||||
}
|
||||
else if (&bm->ldata == data) {
|
||||
|
@ -1016,8 +1036,8 @@ void BM_data_layer_copy(BMesh *bm, CustomData *data, int type, int src_n, int ds
|
|||
|
||||
BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
|
||||
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
|
||||
void *ptr = CustomData_bmesh_get_n(data, l->head.data, type, src_n);
|
||||
CustomData_bmesh_set_n(data, l->head.data, type, dst_n, ptr);
|
||||
void *ptr = CustomData_bmesh_get_n(data, l->head.data, eCustomDataType(type), src_n);
|
||||
CustomData_bmesh_set_n(data, l->head.data, eCustomDataType(type), dst_n, ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1029,13 +1049,15 @@ void BM_data_layer_copy(BMesh *bm, CustomData *data, int type, int src_n, int ds
|
|||
|
||||
float BM_elem_float_data_get(CustomData *cd, void *element, int type)
|
||||
{
|
||||
const float *f = CustomData_bmesh_get(cd, ((BMHeader *)element)->data, type);
|
||||
const float *f = static_cast<const float *>(
|
||||
CustomData_bmesh_get(cd, ((BMHeader *)element)->data, eCustomDataType(type)));
|
||||
return f ? *f : 0.0f;
|
||||
}
|
||||
|
||||
void BM_elem_float_data_set(CustomData *cd, void *element, int type, const float val)
|
||||
{
|
||||
float *f = CustomData_bmesh_get(cd, ((BMHeader *)element)->data, type);
|
||||
float *f = static_cast<float *>(
|
||||
CustomData_bmesh_get(cd, ((BMHeader *)element)->data, eCustomDataType(type)));
|
||||
if (f) {
|
||||
*f = val;
|
||||
}
|
||||
|
@ -1117,8 +1139,9 @@ static void bm_loop_walk_data(struct LoopWalkCtx *lwc, BMLoop *l_walk)
|
|||
{
|
||||
int i;
|
||||
|
||||
BLI_assert(CustomData_data_equals(
|
||||
lwc->type, lwc->data_ref, BM_ELEM_CD_GET_VOID_P(l_walk, lwc->cd_layer_offset)));
|
||||
BLI_assert(CustomData_data_equals(eCustomDataType(lwc->type),
|
||||
lwc->data_ref,
|
||||
BM_ELEM_CD_GET_VOID_P(l_walk, lwc->cd_layer_offset)));
|
||||
BLI_assert(BM_elem_flag_test(l_walk, BM_ELEM_INTERNAL_TAG));
|
||||
|
||||
bm_loop_walk_add(lwc, l_walk);
|
||||
|
@ -1132,8 +1155,9 @@ static void bm_loop_walk_data(struct LoopWalkCtx *lwc, BMLoop *l_walk)
|
|||
}
|
||||
BLI_assert(l_other->v == l_walk->v);
|
||||
if (BM_elem_flag_test(l_other, BM_ELEM_INTERNAL_TAG)) {
|
||||
if (CustomData_data_equals(
|
||||
lwc->type, lwc->data_ref, BM_ELEM_CD_GET_VOID_P(l_other, lwc->cd_layer_offset)))
|
||||
if (CustomData_data_equals(eCustomDataType(lwc->type),
|
||||
lwc->data_ref,
|
||||
BM_ELEM_CD_GET_VOID_P(l_other, lwc->cd_layer_offset)))
|
||||
{
|
||||
bm_loop_walk_data(lwc, l_other);
|
||||
}
|
||||
|
@ -1146,7 +1170,7 @@ LinkNode *BM_vert_loop_groups_data_layer_create(
|
|||
BMesh *bm, BMVert *v, const int layer_n, const float *loop_weights, MemArena *arena)
|
||||
{
|
||||
struct LoopWalkCtx lwc;
|
||||
LinkNode *groups = NULL;
|
||||
LinkNode *groups = nullptr;
|
||||
BMLoop *l;
|
||||
BMIter liter;
|
||||
int loop_num;
|
||||
|
@ -1166,13 +1190,14 @@ LinkNode *BM_vert_loop_groups_data_layer_create(
|
|||
bm->elem_index_dirty |= BM_LOOP;
|
||||
|
||||
lwc.data_len = 0;
|
||||
lwc.data_array = BLI_memarena_alloc(lwc.arena, sizeof(void *) * loop_num);
|
||||
lwc.data_index_array = BLI_memarena_alloc(lwc.arena, sizeof(int) * loop_num);
|
||||
lwc.weight_array = BLI_memarena_alloc(lwc.arena, sizeof(float) * loop_num);
|
||||
lwc.data_array = static_cast<void **>(BLI_memarena_alloc(lwc.arena, sizeof(void *) * loop_num));
|
||||
lwc.data_index_array = static_cast<int *>(BLI_memarena_alloc(lwc.arena, sizeof(int) * loop_num));
|
||||
lwc.weight_array = static_cast<float *>(BLI_memarena_alloc(lwc.arena, sizeof(float) * loop_num));
|
||||
|
||||
BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) {
|
||||
if (BM_elem_flag_test(l, BM_ELEM_INTERNAL_TAG)) {
|
||||
struct LoopGroupCD *lf = BLI_memarena_alloc(lwc.arena, sizeof(*lf));
|
||||
struct LoopGroupCD *lf = static_cast<LoopGroupCD *>(
|
||||
BLI_memarena_alloc(lwc.arena, sizeof(*lf)));
|
||||
int len_prev = lwc.data_len;
|
||||
|
||||
lwc.data_ref = BM_ELEM_CD_GET_VOID_P(l, lwc.cd_layer_offset);
|
||||
|
@ -1208,7 +1233,7 @@ static void bm_vert_loop_groups_data_layer_merge__single(BMesh *bm,
|
|||
int layer_n,
|
||||
void *data_tmp)
|
||||
{
|
||||
struct LoopGroupCD *lf = lf_p;
|
||||
struct LoopGroupCD *lf = static_cast<LoopGroupCD *>(lf_p);
|
||||
const int type = bm->ldata.layers[layer_n].type;
|
||||
int i;
|
||||
const float *data_weights;
|
||||
|
@ -1216,23 +1241,23 @@ static void bm_vert_loop_groups_data_layer_merge__single(BMesh *bm,
|
|||
data_weights = lf->data_weights;
|
||||
|
||||
CustomData_bmesh_interp_n(
|
||||
&bm->ldata, (const void **)lf->data, data_weights, NULL, lf->data_len, data_tmp, layer_n);
|
||||
&bm->ldata, (const void **)lf->data, data_weights, nullptr, lf->data_len, data_tmp, layer_n);
|
||||
|
||||
for (i = 0; i < lf->data_len; i++) {
|
||||
CustomData_copy_elements(type, data_tmp, lf->data[i], 1);
|
||||
CustomData_copy_elements(eCustomDataType(type), data_tmp, lf->data[i], 1);
|
||||
}
|
||||
}
|
||||
|
||||
static void bm_vert_loop_groups_data_layer_merge_weights__single(
|
||||
BMesh *bm, void *lf_p, const int layer_n, void *data_tmp, const float *loop_weights)
|
||||
{
|
||||
struct LoopGroupCD *lf = lf_p;
|
||||
struct LoopGroupCD *lf = static_cast<LoopGroupCD *>(lf_p);
|
||||
const int type = bm->ldata.layers[layer_n].type;
|
||||
int i;
|
||||
const float *data_weights;
|
||||
|
||||
/* re-weight */
|
||||
float *temp_weights = BLI_array_alloca(temp_weights, lf->data_len);
|
||||
float *temp_weights = static_cast<float *>(BLI_array_alloca(temp_weights, lf->data_len));
|
||||
float weight_accum = 0.0f;
|
||||
|
||||
for (i = 0; i < lf->data_len; i++) {
|
||||
|
@ -1250,17 +1275,17 @@ static void bm_vert_loop_groups_data_layer_merge_weights__single(
|
|||
}
|
||||
|
||||
CustomData_bmesh_interp_n(
|
||||
&bm->ldata, (const void **)lf->data, data_weights, NULL, lf->data_len, data_tmp, layer_n);
|
||||
&bm->ldata, (const void **)lf->data, data_weights, nullptr, lf->data_len, data_tmp, layer_n);
|
||||
|
||||
for (i = 0; i < lf->data_len; i++) {
|
||||
CustomData_copy_elements(type, data_tmp, lf->data[i], 1);
|
||||
CustomData_copy_elements(eCustomDataType(type), data_tmp, lf->data[i], 1);
|
||||
}
|
||||
}
|
||||
|
||||
void BM_vert_loop_groups_data_layer_merge(BMesh *bm, LinkNode *groups, const int layer_n)
|
||||
{
|
||||
const int type = bm->ldata.layers[layer_n].type;
|
||||
const int size = CustomData_sizeof(type);
|
||||
const int size = CustomData_sizeof(eCustomDataType(type));
|
||||
void *data_tmp = alloca(size);
|
||||
|
||||
do {
|
||||
|
@ -1274,7 +1299,7 @@ void BM_vert_loop_groups_data_layer_merge_weights(BMesh *bm,
|
|||
const float *loop_weights)
|
||||
{
|
||||
const int type = bm->ldata.layers[layer_n].type;
|
||||
const int size = CustomData_sizeof(type);
|
||||
const int size = CustomData_sizeof(eCustomDataType(type));
|
||||
void *data_tmp = alloca(size);
|
||||
|
||||
do {
|
|
@ -62,7 +62,6 @@ enum {
|
|||
SIMFACE_NORMAL,
|
||||
SIMFACE_COPLANAR,
|
||||
SIMFACE_SMOOTH,
|
||||
SIMFACE_FACEMAP,
|
||||
SIMFACE_FREESTYLE,
|
||||
};
|
||||
|
||||
|
|
|
@ -109,7 +109,7 @@ typedef struct PathLinkState {
|
|||
} PathLinkState;
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Min Dist Dir Util
|
||||
/** \name Min Dist Dir Utilities
|
||||
*
|
||||
* Simply getting the closest intersecting vert/edge is _not_ good enough. see #43792
|
||||
* we need to get the closest in both directions since the absolute closest may be a dead-end.
|
||||
|
|
|
@ -766,7 +766,7 @@ void bmo_inset_region_exec(BMesh *bm, BMOperator *op)
|
|||
vert_coords = BLI_ghash_ptr_new(__func__);
|
||||
}
|
||||
|
||||
/* util macros */
|
||||
/* Utility macros. */
|
||||
#define VERT_ORIG_STORE(_v) \
|
||||
{ \
|
||||
float *_co = BLI_memarena_alloc(vert_coords_orig, sizeof(float[3])); \
|
||||
|
|
|
@ -322,6 +322,8 @@ if(WITH_COMPOSITOR_CPU)
|
|||
nodes/COM_FilterNode.h
|
||||
nodes/COM_InpaintNode.cc
|
||||
nodes/COM_InpaintNode.h
|
||||
nodes/COM_KuwaharaNode.h
|
||||
nodes/COM_KuwaharaNode.cc
|
||||
nodes/COM_PosterizeNode.cc
|
||||
nodes/COM_PosterizeNode.h
|
||||
|
||||
|
@ -349,6 +351,10 @@ if(WITH_COMPOSITOR_CPU)
|
|||
operations/COM_GaussianXBlurOperation.h
|
||||
operations/COM_GaussianYBlurOperation.cc
|
||||
operations/COM_GaussianYBlurOperation.h
|
||||
operations/COM_KuwaharaClassicOperation.h
|
||||
operations/COM_KuwaharaClassicOperation.cc
|
||||
operations/COM_KuwaharaAnisotropicOperation.h
|
||||
operations/COM_KuwaharaAnisotropicOperation.cc
|
||||
operations/COM_MovieClipAttributeOperation.cc
|
||||
operations/COM_MovieClipAttributeOperation.h
|
||||
operations/COM_MovieDistortionOperation.cc
|
||||
|
|
|
@ -62,6 +62,7 @@
|
|||
#include "COM_InvertNode.h"
|
||||
#include "COM_KeyingNode.h"
|
||||
#include "COM_KeyingScreenNode.h"
|
||||
#include "COM_KuwaharaNode.h"
|
||||
#include "COM_LensDistortionNode.h"
|
||||
#include "COM_LuminanceMatteNode.h"
|
||||
#include "COM_MapRangeNode.h"
|
||||
|
@ -436,6 +437,9 @@ Node *COM_convert_bnode(bNode *b_node)
|
|||
case CMP_NODE_COMBINE_XYZ:
|
||||
node = new CombineXYZNode(b_node);
|
||||
break;
|
||||
case CMP_NODE_KUWAHARA:
|
||||
node = new KuwaharaNode(b_node);
|
||||
break;
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,104 @@
|
|||
/* SPDX-FileCopyrightText: 2023 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "COM_KuwaharaNode.h"
|
||||
|
||||
#include "COM_ConvolutionFilterOperation.h"
|
||||
#include "COM_FastGaussianBlurOperation.h"
|
||||
#include "COM_KuwaharaAnisotropicOperation.h"
|
||||
#include "COM_KuwaharaClassicOperation.h"
|
||||
#include "COM_MathBaseOperation.h"
|
||||
#include "COM_SetValueOperation.h"
|
||||
|
||||
namespace blender::compositor {
|
||||
|
||||
void KuwaharaNode::convert_to_operations(NodeConverter &converter,
|
||||
const CompositorContext & /*context*/) const
|
||||
{
|
||||
const bNode *node = this->get_bnode();
|
||||
const NodeKuwaharaData *data = (const NodeKuwaharaData *)node->storage;
|
||||
|
||||
switch (data->variation) {
|
||||
case CMP_NODE_KUWAHARA_CLASSIC: {
|
||||
KuwaharaClassicOperation *operation = new KuwaharaClassicOperation();
|
||||
operation->set_kernel_size(data->size);
|
||||
|
||||
converter.add_operation(operation);
|
||||
converter.map_input_socket(get_input_socket(0), operation->get_input_socket(0));
|
||||
converter.map_output_socket(get_output_socket(0), operation->get_output_socket());
|
||||
break;
|
||||
}
|
||||
|
||||
case CMP_NODE_KUWAHARA_ANISOTROPIC: {
|
||||
/* Edge detection */
|
||||
auto const_fact = new SetValueOperation();
|
||||
const_fact->set_value(1.0f);
|
||||
converter.add_operation(const_fact);
|
||||
|
||||
auto sobel_x = new ConvolutionFilterOperation();
|
||||
sobel_x->set3x3Filter(1, 0, -1, 2, 0, -2, 1, 0, -1);
|
||||
converter.add_operation(sobel_x);
|
||||
converter.map_input_socket(get_input_socket(0), sobel_x->get_input_socket(0));
|
||||
converter.add_link(const_fact->get_output_socket(0), sobel_x->get_input_socket(1));
|
||||
|
||||
auto sobel_y = new ConvolutionFilterOperation();
|
||||
sobel_y->set3x3Filter(1, 2, 1, 0, 0, 0, -1, -2, -1);
|
||||
converter.add_operation(sobel_y);
|
||||
converter.map_input_socket(get_input_socket(0), sobel_y->get_input_socket(0));
|
||||
converter.add_link(const_fact->get_output_socket(0), sobel_y->get_input_socket(1));
|
||||
|
||||
/* Compute intensity of edges */
|
||||
auto sobel_xx = new MathMultiplyOperation();
|
||||
auto sobel_yy = new MathMultiplyOperation();
|
||||
auto sobel_xy = new MathMultiplyOperation();
|
||||
converter.add_operation(sobel_xx);
|
||||
converter.add_operation(sobel_yy);
|
||||
converter.add_operation(sobel_xy);
|
||||
|
||||
converter.add_link(sobel_x->get_output_socket(0), sobel_xx->get_input_socket(0));
|
||||
converter.add_link(sobel_x->get_output_socket(0), sobel_xx->get_input_socket(1));
|
||||
|
||||
converter.add_link(sobel_y->get_output_socket(0), sobel_yy->get_input_socket(0));
|
||||
converter.add_link(sobel_y->get_output_socket(0), sobel_yy->get_input_socket(1));
|
||||
|
||||
converter.add_link(sobel_x->get_output_socket(0), sobel_xy->get_input_socket(0));
|
||||
converter.add_link(sobel_y->get_output_socket(0), sobel_xy->get_input_socket(1));
|
||||
|
||||
/* Blurring for more robustness. */
|
||||
const int sigma = data->smoothing;
|
||||
|
||||
auto blur_sobel_xx = new FastGaussianBlurOperation();
|
||||
auto blur_sobel_yy = new FastGaussianBlurOperation();
|
||||
auto blur_sobel_xy = new FastGaussianBlurOperation();
|
||||
|
||||
blur_sobel_yy->set_size(sigma, sigma);
|
||||
blur_sobel_xx->set_size(sigma, sigma);
|
||||
blur_sobel_xy->set_size(sigma, sigma);
|
||||
|
||||
converter.add_operation(blur_sobel_xx);
|
||||
converter.add_operation(blur_sobel_yy);
|
||||
converter.add_operation(blur_sobel_xy);
|
||||
|
||||
converter.add_link(sobel_xx->get_output_socket(0), blur_sobel_xx->get_input_socket(0));
|
||||
converter.add_link(sobel_yy->get_output_socket(0), blur_sobel_yy->get_input_socket(0));
|
||||
converter.add_link(sobel_xy->get_output_socket(0), blur_sobel_xy->get_input_socket(0));
|
||||
|
||||
/* Apply anisotropic Kuwahara filter. */
|
||||
KuwaharaAnisotropicOperation *aniso = new KuwaharaAnisotropicOperation();
|
||||
aniso->set_kernel_size(data->size + 4);
|
||||
converter.map_input_socket(get_input_socket(0), aniso->get_input_socket(0));
|
||||
converter.add_operation(aniso);
|
||||
|
||||
converter.add_link(blur_sobel_xx->get_output_socket(0), aniso->get_input_socket(1));
|
||||
converter.add_link(blur_sobel_yy->get_output_socket(0), aniso->get_input_socket(2));
|
||||
converter.add_link(blur_sobel_xy->get_output_socket(0), aniso->get_input_socket(3));
|
||||
|
||||
converter.map_output_socket(get_output_socket(0), aniso->get_output_socket(0));
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace blender::compositor
|
|
@ -0,0 +1,23 @@
|
|||
/* SPDX-FileCopyrightText: 2023 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "COM_Node.h"
|
||||
|
||||
namespace blender::compositor {
|
||||
|
||||
/**
|
||||
* \brief KuwaharaNode
|
||||
* \ingroup Node
|
||||
*/
|
||||
|
||||
class KuwaharaNode : public Node {
|
||||
public:
|
||||
KuwaharaNode(bNode *editor_node) : Node(editor_node) {}
|
||||
void convert_to_operations(NodeConverter &converter,
|
||||
const CompositorContext &context) const override;
|
||||
};
|
||||
|
||||
} // namespace blender::compositor
|
|
@ -11,6 +11,7 @@ namespace blender::compositor {
|
|||
FastGaussianBlurOperation::FastGaussianBlurOperation() : BlurBaseOperation(DataType::Color)
|
||||
{
|
||||
iirgaus_ = nullptr;
|
||||
data_.filtertype = R_FILTER_FAST_GAUSS;
|
||||
}
|
||||
|
||||
void FastGaussianBlurOperation::execute_pixel(float output[4], int x, int y, void *data)
|
||||
|
@ -68,6 +69,15 @@ void FastGaussianBlurOperation::deinit_execution()
|
|||
BlurBaseOperation::deinit_mutex();
|
||||
}
|
||||
|
||||
void FastGaussianBlurOperation::set_size(int size_x, int size_y)
|
||||
{
|
||||
/* TODO: there should be a better way to use the operation without knowing specifics of the blur
|
||||
* node (i.e. data_). We could use factory pattern to solve this problem. */
|
||||
data_.sizex = size_x;
|
||||
data_.sizey = size_y;
|
||||
sizeavailable_ = true;
|
||||
}
|
||||
|
||||
void *FastGaussianBlurOperation::initialize_tile_data(rcti *rect)
|
||||
{
|
||||
lock_mutex();
|
||||
|
|
|
@ -28,6 +28,8 @@ class FastGaussianBlurOperation : public BlurBaseOperation {
|
|||
void deinit_execution() override;
|
||||
void init_execution() override;
|
||||
|
||||
void set_size(int size_x, int size_y);
|
||||
|
||||
void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override;
|
||||
void update_memory_buffer_started(MemoryBuffer *output,
|
||||
const rcti &area,
|
||||
|
|
|
@ -0,0 +1,295 @@
|
|||
/* SPDX-FileCopyrightText: 2023 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "COM_KuwaharaAnisotropicOperation.h"
|
||||
|
||||
#include "BLI_math_base.hh"
|
||||
#include "BLI_vector.hh"
|
||||
#include "IMB_colormanagement.h"
|
||||
|
||||
namespace blender::compositor {
|
||||
|
||||
KuwaharaAnisotropicOperation::KuwaharaAnisotropicOperation()
|
||||
{
|
||||
this->add_input_socket(DataType::Color);
|
||||
this->add_input_socket(DataType::Color);
|
||||
this->add_input_socket(DataType::Color);
|
||||
this->add_input_socket(DataType::Color);
|
||||
|
||||
this->add_output_socket(DataType::Color);
|
||||
|
||||
this->n_div_ = 8;
|
||||
this->set_kernel_size(5);
|
||||
|
||||
this->flags_.is_fullframe_operation = true;
|
||||
}
|
||||
|
||||
void KuwaharaAnisotropicOperation::init_execution()
|
||||
{
|
||||
image_reader_ = this->get_input_socket_reader(0);
|
||||
s_xx_reader_ = this->get_input_socket_reader(1);
|
||||
s_yy_reader_ = this->get_input_socket_reader(2);
|
||||
s_xy_reader_ = this->get_input_socket_reader(3);
|
||||
}
|
||||
|
||||
void KuwaharaAnisotropicOperation::deinit_execution()
|
||||
{
|
||||
image_reader_ = nullptr;
|
||||
}
|
||||
|
||||
void KuwaharaAnisotropicOperation::execute_pixel_sampled(float output[4],
|
||||
float x,
|
||||
float y,
|
||||
PixelSampler sampler)
|
||||
{
|
||||
const int width = this->get_width();
|
||||
const int height = this->get_height();
|
||||
|
||||
BLI_assert(width == s_xx_reader_->get_width());
|
||||
BLI_assert(height == s_xx_reader_->get_height());
|
||||
BLI_assert(width == s_yy_reader_->get_width());
|
||||
BLI_assert(height == s_yy_reader_->get_height());
|
||||
BLI_assert(width == s_xy_reader_->get_width());
|
||||
BLI_assert(height == s_xy_reader_->get_height());
|
||||
|
||||
/* Values recommended by authors in original paper. */
|
||||
const float angle = 2.0 * M_PI / n_div_;
|
||||
const float q = 3.0;
|
||||
const float EPS = 1.0e-10;
|
||||
|
||||
/* For now use green channel to compute orientation. */
|
||||
/* TODO: convert to HSV and compute orientation and strength on luminance channel */
|
||||
float tmp[4];
|
||||
s_xx_reader_->read(tmp, x, y, nullptr);
|
||||
const float a = tmp[1];
|
||||
s_xy_reader_->read(tmp, x, y, nullptr);
|
||||
const float b = tmp[1];
|
||||
s_yy_reader_->read(tmp, x, y, nullptr);
|
||||
const float c = tmp[1];
|
||||
|
||||
/* Compute egenvalues of structure tensor. */
|
||||
const double tr = a + c;
|
||||
const double discr = sqrt((a - b) * (a - b) + 4 * b * c);
|
||||
const double lambda1 = (tr + discr) / 2;
|
||||
const double lambda2 = (tr - discr) / 2;
|
||||
|
||||
/* Compute orientation and its strength based on structure tensor. */
|
||||
const double orientation = 0.5 * atan2(2 * b, a - c);
|
||||
const double strength = (lambda1 == 0 && lambda2 == 0) ?
|
||||
0 :
|
||||
(lambda1 - lambda2) / (lambda1 + lambda2);
|
||||
|
||||
Vector<double> mean(n_div_);
|
||||
Vector<double> sum(n_div_);
|
||||
Vector<double> var(n_div_);
|
||||
Vector<double> weight(n_div_);
|
||||
|
||||
for (int ch = 0; ch < 3; ch++) {
|
||||
mean.fill(0.0);
|
||||
sum.fill(0.0);
|
||||
var.fill(0.0);
|
||||
weight.fill(0.0);
|
||||
|
||||
double sx = 1.0f / (strength + 1.0f);
|
||||
double sy = (1.0f + strength) / 1.0f;
|
||||
double theta = -orientation;
|
||||
|
||||
for (int dy = -kernel_size_; dy <= kernel_size_; dy++) {
|
||||
for (int dx = -kernel_size_; dx <= kernel_size_; dx++) {
|
||||
if (dx == 0 && dy == 0)
|
||||
continue;
|
||||
|
||||
/* Rotate and scale the kernel. This is the "anisotropic" part. */
|
||||
int dx2 = int(sx * (cos(theta) * dx - sin(theta) * dy));
|
||||
int dy2 = int(sy * (sin(theta) * dx + cos(theta) * dy));
|
||||
|
||||
/* Clamp image to avoid artifacts at borders. */
|
||||
const int xx = math::clamp(int(x) + dx2, 0, width - 1);
|
||||
const int yy = math::clamp(int(y) + dy2, 0, height - 1);
|
||||
|
||||
const double ddx2 = double(dx2);
|
||||
const double ddy2 = double(dy2);
|
||||
const double theta = atan2(ddy2, ddx2) + M_PI;
|
||||
const int t = int(floor(theta / angle)) % n_div_;
|
||||
double d2 = dx2 * dx2 + dy2 * dy2;
|
||||
double g = exp(-d2 / (2.0 * kernel_size_));
|
||||
float color[4];
|
||||
image_reader_->read(color, xx, yy, nullptr);
|
||||
const double v = color[ch];
|
||||
/* TODO(@zazizizou): only compute lum once per region */
|
||||
const float lum = IMB_colormanagement_get_luminance(color);
|
||||
/* TODO(@zazizizou): only compute mean for the selected region */
|
||||
mean[t] += g * v;
|
||||
sum[t] += g * lum;
|
||||
var[t] += g * lum * lum;
|
||||
weight[t] += g;
|
||||
}
|
||||
}
|
||||
|
||||
/* Calculate weighted average */
|
||||
double de = 0.0;
|
||||
double nu = 0.0;
|
||||
for (int i = 0; i < n_div_; i++) {
|
||||
double weight_inv = 1.0 / weight[i];
|
||||
mean[i] = weight[i] != 0 ? mean[i] * weight_inv : 0.0;
|
||||
sum[i] = weight[i] != 0 ? sum[i] * weight_inv : 0.0;
|
||||
var[i] = weight[i] != 0 ? var[i] * weight_inv : 0.0;
|
||||
var[i] = var[i] - sum[i] * sum[i];
|
||||
var[i] = var[i] > FLT_EPSILON ? sqrt(var[i]) : FLT_EPSILON;
|
||||
double w = powf(var[i], -q);
|
||||
|
||||
de += mean[i] * w;
|
||||
nu += w;
|
||||
}
|
||||
|
||||
double val = nu > EPS ? de / nu : 0.0;
|
||||
output[ch] = val;
|
||||
}
|
||||
|
||||
/* No changes for alpha channel. */
|
||||
image_reader_->read_sampled(tmp, x, y, sampler);
|
||||
output[3] = tmp[3];
|
||||
}
|
||||
|
||||
void KuwaharaAnisotropicOperation::set_kernel_size(int kernel_size)
|
||||
{
|
||||
/* Filter will be split into n_div.
|
||||
* Add n_div / 2 to avoid artifacts such as random black pixels in image. */
|
||||
kernel_size_ = kernel_size + n_div_ / 2;
|
||||
}
|
||||
|
||||
int KuwaharaAnisotropicOperation::get_kernel_size()
|
||||
{
|
||||
return kernel_size_;
|
||||
}
|
||||
|
||||
int KuwaharaAnisotropicOperation::get_n_div()
|
||||
{
|
||||
return n_div_;
|
||||
}
|
||||
|
||||
void KuwaharaAnisotropicOperation::update_memory_buffer_partial(MemoryBuffer *output,
|
||||
const rcti &area,
|
||||
Span<MemoryBuffer *> inputs)
|
||||
{
|
||||
/* Implementation based on Kyprianidis, Jan & Kang, Henry & Döllner, Jürgen. (2009).
|
||||
* "Image and Video Abstraction by Anisotropic Kuwahara Filtering".
|
||||
* Comput. Graph. Forum. 28. 1955-1963. 10.1111/j.1467-8659.2009.01574.x.
|
||||
* Used reference implementation from lime image processing library (MIT license). */
|
||||
|
||||
MemoryBuffer *image = inputs[0];
|
||||
MemoryBuffer *s_xx = inputs[1];
|
||||
MemoryBuffer *s_yy = inputs[2];
|
||||
MemoryBuffer *s_xy = inputs[3];
|
||||
|
||||
const int width = image->get_width();
|
||||
const int height = image->get_height();
|
||||
|
||||
BLI_assert(width == s_xx->get_width());
|
||||
BLI_assert(height == s_xx->get_height());
|
||||
BLI_assert(width == s_yy->get_width());
|
||||
BLI_assert(height == s_yy->get_height());
|
||||
BLI_assert(width == s_xy->get_width());
|
||||
BLI_assert(height == s_xy->get_height());
|
||||
|
||||
/* Values recommended by authors in original paper. */
|
||||
const float angle = 2.0 * M_PI / n_div_;
|
||||
const float q = 3.0;
|
||||
const float EPS = 1.0e-10;
|
||||
|
||||
for (BuffersIterator<float> it = output->iterate_with(inputs, area); !it.is_end(); ++it) {
|
||||
const int x = it.x;
|
||||
const int y = it.y;
|
||||
|
||||
/* For now use green channel to compute orientation. */
|
||||
/* TODO: convert to HSV and compute orientation and strength on luminance channel. */
|
||||
const float a = s_xx->get_value(x, y, 1);
|
||||
const float b = s_xy->get_value(x, y, 1);
|
||||
const float c = s_yy->get_value(x, y, 1);
|
||||
|
||||
/* Compute egenvalues of structure tensor */
|
||||
const double tr = a + c;
|
||||
const double discr = sqrt((a - b) * (a - b) + 4 * b * c);
|
||||
const double lambda1 = (tr + discr) / 2;
|
||||
const double lambda2 = (tr - discr) / 2;
|
||||
|
||||
/* Compute orientation and its strength based on structure tensor. */
|
||||
const double orientation = 0.5 * atan2(2 * b, a - c);
|
||||
const double strength = (lambda1 == 0 && lambda2 == 0) ?
|
||||
0 :
|
||||
(lambda1 - lambda2) / (lambda1 + lambda2);
|
||||
|
||||
Vector<double> mean(n_div_);
|
||||
Vector<double> sum(n_div_);
|
||||
Vector<double> var(n_div_);
|
||||
Vector<double> weight(n_div_);
|
||||
|
||||
for (int ch = 0; ch < 3; ch++) {
|
||||
mean.fill(0.0);
|
||||
sum.fill(0.0);
|
||||
var.fill(0.0);
|
||||
weight.fill(0.0);
|
||||
|
||||
double sx = 1.0f / (strength + 1.0f);
|
||||
double sy = (1.0f + strength) / 1.0f;
|
||||
double theta = -orientation;
|
||||
|
||||
for (int dy = -kernel_size_; dy <= kernel_size_; dy++) {
|
||||
for (int dx = -kernel_size_; dx <= kernel_size_; dx++) {
|
||||
if (dx == 0 && dy == 0)
|
||||
continue;
|
||||
|
||||
/* Rotate and scale the kernel. This is the "anisotropic" part. */
|
||||
int dx2 = int(sx * (cos(theta) * dx - sin(theta) * dy));
|
||||
int dy2 = int(sy * (sin(theta) * dx + cos(theta) * dy));
|
||||
|
||||
/* Clamp image to avoid artifacts at borders. */
|
||||
const int xx = math::clamp(x + dx2, 0, width - 1);
|
||||
const int yy = math::clamp(y + dy2, 0, height - 1);
|
||||
|
||||
const double ddx2 = double(dx2);
|
||||
const double ddy2 = double(dy2);
|
||||
const double theta = atan2(ddy2, ddx2) + M_PI;
|
||||
const int t = int(floor(theta / angle)) % n_div_;
|
||||
double d2 = dx2 * dx2 + dy2 * dy2;
|
||||
double g = exp(-d2 / (2.0 * kernel_size_));
|
||||
const double v = image->get_value(xx, yy, ch);
|
||||
float color[4];
|
||||
image->read_elem(xx, yy, color);
|
||||
/* TODO(@zazizizou): only compute lum once per region. */
|
||||
const float lum = IMB_colormanagement_get_luminance(color);
|
||||
/* TODO(@zazizizou): only compute mean for the selected region. */
|
||||
mean[t] += g * v;
|
||||
sum[t] += g * lum;
|
||||
var[t] += g * lum * lum;
|
||||
weight[t] += g;
|
||||
}
|
||||
}
|
||||
|
||||
/* Calculate weighted average. */
|
||||
double de = 0.0;
|
||||
double nu = 0.0;
|
||||
for (int i = 0; i < n_div_; i++) {
|
||||
double weight_inv = 1.0 / weight[i];
|
||||
mean[i] = weight[i] != 0 ? mean[i] * weight_inv : 0.0;
|
||||
sum[i] = weight[i] != 0 ? sum[i] * weight_inv : 0.0;
|
||||
var[i] = weight[i] != 0 ? var[i] * weight_inv : 0.0;
|
||||
var[i] = var[i] - sum[i] * sum[i];
|
||||
var[i] = var[i] > FLT_EPSILON ? sqrt(var[i]) : FLT_EPSILON;
|
||||
double w = powf(var[i], -q);
|
||||
|
||||
de += mean[i] * w;
|
||||
nu += w;
|
||||
}
|
||||
|
||||
double val = nu > EPS ? de / nu : 0.0;
|
||||
it.out[ch] = val;
|
||||
}
|
||||
|
||||
/* No changes for alpha channel. */
|
||||
it.out[3] = image->get_value(x, y, 3);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace blender::compositor
|
|
@ -0,0 +1,36 @@
|
|||
/* SPDX-FileCopyrightText: 2023 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "COM_MultiThreadedOperation.h"
|
||||
|
||||
namespace blender::compositor {
|
||||
|
||||
class KuwaharaAnisotropicOperation : public MultiThreadedOperation {
|
||||
SocketReader *image_reader_;
|
||||
SocketReader *s_xx_reader_;
|
||||
SocketReader *s_yy_reader_;
|
||||
SocketReader *s_xy_reader_;
|
||||
|
||||
int kernel_size_;
|
||||
int n_div_;
|
||||
|
||||
public:
|
||||
KuwaharaAnisotropicOperation();
|
||||
|
||||
void init_execution() override;
|
||||
void deinit_execution() override;
|
||||
void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
|
||||
|
||||
void set_kernel_size(int kernel_size);
|
||||
int get_kernel_size();
|
||||
int get_n_div();
|
||||
|
||||
void update_memory_buffer_partial(MemoryBuffer *output,
|
||||
const rcti &area,
|
||||
Span<MemoryBuffer *> inputs) override;
|
||||
};
|
||||
|
||||
} // namespace blender::compositor
|
|
@ -0,0 +1,204 @@
|
|||
/* SPDX-FileCopyrightText: 2023 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "COM_KuwaharaClassicOperation.h"
|
||||
|
||||
#include "IMB_colormanagement.h"
|
||||
|
||||
namespace blender::compositor {
|
||||
|
||||
KuwaharaClassicOperation::KuwaharaClassicOperation()
|
||||
{
|
||||
this->add_input_socket(DataType::Color);
|
||||
this->add_output_socket(DataType::Color);
|
||||
this->set_kernel_size(4);
|
||||
|
||||
this->flags_.is_fullframe_operation = true;
|
||||
}
|
||||
|
||||
void KuwaharaClassicOperation::init_execution()
|
||||
{
|
||||
image_reader_ = this->get_input_socket_reader(0);
|
||||
}
|
||||
|
||||
void KuwaharaClassicOperation::deinit_execution()
|
||||
{
|
||||
image_reader_ = nullptr;
|
||||
}
|
||||
|
||||
void KuwaharaClassicOperation::execute_pixel_sampled(float output[4],
|
||||
float x,
|
||||
float y,
|
||||
PixelSampler sampler)
|
||||
{
|
||||
for (int ch = 0; ch < 3; ch++) {
|
||||
float sum[4] = {0.0f, 0.0f, 0.0f, 0.0f};
|
||||
float mean[4] = {0.0f, 0.0f, 0.0f, 0.0f};
|
||||
float var[4] = {0.0f, 0.0f, 0.0f, 0.0f};
|
||||
int cnt[4] = {0, 0, 0, 0};
|
||||
|
||||
/* Split surroundings of pixel into 4 overlapping regions. */
|
||||
for (int dy = -kernel_size_; dy <= kernel_size_; dy++) {
|
||||
for (int dx = -kernel_size_; dx <= kernel_size_; dx++) {
|
||||
|
||||
int xx = x + dx;
|
||||
int yy = y + dy;
|
||||
if (xx >= 0 && yy >= 0 && xx < this->get_width() && yy < this->get_height()) {
|
||||
float color[4];
|
||||
image_reader_->read_sampled(color, xx, yy, sampler);
|
||||
const float v = color[ch];
|
||||
const float lum = IMB_colormanagement_get_luminance(color);
|
||||
|
||||
if (dx <= 0 && dy <= 0) {
|
||||
mean[0] += v;
|
||||
sum[0] += lum;
|
||||
var[0] += lum * lum;
|
||||
cnt[0]++;
|
||||
}
|
||||
|
||||
if (dx >= 0 && dy <= 0) {
|
||||
mean[1] += v;
|
||||
sum[1] += lum;
|
||||
var[1] += lum * lum;
|
||||
cnt[1]++;
|
||||
}
|
||||
|
||||
if (dx <= 0 && dy >= 0) {
|
||||
mean[2] += v;
|
||||
sum[2] += lum;
|
||||
var[2] += lum * lum;
|
||||
cnt[2]++;
|
||||
}
|
||||
|
||||
if (dx >= 0 && dy >= 0) {
|
||||
mean[3] += v;
|
||||
sum[3] += lum;
|
||||
var[3] += lum * lum;
|
||||
cnt[3]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Compute region variances. */
|
||||
for (int i = 0; i < 4; i++) {
|
||||
mean[i] = cnt[i] != 0 ? mean[i] / cnt[i] : 0.0f;
|
||||
sum[i] = cnt[i] != 0 ? sum[i] / cnt[i] : 0.0f;
|
||||
var[i] = cnt[i] != 0 ? var[i] / cnt[i] : 0.0f;
|
||||
const float temp = sum[i] * sum[i];
|
||||
var[i] = var[i] > temp ? sqrt(var[i] - temp) : 0.0f;
|
||||
}
|
||||
|
||||
/* Choose the region with lowest variance. */
|
||||
float min_var = FLT_MAX;
|
||||
int min_index = 0;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (var[i] < min_var) {
|
||||
min_var = var[i];
|
||||
min_index = i;
|
||||
}
|
||||
}
|
||||
output[ch] = mean[min_index];
|
||||
}
|
||||
|
||||
/* No changes for alpha channel. */
|
||||
float tmp[4];
|
||||
image_reader_->read_sampled(tmp, x, y, sampler);
|
||||
output[3] = tmp[3];
|
||||
}
|
||||
|
||||
void KuwaharaClassicOperation::set_kernel_size(int kernel_size)
|
||||
{
|
||||
kernel_size_ = kernel_size;
|
||||
}
|
||||
|
||||
int KuwaharaClassicOperation::get_kernel_size()
|
||||
{
|
||||
return kernel_size_;
|
||||
}
|
||||
|
||||
void KuwaharaClassicOperation::update_memory_buffer_partial(MemoryBuffer *output,
|
||||
const rcti &area,
|
||||
Span<MemoryBuffer *> inputs)
|
||||
{
|
||||
MemoryBuffer *image = inputs[0];
|
||||
|
||||
for (BuffersIterator<float> it = output->iterate_with(inputs, area); !it.is_end(); ++it) {
|
||||
const int x = it.x;
|
||||
const int y = it.y;
|
||||
it.out[3] = image->get_value(x, y, 3);
|
||||
|
||||
for (int ch = 0; ch < 3; ch++) {
|
||||
float sum[4] = {0.0f, 0.0f, 0.0f, 0.0f};
|
||||
float mean[4] = {0.0f, 0.0f, 0.0f, 0.0f};
|
||||
float var[4] = {0.0f, 0.0f, 0.0f, 0.0f};
|
||||
int cnt[4] = {0, 0, 0, 0};
|
||||
|
||||
/* Split surroundings of pixel into 4 overlapping regions. */
|
||||
for (int dy = -kernel_size_; dy <= kernel_size_; dy++) {
|
||||
for (int dx = -kernel_size_; dx <= kernel_size_; dx++) {
|
||||
|
||||
int xx = x + dx;
|
||||
int yy = y + dy;
|
||||
if (xx >= 0 && yy >= 0 && xx < image->get_width() && yy < image->get_height()) {
|
||||
const float v = image->get_value(xx, yy, ch);
|
||||
float color[4];
|
||||
image->read_elem(xx, yy, color);
|
||||
const float lum = IMB_colormanagement_get_luminance(color);
|
||||
|
||||
if (dx <= 0 && dy <= 0) {
|
||||
mean[0] += v;
|
||||
sum[0] += lum;
|
||||
var[0] += lum * lum;
|
||||
cnt[0]++;
|
||||
}
|
||||
|
||||
if (dx >= 0 && dy <= 0) {
|
||||
mean[1] += v;
|
||||
sum[1] += lum;
|
||||
var[1] += lum * lum;
|
||||
cnt[1]++;
|
||||
}
|
||||
|
||||
if (dx <= 0 && dy >= 0) {
|
||||
mean[2] += v;
|
||||
sum[2] += lum;
|
||||
var[2] += lum * lum;
|
||||
cnt[2]++;
|
||||
}
|
||||
|
||||
if (dx >= 0 && dy >= 0) {
|
||||
mean[3] += v;
|
||||
sum[3] += lum;
|
||||
var[3] += lum * lum;
|
||||
cnt[3]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Compute region variances. */
|
||||
for (int i = 0; i < 4; i++) {
|
||||
mean[i] = cnt[i] != 0 ? mean[i] / cnt[i] : 0.0f;
|
||||
sum[i] = cnt[i] != 0 ? sum[i] / cnt[i] : 0.0f;
|
||||
var[i] = cnt[i] != 0 ? var[i] / cnt[i] : 0.0f;
|
||||
const float temp = sum[i] * sum[i];
|
||||
var[i] = var[i] > temp ? sqrt(var[i] - temp) : 0.0f;
|
||||
}
|
||||
|
||||
/* Choose the region with lowest variance. */
|
||||
float min_var = FLT_MAX;
|
||||
int min_index = 0;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (var[i] < min_var) {
|
||||
min_var = var[i];
|
||||
min_index = i;
|
||||
}
|
||||
}
|
||||
output->get_value(x, y, ch) = mean[min_index];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace blender::compositor
|
|
@ -0,0 +1,31 @@
|
|||
/* SPDX-FileCopyrightText: 2023 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "COM_MultiThreadedOperation.h"
|
||||
|
||||
namespace blender::compositor {
|
||||
|
||||
class KuwaharaClassicOperation : public MultiThreadedOperation {
|
||||
SocketReader *image_reader_;
|
||||
|
||||
int kernel_size_;
|
||||
|
||||
public:
|
||||
KuwaharaClassicOperation();
|
||||
|
||||
void init_execution() override;
|
||||
void deinit_execution() override;
|
||||
void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
|
||||
|
||||
void set_kernel_size(int kernel_size);
|
||||
int get_kernel_size();
|
||||
|
||||
void update_memory_buffer_partial(MemoryBuffer *output,
|
||||
const rcti &area,
|
||||
Span<MemoryBuffer *> inputs) override;
|
||||
};
|
||||
|
||||
} // namespace blender::compositor
|
|
@ -152,6 +152,7 @@ set(GLSL_SRC
|
|||
shaders/compositor_smaa_edge_detection.glsl
|
||||
shaders/compositor_smaa_neighborhood_blending.glsl
|
||||
shaders/compositor_split_viewer.glsl
|
||||
shaders/compositor_sun_beams.glsl
|
||||
shaders/compositor_symmetric_blur.glsl
|
||||
shaders/compositor_symmetric_blur_variable_size.glsl
|
||||
shaders/compositor_symmetric_separable_blur.glsl
|
||||
|
@ -252,6 +253,7 @@ set(SRC_SHADER_CREATE_INFOS
|
|||
shaders/infos/compositor_screen_lens_distortion_info.hh
|
||||
shaders/infos/compositor_smaa_info.hh
|
||||
shaders/infos/compositor_split_viewer_info.hh
|
||||
shaders/infos/compositor_sun_beams_info.hh
|
||||
shaders/infos/compositor_symmetric_blur_info.hh
|
||||
shaders/infos/compositor_symmetric_blur_variable_size_info.hh
|
||||
shaders/infos/compositor_symmetric_separable_blur_info.hh
|
||||
|
|
|
@ -45,9 +45,14 @@ class Context {
|
|||
/* Get the node tree used for compositing. */
|
||||
virtual const bNodeTree &get_node_tree() const = 0;
|
||||
|
||||
/* True if compositor should do write file outputs, false if only running for viewing. */
|
||||
/* True if the compositor should write file outputs, false otherwise. */
|
||||
virtual bool use_file_output() const = 0;
|
||||
|
||||
/* True if the compositor should write the composite output, otherwise, the compositor is assumed
|
||||
* to not support the composite output and just displays its viewer output. In that case, the
|
||||
* composite output will be used as a fallback viewer if no other viewer exists */
|
||||
virtual bool use_composite_output() const = 0;
|
||||
|
||||
/* True if color management should be used for texture evaluation. */
|
||||
virtual bool use_texture_color_management() const = 0;
|
||||
|
||||
|
@ -66,10 +71,14 @@ class Context {
|
|||
* region. */
|
||||
virtual rcti get_compositing_region() const = 0;
|
||||
|
||||
/* Get the texture representing the output where the result of the compositor should be
|
||||
* written. This should be called by output nodes to get their target texture. */
|
||||
/* Get the texture where the result of the compositor should be written. This should be called by
|
||||
* the composite output node to get its target texture. */
|
||||
virtual GPUTexture *get_output_texture() = 0;
|
||||
|
||||
/* Get the texture where the result of the compositor viewer should be written. This should be
|
||||
* called by viewer output nodes to get their target texture. */
|
||||
virtual GPUTexture *get_viewer_output_texture() = 0;
|
||||
|
||||
/* Get the texture where the given render pass is stored. This should be called by the Render
|
||||
* Layer node to populate its outputs. */
|
||||
virtual GPUTexture *get_input_texture(int view_layer, const char *pass_name) = 0;
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
|
||||
#include "NOD_derived_node_tree.hh"
|
||||
|
||||
#include "COM_context.hh"
|
||||
|
||||
namespace blender::realtime_compositor {
|
||||
|
||||
using namespace nodes::derived_node_tree_types;
|
||||
|
@ -18,6 +20,6 @@ using Schedule = VectorSet<DNode>;
|
|||
/* Computes the execution schedule of the node tree. This is essentially a post-order depth first
|
||||
* traversal of the node tree from the output node to the leaf input nodes, with informed order of
|
||||
* traversal of dependencies based on a heuristic estimation of the number of needed buffers. */
|
||||
Schedule compute_schedule(const DerivedNodeTree &tree);
|
||||
Schedule compute_schedule(const Context &context, const DerivedNodeTree &tree);
|
||||
|
||||
} // namespace blender::realtime_compositor
|
||||
|
|
|
@ -72,7 +72,7 @@ void Evaluator::compile_and_evaluate()
|
|||
return;
|
||||
}
|
||||
|
||||
const Schedule schedule = compute_schedule(*derived_node_tree_);
|
||||
const Schedule schedule = compute_schedule(context_, *derived_node_tree_);
|
||||
|
||||
CompileState compile_state(schedule);
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "BKE_node.hh"
|
||||
#include "BKE_node_runtime.hh"
|
||||
|
||||
#include "COM_context.hh"
|
||||
#include "COM_scheduler.hh"
|
||||
#include "COM_utilities.hh"
|
||||
|
||||
|
@ -72,55 +73,88 @@ static const DTreeContext *find_active_context(const DerivedNodeTree &tree)
|
|||
return find_active_context_recursive(&tree.root_context(), NODE_INSTANCE_KEY_BASE);
|
||||
}
|
||||
|
||||
/* Return the output node which is marked as NODE_DO_OUTPUT. If multiple types of output nodes are
|
||||
* marked, then the preference will be CMP_NODE_VIEWER > CMP_NODE_SPLITVIEWER > CMP_NODE_COMPOSITE.
|
||||
* If no output node exists, a null node will be returned. */
|
||||
static DNode find_output_in_context(const DTreeContext *context)
|
||||
/* Add the viewer node which is marked as NODE_DO_OUTPUT in the given context to the given stack.
|
||||
* If multiple types of viewer nodes are marked, then the preference will be CMP_NODE_VIEWER >
|
||||
* CMP_NODE_SPLITVIEWER. If no viewer nodes were found, composite nodes can be added as a fallback
|
||||
* viewer node. */
|
||||
static bool add_viewer_nodes_in_context(const DTreeContext *context, Stack<DNode> &node_stack)
|
||||
{
|
||||
const bNodeTree &tree = context->btree();
|
||||
|
||||
for (const bNode *node : tree.nodes_by_type("CompositorNodeViewer")) {
|
||||
for (const bNode *node : context->btree().nodes_by_type("CompositorNodeViewer")) {
|
||||
if (node->flag & NODE_DO_OUTPUT) {
|
||||
return DNode(context, node);
|
||||
node_stack.push(DNode(context, node));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
for (const bNode *node : tree.nodes_by_type("CompositorNodeSplitViewer")) {
|
||||
for (const bNode *node : context->btree().nodes_by_type("CompositorNodeSplitViewer")) {
|
||||
if (node->flag & NODE_DO_OUTPUT) {
|
||||
return DNode(context, node);
|
||||
node_stack.push(DNode(context, node));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
for (const bNode *node : tree.nodes_by_type("CompositorNodeComposite")) {
|
||||
/* The active Composite node was already added, no need to add it again, see the next block. */
|
||||
if (!node_stack.is_empty() && node_stack.peek()->type == CMP_NODE_COMPOSITE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* No active viewers exist in this context, try to add the Composite node as a fallback viewer if
|
||||
* it was not already added. */
|
||||
for (const bNode *node : context->btree().nodes_by_type("CompositorNodeComposite")) {
|
||||
if (node->flag & NODE_DO_OUTPUT) {
|
||||
return DNode(context, node);
|
||||
node_stack.push(DNode(context, node));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return DNode();
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Compute the output node whose result should be computed. This node is the output node that
|
||||
* satisfies the requirements in the find_output_in_context function. First, the active context is
|
||||
* searched for an output node, if non was found, the root context is search. For more information
|
||||
* on what contexts mean here, see the find_active_context function. */
|
||||
static DNode compute_output_node(const DerivedNodeTree &tree)
|
||||
/* Add the output nodes whose result should be computed to the given stack. This includes File
|
||||
* Output, Composite, and Viewer nodes. Viewer nodes are a special case, as only the nodes that
|
||||
* satisfies the requirements in the add_viewer_nodes_in_context function are added. First, the
|
||||
* active context is searched for viewer nodes, if non were found, the root context is searched.
|
||||
* For more information on what contexts mean here, see the find_active_context function. */
|
||||
static void add_output_nodes(const Context &context,
|
||||
const DerivedNodeTree &tree,
|
||||
Stack<DNode> &node_stack)
|
||||
{
|
||||
const DTreeContext &root_context = tree.root_context();
|
||||
|
||||
/* Only add File Output nodes if the context supports them. */
|
||||
if (context.use_file_output()) {
|
||||
for (const bNode *node : root_context.btree().nodes_by_type("CompositorNodeOutputFile")) {
|
||||
node_stack.push(DNode(&root_context, node));
|
||||
}
|
||||
}
|
||||
|
||||
/* Only add the Composite output node if the context supports composite outputs. The active
|
||||
* Composite node may still be added as a fallback viewer output below. */
|
||||
if (context.use_composite_output()) {
|
||||
for (const bNode *node : root_context.btree().nodes_by_type("CompositorNodeComposite")) {
|
||||
if (node->flag & NODE_DO_OUTPUT) {
|
||||
node_stack.push(DNode(&root_context, node));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const DTreeContext *active_context = find_active_context(tree);
|
||||
const bool viewer_was_added = add_viewer_nodes_in_context(active_context, node_stack);
|
||||
|
||||
const DNode node = find_output_in_context(active_context);
|
||||
if (node) {
|
||||
return node;
|
||||
/* An active viewer was added, no need to search further. */
|
||||
if (viewer_was_added) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* If the active context is the root one and no output node was found, we consider this node tree
|
||||
* to have no output node, even if one of the non-active descendants have an output node. */
|
||||
/* If the active context is the root one and no viewer nodes were found, we consider this node
|
||||
* tree to have no viewer nodes, even if one of the non-active descendants have viewer nodes. */
|
||||
if (active_context->is_root()) {
|
||||
return DNode();
|
||||
return;
|
||||
}
|
||||
|
||||
/* The active context doesn't have an output node, search in the root context as a fallback. */
|
||||
return find_output_in_context(&tree.root_context());
|
||||
/* The active context doesn't have a viewer node, search in the root context as a fallback. */
|
||||
add_viewer_nodes_in_context(&tree.root_context(), node_stack);
|
||||
}
|
||||
|
||||
/* A type representing a mapping that associates each node with a heuristic estimation of the
|
||||
|
@ -177,12 +211,12 @@ using NeededBuffers = Map<DNode, int>;
|
|||
* implementation because it rarely affects the output and is done by very few nodes.
|
||||
* - The compiler may decide to compiler the schedule differently depending on runtime information
|
||||
* which we can merely speculate at scheduling-time as described above. */
|
||||
static NeededBuffers compute_number_of_needed_buffers(DNode output_node)
|
||||
static NeededBuffers compute_number_of_needed_buffers(Stack<DNode> &output_nodes)
|
||||
{
|
||||
NeededBuffers needed_buffers;
|
||||
|
||||
/* A stack of nodes used to traverse the node tree starting from the output node. */
|
||||
Stack<DNode> node_stack = {output_node};
|
||||
/* A stack of nodes used to traverse the node tree starting from the output nodes. */
|
||||
Stack<DNode> node_stack = output_nodes;
|
||||
|
||||
/* Traverse the node tree in a post order depth first manner and compute the number of needed
|
||||
* buffers for each node. Post order traversal guarantee that all the node dependencies of each
|
||||
|
@ -301,23 +335,23 @@ static NeededBuffers compute_number_of_needed_buffers(DNode output_node)
|
|||
* doesn't always guarantee an optimal evaluation order, as the optimal evaluation order is very
|
||||
* difficult to compute, however, this method works well in most cases. Moreover it assumes that
|
||||
* all buffers will have roughly the same size, which may not always be the case. */
|
||||
Schedule compute_schedule(const DerivedNodeTree &tree)
|
||||
Schedule compute_schedule(const Context &context, const DerivedNodeTree &tree)
|
||||
{
|
||||
Schedule schedule;
|
||||
|
||||
/* Compute the output node whose result should be computed. */
|
||||
const DNode output_node = compute_output_node(tree);
|
||||
/* A stack of nodes used to traverse the node tree starting from the output nodes. */
|
||||
Stack<DNode> node_stack;
|
||||
|
||||
/* No output node, the node tree has no effect, return an empty schedule. */
|
||||
if (!output_node) {
|
||||
/* Add the output nodes whose result should be computed to the stack. */
|
||||
add_output_nodes(context, tree, node_stack);
|
||||
|
||||
/* No output nodes, the node tree has no effect, return an empty schedule. */
|
||||
if (node_stack.is_empty()) {
|
||||
return schedule;
|
||||
}
|
||||
|
||||
/* Compute the number of buffers needed by each node connected to the output. */
|
||||
const NeededBuffers needed_buffers = compute_number_of_needed_buffers(output_node);
|
||||
|
||||
/* A stack of nodes used to traverse the node tree starting from the output node. */
|
||||
Stack<DNode> node_stack = {output_node};
|
||||
/* Compute the number of buffers needed by each node connected to the outputs. */
|
||||
const NeededBuffers needed_buffers = compute_number_of_needed_buffers(node_stack);
|
||||
|
||||
/* Traverse the node tree in a post order depth first manner, scheduling the nodes in an order
|
||||
* informed by the number of buffers needed by each node. Post order traversal guarantee that all
|
||||
|
@ -360,7 +394,8 @@ Schedule compute_schedule(const DerivedNodeTree &tree)
|
|||
int insertion_position = 0;
|
||||
for (int i = 0; i < sorted_dependency_nodes.size(); i++) {
|
||||
if (needed_buffers.lookup(doutput.node()) >
|
||||
needed_buffers.lookup(sorted_dependency_nodes[i])) {
|
||||
needed_buffers.lookup(sorted_dependency_nodes[i]))
|
||||
{
|
||||
insertion_position++;
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
#pragma BLENDER_REQUIRE(gpu_shader_compositor_texture_utilities.glsl)
|
||||
|
||||
void main()
|
||||
{
|
||||
ivec2 texel = ivec2(gl_GlobalInvocationID.xy);
|
||||
ivec2 input_size = texture_size(input_tx);
|
||||
|
||||
vec2 coordinates = (vec2(texel) + vec2(0.5)) / vec2(input_size);
|
||||
|
||||
vec2 vector_to_source = source - coordinates;
|
||||
float distance_to_source = length(vector_to_source);
|
||||
vec2 direction_to_source = vector_to_source / distance_to_source;
|
||||
|
||||
/* We integrate from the current pixel to the source pixel, but up until the user specified
|
||||
* maximum ray length. The number of integration steps is roughly equivalent to the number of
|
||||
* pixels along the integration path. Assume a minimum number of steps of 1 to avoid zero
|
||||
* division handling and return source pixels as is. */
|
||||
float integration_length = min(distance_to_source, max_ray_length);
|
||||
float integration_length_in_pixels = length(input_size) * integration_length;
|
||||
int steps = max(1, int(integration_length_in_pixels));
|
||||
vec2 step_vector = (direction_to_source * integration_length) / steps;
|
||||
|
||||
vec4 accumulated_color = vec4(0.0);
|
||||
for (int i = 0; i < steps; i++) {
|
||||
/* Attenuate the contributions of pixels that are further away from the source using a
|
||||
* quadratic falloff. */
|
||||
float weight = pow(1.0f - i / integration_length_in_pixels, 2.0);
|
||||
accumulated_color += texture(input_tx, coordinates + i * step_vector) * weight;
|
||||
}
|
||||
|
||||
imageStore(output_img, texel, accumulated_color / steps);
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
/* SPDX-FileCopyrightText: 2023 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "gpu_shader_create_info.hh"
|
||||
|
||||
GPU_SHADER_CREATE_INFO(compositor_sun_beams)
|
||||
.local_group_size(16, 16)
|
||||
.push_constant(Type::VEC2, "source")
|
||||
.push_constant(Type::FLOAT, "max_ray_length")
|
||||
.sampler(0, ImageType::FLOAT_2D, "input_tx")
|
||||
.image(0, GPU_RGBA16F, Qualifier::WRITE, ImageType::FLOAT_2D, "output_img")
|
||||
.compute_source("compositor_sun_beams.glsl")
|
||||
.do_static_compilation(true);
|
|
@ -162,15 +162,15 @@ void DRW_uniform_attrs_pool_free(struct GHash *table);
|
|||
void DRW_render_context_enable(struct Render *render);
|
||||
void DRW_render_context_disable(struct Render *render);
|
||||
|
||||
void DRW_opengl_context_create(void);
|
||||
void DRW_opengl_context_destroy(void);
|
||||
void DRW_opengl_context_enable(void);
|
||||
void DRW_opengl_context_disable(void);
|
||||
void DRW_gpu_context_create(void);
|
||||
void DRW_gpu_context_destroy(void);
|
||||
void DRW_gpu_context_enable(void);
|
||||
void DRW_gpu_context_disable(void);
|
||||
|
||||
#ifdef WITH_XR_OPENXR
|
||||
/* XXX: see comment on #DRW_xr_opengl_context_get() */
|
||||
void *DRW_xr_opengl_context_get(void);
|
||||
void *DRW_xr_gpu_context_get(void);
|
||||
/* XXX: see comment on #DRW_system_gpu_context_get() */
|
||||
void *DRW_system_gpu_context_get(void);
|
||||
void *DRW_xr_blender_gpu_context_get(void);
|
||||
void DRW_xr_drawing_begin(void);
|
||||
void DRW_xr_drawing_end(void);
|
||||
#endif
|
||||
|
@ -183,19 +183,16 @@ void DRW_cache_free_old_subdiv(void);
|
|||
void DRW_subdiv_free(void);
|
||||
|
||||
/* Never use this. Only for closing blender. */
|
||||
void DRW_opengl_context_enable_ex(bool restore);
|
||||
void DRW_opengl_context_disable_ex(bool restore);
|
||||
void DRW_gpu_context_enable_ex(bool restore);
|
||||
void DRW_gpu_context_disable_ex(bool restore);
|
||||
|
||||
void DRW_opengl_render_context_enable(void *re_gl_context);
|
||||
void DRW_opengl_render_context_disable(void *re_gl_context);
|
||||
/**
|
||||
* Needs to be called AFTER #DRW_opengl_render_context_enable().
|
||||
*/
|
||||
void DRW_gpu_render_context_enable(void *re_gpu_context);
|
||||
/**
|
||||
* Needs to be called BEFORE #DRW_opengl_render_context_disable().
|
||||
*/
|
||||
void DRW_gpu_render_context_disable(void *re_gpu_context);
|
||||
/* Render pipeline GPU context control.
|
||||
* Enable system context first, then enable blender context,
|
||||
* then disable blender context, then disable system context. */
|
||||
void DRW_system_gpu_render_context_enable(void *re_system_gpu_context);
|
||||
void DRW_system_gpu_render_context_disable(void *re_system_gpu_context);
|
||||
void DRW_blender_gpu_render_context_enable(void *re_gpu_context);
|
||||
void DRW_blender_gpu_render_context_disable(void *re_gpu_context);
|
||||
|
||||
void DRW_deferred_shader_remove(struct GPUMaterial *mat);
|
||||
void DRW_deferred_shader_optimize_remove(struct GPUMaterial *mat);
|
||||
|
@ -210,8 +207,8 @@ void DRW_drawdata_free(struct ID *id);
|
|||
struct DRWData *DRW_viewport_data_create(void);
|
||||
void DRW_viewport_data_free(struct DRWData *drw_data);
|
||||
|
||||
bool DRW_opengl_context_release(void);
|
||||
void DRW_opengl_context_activate(bool drw_state);
|
||||
bool DRW_gpu_context_release(void);
|
||||
void DRW_gpu_context_activate(bool drw_state);
|
||||
|
||||
/**
|
||||
* We may want to move this into a more general location.
|
||||
|
|
|
@ -68,6 +68,14 @@ class Context : public realtime_compositor::Context {
|
|||
return false;
|
||||
}
|
||||
|
||||
/* The viewport compositor doesn't really support the composite output, it only displays the
|
||||
* viewer output in the viewport. Settings this to false will make the compositor use the
|
||||
* composite output as fallback viewer if no other viewer exists. */
|
||||
bool use_composite_output() const override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool use_texture_color_management() const override
|
||||
{
|
||||
return BKE_scene_check_color_management_enabled(DRW_context_state_get()->scene);
|
||||
|
@ -145,6 +153,11 @@ class Context : public realtime_compositor::Context {
|
|||
return DRW_viewport_texture_list_get()->color;
|
||||
}
|
||||
|
||||
GPUTexture *get_viewer_output_texture() override
|
||||
{
|
||||
return DRW_viewport_texture_list_get()->color;
|
||||
}
|
||||
|
||||
GPUTexture *get_input_texture(int view_layer, const char *pass_name) override
|
||||
{
|
||||
if (view_layer == 0 && STREQ(pass_name, RE_PASSNAME_COMBINED)) {
|
||||
|
|
|
@ -62,13 +62,13 @@
|
|||
(IRRADIANCE_MAX_POOL_SIZE / IRRADIANCE_SAMPLE_SIZE_Y)
|
||||
|
||||
/* TODO: should be replace by a more elegant alternative. */
|
||||
extern void DRW_opengl_context_enable(void);
|
||||
extern void DRW_opengl_context_disable(void);
|
||||
extern void DRW_gpu_context_enable(void);
|
||||
extern void DRW_gpu_context_disable(void);
|
||||
|
||||
extern void DRW_opengl_render_context_enable(void *re_gl_context);
|
||||
extern void DRW_opengl_render_context_disable(void *re_gl_context);
|
||||
extern void DRW_gpu_render_context_enable(void *re_gpu_context);
|
||||
extern void DRW_gpu_render_context_disable(void *re_gpu_context);
|
||||
extern void DRW_system_gpu_render_context_enable(void *re_system_gpu_context);
|
||||
extern void DRW_system_gpu_render_context_disable(void *re_system_gpu_context);
|
||||
extern void DRW_blender_gpu_render_context_enable(void *re_blender_gpu_context);
|
||||
extern void DRW_blender_gpu_render_context_disable(void *re_blender_gpu_context);
|
||||
|
||||
typedef struct EEVEE_LightBake {
|
||||
Depsgraph *depsgraph;
|
||||
|
@ -157,7 +157,7 @@ typedef struct EEVEE_LightBake {
|
|||
int frame;
|
||||
|
||||
/** If running in parallel (in a separate thread), use this context. */
|
||||
void *gl_context, *gpu_context;
|
||||
void *system_gpu_context, *blender_gpu_context;
|
||||
|
||||
ThreadMutex *mutex;
|
||||
} EEVEE_LightBake;
|
||||
|
@ -601,20 +601,20 @@ static void eevee_lightbake_context_enable(EEVEE_LightBake *lbake)
|
|||
{
|
||||
if (GPU_use_main_context_workaround() && !BLI_thread_is_main()) {
|
||||
GPU_context_main_lock();
|
||||
DRW_opengl_context_enable();
|
||||
DRW_gpu_context_enable();
|
||||
GPU_render_begin();
|
||||
return;
|
||||
}
|
||||
|
||||
if (lbake->gl_context) {
|
||||
DRW_opengl_render_context_enable(lbake->gl_context);
|
||||
if (lbake->gpu_context == NULL) {
|
||||
lbake->gpu_context = GPU_context_create(NULL, lbake->gl_context);
|
||||
if (lbake->system_gpu_context) {
|
||||
DRW_system_gpu_render_context_enable(lbake->system_gpu_context);
|
||||
if (lbake->blender_gpu_context == NULL) {
|
||||
lbake->blender_gpu_context = GPU_context_create(NULL, lbake->system_gpu_context);
|
||||
}
|
||||
DRW_gpu_render_context_enable(lbake->gpu_context);
|
||||
DRW_blender_gpu_render_context_enable(lbake->blender_gpu_context);
|
||||
}
|
||||
else {
|
||||
DRW_opengl_context_enable();
|
||||
DRW_gpu_context_enable();
|
||||
}
|
||||
GPU_render_begin();
|
||||
}
|
||||
|
@ -623,19 +623,19 @@ static void eevee_lightbake_context_disable(EEVEE_LightBake *lbake)
|
|||
{
|
||||
|
||||
if (GPU_use_main_context_workaround() && !BLI_thread_is_main()) {
|
||||
DRW_opengl_context_disable();
|
||||
DRW_gpu_context_disable();
|
||||
GPU_render_end();
|
||||
GPU_context_main_unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
if (lbake->gl_context) {
|
||||
DRW_gpu_render_context_disable(lbake->gpu_context);
|
||||
if (lbake->system_gpu_context) {
|
||||
DRW_blender_gpu_render_context_disable(lbake->blender_gpu_context);
|
||||
GPU_render_end();
|
||||
DRW_opengl_render_context_disable(lbake->gl_context);
|
||||
DRW_system_gpu_render_context_disable(lbake->system_gpu_context);
|
||||
}
|
||||
else {
|
||||
DRW_opengl_context_disable();
|
||||
DRW_gpu_context_disable();
|
||||
GPU_render_end();
|
||||
}
|
||||
}
|
||||
|
@ -788,13 +788,13 @@ wmJob *EEVEE_lightbake_job_create(wmWindowManager *wm,
|
|||
lbake->scene = scene;
|
||||
lbake->bmain = bmain;
|
||||
lbake->view_layer_input = view_layer;
|
||||
lbake->gl_context = old_lbake->gl_context;
|
||||
lbake->system_gpu_context = old_lbake->system_gpu_context;
|
||||
lbake->own_resources = true;
|
||||
lbake->delay = delay;
|
||||
lbake->frame = frame;
|
||||
|
||||
if (lbake->gl_context == NULL && !GPU_use_main_context_workaround()) {
|
||||
lbake->gl_context = WM_opengl_context_create();
|
||||
if (lbake->system_gpu_context == NULL && !GPU_use_main_context_workaround()) {
|
||||
lbake->system_gpu_context = WM_system_gpu_context_create();
|
||||
wm_window_reset_drawable();
|
||||
}
|
||||
|
||||
|
@ -835,7 +835,7 @@ void *EEVEE_lightbake_job_data_alloc(
|
|||
lbake->frame = frame;
|
||||
|
||||
if (run_as_job && !GPU_use_main_context_workaround()) {
|
||||
lbake->gl_context = WM_opengl_context_create();
|
||||
lbake->system_gpu_context = WM_system_gpu_context_create();
|
||||
wm_window_reset_drawable();
|
||||
}
|
||||
|
||||
|
@ -865,12 +865,12 @@ static void eevee_lightbake_delete_resources(EEVEE_LightBake *lbake)
|
|||
BLI_mutex_lock(lbake->mutex);
|
||||
}
|
||||
|
||||
if (lbake->gl_context) {
|
||||
DRW_opengl_render_context_enable(lbake->gl_context);
|
||||
DRW_gpu_render_context_enable(lbake->gpu_context);
|
||||
if (lbake->system_gpu_context) {
|
||||
DRW_system_gpu_render_context_enable(lbake->system_gpu_context);
|
||||
DRW_blender_gpu_render_context_enable(lbake->blender_gpu_context);
|
||||
}
|
||||
else if (!lbake->resource_only) {
|
||||
DRW_opengl_context_enable();
|
||||
DRW_gpu_context_enable();
|
||||
}
|
||||
|
||||
/* XXX: Free the resources contained in the view-layer data
|
||||
|
@ -887,24 +887,24 @@ static void eevee_lightbake_delete_resources(EEVEE_LightBake *lbake)
|
|||
GPU_FRAMEBUFFER_FREE_SAFE(lbake->rt_fb[i]);
|
||||
}
|
||||
|
||||
if (lbake->gpu_context) {
|
||||
DRW_gpu_render_context_disable(lbake->gpu_context);
|
||||
DRW_gpu_render_context_enable(lbake->gpu_context);
|
||||
GPU_context_discard(lbake->gpu_context);
|
||||
if (lbake->blender_gpu_context) {
|
||||
DRW_blender_gpu_render_context_disable(lbake->blender_gpu_context);
|
||||
DRW_blender_gpu_render_context_enable(lbake->blender_gpu_context);
|
||||
GPU_context_discard(lbake->blender_gpu_context);
|
||||
}
|
||||
|
||||
if (lbake->gl_context && lbake->own_resources) {
|
||||
if (lbake->system_gpu_context && lbake->own_resources) {
|
||||
/* Delete the baking context. */
|
||||
DRW_opengl_render_context_disable(lbake->gl_context);
|
||||
WM_opengl_context_dispose(lbake->gl_context);
|
||||
lbake->gpu_context = NULL;
|
||||
lbake->gl_context = NULL;
|
||||
DRW_system_gpu_render_context_disable(lbake->system_gpu_context);
|
||||
WM_system_gpu_context_dispose(lbake->system_gpu_context);
|
||||
lbake->blender_gpu_context = NULL;
|
||||
lbake->system_gpu_context = NULL;
|
||||
}
|
||||
else if (lbake->gl_context) {
|
||||
DRW_opengl_render_context_disable(lbake->gl_context);
|
||||
else if (lbake->system_gpu_context) {
|
||||
DRW_system_gpu_render_context_disable(lbake->system_gpu_context);
|
||||
}
|
||||
else if (!lbake->resource_only) {
|
||||
DRW_opengl_context_disable();
|
||||
DRW_gpu_context_disable();
|
||||
}
|
||||
|
||||
if (!lbake->resource_only) {
|
||||
|
@ -1490,10 +1490,10 @@ void EEVEE_lightbake_job(void *custom_data, bool *stop, bool *do_update, float *
|
|||
lcache->flag |= LIGHTCACHE_BAKED;
|
||||
lcache->flag &= ~LIGHTCACHE_BAKING;
|
||||
|
||||
/* Assume that if lbake->gl_context is NULL
|
||||
/* Assume that if lbake->system_gpu_context is NULL
|
||||
* we are not running in this in a job, so update
|
||||
* the scene light-cache pointer before deleting it. */
|
||||
if (lbake->gl_context == NULL) {
|
||||
if (lbake->system_gpu_context == NULL) {
|
||||
BLI_assert(BLI_thread_is_main());
|
||||
EEVEE_lightbake_update(lbake);
|
||||
}
|
||||
|
|
|
@ -710,7 +710,7 @@ void EEVEE_lightprobes_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *ved
|
|||
|
||||
/* If light-cache auto-update is enable we tag the relevant part
|
||||
* of the cache to update and fire up a baking job. */
|
||||
if (!DRW_state_is_image_render() && !DRW_state_is_opengl_render() &&
|
||||
if (!DRW_state_is_image_render() && !DRW_state_is_viewport_image_render() &&
|
||||
(pinfo->do_grid_update || pinfo->do_cube_update))
|
||||
{
|
||||
BLI_assert(draw_ctx->evil_C);
|
||||
|
|
|
@ -94,7 +94,7 @@ void EEVEE_lookdev_init(EEVEE_Data *vedata)
|
|||
/* Viewport / Spheres size. */
|
||||
const rcti *rect;
|
||||
rcti fallback_rect;
|
||||
if (DRW_state_is_opengl_render()) {
|
||||
if (DRW_state_is_viewport_image_render()) {
|
||||
const float *vp_size = DRW_viewport_size_get();
|
||||
fallback_rect.xmax = vp_size[0];
|
||||
fallback_rect.ymax = vp_size[1];
|
||||
|
|
|
@ -431,7 +431,7 @@ void EEVEE_renderpasses_draw(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
|
|||
|
||||
bool is_valid = (render_pass & EEVEE_RENDERPASSES_ALL) != 0;
|
||||
bool needs_color_transfer = (render_pass & EEVEE_RENDERPASSES_COLOR_PASS) != 0 &&
|
||||
DRW_state_is_opengl_render();
|
||||
DRW_state_is_viewport_image_render();
|
||||
UNUSED_VARS(needs_color_transfer);
|
||||
|
||||
if ((render_pass & EEVEE_RENDER_PASS_BLOOM) != 0 &&
|
||||
|
|
|
@ -245,7 +245,7 @@ int EEVEE_temporal_sampling_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data
|
|||
* Reset for each "redraw". When rendering using OpenGL render,
|
||||
* we accumulate the redraw inside the drawing loop in eevee_draw_scene().
|
||||
*/
|
||||
if (DRW_state_is_opengl_render()) {
|
||||
if (DRW_state_is_viewport_image_render()) {
|
||||
effects->taa_render_sample = 1;
|
||||
}
|
||||
effects->bypass_drawing = false;
|
||||
|
|
|
@ -11,6 +11,11 @@ shared float zdists_cache[gl_WorkGroupSize.x];
|
|||
|
||||
void main()
|
||||
{
|
||||
/* Early exit if no lights are present to prevent out of bounds buffer read. */
|
||||
if (light_cull_buf.visible_count == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint src_index = gl_GlobalInvocationID.x;
|
||||
bool valid_thread = true;
|
||||
|
||||
|
|
|
@ -40,7 +40,7 @@ void main()
|
|||
tile.is_used = true;
|
||||
}
|
||||
/* Reset count for next level. */
|
||||
usage_grid[tile_co.y][tile_co.x] = 0u;
|
||||
usage_grid[tile_co.y / 2][tile_co.x / 2] = 0u;
|
||||
}
|
||||
|
||||
barrier();
|
||||
|
|
|
@ -57,7 +57,8 @@ void main()
|
|||
|
||||
ivec2 tile_co = ivec2(gl_GlobalInvocationID.xy);
|
||||
ivec2 tile_shifted = tile_co + tilemap.grid_shift;
|
||||
ivec2 tile_wrapped = ivec2(tile_shifted % SHADOW_TILEMAP_RES);
|
||||
/* Ensure value is shifted into positive range to avoid modulo on negative. */
|
||||
ivec2 tile_wrapped = ivec2((ivec2(SHADOW_TILEMAP_RES) + tile_shifted) % SHADOW_TILEMAP_RES);
|
||||
|
||||
/* If this tile was shifted in and contains old information, update it.
|
||||
* Note that cubemap always shift all tiles on update. */
|
||||
|
@ -72,7 +73,7 @@ void main()
|
|||
uint lod_size = uint(SHADOW_TILEMAP_RES);
|
||||
for (int lod = 0; lod <= lod_max; lod++, lod_size >>= 1u) {
|
||||
bool thread_active = all(lessThan(tile_co, ivec2(lod_size)));
|
||||
ShadowTileDataPacked tile;
|
||||
ShadowTileDataPacked tile = 0;
|
||||
int tile_load = shadow_tile_offset(tile_wrapped, tilemap.tiles_index, lod);
|
||||
if (thread_active) {
|
||||
tile = init_tile_data(tiles_buf[tile_load], do_update);
|
||||
|
|
|
@ -30,7 +30,7 @@ void OVERLAY_background_cache_init(OVERLAY_Data *vedata)
|
|||
float color_override[4] = {0.0f, 0.0f, 0.0f, 0.0f};
|
||||
int background_type;
|
||||
|
||||
if (DRW_state_is_opengl_render() && !DRW_state_draw_background()) {
|
||||
if (DRW_state_is_viewport_image_render() && !DRW_state_draw_background()) {
|
||||
background_type = BG_SOLID;
|
||||
color_override[3] = 1.0f;
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ class Background {
|
|||
float4 color_override(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
int background_type;
|
||||
|
||||
if (DRW_state_is_opengl_render() && !DRW_state_draw_background()) {
|
||||
if (DRW_state_is_viewport_image_render() && !DRW_state_draw_background()) {
|
||||
background_type = BG_SOLID;
|
||||
color_override[3] = 1.0f;
|
||||
}
|
||||
|
|
|
@ -630,7 +630,7 @@ static void workbench_draw_scene(void *ved)
|
|||
WORKBENCH_Data *vedata = ved;
|
||||
WORKBENCH_PrivateData *wpd = vedata->stl->wpd;
|
||||
|
||||
if (DRW_state_is_opengl_render()) {
|
||||
if (DRW_state_is_viewport_image_render()) {
|
||||
while (wpd->taa_sample < max_ii(1, wpd->taa_sample_len)) {
|
||||
workbench_update_world_ubo(wpd);
|
||||
|
||||
|
|
|
@ -944,7 +944,7 @@ bool DRW_state_is_scene_render(void);
|
|||
/**
|
||||
* Whether we are rendering simple opengl render
|
||||
*/
|
||||
bool DRW_state_is_opengl_render(void);
|
||||
bool DRW_state_is_viewport_image_render(void);
|
||||
bool DRW_state_is_playback(void);
|
||||
/**
|
||||
* Is the user navigating the region.
|
||||
|
|
|
@ -61,7 +61,7 @@ BLI_INLINE void DRW_ibo_request(GPUBatch *batch, GPUIndexBuf **ibo)
|
|||
BLI_INLINE bool DRW_ibo_requested(GPUIndexBuf *ibo)
|
||||
{
|
||||
/* TODO: do not rely on data uploaded. This prevents multi-threading.
|
||||
* (need access to a OpenGL context). */
|
||||
* (need access to a GPU context). */
|
||||
return (ibo != NULL && !GPU_indexbuf_is_init(ibo));
|
||||
}
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue