UI: Asset Shelf (Experimental Feature) #104831

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

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
535 changed files with 18622 additions and 16136 deletions
Showing only changes of commit 3d073a1998 - Show all commits

View File

@ -22,6 +22,7 @@ endif()
add_subdirectory(rangetree)
add_subdirectory(nanosvg)
add_subdirectory(wcwidth)
if(WITH_BULLET)

View File

@ -1,5 +1,5 @@
Project: JSON
URL: https://github.com/nlohmann/json/
License: MIT License
Upstream version: 3.10.2
Upstream version: 3.11.2
Local modifications: None

File diff suppressed because it is too large Load Diff

21
extern/nanosvg/CMakeLists.txt vendored Normal file
View File

@ -0,0 +1,21 @@
# SPDX-FileCopyrightText: 2002-2022 Blender Foundation
#
# SPDX-License-Identifier: GPL-2.0-or-later
set(INC
PUBLIC .
../../source/blender/blenlib
)
set(SRC
nanosvg.h
nanosvgrast.h
blender_nanosvg.c
blender_raster.c
)
set(LIB
)
blender_add_lib(extern_nanosvg "${SRC}" "${INC}" "" "${LIB}")
add_library(bf::extern::nanosvg ALIAS extern_nanosvg)

View File

@ -1,7 +1,9 @@
Project: NanoSVG
URL: https://github.com/memononen/nanosvg
License: zlib
Upstream version: 3cdd4a9d7886
Local modifications: Added some functionality to manage grease pencil layers
Upstream SHA: 9da543e8329fdd81b64eb48742d8ccb09377aed1
GPG key ID: 4AEE18F83AFDEB23
Last Commit: "Merge pull request #236 from sezero/signed-char"
Last Commit Date: December 4, 2022
Added a fix to SVG import arc and float errors (https://developer.blender.org/rB11dc674c78b49fc4e0b7c134c375b6c8b8eacbcc)
Local modifications: Added some functionality to manage grease pencil layers

10
extern/nanosvg/blender_nanosvg.c vendored Normal file
View File

@ -0,0 +1,10 @@
/* SPDX-FileCopyrightText: 2023 Blender Foundation
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#define NANOSVG_IMPLEMENTATION
#define NANOSVG_ALL_COLOR_KEYWORDS
#include <stdio.h>
#include "BLI_utildefines.h"
#include "nanosvg.h"

6
extern/nanosvg/blender_raster.c vendored Normal file
View File

@ -0,0 +1,6 @@
/* SPDX-FileCopyrightText: 2023 Blender Foundation
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#define NANOSVGRAST_IMPLEMENTATION
#include "nanosvgrast.h"

5072
extern/nanosvg/nanosvg.h vendored

File diff suppressed because it is too large Load Diff

1458
extern/nanosvg/nanosvgrast.h vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,86 +1,647 @@
diff --git a/c:/tmp/nanosvg_original.h b/c:/tmp/nanosvg_modif.h
index 24a01a86d3d..eca0d07e79d 100644
--- a/c:/tmp/nanosvg_original.h
+++ b/c:/tmp/nanosvg_modif.h
@@ -24,7 +24,8 @@
diff --git a/extern/nanosvg/nanosvg.h b/extern/nanosvg/nanosvg.h
index 60a323820cb..1bfb891c397 100644
--- a/extern/nanosvg/nanosvg.h
+++ b/extern/nanosvg/nanosvg.h
@@ -1,56 +1,58 @@
/*
* Copyright (c) 2013-14 Mikko Mononen memon@inside.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*
* The SVG parser is based on Anti-Grain Geometry 2.4 SVG example
* Copyright (C) 2002-2004 Maxim Shemanarev (McSeem) (http://www.antigrain.com/)
*
* Arc calculation code based on canvg (https://code.google.com/p/canvg/)
*
* Bounding box calculation based on http://blog.hackers-cafe.net/2009/06/how-to-calculate-bezier-curves-bounding.html
*
- */
+ * This is a modified version for Blender used by importers.
+ **/
+ *
*/
#ifndef NANOSVG_H
#define NANOSVG_H
@@ -148,6 +149,8 @@ extern "C" {
typedef struct NSVGshape
{
char id[64]; // Optional 'id' attr of the shape or its group
+ /* Blender: Parent ID used for layer creation. */
+ char id_parent[64];
NSVGpaint fill; // Fill paint
NSVGpaint stroke; // Stroke paint
float opacity; // Opacity of the shape.
@@ -370,6 +373,7 @@ int nsvg__parseXML(char* input,
#ifndef NANOSVG_CPLUSPLUS
#ifdef __cplusplus
extern "C" {
#endif
#endif
// NanoSVG is a simple stupid single-header-file SVG parse. The output of the parser is a list of cubic bezier shapes.
//
// The library suits well for anything from rendering scalable icons in your editor application to prototyping a game.
//
// NanoSVG supports a wide range of SVG features, but something may be missing, feel free to create a pull request!
//
// The shapes in the SVG images are transformed by the viewBox and converted to specified units.
// That is, you should get the same looking data as your designed in your favorite app.
//
// NanoSVG can return the paths in few different units. For example if you want to render an image, you may choose
// to get the paths in pixels, or if you are feeding the data into a CNC-cutter, you may want to use millimeters.
//
// The units passed to NanoSVG should be one of: 'px', 'pt', 'pc' 'mm', 'cm', or 'in'.
// DPI (dots-per-inch) controls how the unit conversion is done.
//
// If you don't know or care about the units stuff, "px" and 96 should get you going.
/* Example Usage:
@@ -112,60 +114,61 @@ typedef struct NSVGgradientStop {
} NSVGgradientStop;
typedef struct NSVGgradient {
float xform[6];
char spread;
float fx, fy;
int nstops;
NSVGgradientStop stops[1];
} NSVGgradient;
typedef struct NSVGpaint {
signed char type;
union {
unsigned int color;
NSVGgradient* gradient;
};
} NSVGpaint;
typedef struct NSVGpath
{
float* pts; // Cubic bezier points: x0,y0, [cpx1,cpx1,cpx2,cpy2,x1,y1], ...
int npts; // Total number of bezier points.
char closed; // Flag indicating if shapes should be treated as closed.
float bounds[4]; // Tight bounding box of the shape [minx,miny,maxx,maxy].
struct NSVGpath* next; // Pointer to next path, or NULL if last element.
} NSVGpath;
typedef struct NSVGshape
{
char id[64]; // Optional 'id' attr of the shape or its group
+ char id_parent[64]; // Blender: Parent ID used for layer creation.
NSVGpaint fill; // Fill paint
NSVGpaint stroke; // Stroke paint
float opacity; // Opacity of the shape.
float strokeWidth; // Stroke width (scaled).
float strokeDashOffset; // Stroke dash offset (scaled).
float strokeDashArray[8]; // Stroke dash array (scaled).
char strokeDashCount; // Number of dash values in dash array.
char strokeLineJoin; // Stroke join type.
char strokeLineCap; // Stroke cap type.
float miterLimit; // Miter limit
char fillRule; // Fill rule, see NSVGfillRule.
unsigned char flags; // Logical or of NSVG_FLAGS_* flags
float bounds[4]; // Tight bounding box of the shape [minx,miny,maxx,maxy].
char fillGradient[64]; // Optional 'id' of fill gradient
char strokeGradient[64]; // Optional 'id' of stroke gradient
float xform[6]; // Root transformation for fill/stroke gradient
NSVGpath* paths; // Linked list of paths in the image.
struct NSVGshape* next; // Pointer to next shape, or NULL if last element.
} NSVGshape;
typedef struct NSVGimage
{
float width; // Width of the image.
float height; // Height of the image.
NSVGshape* shapes; // Linked list of shapes in the image.
} NSVGimage;
// Parses SVG file from a file, returns SVG image as paths.
NSVGimage* nsvgParseFromFile(const char* filename, const char* units, float dpi);
@@ -333,60 +336,61 @@ int nsvg__parseXML(char* input,
void* ud)
{
char* s = input;
char* mark = s;
int state = NSVG_XML_CONTENT;
while (*s) {
if (*s == '<' && state == NSVG_XML_CONTENT) {
// Start of a tag
*s++ = '\0';
nsvg__parseContent(mark, contentCb, ud);
mark = s;
state = NSVG_XML_TAG;
} else if (*s == '>' && state == NSVG_XML_TAG) {
// Start of a content or new tag.
*s++ = '\0';
nsvg__parseElement(mark, startelCb, endelCb, ud);
mark = s;
state = NSVG_XML_CONTENT;
} else {
s++;
}
}
return 1;
}
/* Simple SVG parser. */
#define NSVG_MAX_ATTR 128
+#define NSVG_MAX_BREADCRUMB 5
enum NSVGgradientUnits
enum NSVGgradientUnits {
NSVG_USER_SPACE = 0,
NSVG_OBJECT_SPACE = 1
};
#define NSVG_MAX_DASHES 8
enum NSVGunits {
NSVG_UNITS_USER,
NSVG_UNITS_PX,
NSVG_UNITS_PT,
NSVG_UNITS_PC,
NSVG_UNITS_MM,
NSVG_UNITS_CM,
NSVG_UNITS_IN,
NSVG_UNITS_PERCENT,
NSVG_UNITS_EM,
NSVG_UNITS_EX
};
typedef struct NSVGcoordinate {
float value;
int units;
} NSVGcoordinate;
typedef struct NSVGlinearData {
NSVGcoordinate x1, y1, x2, y2;
} NSVGlinearData;
@@ -428,60 +432,64 @@ typedef struct NSVGattrib
int strokeDashCount;
char strokeLineJoin;
char strokeLineCap;
float miterLimit;
char fillRule;
float fontSize;
unsigned int stopColor;
float stopOpacity;
float stopOffset;
char hasFill;
char hasStroke;
char visible;
} NSVGattrib;
typedef struct NSVGparser
{
@@ -471,6 +475,10 @@ typedef struct NSVGparser
NSVGattrib attr[NSVG_MAX_ATTR];
int attrHead;
float* pts;
int npts;
int cpts;
NSVGpath* plist;
NSVGimage* image;
NSVGgradientData* gradients;
NSVGshape* shapesTail;
float viewMinx, viewMiny, viewWidth, viewHeight;
int alignX, alignY, alignType;
float dpi;
char pathFlag;
char defsFlag;
+ /** Blender breadcrumb for layers. */
+ char breadcrumb[NSVG_MAX_BREADCRUMB][64];
+ /** Blender number of elements in breadcrumb. */
+ int breadcrumb_len;
+ /** Blender breadcrumb for layers. */
+ char breadcrumb[NSVG_MAX_BREADCRUMB][64];
+ /** Blender number of elements in breadcrumb. */
+ int breadcrumb_len;
} NSVGparser;
static void nsvg__xformIdentity(float* t)
@@ -980,6 +988,14 @@ static void nsvg__addShape(NSVGparser* p)
{
t[0] = 1.0f; t[1] = 0.0f;
t[2] = 0.0f; t[3] = 1.0f;
t[4] = 0.0f; t[5] = 0.0f;
}
static void nsvg__xformSetTranslation(float* t, float tx, float ty)
{
t[0] = 1.0f; t[1] = 0.0f;
t[2] = 0.0f; t[3] = 1.0f;
t[4] = tx; t[5] = ty;
}
static void nsvg__xformSetScale(float* t, float sx, float sy)
{
t[0] = sx; t[1] = 0.0f;
t[2] = 0.0f; t[3] = sy;
t[4] = 0.0f; t[5] = 0.0f;
}
static void nsvg__xformSetSkewX(float* t, float a)
{
t[0] = 1.0f; t[1] = 0.0f;
t[2] = tanf(a); t[3] = 1.0f;
t[4] = 0.0f; t[5] = 0.0f;
}
@@ -930,60 +938,68 @@ static void nsvg__getLocalBounds(float* bounds, NSVGshape *shape, float* xform)
bounds[2] = curveBounds[2];
bounds[3] = curveBounds[3];
first = 0;
} else {
bounds[0] = nsvg__minf(bounds[0], curveBounds[0]);
bounds[1] = nsvg__minf(bounds[1], curveBounds[1]);
bounds[2] = nsvg__maxf(bounds[2], curveBounds[2]);
bounds[3] = nsvg__maxf(bounds[3], curveBounds[3]);
}
curve[0] = curve[6];
curve[1] = curve[7];
}
}
}
static void nsvg__addShape(NSVGparser* p)
{
NSVGattrib* attr = nsvg__getAttr(p);
float scale = 1.0f;
NSVGshape* shape;
NSVGpath* path;
int i;
if (p->plist == NULL)
return;
shape = (NSVGshape*)malloc(sizeof(NSVGshape));
if (shape == NULL) goto error;
memset(shape, 0, sizeof(NSVGshape));
memcpy(shape->id, attr->id, sizeof shape->id);
+ /* Copy parent id from breadcrumb. */
+ if (p->breadcrumb_len > 0) {
+ memcpy(shape->id_parent, p->breadcrumb[0], sizeof shape->id_parent);
+ }
+ else {
+ memcpy(shape->id_parent, attr->id, sizeof shape->id_parent);
+ }
+ /* Copy parent id from breadcrumb. */
+ if (p->breadcrumb_len > 0) {
+ memcpy(shape->id_parent, p->breadcrumb[0], sizeof shape->id_parent);
+ }
+ else {
+ memcpy(shape->id_parent, attr->id, sizeof shape->id_parent);
+ }
+
memcpy(shape->id, attr->id, sizeof shape->id);
memcpy(shape->fillGradient, attr->fillGradient, sizeof shape->fillGradient);
memcpy(shape->strokeGradient, attr->strokeGradient, sizeof shape->strokeGradient);
memcpy(shape->xform, attr->xform, sizeof shape->xform);
scale = nsvg__getAverageScale(attr->xform);
shape->strokeWidth = attr->strokeWidth * scale;
shape->strokeDashOffset = attr->strokeDashOffset * scale;
@@ -2814,6 +2830,14 @@ static void nsvg__startElement(void* ud, const char* el, const char** attr)
shape->strokeDashCount = (char)attr->strokeDashCount;
for (i = 0; i < attr->strokeDashCount; i++)
shape->strokeDashArray[i] = attr->strokeDashArray[i] * scale;
shape->strokeLineJoin = attr->strokeLineJoin;
shape->strokeLineCap = attr->strokeLineCap;
shape->miterLimit = attr->miterLimit;
shape->fillRule = attr->fillRule;
shape->opacity = attr->opacity;
shape->paths = p->plist;
p->plist = NULL;
// Calculate shape bounds
shape->bounds[0] = shape->paths->bounds[0];
shape->bounds[1] = shape->paths->bounds[1];
shape->bounds[2] = shape->paths->bounds[2];
shape->bounds[3] = shape->paths->bounds[3];
for (path = shape->paths->next; path != NULL; path = path->next) {
shape->bounds[0] = nsvg__minf(shape->bounds[0], path->bounds[0]);
shape->bounds[1] = nsvg__minf(shape->bounds[1], path->bounds[1]);
shape->bounds[2] = nsvg__maxf(shape->bounds[2], path->bounds[2]);
shape->bounds[3] = nsvg__maxf(shape->bounds[3], path->bounds[3]);
}
@@ -1175,66 +1191,75 @@ static const char* nsvg__parseNumber(const char* s, char* it, const int size)
if ((*s == 'e' || *s == 'E') && (s[1] != 'm' && s[1] != 'x')) {
if (i < last) it[i++] = *s;
s++;
if (*s == '-' || *s == '+') {
if (i < last) it[i++] = *s;
s++;
}
while (*s && nsvg__isdigit(*s)) {
if (i < last) it[i++] = *s;
s++;
}
}
it[i] = '\0';
return s;
}
static const char* nsvg__getNextPathItemWhenArcFlag(const char* s, char* it)
{
it[0] = '\0';
while (*s && (nsvg__isspace(*s) || *s == ',')) s++;
if (!*s) return s;
if (*s == '0' || *s == '1') {
it[0] = *s++;
it[1] = '\0';
return s;
}
return s;
}
-static const char* nsvg__getNextPathItem(const char* s, char* it)
+static const char* nsvg__getNextPathItem(const char* s, char* it, char cmd, int nargs)
{
it[0] = '\0';
// Skip white spaces and commas
while (*s && (nsvg__isspace(*s) || *s == ',')) s++;
if (!*s) return s;
+
+ /* Blender: Special case for arc command's 4th and 5th arguments. */
+ if ((cmd == 'a' || cmd == 'A') && (nargs == 3 || nargs == 4)) {
+ it[0] = s[0];
+ it[1] = '\0';
+ s++;
+ return s;
+ }
+
if (*s == '-' || *s == '+' || *s == '.' || nsvg__isdigit(*s)) {
s = nsvg__parseNumber(s, it, 64);
} else {
// Parse command
it[0] = *s++;
it[1] = '\0';
return s;
}
return s;
}
static unsigned int nsvg__parseColorHex(const char* str)
{
unsigned int r=0, g=0, b=0;
if (sscanf(str, "#%2x%2x%2x", &r, &g, &b) == 3 ) // 2 digit hex
return NSVG_RGB(r, g, b);
if (sscanf(str, "#%1x%1x%1x", &r, &g, &b) == 3 ) // 1 digit hex, e.g. #abc -> 0xccbbaa
return NSVG_RGB(r*17, g*17, b*17); // same effect as (r<<4|r), (g<<4|g), ..
return NSVG_RGB(128, 128, 128);
}
// Parse rgb color. The pointer 'str' must point at "rgb(" (4+ characters).
// This function returns gray (rgb(128, 128, 128) == '#808080') on parse errors
// for backwards compatibility. Note: other image viewers return black instead.
static unsigned int nsvg__parseColorRGB(const char* str)
{
int i;
unsigned int rgbi[3];
@@ -2264,61 +2289,61 @@ static void nsvg__parsePath(NSVGparser* p, const char** attr)
const char* tmp[4];
char closedFlag;
int i;
char item[64];
for (i = 0; attr[i]; i += 2) {
if (strcmp(attr[i], "d") == 0) {
s = attr[i + 1];
} else {
tmp[0] = attr[i];
tmp[1] = attr[i + 1];
tmp[2] = 0;
tmp[3] = 0;
nsvg__parseAttribs(p, tmp);
}
}
if (s) {
nsvg__resetPath(p);
cpx = 0; cpy = 0;
cpx2 = 0; cpy2 = 0;
initPoint = 0;
closedFlag = 0;
nargs = 0;
while (*s) {
item[0] = '\0';
if ((cmd == 'A' || cmd == 'a') && (nargs == 3 || nargs == 4))
s = nsvg__getNextPathItemWhenArcFlag(s, item);
if (!*item)
- s = nsvg__getNextPathItem(s, item);
+ s = nsvg__getNextPathItem(s, item, cmd, nargs);
if (!*item) break;
if (cmd != '\0' && nsvg__isCoordinate(item)) {
if (nargs < 10)
args[nargs++] = (float)nsvg__atof(item);
if (nargs >= rargs) {
switch (cmd) {
case 'm':
case 'M':
nsvg__pathMoveTo(p, &cpx, &cpy, args, cmd == 'm' ? 1 : 0);
// Moveto can be followed by multiple coordinate pairs,
// which should be treated as linetos.
cmd = (cmd == 'm') ? 'l' : 'L';
rargs = nsvg__getArgsPerElement(cmd);
cpx2 = cpx; cpy2 = cpy;
initPoint = 1;
break;
case 'l':
case 'L':
nsvg__pathLineTo(p, &cpx, &cpy, args, cmd == 'l' ? 1 : 0);
cpx2 = cpx; cpy2 = cpy;
break;
case 'H':
case 'h':
nsvg__pathHLineTo(p, &cpx, &cpy, args, cmd == 'h' ? 1 : 0);
cpx2 = cpx; cpy2 = cpy;
break;
case 'V':
case 'v':
nsvg__pathVLineTo(p, &cpx, &cpy, args, cmd == 'v' ? 1 : 0);
cpx2 = cpx; cpy2 = cpy;
@@ -2534,61 +2559,61 @@ static void nsvg__parseLine(NSVGparser* p, const char** attr)
if (strcmp(attr[i], "y2") == 0) y2 = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigY(p), nsvg__actualHeight(p));
}
}
nsvg__resetPath(p);
nsvg__moveTo(p, x1, y1);
nsvg__lineTo(p, x2, y2);
nsvg__addPath(p, 0);
nsvg__addShape(p);
}
static void nsvg__parsePoly(NSVGparser* p, const char** attr, int closeFlag)
{
int i;
const char* s;
float args[2];
int nargs, npts = 0;
char item[64];
nsvg__resetPath(p);
for (i = 0; attr[i]; i += 2) {
if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) {
if (strcmp(attr[i], "points") == 0) {
s = attr[i + 1];
nargs = 0;
while (*s) {
- s = nsvg__getNextPathItem(s, item);
+ s = nsvg__getNextPathItem(s, item, '\0', nargs);
args[nargs++] = (float)nsvg__atof(item);
if (nargs >= 2) {
if (npts == 0)
nsvg__moveTo(p, args[0], args[1]);
else
nsvg__lineTo(p, args[0], args[1]);
nargs = 0;
npts++;
}
}
}
}
}
nsvg__addPath(p, (char)closeFlag);
nsvg__addShape(p);
}
static void nsvg__parseSVG(NSVGparser* p, const char** attr)
{
int i;
for (i = 0; attr[i]; i += 2) {
if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) {
if (strcmp(attr[i], "width") == 0) {
p->image->width = nsvg__parseCoordinate(p, attr[i + 1], 0.0f, 0.0f);
} else if (strcmp(attr[i], "height") == 0) {
p->image->height = nsvg__parseCoordinate(p, attr[i + 1], 0.0f, 0.0f);
} else if (strcmp(attr[i], "viewBox") == 0) {
const char *s = attr[i + 1];
@@ -2740,108 +2765,122 @@ static void nsvg__parseGradientStop(NSVGparser* p, const char** attr)
if (idx != grad->nstops-1) {
for (i = grad->nstops-1; i > idx; i--)
grad->stops[i] = grad->stops[i-1];
}
stop = &grad->stops[idx];
stop->color = curAttr->stopColor;
stop->color |= (unsigned int)(curAttr->stopOpacity*255) << 24;
stop->offset = curAttr->stopOffset;
}
static void nsvg__startElement(void* ud, const char* el, const char** attr)
{
NSVGparser* p = (NSVGparser*)ud;
if (p->defsFlag) {
// Skip everything but gradients in defs
if (strcmp(el, "linearGradient") == 0) {
nsvg__parseGradient(p, attr, NSVG_PAINT_LINEAR_GRADIENT);
} else if (strcmp(el, "radialGradient") == 0) {
nsvg__parseGradient(p, attr, NSVG_PAINT_RADIAL_GRADIENT);
} else if (strcmp(el, "stop") == 0) {
nsvg__parseGradientStop(p, attr);
}
return;
}
if (strcmp(el, "g") == 0) {
nsvg__pushAttr(p);
nsvg__parseAttribs(p, attr);
+
+ /* Save the breadcrumb of groups. */
+ if (p->breadcrumb_len < NSVG_MAX_BREADCRUMB) {
+ NSVGattrib *attr_id = nsvg__getAttr(p);
+ memcpy(
+ p->breadcrumb[p->breadcrumb_len], attr_id->id, sizeof(p->breadcrumb[p->breadcrumb_len]));
+ p->breadcrumb_len++;
+ }
}
else if (strcmp(el, "path") == 0) {
+ /* Save the breadcrumb of groups. */
+ if (p->breadcrumb_len < NSVG_MAX_BREADCRUMB) {
+ NSVGattrib *attr_id = nsvg__getAttr(p);
+ memcpy(
+ p->breadcrumb[p->breadcrumb_len], attr_id->id, sizeof(p->breadcrumb[p->breadcrumb_len]));
+ p->breadcrumb_len++;
+ }
} else if (strcmp(el, "path") == 0) {
if (p->pathFlag) // Do not allow nested paths.
@@ -2874,7 +2898,12 @@ static void nsvg__endElement(void* ud, const char* el)
return;
nsvg__pushAttr(p);
nsvg__parsePath(p, attr);
nsvg__popAttr(p);
} else if (strcmp(el, "rect") == 0) {
nsvg__pushAttr(p);
nsvg__parseRect(p, attr);
nsvg__popAttr(p);
} else if (strcmp(el, "circle") == 0) {
nsvg__pushAttr(p);
nsvg__parseCircle(p, attr);
nsvg__popAttr(p);
} else if (strcmp(el, "ellipse") == 0) {
nsvg__pushAttr(p);
nsvg__parseEllipse(p, attr);
nsvg__popAttr(p);
} else if (strcmp(el, "line") == 0) {
nsvg__pushAttr(p);
nsvg__parseLine(p, attr);
nsvg__popAttr(p);
} else if (strcmp(el, "polyline") == 0) {
nsvg__pushAttr(p);
nsvg__parsePoly(p, attr, 0);
nsvg__popAttr(p);
} else if (strcmp(el, "polygon") == 0) {
nsvg__pushAttr(p);
nsvg__parsePoly(p, attr, 1);
nsvg__popAttr(p);
} else if (strcmp(el, "linearGradient") == 0) {
nsvg__parseGradient(p, attr, NSVG_PAINT_LINEAR_GRADIENT);
} else if (strcmp(el, "radialGradient") == 0) {
nsvg__parseGradient(p, attr, NSVG_PAINT_RADIAL_GRADIENT);
} else if (strcmp(el, "stop") == 0) {
nsvg__parseGradientStop(p, attr);
} else if (strcmp(el, "defs") == 0) {
p->defsFlag = 1;
} else if (strcmp(el, "svg") == 0) {
nsvg__parseSVG(p, attr);
}
}
static void nsvg__endElement(void* ud, const char* el)
{
NSVGparser* p = (NSVGparser*)ud;
if (strcmp(el, "g") == 0) {
- nsvg__popAttr(p);
+ /* Remove the breadcrumb level. */
+ if (p->breadcrumb_len > 0) {
+ p->breadcrumb[p->breadcrumb_len - 1][0] = '\0';
+ p->breadcrumb_len--;
+ }
+ nsvg__popAttr(p);
}
else if (strcmp(el, "path") == 0) {
+ /* Remove the breadcrumb level. */
+ if (p->breadcrumb_len > 0) {
+ p->breadcrumb[p->breadcrumb_len - 1][0] = '\0';
+ p->breadcrumb_len--;
+ }
+
nsvg__popAttr(p);
} else if (strcmp(el, "path") == 0) {
p->pathFlag = 0;
} else if (strcmp(el, "defs") == 0) {
p->defsFlag = 0;
}
}
static void nsvg__content(void* ud, const char* s)
{
NSVG_NOTUSED(ud);
NSVG_NOTUSED(s);
// empty
}
static void nsvg__imageBounds(NSVGparser* p, float* bounds)
{
NSVGshape* shape;
shape = p->image->shapes;
if (shape == NULL) {
bounds[0] = bounds[1] = bounds[2] = bounds[3] = 0.0;
return;
}
bounds[0] = shape->bounds[0];
bounds[1] = shape->bounds[1];
bounds[2] = shape->bounds[2];
bounds[3] = shape->bounds[3];
for (shape = shape->next; shape != NULL; shape = shape->next) {
bounds[0] = nsvg__minf(bounds[0], shape->bounds[0]);
bounds[1] = nsvg__minf(bounds[1], shape->bounds[1]);

View File

@ -6,7 +6,6 @@ set(INC
..
../../mikktspace
../../../source/blender/makesrna
../../../source/blender/blenkernel
../../../source/blender/gpu
../../../source/blender/render
${CMAKE_BINARY_DIR}/source/blender/makesrna/intern
@ -57,6 +56,7 @@ set(SRC
)
set(LIB
PRIVATE bf::blenkernel
PRIVATE bf::blenlib
PRIVATE bf::dna
PRIVATE bf::intern::guardedalloc

View File

@ -860,7 +860,7 @@ bool BlenderDisplayDriver::gpu_resources_create()
gpu_render_sync_ = GPU_fence_create();
if (!DCHECK_NOTNULL(gpu_upload_sync_) || !DCHECK_NOTNULL(gpu_render_sync_)) {
LOG(ERROR) << "Error creating GPU synchronization primtiives.";
LOG(ERROR) << "Error creating GPU synchronization primitives.";
assert(0);
return false;
}

View File

@ -157,12 +157,6 @@ ccl_device_inline int bsdf_sample(KernelGlobals kg,
*sampled_roughness = zero_float2();
*eta = 1.0f;
break;
case CLOSURE_BSDF_REFLECTION_ID:
case CLOSURE_BSDF_REFRACTION_ID:
case CLOSURE_BSDF_SHARP_GLASS_ID:
label = bsdf_microfacet_sharp_sample(
sc, path_flag, Ng, sd->wi, rand, eval, wo, pdf, sampled_roughness, eta);
break;
case CLOSURE_BSDF_MICROFACET_GGX_ID:
case CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID:
case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID:
@ -296,9 +290,6 @@ ccl_device_inline void bsdf_roughness_eta(const KernelGlobals kg,
*roughness = zero_float2();
*eta = 1.0f;
break;
case CLOSURE_BSDF_REFLECTION_ID:
case CLOSURE_BSDF_REFRACTION_ID:
case CLOSURE_BSDF_SHARP_GLASS_ID:
case CLOSURE_BSDF_MICROFACET_GGX_ID:
case CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID:
case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID:
@ -398,9 +389,6 @@ ccl_device_inline int bsdf_label(const KernelGlobals kg,
case CLOSURE_BSDF_TRANSPARENT_ID:
label = LABEL_TRANSMIT | LABEL_TRANSPARENT;
break;
case CLOSURE_BSDF_REFLECTION_ID:
case CLOSURE_BSDF_REFRACTION_ID:
case CLOSURE_BSDF_SHARP_GLASS_ID:
case CLOSURE_BSDF_MICROFACET_GGX_ID:
case CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID:
case CLOSURE_BSDF_MICROFACET_BECKMANN_ID:
@ -410,7 +398,7 @@ ccl_device_inline int bsdf_label(const KernelGlobals kg,
case CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID: {
ccl_private const MicrofacetBsdf *bsdf = (ccl_private const MicrofacetBsdf *)sc;
label = ((bsdf_is_transmission(sc, wo)) ? LABEL_TRANSMIT : LABEL_REFLECT) |
((bsdf->alpha_x * bsdf->alpha_y <= 1e-7f) ? LABEL_SINGULAR : LABEL_GLOSSY);
((bsdf_microfacet_eval_flag(bsdf)) ? LABEL_GLOSSY : LABEL_SINGULAR);
break;
}
case CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID:
@ -499,11 +487,6 @@ ccl_device_inline
case CLOSURE_BSDF_TRANSPARENT_ID:
eval = bsdf_transparent_eval(sc, sd->wi, wo, pdf);
break;
case CLOSURE_BSDF_REFLECTION_ID:
case CLOSURE_BSDF_REFRACTION_ID:
case CLOSURE_BSDF_SHARP_GLASS_ID:
eval = bsdf_microfacet_sharp_eval(sc, sd->N, sd->wi, wo, pdf);
break;
case CLOSURE_BSDF_MICROFACET_GGX_ID:
case CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID:
case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID:
@ -579,13 +562,11 @@ ccl_device void bsdf_blur(KernelGlobals kg, ccl_private ShaderClosure *sc, float
case CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID:
case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID:
case CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID:
/* TODO: Recompute energy preservation after blur? */
bsdf_microfacet_ggx_blur(sc, roughness);
break;
case CLOSURE_BSDF_MICROFACET_BECKMANN_ID:
case CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID:
case CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID:
bsdf_microfacet_beckmann_blur(sc, roughness);
/* TODO: Recompute energy preservation after blur? */
bsdf_microfacet_blur(sc, roughness);
break;
case CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID:
bsdf_ashikhmin_shirley_blur(sc, roughness);

View File

@ -18,7 +18,6 @@ CCL_NAMESPACE_BEGIN
enum MicrofacetType {
BECKMANN,
GGX,
SHARP,
};
enum MicrofacetFresnel {
@ -444,6 +443,12 @@ ccl_device_inline float bsdf_aniso_D(float alpha_x, float alpha_y, float3 H)
}
}
/* Do not set `SD_BSDF_HAS_EVAL` flag if the squared roughness is below a certain threshold. */
ccl_device_forceinline int bsdf_microfacet_eval_flag(const ccl_private MicrofacetBsdf *bsdf)
{
return (bsdf->alpha_x * bsdf->alpha_y > BSDF_ROUGHNESS_SQ_THRESH) ? SD_BSDF_HAS_EVAL : 0;
}
template<MicrofacetType m_type>
ccl_device Spectrum bsdf_microfacet_eval(ccl_private const ShaderClosure *sc,
const float3 Ng,
@ -451,11 +456,6 @@ ccl_device Spectrum bsdf_microfacet_eval(ccl_private const ShaderClosure *sc,
const float3 wo,
ccl_private float *pdf)
{
if (m_type == MicrofacetType::SHARP) {
*pdf = 0.0f;
return zero_spectrum();
}
ccl_private const MicrofacetBsdf *bsdf = (ccl_private const MicrofacetBsdf *)sc;
/* Refraction: Only consider BTDF
* Glass: Consider both BRDF and BTDF, mix based on Fresnel
@ -481,7 +481,7 @@ ccl_device Spectrum bsdf_microfacet_eval(ccl_private const ShaderClosure *sc,
* - Purely reflective closures can't have refraction.
* - Purely refractive closures can't have reflection.
*/
if ((cos_NI <= 0) || (alpha_x * alpha_y <= 5e-7f) || ((cos_NgO < 0.0f) != is_transmission) ||
if ((cos_NI <= 0) || !bsdf_microfacet_eval_flag(bsdf) || ((cos_NgO < 0.0f) != is_transmission) ||
(is_transmission && m_reflection) || (!is_transmission && m_refraction))
{
*pdf = 0.0f;
@ -565,7 +565,7 @@ ccl_device int bsdf_microfacet_sample(ccl_private const ShaderClosure *sc,
const bool m_reflection = !(m_refraction || m_glass);
const float alpha_x = bsdf->alpha_x;
const float alpha_y = bsdf->alpha_y;
bool m_singular = (m_type == MicrofacetType::SHARP) || (alpha_x * alpha_y <= 5e-7f);
bool m_singular = !bsdf_microfacet_eval_flag(bsdf);
const float3 N = bsdf->N;
const float cos_NI = dot(N, wi);
@ -848,7 +848,7 @@ ccl_device int bsdf_microfacet_ggx_setup(ccl_private MicrofacetBsdf *bsdf)
bsdf->energy_scale = 1.0f;
bsdf->type = CLOSURE_BSDF_MICROFACET_GGX_ID;
return SD_BSDF | SD_BSDF_HAS_EVAL;
return SD_BSDF | bsdf_microfacet_eval_flag(bsdf);
}
ccl_device int bsdf_microfacet_ggx_clearcoat_setup(ccl_private MicrofacetBsdf *bsdf,
@ -862,7 +862,7 @@ ccl_device int bsdf_microfacet_ggx_clearcoat_setup(ccl_private MicrofacetBsdf *b
bsdf->type = CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID;
bsdf->sample_weight *= average(bsdf_microfacet_estimate_fresnel(sd, bsdf, true, true));
return SD_BSDF | SD_BSDF_HAS_EVAL;
return SD_BSDF | bsdf_microfacet_eval_flag(bsdf);
}
ccl_device int bsdf_microfacet_ggx_refraction_setup(ccl_private MicrofacetBsdf *bsdf)
@ -874,7 +874,7 @@ ccl_device int bsdf_microfacet_ggx_refraction_setup(ccl_private MicrofacetBsdf *
bsdf->energy_scale = 1.0f;
bsdf->type = CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID;
return SD_BSDF | SD_BSDF_HAS_EVAL | SD_BSDF_HAS_TRANSMISSION;
return SD_BSDF | SD_BSDF_HAS_TRANSMISSION | bsdf_microfacet_eval_flag(bsdf);
}
ccl_device int bsdf_microfacet_ggx_glass_setup(ccl_private MicrofacetBsdf *bsdf)
@ -886,10 +886,10 @@ ccl_device int bsdf_microfacet_ggx_glass_setup(ccl_private MicrofacetBsdf *bsdf)
bsdf->energy_scale = 1.0f;
bsdf->type = CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID;
return SD_BSDF | SD_BSDF_HAS_EVAL | SD_BSDF_HAS_TRANSMISSION;
return SD_BSDF | SD_BSDF_HAS_TRANSMISSION | bsdf_microfacet_eval_flag(bsdf);
}
ccl_device void bsdf_microfacet_ggx_blur(ccl_private ShaderClosure *sc, float roughness)
ccl_device void bsdf_microfacet_blur(ccl_private ShaderClosure *sc, float roughness)
{
ccl_private MicrofacetBsdf *bsdf = (ccl_private MicrofacetBsdf *)sc;
@ -937,7 +937,8 @@ ccl_device int bsdf_microfacet_beckmann_setup(ccl_private MicrofacetBsdf *bsdf)
bsdf->fresnel_type = MicrofacetFresnel::NONE;
bsdf->type = CLOSURE_BSDF_MICROFACET_BECKMANN_ID;
return SD_BSDF | SD_BSDF_HAS_EVAL;
return SD_BSDF | bsdf_microfacet_eval_flag(bsdf);
}
ccl_device int bsdf_microfacet_beckmann_refraction_setup(ccl_private MicrofacetBsdf *bsdf)
@ -947,7 +948,8 @@ ccl_device int bsdf_microfacet_beckmann_refraction_setup(ccl_private MicrofacetB
bsdf->fresnel_type = MicrofacetFresnel::NONE;
bsdf->type = CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID;
return SD_BSDF | SD_BSDF_HAS_EVAL | SD_BSDF_HAS_TRANSMISSION;
return SD_BSDF | SD_BSDF_HAS_TRANSMISSION | bsdf_microfacet_eval_flag(bsdf);
}
ccl_device int bsdf_microfacet_beckmann_glass_setup(ccl_private MicrofacetBsdf *bsdf)
@ -957,15 +959,8 @@ ccl_device int bsdf_microfacet_beckmann_glass_setup(ccl_private MicrofacetBsdf *
bsdf->fresnel_type = MicrofacetFresnel::DIELECTRIC;
bsdf->type = CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID;
return SD_BSDF | SD_BSDF_HAS_EVAL | SD_BSDF_HAS_TRANSMISSION;
}
ccl_device void bsdf_microfacet_beckmann_blur(ccl_private ShaderClosure *sc, float roughness)
{
ccl_private MicrofacetBsdf *bsdf = (ccl_private MicrofacetBsdf *)sc;
bsdf->alpha_x = fmaxf(roughness, bsdf->alpha_x);
bsdf->alpha_y = fmaxf(roughness, bsdf->alpha_y);
return SD_BSDF | SD_BSDF_HAS_TRANSMISSION | bsdf_microfacet_eval_flag(bsdf);
}
ccl_device Spectrum bsdf_microfacet_beckmann_eval(ccl_private const ShaderClosure *sc,
@ -992,58 +987,4 @@ ccl_device int bsdf_microfacet_beckmann_sample(ccl_private const ShaderClosure *
sc, path_flag, Ng, wi, rand, eval, wo, pdf, sampled_roughness, eta);
}
/* Specular interface, not really a microfacet model but close enough that sharing code makes
* sense. */
ccl_device int bsdf_reflection_setup(ccl_private MicrofacetBsdf *bsdf)
{
bsdf->fresnel_type = MicrofacetFresnel::NONE;
bsdf->type = CLOSURE_BSDF_REFLECTION_ID;
bsdf->alpha_x = 0.0f;
bsdf->alpha_y = 0.0f;
return SD_BSDF;
}
ccl_device int bsdf_refraction_setup(ccl_private MicrofacetBsdf *bsdf)
{
bsdf->fresnel_type = MicrofacetFresnel::NONE;
bsdf->type = CLOSURE_BSDF_REFRACTION_ID;
bsdf->alpha_x = 0.0f;
bsdf->alpha_y = 0.0f;
return SD_BSDF | SD_BSDF_HAS_TRANSMISSION;
}
ccl_device int bsdf_sharp_glass_setup(ccl_private MicrofacetBsdf *bsdf)
{
bsdf->fresnel_type = MicrofacetFresnel::DIELECTRIC;
bsdf->type = CLOSURE_BSDF_SHARP_GLASS_ID;
bsdf->alpha_x = 0.0f;
bsdf->alpha_y = 0.0f;
return SD_BSDF | SD_BSDF_HAS_TRANSMISSION;
}
ccl_device Spectrum bsdf_microfacet_sharp_eval(ccl_private const ShaderClosure *sc,
const float3 Ng,
const float3 wi,
const float3 wo,
ccl_private float *pdf)
{
return bsdf_microfacet_eval<MicrofacetType::SHARP>(sc, Ng, wi, wo, pdf);
}
ccl_device int bsdf_microfacet_sharp_sample(ccl_private const ShaderClosure *sc,
const int path_flag,
float3 Ng,
float3 wi,
const float3 rand,
ccl_private Spectrum *eval,
ccl_private float3 *wo,
ccl_private float *pdf,
ccl_private float2 *sampled_roughness,
ccl_private float *eta)
{
return bsdf_microfacet_sample<MicrofacetType::SHARP>(
sc, path_flag, Ng, wi, rand, eval, wo, pdf, sampled_roughness, eta);
}
CCL_NAMESPACE_END

View File

@ -224,6 +224,12 @@ ccl_device_inline void surface_shader_prepare_closures(KernelGlobals kg,
bsdf_blur(kg, sc, blur_roughness);
}
}
/* NOTE: this is a sufficient condition. If `blur_roughness < THRESH < original_roughness`
* then the flag was already set. */
if (sqr(blur_roughness) > BSDF_ROUGHNESS_SQ_THRESH) {
sd->flag |= SD_BSDF_HAS_EVAL;
}
}
}
}

View File

@ -142,8 +142,9 @@ ccl_device void osl_closure_reflection_setup(KernelGlobals kg,
}
bsdf->N = ensure_valid_specular_reflection(sd->Ng, sd->wi, closure->N);
bsdf->alpha_x = bsdf->alpha_y = 0.0f;
sd->flag |= bsdf_reflection_setup(bsdf);
sd->flag |= bsdf_microfacet_ggx_setup(bsdf);
}
ccl_device void osl_closure_refraction_setup(KernelGlobals kg,
@ -164,8 +165,9 @@ ccl_device void osl_closure_refraction_setup(KernelGlobals kg,
bsdf->N = ensure_valid_specular_reflection(sd->Ng, sd->wi, closure->N);
bsdf->ior = closure->ior;
bsdf->alpha_x = bsdf->alpha_y = 0.0f;
sd->flag |= bsdf_refraction_setup(bsdf);
sd->flag |= bsdf_microfacet_ggx_refraction_setup(bsdf);
}
ccl_device void osl_closure_transparent_setup(KernelGlobals kg,
@ -397,18 +399,6 @@ ccl_device void osl_closure_microfacet_setup(KernelGlobals kg,
sd->flag |= bsdf_microfacet_beckmann_setup(bsdf);
}
}
/* Sharp */
else if (closure->distribution == make_string("sharp", 1870681295563127462ull)) {
if (closure->refract == 1) {
sd->flag |= bsdf_refraction_setup(bsdf);
}
else if (closure->refract == 2) {
sd->flag |= bsdf_sharp_glass_setup(bsdf);
}
else {
sd->flag |= bsdf_reflection_setup(bsdf);
}
}
/* Ashikhmin-Shirley */
else if (closure->distribution == make_string("ashikhmin_shirley", 11318482998918370922ull)) {
sd->flag |= bsdf_ashikhmin_shirley_setup(bsdf);

View File

@ -5,7 +5,7 @@
#include "stdcycles.h"
shader node_glass_bsdf(color Color = 0.8,
string distribution = "sharp",
string distribution = "ggx",
float Roughness = 0.2,
float IOR = 1.45,
normal Normal = N,

View File

@ -4,7 +4,7 @@
#include "stdcycles.h"
shader node_refraction_bsdf(color Color = 0.8,
string distribution = "sharp",
string distribution = "ggx",
float Roughness = 0.2,
float IOR = 1.45,
normal Normal = N,

View File

@ -472,7 +472,6 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg,
bsdf_transparent_setup(sd, weight, path_flag);
break;
}
case CLOSURE_BSDF_REFLECTION_ID:
case CLOSURE_BSDF_MICROFACET_GGX_ID:
case CLOSURE_BSDF_MICROFACET_BECKMANN_ID:
case CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID:
@ -521,10 +520,9 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg,
}
/* setup bsdf */
if (type == CLOSURE_BSDF_REFLECTION_ID)
sd->flag |= bsdf_reflection_setup(bsdf);
else if (type == CLOSURE_BSDF_MICROFACET_BECKMANN_ID)
if (type == CLOSURE_BSDF_MICROFACET_BECKMANN_ID) {
sd->flag |= bsdf_microfacet_beckmann_setup(bsdf);
}
else if (type == CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID) {
sd->flag |= bsdf_ashikhmin_shirley_setup(bsdf);
}
@ -539,7 +537,6 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg,
break;
}
case CLOSURE_BSDF_REFRACTION_ID:
case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID:
case CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID: {
#ifdef __CAUSTICS_TRICKS__
@ -558,29 +555,21 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg,
eta = (sd->flag & SD_BACKFACING) ? 1.0f / eta : eta;
/* setup bsdf */
if (type == CLOSURE_BSDF_REFRACTION_ID) {
bsdf->alpha_x = 0.0f;
bsdf->alpha_y = 0.0f;
bsdf->ior = eta;
float roughness = sqr(param1);
bsdf->alpha_x = roughness;
bsdf->alpha_y = roughness;
bsdf->ior = eta;
sd->flag |= bsdf_refraction_setup(bsdf);
if (type == CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID) {
sd->flag |= bsdf_microfacet_beckmann_refraction_setup(bsdf);
}
else {
float roughness = sqr(param1);
bsdf->alpha_x = roughness;
bsdf->alpha_y = roughness;
bsdf->ior = eta;
if (type == CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID)
sd->flag |= bsdf_microfacet_beckmann_refraction_setup(bsdf);
else
sd->flag |= bsdf_microfacet_ggx_refraction_setup(bsdf);
sd->flag |= bsdf_microfacet_ggx_refraction_setup(bsdf);
}
}
break;
}
case CLOSURE_BSDF_SHARP_GLASS_ID:
case CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID:
case CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID:
case CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID: {
@ -602,28 +591,20 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg,
eta = (sd->flag & SD_BACKFACING) ? 1.0f / eta : eta;
/* setup bsdf */
if (type == CLOSURE_BSDF_SHARP_GLASS_ID) {
bsdf->alpha_x = 0.0f;
bsdf->alpha_y = 0.0f;
bsdf->ior = eta;
float roughness = sqr(param1);
bsdf->alpha_x = roughness;
bsdf->alpha_y = roughness;
bsdf->ior = eta;
sd->flag |= bsdf_sharp_glass_setup(bsdf);
if (type == CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID) {
sd->flag |= bsdf_microfacet_beckmann_glass_setup(bsdf);
}
else {
float roughness = sqr(param1);
bsdf->alpha_x = roughness;
bsdf->alpha_y = roughness;
bsdf->ior = eta;
if (type == CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID)
sd->flag |= bsdf_microfacet_beckmann_glass_setup(bsdf);
else {
sd->flag |= bsdf_microfacet_ggx_glass_setup(bsdf);
if (type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID) {
kernel_assert(stack_valid(data_node.z));
const Spectrum color = rgb_to_spectrum(stack_load_float3(stack, data_node.z));
bsdf_microfacet_setup_fresnel_constant(kg, bsdf, sd, color);
}
sd->flag |= bsdf_microfacet_ggx_glass_setup(bsdf);
if (type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID) {
kernel_assert(stack_valid(data_node.z));
const Spectrum color = rgb_to_spectrum(stack_load_float3(stack, data_node.z));
bsdf_microfacet_setup_fresnel_constant(kg, bsdf, sd, color);
}
}
}

View File

@ -420,7 +420,6 @@ typedef enum ClosureType {
CLOSURE_BSDF_TRANSLUCENT_ID,
/* Glossy */
CLOSURE_BSDF_REFLECTION_ID,
CLOSURE_BSDF_MICROFACET_GGX_ID,
CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID,
CLOSURE_BSDF_MICROFACET_BECKMANN_ID,
@ -432,14 +431,12 @@ typedef enum ClosureType {
CLOSURE_BSDF_HAIR_REFLECTION_ID,
/* Transmission */
CLOSURE_BSDF_REFRACTION_ID,
CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID,
CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID,
CLOSURE_BSDF_HAIR_PRINCIPLED_ID,
CLOSURE_BSDF_HAIR_TRANSMISSION_ID,
/* Glass */
CLOSURE_BSDF_SHARP_GLASS_ID,
CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID,
CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID,
CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID, /* virtual closure */
@ -470,21 +467,22 @@ typedef enum ClosureType {
#define CLOSURE_IS_BSDF_DIFFUSE(type) \
(type >= CLOSURE_BSDF_DIFFUSE_ID && type <= CLOSURE_BSDF_TRANSLUCENT_ID)
#define CLOSURE_IS_BSDF_GLOSSY(type) \
((type >= CLOSURE_BSDF_REFLECTION_ID && type <= CLOSURE_BSDF_HAIR_REFLECTION_ID) || \
((type >= CLOSURE_BSDF_MICROFACET_GGX_ID && type <= CLOSURE_BSDF_HAIR_REFLECTION_ID) || \
(type == CLOSURE_BSDF_HAIR_PRINCIPLED_ID))
#define CLOSURE_IS_BSDF_TRANSMISSION(type) \
(type >= CLOSURE_BSDF_REFRACTION_ID && type <= CLOSURE_BSDF_HAIR_TRANSMISSION_ID)
#define CLOSURE_IS_BSDF_SINGULAR(type) \
(type == CLOSURE_BSDF_REFLECTION_ID || type == CLOSURE_BSDF_REFRACTION_ID || \
type == CLOSURE_BSDF_TRANSPARENT_ID || type == CLOSURE_BSDF_SHARP_GLASS_ID)
(type >= CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID && \
type <= CLOSURE_BSDF_HAIR_TRANSMISSION_ID)
#define CLOSURE_IS_BSDF_SINGULAR(type) (type == CLOSURE_BSDF_TRANSPARENT_ID)
#define CLOSURE_IS_BSDF_TRANSPARENT(type) (type == CLOSURE_BSDF_TRANSPARENT_ID)
#define CLOSURE_IS_BSDF_MULTISCATTER(type) \
(type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID || \
type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID)
#define CLOSURE_IS_BSDF_MICROFACET(type) \
((type >= CLOSURE_BSDF_REFLECTION_ID && type <= CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID) || \
(type >= CLOSURE_BSDF_REFRACTION_ID && type <= CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID) || \
(type >= CLOSURE_BSDF_SHARP_GLASS_ID && type <= CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID))
((type >= CLOSURE_BSDF_MICROFACET_GGX_ID && type <= CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID) || \
(type >= CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID && \
type <= CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID) || \
(type >= CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID && \
type <= CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID))
#define CLOSURE_IS_BSDF_OR_BSSRDF(type) (type <= CLOSURE_BSSRDF_RANDOM_WALK_FIXED_RADIUS_ID)
#define CLOSURE_IS_BSSRDF(type) \
(type >= CLOSURE_BSSRDF_BURLEY_ID && type <= CLOSURE_BSSRDF_RANDOM_WALK_FIXED_RADIUS_ID)
@ -495,11 +493,15 @@ typedef enum ClosureType {
#define CLOSURE_IS_HOLDOUT(type) (type == CLOSURE_HOLDOUT_ID)
#define CLOSURE_IS_PHASE(type) (type == CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID)
#define CLOSURE_IS_REFRACTION(type) \
(type >= CLOSURE_BSDF_REFRACTION_ID && type <= CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID)
(type >= CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID && \
type <= CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID)
#define CLOSURE_IS_GLASS(type) \
(type >= CLOSURE_BSDF_SHARP_GLASS_ID && type <= CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID)
(type >= CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID && \
type <= CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID)
#define CLOSURE_IS_PRINCIPLED(type) (type == CLOSURE_BSDF_PRINCIPLED_ID)
#define CLOSURE_WEIGHT_CUTOFF 1e-5f
/* Treat closure as singular if the squared roughness is below this threshold. */
#define BSDF_ROUGHNESS_SQ_THRESH 5e-7f
CCL_NAMESPACE_END

View File

@ -324,15 +324,6 @@ void Integrator::tag_update(Scene *scene, uint32_t flag)
tag_ao_bounces_modified();
}
if (filter_glossy_is_modified()) {
foreach (Shader *shader, scene->shaders) {
if (shader->has_integrator_dependency) {
scene->shader_manager->tag_update(scene, ShaderManager::INTEGRATOR_MODIFIED);
break;
}
}
}
if (motion_blur_is_modified()) {
scene->object_manager->tag_update(scene, ObjectManager::MOTION_BLUR_MODIFIED);
scene->camera->tag_modified();

View File

@ -1253,7 +1253,9 @@ void LightManager::device_update_lights(Device *device, DeviceScene *dscene, Sce
klights[light_index].distant.eval_fac = (light->normalize && angle > 0) ?
M_1_PI_F / sqr(sinf(angle)) :
1.0f;
klights[light_index].distant.half_inv_sin_half_angle = 0.5f / sinf(0.5f * angle);
klights[light_index].distant.half_inv_sin_half_angle = (angle == 0.0f) ?
0.0f :
0.5f / sinf(0.5f * angle);
}
else if (light->light_type == LIGHT_BACKGROUND) {
uint visibility = scene->background->get_visibility();

View File

@ -895,10 +895,6 @@ void OSLCompiler::add(ShaderNode *node, const char *name, bool isfilepath)
if (node->has_attribute_dependency())
current_shader->has_volume_attribute_dependency = true;
}
if (node->has_integrator_dependency()) {
current_shader->has_integrator_dependency = true;
}
}
static TypeDesc array_typedesc(TypeDesc typedesc, int arraylength)
@ -1259,10 +1255,7 @@ void OSLCompiler::compile(OSLGlobals *og, Shader *shader)
output->input("Surface")->link && output->input("Displacement")->link;
/* finalize */
shader->graph->finalize(scene,
has_bump,
shader->has_integrator_dependency,
shader->get_displacement_method() == DISPLACE_BOTH);
shader->graph->finalize(scene, has_bump, shader->get_displacement_method() == DISPLACE_BOTH);
current_shader = shader;
@ -1277,7 +1270,6 @@ void OSLCompiler::compile(OSLGlobals *og, Shader *shader)
shader->has_surface_spatial_varying = false;
shader->has_volume_spatial_varying = false;
shader->has_volume_attribute_dependency = false;
shader->has_integrator_dependency = false;
/* generate surface shader */
if (shader->reference_count() && graph && output->input("Surface")->link) {

View File

@ -103,7 +103,6 @@ Shader::Shader() : Node(get_node_type())
has_surface_spatial_varying = false;
has_volume_spatial_varying = false;
has_volume_attribute_dependency = false;
has_integrator_dependency = false;
has_volume_connected = false;
prev_volume_step_rate = 0.0f;

View File

@ -113,7 +113,6 @@ class Shader : public Node {
bool has_surface_spatial_varying;
bool has_volume_spatial_varying;
bool has_volume_attribute_dependency;
bool has_integrator_dependency;
float3 emission_estimate;
EmissionSampling emission_sampling;
@ -168,7 +167,6 @@ class ShaderManager {
enum : uint32_t {
SHADER_ADDED = (1 << 0),
SHADER_MODIFIED = (1 << 2),
INTEGRATOR_MODIFIED = (1 << 3),
/* tag everything in the manager for an update */
UPDATE_ALL = ~0u,

View File

@ -359,7 +359,7 @@ void ShaderGraph::simplify(Scene *scene)
}
}
void ShaderGraph::finalize(Scene *scene, bool do_bump, bool do_simplify, bool bump_in_object_space)
void ShaderGraph::finalize(Scene *scene, bool do_bump, bool bump_in_object_space)
{
/* before compiling, the shader graph may undergo a number of modifications.
* currently we set default geometry shader inputs, and create automatic bump
@ -384,9 +384,6 @@ void ShaderGraph::finalize(Scene *scene, bool do_bump, bool do_simplify, bool bu
finalized = true;
}
else if (do_simplify) {
simplify_settings(scene);
}
}
void ShaderGraph::find_dependencies(ShaderNodeSet &dependencies, ShaderInput *input)

View File

@ -200,10 +200,6 @@ class ShaderNode : public Node {
{
return false;
}
virtual bool has_integrator_dependency()
{
return false;
}
virtual bool has_volume_support()
{
return false;
@ -315,10 +311,7 @@ class ShaderGraph : public NodeOwner {
void remove_proxy_nodes();
void compute_displacement_hash();
void simplify(Scene *scene);
void finalize(Scene *scene,
bool do_bump = false,
bool do_simplify = false,
bool bump_in_object_space = false);
void finalize(Scene *scene, bool do_bump = false, bool bump_in_object_space = false);
int get_num_closures();

View File

@ -2361,7 +2361,6 @@ NODE_DEFINE(GlossyBsdfNode)
SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
static NodeEnum distribution_enum;
distribution_enum.insert("sharp", CLOSURE_BSDF_REFLECTION_ID);
distribution_enum.insert("beckmann", CLOSURE_BSDF_MICROFACET_BECKMANN_ID);
distribution_enum.insert("ggx", CLOSURE_BSDF_MICROFACET_GGX_ID);
distribution_enum.insert("ashikhmin_shirley", CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID);
@ -2382,7 +2381,6 @@ NODE_DEFINE(GlossyBsdfNode)
GlossyBsdfNode::GlossyBsdfNode() : BsdfNode(get_node_type())
{
closure = CLOSURE_BSDF_MICROFACET_GGX_ID;
distribution_orig = NBUILTIN_CLOSURES;
}
bool GlossyBsdfNode::is_isotropic()
@ -2403,68 +2401,27 @@ void GlossyBsdfNode::attributes(Shader *shader, AttributeRequestSet *attributes)
ShaderNode::attributes(shader, attributes);
}
void GlossyBsdfNode::simplify_settings(Scene *scene)
void GlossyBsdfNode::simplify_settings(Scene * /* scene */)
{
/* If the anisotropy is close enough to zero, fall back to the isotropic case. */
ShaderInput *tangent_input = input("Tangent");
if (tangent_input->link && is_isotropic()) {
tangent_input->disconnect();
}
if (distribution_orig == NBUILTIN_CLOSURES) {
roughness_orig = roughness;
distribution_orig = distribution;
}
else {
/* By default we use original values, so we don't worry about restoring
* defaults later one and can only do override when needed.
*/
roughness = roughness_orig;
distribution = distribution_orig;
}
Integrator *integrator = scene->integrator;
ShaderInput *roughness_input = input("Roughness");
if (integrator->get_filter_glossy() == 0.0f) {
/* Fallback to Sharp closure for Roughness close to 0.
* NOTE: Keep the epsilon in sync with kernel!
*/
if (!roughness_input->link && roughness <= 1e-4f) {
VLOG_DEBUG << "Using sharp glossy BSDF.";
distribution = CLOSURE_BSDF_REFLECTION_ID;
}
}
else {
/* If filter glossy is used we replace Sharp glossy with GGX so we can
* benefit from closure blur to remove unwanted noise.
*/
if (roughness_input->link == NULL && distribution == CLOSURE_BSDF_REFLECTION_ID) {
VLOG_DEBUG << "Using GGX glossy with filter glossy.";
distribution = CLOSURE_BSDF_MICROFACET_GGX_ID;
roughness = 0.0f;
}
}
closure = distribution;
}
bool GlossyBsdfNode::has_integrator_dependency()
{
ShaderInput *roughness_input = input("Roughness");
return !roughness_input->link &&
(distribution == CLOSURE_BSDF_REFLECTION_ID || roughness <= 1e-4f);
}
void GlossyBsdfNode::compile(SVMCompiler &compiler)
{
closure = distribution;
if (closure == CLOSURE_BSDF_REFLECTION_ID)
BsdfNode::compile(compiler, NULL, NULL);
/* TODO: Just use weight for legacy MultiGGX? Would also simplify OSL. */
else if (closure == CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID)
if (closure == CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID) {
BsdfNode::compile(
compiler, input("Roughness"), input("Anisotropy"), input("Rotation"), input("Color"));
else
}
else {
BsdfNode::compile(compiler, input("Roughness"), input("Anisotropy"), input("Rotation"));
}
}
void GlossyBsdfNode::compile(OSLCompiler &compiler)
@ -2484,7 +2441,6 @@ NODE_DEFINE(GlassBsdfNode)
SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
static NodeEnum distribution_enum;
distribution_enum.insert("sharp", CLOSURE_BSDF_SHARP_GLASS_ID);
distribution_enum.insert("beckmann", CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID);
distribution_enum.insert("ggx", CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID);
distribution_enum.insert("multi_ggx", CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID);
@ -2500,64 +2456,19 @@ NODE_DEFINE(GlassBsdfNode)
GlassBsdfNode::GlassBsdfNode() : BsdfNode(get_node_type())
{
closure = CLOSURE_BSDF_SHARP_GLASS_ID;
distribution_orig = NBUILTIN_CLOSURES;
}
void GlassBsdfNode::simplify_settings(Scene *scene)
{
if (distribution_orig == NBUILTIN_CLOSURES) {
roughness_orig = roughness;
distribution_orig = distribution;
}
else {
/* By default we use original values, so we don't worry about restoring
* defaults later one and can only do override when needed.
*/
roughness = roughness_orig;
distribution = distribution_orig;
}
Integrator *integrator = scene->integrator;
ShaderInput *roughness_input = input("Roughness");
if (integrator->get_filter_glossy() == 0.0f) {
/* Fallback to Sharp closure for Roughness close to 0.
* NOTE: Keep the epsilon in sync with kernel!
*/
if (!roughness_input->link && roughness <= 1e-4f) {
VLOG_DEBUG << "Using sharp glass BSDF.";
distribution = CLOSURE_BSDF_SHARP_GLASS_ID;
}
}
else {
/* If filter glossy is used we replace Sharp glossy with GGX so we can
* benefit from closure blur to remove unwanted noise.
*/
if (roughness_input->link == NULL && distribution == CLOSURE_BSDF_SHARP_GLASS_ID) {
VLOG_DEBUG << "Using GGX glass with filter glossy.";
distribution = CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID;
roughness = 0.0f;
}
}
closure = distribution;
}
bool GlassBsdfNode::has_integrator_dependency()
{
ShaderInput *roughness_input = input("Roughness");
return !roughness_input->link &&
(distribution == CLOSURE_BSDF_SHARP_GLASS_ID || roughness <= 1e-4f);
closure = CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID;
}
void GlassBsdfNode::compile(SVMCompiler &compiler)
{
closure = distribution;
if (closure == CLOSURE_BSDF_SHARP_GLASS_ID)
BsdfNode::compile(compiler, NULL, input("IOR"));
else if (closure == CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID)
if (closure == CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID) {
BsdfNode::compile(compiler, input("Roughness"), input("IOR"), input("Color"));
else
}
else {
BsdfNode::compile(compiler, input("Roughness"), input("IOR"));
}
}
void GlassBsdfNode::compile(OSLCompiler &compiler)
@ -2577,7 +2488,6 @@ NODE_DEFINE(RefractionBsdfNode)
SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
static NodeEnum distribution_enum;
distribution_enum.insert("sharp", CLOSURE_BSDF_REFRACTION_ID);
distribution_enum.insert("beckmann", CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID);
distribution_enum.insert("ggx", CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID);
SOCKET_ENUM(
@ -2593,62 +2503,14 @@ NODE_DEFINE(RefractionBsdfNode)
RefractionBsdfNode::RefractionBsdfNode() : BsdfNode(get_node_type())
{
closure = CLOSURE_BSDF_REFRACTION_ID;
distribution_orig = NBUILTIN_CLOSURES;
}
void RefractionBsdfNode::simplify_settings(Scene *scene)
{
if (distribution_orig == NBUILTIN_CLOSURES) {
roughness_orig = roughness;
distribution_orig = distribution;
}
else {
/* By default we use original values, so we don't worry about restoring
* defaults later one and can only do override when needed.
*/
roughness = roughness_orig;
distribution = distribution_orig;
}
Integrator *integrator = scene->integrator;
ShaderInput *roughness_input = input("Roughness");
if (integrator->get_filter_glossy() == 0.0f) {
/* Fallback to Sharp closure for Roughness close to 0.
* NOTE: Keep the epsilon in sync with kernel!
*/
if (!roughness_input->link && roughness <= 1e-4f) {
VLOG_DEBUG << "Using sharp refraction BSDF.";
distribution = CLOSURE_BSDF_REFRACTION_ID;
}
}
else {
/* If filter glossy is used we replace Sharp glossy with GGX so we can
* benefit from closure blur to remove unwanted noise.
*/
if (roughness_input->link == NULL && distribution == CLOSURE_BSDF_REFRACTION_ID) {
VLOG_DEBUG << "Using GGX refraction with filter glossy.";
distribution = CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID;
roughness = 0.0f;
}
}
closure = distribution;
}
bool RefractionBsdfNode::has_integrator_dependency()
{
ShaderInput *roughness_input = input("Roughness");
return !roughness_input->link &&
(distribution == CLOSURE_BSDF_REFRACTION_ID || roughness <= 1e-4f);
closure = CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID;
}
void RefractionBsdfNode::compile(SVMCompiler &compiler)
{
closure = distribution;
if (closure == CLOSURE_BSDF_REFRACTION_ID)
BsdfNode::compile(compiler, NULL, input("IOR"));
else
BsdfNode::compile(compiler, input("Roughness"), input("IOR"));
BsdfNode::compile(compiler, input("Roughness"), input("IOR"));
}
void RefractionBsdfNode::compile(OSLCompiler &compiler)
@ -2816,7 +2678,6 @@ PrincipledBsdfNode::PrincipledBsdfNode() : BsdfBaseNode(get_node_type())
{
closure = CLOSURE_BSDF_PRINCIPLED_ID;
distribution = CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID;
distribution_orig = NBUILTIN_CLOSURES;
}
void PrincipledBsdfNode::expand(ShaderGraph *graph)
@ -2987,12 +2848,6 @@ void PrincipledBsdfNode::compile(SVMCompiler &compiler,
__float_as_int(ss_default.z));
}
bool PrincipledBsdfNode::has_integrator_dependency()
{
ShaderInput *roughness_input = input("Roughness");
return !roughness_input->link && roughness <= 1e-4f;
}
void PrincipledBsdfNode::compile(SVMCompiler &compiler)
{
compile(compiler,

View File

@ -563,11 +563,7 @@ class PrincipledBsdfNode : public BsdfBaseNode {
NODE_SOCKET_API(float, emission_strength)
NODE_SOCKET_API(float, alpha)
private:
ClosureType distribution_orig;
public:
bool has_integrator_dependency();
void attributes(Shader *shader, AttributeRequestSet *attributes);
bool has_attribute_dependency()
{
@ -602,7 +598,6 @@ class GlossyBsdfNode : public BsdfNode {
SHADER_NODE_CLASS(GlossyBsdfNode)
void simplify_settings(Scene *scene);
bool has_integrator_dependency();
ClosureType get_closure_type()
{
return distribution;
@ -620,10 +615,6 @@ class GlossyBsdfNode : public BsdfNode {
return true;
}
private:
float roughness_orig;
ClosureType distribution_orig;
bool is_isotropic();
};
@ -631,8 +622,6 @@ class GlassBsdfNode : public BsdfNode {
public:
SHADER_NODE_CLASS(GlassBsdfNode)
void simplify_settings(Scene *scene);
bool has_integrator_dependency();
ClosureType get_closure_type()
{
return distribution;
@ -641,18 +630,12 @@ class GlassBsdfNode : public BsdfNode {
NODE_SOCKET_API(float, roughness)
NODE_SOCKET_API(float, IOR)
NODE_SOCKET_API(ClosureType, distribution)
private:
float roughness_orig;
ClosureType distribution_orig;
};
class RefractionBsdfNode : public BsdfNode {
public:
SHADER_NODE_CLASS(RefractionBsdfNode)
void simplify_settings(Scene *scene);
bool has_integrator_dependency();
ClosureType get_closure_type()
{
return distribution;
@ -661,10 +644,6 @@ class RefractionBsdfNode : public BsdfNode {
NODE_SOCKET_API(float, roughness)
NODE_SOCKET_API(float, IOR)
NODE_SOCKET_API(ClosureType, distribution)
private:
float roughness_orig;
ClosureType distribution_orig;
};
class ToonBsdfNode : public BsdfNode {

View File

@ -442,10 +442,6 @@ void SVMCompiler::generate_node(ShaderNode *node, ShaderNodeSet &done)
if (node->has_attribute_dependency())
current_shader->has_volume_attribute_dependency = true;
}
if (node->has_integrator_dependency()) {
current_shader->has_integrator_dependency = true;
}
}
void SVMCompiler::generate_svm_nodes(const ShaderNodeSet &nodes, CompilerState *state)
@ -858,10 +854,7 @@ void SVMCompiler::compile(Shader *shader, array<int4> &svm_nodes, int index, Sum
/* finalize */
{
scoped_timer timer((summary != NULL) ? &summary->time_finalize : NULL);
shader->graph->finalize(scene,
has_bump,
shader->has_integrator_dependency,
shader->get_displacement_method() == DISPLACE_BOTH);
shader->graph->finalize(scene, has_bump, shader->get_displacement_method() == DISPLACE_BOTH);
}
current_shader = shader;
@ -877,7 +870,6 @@ void SVMCompiler::compile(Shader *shader, array<int4> &svm_nodes, int index, Sum
shader->has_surface_spatial_varying = false;
shader->has_volume_spatial_varying = false;
shader->has_volume_attribute_dependency = false;
shader->has_integrator_dependency = false;
/* generate bump shader */
if (has_bump) {

View File

@ -77,7 +77,7 @@ static GHOST_TButton convertButton(int button)
* \param recvChar: the character ignoring modifiers (except for shift)
* \return Ghost key code
*/
static GHOST_TKey convertKey(int rawCode, unichar recvChar, UInt16 keyAction)
static GHOST_TKey convertKey(int rawCode, unichar recvChar)
{
// printf("\nrecvchar %c 0x%x",recvChar,recvChar);
switch (rawCode) {
@ -238,7 +238,10 @@ static GHOST_TKey convertKey(int rawCode, unichar recvChar, UInt16 keyAction)
return GHOST_kKeyUpPage;
case kVK_PageDown:
return GHOST_kKeyDownPage;
#if 0 /* TODO: why are these commented? */
#if 0
/* These constants with "ANSI" in the name are labeled according to the key position on an
* ANSI-standard US keyboard. Therefore they may not match the physical key label on other
* keyboard layouts. */
case kVK_ANSI_Minus: return GHOST_kKeyMinus;
case kVK_ANSI_Equal: return GHOST_kKeyEqual;
case kVK_ANSI_Comma: return GHOST_kKeyComma;
@ -284,10 +287,10 @@ static GHOST_TKey convertKey(int rawCode, unichar recvChar, UInt16 keyAction)
UCKeyTranslate((UCKeyboardLayout *)CFDataGetBytePtr(uchrHandle),
rawCode,
keyAction,
kUCKeyActionDown,
0,
LMGetKbdType(),
kUCKeyTranslateNoDeadKeysBit,
kUCKeyTranslateNoDeadKeysMask,
&deadKeyState,
1,
&actualStrLength,
@ -1830,18 +1833,13 @@ GHOST_TSuccess GHOST_SystemCocoa::handleKeyEvent(void *eventPtr)
case NSEventTypeKeyDown:
case NSEventTypeKeyUp:
/* Returns an empty string for dead keys. */
charsIgnoringModifiers = [event charactersIgnoringModifiers];
if ([charsIgnoringModifiers length] > 0) {
keyCode = convertKey([event keyCode],
[charsIgnoringModifiers characterAtIndex:0],
[event type] == NSEventTypeKeyDown ? kUCKeyActionDown :
kUCKeyActionUp);
keyCode = convertKey([event keyCode], [charsIgnoringModifiers characterAtIndex:0]);
}
else {
keyCode = convertKey([event keyCode],
0,
[event type] == NSEventTypeKeyDown ? kUCKeyActionDown :
kUCKeyActionUp);
keyCode = convertKey([event keyCode], 0);
}
characters = [event characters];

View File

@ -464,24 +464,27 @@ GHOST_TSuccess GHOST_SystemWin32::setCursorPosition(int32_t x, int32_t y)
GHOST_TSuccess GHOST_SystemWin32::getModifierKeys(GHOST_ModifierKeys &keys) const
{
bool down = HIBYTE(::GetKeyState(VK_LSHIFT)) != 0;
/* `GetAsyncKeyState` returns the current interrupt-level state of the hardware, which is needed
* when passing key states to a newly-activated window - #40059. Alterative `GetKeyState` only
* returns the state as processed by the thread's message queue. */
bool down = HIBYTE(::GetAsyncKeyState(VK_LSHIFT)) != 0;
keys.set(GHOST_kModifierKeyLeftShift, down);
down = HIBYTE(::GetKeyState(VK_RSHIFT)) != 0;
down = HIBYTE(::GetAsyncKeyState(VK_RSHIFT)) != 0;
keys.set(GHOST_kModifierKeyRightShift, down);
down = HIBYTE(::GetKeyState(VK_LMENU)) != 0;
down = HIBYTE(::GetAsyncKeyState(VK_LMENU)) != 0;
keys.set(GHOST_kModifierKeyLeftAlt, down);
down = HIBYTE(::GetKeyState(VK_RMENU)) != 0;
down = HIBYTE(::GetAsyncKeyState(VK_RMENU)) != 0;
keys.set(GHOST_kModifierKeyRightAlt, down);
down = HIBYTE(::GetKeyState(VK_LCONTROL)) != 0;
down = HIBYTE(::GetAsyncKeyState(VK_LCONTROL)) != 0;
keys.set(GHOST_kModifierKeyLeftControl, down);
down = HIBYTE(::GetKeyState(VK_RCONTROL)) != 0;
down = HIBYTE(::GetAsyncKeyState(VK_RCONTROL)) != 0;
keys.set(GHOST_kModifierKeyRightControl, down);
down = HIBYTE(::GetKeyState(VK_LWIN)) != 0;
down = HIBYTE(::GetAsyncKeyState(VK_LWIN)) != 0;
keys.set(GHOST_kModifierKeyLeftOS, down);
down = HIBYTE(::GetKeyState(VK_RWIN)) != 0;
down = HIBYTE(::GetAsyncKeyState(VK_RWIN)) != 0;
keys.set(GHOST_kModifierKeyRightOS, down);
return GHOST_kSuccess;
@ -1207,16 +1210,11 @@ GHOST_EventKey *GHOST_SystemWin32::processKeyEvent(GHOST_WindowWin32 *window, RA
bool is_repeat = false;
bool is_repeated_modifier = false;
if (key_down) {
if (system->m_keycode_last_repeat_key == vk) {
if (HIBYTE(::GetKeyState(vk)) != 0) {
/* This thread's message queue shows this key as already down. */
is_repeat = true;
is_repeated_modifier = GHOST_KEY_MODIFIER_CHECK(key);
}
system->m_keycode_last_repeat_key = vk;
}
else {
if (system->m_keycode_last_repeat_key == vk) {
system->m_keycode_last_repeat_key = 0;
}
}
/* We used to check `if (key != GHOST_kKeyUnknown)`, but since the message
@ -1890,8 +1888,14 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, uint msg, WPARAM wParam,
else if (!new_parent && !old_parent) {
/* Between main windows that don't overlap. */
RECT new_rect, old_rect, dest_rect;
::GetWindowRect(hwnd, &new_rect);
::GetWindowRect(old_hwnd, &old_rect);
/* The rects without the outside shadows and slightly inset. */
DwmGetWindowAttribute(hwnd, DWMWA_EXTENDED_FRAME_BOUNDS, &new_rect, sizeof(RECT));
::InflateRect(&new_rect, -1, -1);
DwmGetWindowAttribute(
old_hwnd, DWMWA_EXTENDED_FRAME_BOUNDS, &old_rect, sizeof(RECT));
::InflateRect(&old_rect, -1, -1);
if (!IntersectRect(&dest_rect, &new_rect, &old_rect)) {
::SetFocus(hwnd);
}
@ -1986,7 +1990,6 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, uint msg, WPARAM wParam,
* so the window is activated immediately. */
system->m_wheelDeltaAccum = 0;
system->m_keycode_last_repeat_key = 0;
event = processWindowEvent(
LOWORD(wParam) ? GHOST_kEventWindowActivate : GHOST_kEventWindowDeactivate, window);
/* WARNING: Let DefWindowProc handle WM_ACTIVATE, otherwise WM_MOUSEWHEEL

View File

@ -455,8 +455,6 @@ class GHOST_SystemWin32 : public GHOST_System {
*/
bool setConsoleWindowState(GHOST_TConsoleWindowState action);
/** The virtual-key code (VKey) of the last press event. Used to detect repeat events. */
unsigned short m_keycode_last_repeat_key;
/** State variable set at initialization. */
bool m_hasPerformanceCounter;
/** High frequency timer variable. */

View File

@ -90,7 +90,9 @@ GHOST_Wintab *GHOST_Wintab::loadWintab(HWND hwnd)
/* Wintab provides no way to determine the maximum queue size aside from checking if attempts
* to change the queue size are successful. */
const int maxQueue = 500;
int queueSize = queueSizeGet(hctx.get());
/* < 0 should realistically never happen, but given we cast to size_t later on better safe than
* sorry. */
int queueSize = max(0, queueSizeGet(hctx.get()));
while (queueSize < maxQueue) {
int testSize = min(queueSize + 16, maxQueue);
@ -136,7 +138,7 @@ GHOST_Wintab *GHOST_Wintab::loadWintab(HWND hwnd)
std::move(hctx),
tablet,
system,
queueSize);
size_t(queueSize));
}
void GHOST_Wintab::modifyContext(LOGCONTEXT &lc)
@ -179,7 +181,7 @@ GHOST_Wintab::GHOST_Wintab(unique_hmodule handle,
unique_hctx hctx,
Coord tablet,
Coord system,
int queueSize)
size_t queueSize)
: m_handle{std::move(handle)},
m_fpInfo{info},
m_fpGet{get},

View File

@ -237,7 +237,7 @@ class GHOST_Wintab {
unique_hctx hctx,
Coord tablet,
Coord system,
int queueSize);
size_t queueSize);
/**
* Convert Wintab system mapped (mouse) buttons into Ghost button mask.

View File

@ -9,6 +9,7 @@
#include <algorithm>
#include <cassert>
#include <unordered_map>
#ifdef WITH_TBB
# include <tbb/parallel_for.h>

View File

@ -877,6 +877,7 @@ const bTheme U_theme_default = {
.nodeclass_geometry = RGBA(0x00d6a3ff),
.nodeclass_attribute = RGBA(0x001566ff),
.node_zone_simulation = RGBA(0x66416233),
.node_zone_repeat = RGBA(0x76512f33),
.movie = RGBA(0x0f0f0fcc),
.gp_vertex_size = 3,
.gp_vertex = RGBA(0x97979700),

View File

@ -350,6 +350,105 @@ class SimulationZoneItemMoveOperator(SimulationZoneOperator, Operator):
return {'FINISHED'}
class RepeatZoneOperator:
input_node_type = 'GeometryNodeRepeatInput'
output_node_type = 'GeometryNodeRepeatOutput'
@classmethod
def get_output_node(cls, context):
node = context.active_node
if node.bl_idname == cls.input_node_type:
return node.paired_output
if node.bl_idname == cls.output_node_type:
return node
return None
@classmethod
def poll(cls, context):
space = context.space_data
# Needs active node editor and a tree.
if not space or space.type != 'NODE_EDITOR' or not space.edit_tree or space.edit_tree.library:
return False
node = context.active_node
if node is None or node.bl_idname not in [cls.input_node_type, cls.output_node_type]:
return False
if cls.get_output_node(context) is None:
return False
return True
class RepeatZoneItemAddOperator(RepeatZoneOperator, Operator):
"""Add a repeat item to the repeat zone"""
bl_idname = "node.repeat_zone_item_add"
bl_label = "Add Repeat Item"
bl_options = {'REGISTER', 'UNDO'}
default_socket_type = 'GEOMETRY'
def execute(self, context):
node = self.get_output_node(context)
repeat_items = node.repeat_items
# Remember index to move the item.
if node.active_item:
dst_index = node.active_index + 1
dst_type = node.active_item.socket_type
dst_name = node.active_item.name
else:
dst_index = len(repeat_items)
dst_type = self.default_socket_type
# Empty name so it is based on the type.
dst_name = ""
repeat_items.new(dst_type, dst_name)
repeat_items.move(len(repeat_items) - 1, dst_index)
node.active_index = dst_index
return {'FINISHED'}
class RepeatZoneItemRemoveOperator(RepeatZoneOperator, Operator):
"""Remove a repeat item from the repeat zone"""
bl_idname = "node.repeat_zone_item_remove"
bl_label = "Remove Repeat Item"
bl_options = {'REGISTER', 'UNDO'}
def execute(self, context):
node = self.get_output_node(context)
repeat_items = node.repeat_items
if node.active_item:
repeat_items.remove(node.active_item)
node.active_index = min(node.active_index, len(repeat_items) - 1)
return {'FINISHED'}
class RepeatZoneItemMoveOperator(RepeatZoneOperator, Operator):
"""Move a repeat item up or down in the list"""
bl_idname = "node.repeat_zone_item_move"
bl_label = "Move Repeat Item"
bl_options = {'REGISTER', 'UNDO'}
direction: EnumProperty(
name="Direction",
items=[('UP', "Up", ""), ('DOWN', "Down", "")],
default='UP',
)
def execute(self, context):
node = self.get_output_node(context)
repeat_items = node.repeat_items
if self.direction == 'UP' and node.active_index > 0:
repeat_items.move(node.active_index, node.active_index - 1)
node.active_index = node.active_index - 1
elif self.direction == 'DOWN' and node.active_index < len(repeat_items) - 1:
repeat_items.move(node.active_index, node.active_index + 1)
node.active_index = node.active_index + 1
return {'FINISHED'}
classes = (
NewGeometryNodesModifier,
NewGeometryNodeTreeAssign,
@ -357,4 +456,7 @@ classes = (
SimulationZoneItemAddOperator,
SimulationZoneItemRemoveOperator,
SimulationZoneItemMoveOperator,
RepeatZoneItemAddOperator,
RepeatZoneItemRemoveOperator,
RepeatZoneItemMoveOperator,
)

View File

@ -154,14 +154,7 @@ class NODE_OT_add_node(NodeAddOperator, Operator):
return ""
class NODE_OT_add_simulation_zone(NodeAddOperator, Operator):
"""Add simulation zone input and output nodes to the active tree"""
bl_idname = "node.add_simulation_zone"
bl_label = "Add Simulation Zone"
bl_options = {'REGISTER', 'UNDO'}
input_node_type = "GeometryNodeSimulationInput"
output_node_type = "GeometryNodeSimulationOutput"
class NodeAddZoneOperator(NodeAddOperator):
offset: FloatVectorProperty(
name="Offset",
description="Offset of nodes from the cursor when added",
@ -196,6 +189,26 @@ class NODE_OT_add_simulation_zone(NodeAddOperator, Operator):
return {'FINISHED'}
class NODE_OT_add_simulation_zone(NodeAddZoneOperator, Operator):
"""Add simulation zone input and output nodes to the active tree"""
bl_idname = "node.add_simulation_zone"
bl_label = "Add Simulation Zone"
bl_options = {'REGISTER', 'UNDO'}
input_node_type = "GeometryNodeSimulationInput"
output_node_type = "GeometryNodeSimulationOutput"
class NODE_OT_add_repeat_zone(NodeAddZoneOperator, Operator):
"""Add a repeat zone that allows executing nodes a dynamic number of times"""
bl_idname = "node.add_repeat_zone"
bl_label = "Add Repeat Zone"
bl_options = {'REGISTER', 'UNDO'}
input_node_type = "GeometryNodeRepeatInput"
output_node_type = "GeometryNodeRepeatOutput"
class NODE_OT_collapse_hide_unused_toggle(Operator):
"""Toggle collapsed nodes and hide unused sockets"""
bl_idname = "node.collapse_hide_unused_toggle"
@ -328,6 +341,7 @@ classes = (
NODE_OT_add_node,
NODE_OT_add_simulation_zone,
NODE_OT_add_repeat_zone,
NODE_OT_collapse_hide_unused_toggle,
NODE_OT_panel_add,
NODE_OT_panel_remove,

View File

@ -72,6 +72,12 @@ def add_simulation_zone(layout, label):
return props
def add_repeat_zone(layout, label):
props = layout.operator("node.add_repeat_zone", text=label)
props.use_transform = True
return props
classes = (
)

View File

@ -530,6 +530,7 @@ class NODE_MT_category_GEO_UTILITIES(Menu):
layout.menu("NODE_MT_category_GEO_UTILITIES_ROTATION")
layout.separator()
node_add_menu.add_node_type(layout, "FunctionNodeRandomValue")
node_add_menu.add_repeat_zone(layout, label="Repeat Zone")
node_add_menu.add_node_type(layout, "GeometryNodeSwitch")
node_add_menu.draw_assets_for_catalog(layout, self.bl_label)

View File

@ -309,6 +309,7 @@ class GRAPH_MT_key_smoothing(Menu):
layout.operator_context = 'INVOKE_DEFAULT'
layout.operator("graph.gaussian_smooth", text="Smooth (Gaussian)")
layout.operator("graph.smooth", text="Smooth (Legacy)")
layout.operator("graph.butterworth_smooth")
class GRAPH_MT_key(Menu):

View File

@ -139,7 +139,8 @@ class NODE_HT_header(Header):
layout.prop(snode_id, "use_nodes")
elif snode.tree_type == 'GeometryNodeTree':
layout.prop(snode, "geometry_nodes_type", text="")
if context.preferences.experimental.use_node_group_operators:
layout.prop(snode, "geometry_nodes_type", text="")
NODE_MT_editor_menus.draw_collapsible(context, layout)
layout.separator_spacer()
@ -816,6 +817,10 @@ class NODE_PT_overlay(Panel):
col.prop(overlay, "show_context_path", text="Context Path")
col.prop(snode, "show_annotation", text="Annotations")
if snode.supports_preview:
col.separator()
col.prop(overlay, "show_previews", text="Previews")
if snode.tree_type == 'GeometryNodeTree':
col.separator()
col.prop(overlay, "show_timing", text="Timings")
@ -1106,6 +1111,80 @@ class NODE_PT_simulation_zone_items(Panel):
layout.prop(active_item, "attribute_domain")
class NODE_UL_repeat_zone_items(bpy.types.UIList):
def draw_item(self, _context, layout, _data, item, icon, _active_data, _active_propname, _index):
if self.layout_type in {'DEFAULT', 'COMPACT'}:
row = layout.row(align=True)
row.template_node_socket(color=item.color)
row.prop(item, "name", text="", emboss=False, icon_value=icon)
elif self.layout_type == 'GRID':
layout.alignment = 'CENTER'
layout.template_node_socket(color=item.color)
class NODE_PT_repeat_zone_items(Panel):
bl_space_type = 'NODE_EDITOR'
bl_region_type = 'UI'
bl_category = "Node"
bl_label = "Repeat"
input_node_type = 'GeometryNodeRepeatInput'
output_node_type = 'GeometryNodeRepeatOutput'
@classmethod
def get_output_node(cls, context):
node = context.active_node
if node.bl_idname == cls.input_node_type:
return node.paired_output
if node.bl_idname == cls.output_node_type:
return node
return None
@classmethod
def poll(cls, context):
snode = context.space_data
if snode is None:
return False
node = context.active_node
if node is None or node.bl_idname not in (cls.input_node_type, cls.output_node_type):
return False
if cls.get_output_node(context) is None:
return False
return True
def draw(self, context):
layout = self.layout
output_node = self.get_output_node(context)
split = layout.row()
split.template_list(
"NODE_UL_repeat_zone_items",
"",
output_node,
"repeat_items",
output_node,
"active_index")
ops_col = split.column()
add_remove_col = ops_col.column(align=True)
add_remove_col.operator("node.repeat_zone_item_add", icon='ADD', text="")
add_remove_col.operator("node.repeat_zone_item_remove", icon='REMOVE', text="")
ops_col.separator()
up_down_col = ops_col.column(align=True)
props = up_down_col.operator("node.repeat_zone_item_move", icon='TRIA_UP', text="")
props.direction = 'UP'
props = up_down_col.operator("node.repeat_zone_item_move", icon='TRIA_DOWN', text="")
props.direction = 'DOWN'
active_item = output_node.active_item
if active_item is not None:
layout.use_property_split = True
layout.use_property_decorate = False
layout.prop(active_item, "socket_type")
# Grease Pencil properties
class NODE_PT_annotation(AnnotationDataPanel, Panel):
bl_space_type = 'NODE_EDITOR'
@ -1173,6 +1252,8 @@ classes = (
NODE_PT_panels,
NODE_UL_simulation_zone_items,
NODE_PT_simulation_zone_items,
NODE_UL_repeat_zone_items,
NODE_PT_repeat_zone_items,
NODE_PT_active_node_properties,
node_panel(EEVEE_MATERIAL_PT_settings),

View File

@ -2490,6 +2490,7 @@ class SEQUENCER_PT_view_safe_areas_center_cut(SequencerButtonsPanel_Output, Pane
col = layout.column()
col.prop(safe_data, "title_center", slider=True)
col.prop(safe_data, "action_center", slider=True)
class SEQUENCER_PT_modifiers(SequencerButtonsPanel, Panel):

View File

@ -91,6 +91,8 @@ class SPREADSHEET_HT_header(bpy.types.Header):
layout.label(text=ctx.ui_name, icon='NODE')
elif ctx.type == 'SIMULATION_ZONE':
layout.label(text="Simulation Zone")
elif ctx.type == 'REPEAT_ZONE':
layout.label(text="Repeat Zone")
elif ctx.type == 'VIEWER_NODE':
layout.label(text=ctx.ui_name)

View File

@ -2428,6 +2428,7 @@ class USERPREF_PT_experimental_new_features(ExperimentalPanel, Panel):
({"property": "use_new_volume_nodes"}, ("blender/blender/issues/103248", "#103248")),
({"property": "use_node_panels"}, ("blender/blender/issues/105248", "#105248")),
({"property": "use_rotation_socket"}, ("/blender/blender/issues/92967", "#92967")),
({"property": "use_node_group_operators"}, ("/blender/blender/issues/101778", "#101778")),
),
)

View File

@ -752,8 +752,18 @@ class VIEW3D_HT_header(Header):
# Select mode for Editing
if object_mode == 'EDIT':
row = layout.row(align=True)
row.prop_enum(tool_settings, "gpencil_selectmode_edit", text="", value='POINT')
row.prop_enum(tool_settings, "gpencil_selectmode_edit", text="", value='STROKE')
row.operator(
"grease_pencil.set_selection_mode",
text="",
icon="GP_SELECT_POINTS",
depress=(tool_settings.gpencil_selectmode_edit == 'POINT'),
).mode = 'POINT'
row.operator(
"grease_pencil.set_selection_mode",
text="",
icon="GP_SELECT_STROKES",
depress=(tool_settings.gpencil_selectmode_edit == 'STROKE'),
).mode = 'STROKE'
# Grease Pencil (legacy)
if obj and obj.type == 'GPENCIL' and context.gpencil_data:

View File

@ -70,7 +70,6 @@ set(SRC_DNA_INC
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_sequence_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_session_uuid_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_shader_fx_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_simulation_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_sound_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_space_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_speaker_types.h
@ -119,7 +118,6 @@ set(SRC_DNA_DEFAULTS_INC
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_particle_defaults.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_pointcloud_defaults.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_scene_defaults.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_simulation_defaults.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_space_defaults.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_speaker_defaults.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_texture_defaults.h

View File

@ -5,7 +5,6 @@
set(INC
.
intern
../blenkernel
../../../intern/clog
)
@ -39,7 +38,7 @@ set(SRC
)
set(LIB
bf_blenkernel
PRIVATE bf::blenkernel
PRIVATE bf::blenlib
PRIVATE bf::dna
PRIVATE bf::intern::guardedalloc

View File

@ -4,7 +4,6 @@
set(INC
.
../blenkernel
../blentranslation
../gpu
../imbuf
@ -31,6 +30,7 @@ set(SRC
)
set(LIB
PRIVATE bf::blenkernel
PRIVATE bf::blenlib
PRIVATE bf::dna
bf_gpu

View File

@ -9,6 +9,8 @@
* \brief Blender kernel action and pose functionality.
*/
#include "BLI_compiler_attrs.h"
#include "DNA_listBase.h"
#ifdef __cplusplus
@ -73,7 +75,8 @@ typedef enum eAction_TransformFlags {
eAction_TransformFlags BKE_action_get_item_transform_flags(struct bAction *act,
struct Object *ob,
struct bPoseChannel *pchan,
ListBase *curves);
ListBase *curves)
ATTR_WARN_UNUSED_RESULT;
/**
* Calculate the extents of given action.
@ -81,23 +84,24 @@ eAction_TransformFlags BKE_action_get_item_transform_flags(struct bAction *act,
void BKE_action_frame_range_calc(const struct bAction *act,
bool include_modifiers,
float *r_start,
float *r_end);
float *r_end) ATTR_NONNULL(3, 4);
/**
* Retrieve the intended playback frame range, using the manually set range if available,
* or falling back to scanning F-Curves for their first & last frames otherwise.
*/
void BKE_action_frame_range_get(const struct bAction *act, float *r_start, float *r_end);
void BKE_action_frame_range_get(const struct bAction *act, float *r_start, float *r_end)
ATTR_NONNULL(2, 3);
/**
* Check if the given action has any keyframes.
*/
bool BKE_action_has_motion(const struct bAction *act);
bool BKE_action_has_motion(const struct bAction *act) ATTR_WARN_UNUSED_RESULT;
/**
* Is the action configured as cyclic.
*/
bool BKE_action_is_cyclic(const struct bAction *act);
bool BKE_action_is_cyclic(const struct bAction *act) ATTR_WARN_UNUSED_RESULT;
/**
* Remove all fcurves from the action.
@ -109,7 +113,7 @@ void BKE_action_fcurves_clear(struct bAction *act);
/**
* Get the active action-group for an Action.
*/
struct bActionGroup *get_active_actiongroup(struct bAction *act);
struct bActionGroup *get_active_actiongroup(struct bAction *act) ATTR_WARN_UNUSED_RESULT;
/**
* Make the given Action-Group the active one.
@ -166,58 +170,58 @@ void action_groups_clear_tempflags(struct bAction *act);
* \return `false` when there is no keyframe at all or keys on different points in time, `true`
* when exactly one point in time is keyed.
*/
bool BKE_action_has_single_frame(const struct bAction *act);
bool BKE_action_has_single_frame(const struct bAction *act) ATTR_WARN_UNUSED_RESULT;
/* Pose API ----------------- */
void BKE_pose_channel_free(struct bPoseChannel *pchan);
void BKE_pose_channel_free(struct bPoseChannel *pchan) ATTR_NONNULL(1);
/**
* Deallocates a pose channel.
* Does not free the pose channel itself.
*/
void BKE_pose_channel_free_ex(struct bPoseChannel *pchan, bool do_id_user);
void BKE_pose_channel_free_ex(struct bPoseChannel *pchan, bool do_id_user) ATTR_NONNULL(1);
/**
* Clears the runtime cache of a pose channel without free.
*/
void BKE_pose_channel_runtime_reset(struct bPoseChannel_Runtime *runtime);
void BKE_pose_channel_runtime_reset(struct bPoseChannel_Runtime *runtime) ATTR_NONNULL(1);
/**
* Reset all non-persistent fields.
*/
void BKE_pose_channel_runtime_reset_on_copy(struct bPoseChannel_Runtime *runtime);
void BKE_pose_channel_runtime_reset_on_copy(struct bPoseChannel_Runtime *runtime) ATTR_NONNULL(1);
/**
* Deallocates runtime cache of a pose channel
*/
void BKE_pose_channel_runtime_free(struct bPoseChannel_Runtime *runtime);
void BKE_pose_channel_runtime_free(struct bPoseChannel_Runtime *runtime) ATTR_NONNULL(1);
/**
* Deallocates runtime cache of a pose channel's B-Bone shape.
*/
void BKE_pose_channel_free_bbone_cache(struct bPoseChannel_Runtime *runtime);
void BKE_pose_channel_free_bbone_cache(struct bPoseChannel_Runtime *runtime) ATTR_NONNULL(1);
void BKE_pose_channels_free(struct bPose *pose);
void BKE_pose_channels_free(struct bPose *pose) ATTR_NONNULL(1);
/**
* Removes and deallocates all channels from a pose.
* Does not free the pose itself.
*/
void BKE_pose_channels_free_ex(struct bPose *pose, bool do_id_user);
void BKE_pose_channels_free_ex(struct bPose *pose, bool do_id_user) ATTR_NONNULL(1);
/**
* Removes the hash for quick lookup of channels, must be done when adding/removing channels.
*/
void BKE_pose_channels_hash_ensure(struct bPose *pose);
void BKE_pose_channels_hash_free(struct bPose *pose);
void BKE_pose_channels_hash_ensure(struct bPose *pose) ATTR_NONNULL(1);
void BKE_pose_channels_hash_free(struct bPose *pose) ATTR_NONNULL(1);
/**
* Selectively remove pose channels.
*/
void BKE_pose_channels_remove(struct Object *ob,
bool (*filter_fn)(const char *bone_name, void *user_data),
void *user_data);
void *user_data) ATTR_NONNULL(1, 2);
void BKE_pose_free_data_ex(struct bPose *pose, bool do_id_user);
void BKE_pose_free_data(struct bPose *pose);
void BKE_pose_free_data_ex(struct bPose *pose, bool do_id_user) ATTR_NONNULL(1);
void BKE_pose_free_data(struct bPose *pose) ATTR_NONNULL(1);
void BKE_pose_free(struct bPose *pose);
/**
* Removes and deallocates all data from a pose, and also frees the pose.
@ -253,7 +257,8 @@ struct bPoseChannel *BKE_pose_channel_find_name(const struct bPose *pose, const
*
* \return true if on a visible layer, false otherwise.
*/
bool BKE_pose_is_layer_visible(const struct bArmature *arm, const struct bPoseChannel *pchan);
bool BKE_pose_is_layer_visible(const struct bArmature *arm,
const struct bPoseChannel *pchan) ATTR_WARN_UNUSED_RESULT;
/**
* Find the active pose-channel for an object
*
@ -270,7 +275,8 @@ struct bPoseChannel *BKE_pose_channel_active(struct Object *ob, bool check_arm_l
* \return #bPoseChannel if found or NULL.
* \note #Object, not #bPose is used here, as we need info (layer/active bone) from Armature.
*/
struct bPoseChannel *BKE_pose_channel_active_if_layer_visible(struct Object *ob);
struct bPoseChannel *BKE_pose_channel_active_if_layer_visible(struct Object *ob)
ATTR_WARN_UNUSED_RESULT;
/**
* Use this when detecting the "other selected bone",
* when we have multiple armatures in pose mode.
@ -280,7 +286,8 @@ struct bPoseChannel *BKE_pose_channel_active_if_layer_visible(struct Object *ob)
* active object is the _real_ active bone, so any other non-active selected bone
* is a candidate for being the other selected bone, see: #58447.
*/
struct bPoseChannel *BKE_pose_channel_active_or_first_selected(struct Object *ob);
struct bPoseChannel *BKE_pose_channel_active_or_first_selected(struct Object *ob)
ATTR_WARN_UNUSED_RESULT;
/**
* Looks to see if the channel with the given name already exists
* in this pose - if not a new one is allocated and initialized.
@ -288,38 +295,39 @@ struct bPoseChannel *BKE_pose_channel_active_or_first_selected(struct Object *ob
* \note Use with care, not on Armature poses but for temporal ones.
* \note (currently used for action constraints and in rebuild_pose).
*/
struct bPoseChannel *BKE_pose_channel_ensure(struct bPose *pose, const char *name);
struct bPoseChannel *BKE_pose_channel_ensure(struct bPose *pose, const char *name) ATTR_NONNULL(2);
/**
* \see #ED_armature_ebone_get_mirrored (edit-mode, matching function)
*/
struct bPoseChannel *BKE_pose_channel_get_mirrored(const struct bPose *pose, const char *name);
struct bPoseChannel *BKE_pose_channel_get_mirrored(const struct bPose *pose,
const char *name) ATTR_WARN_UNUSED_RESULT;
void BKE_pose_check_uuids_unique_and_report(const struct bPose *pose);
#ifndef NDEBUG
bool BKE_pose_channels_is_valid(const struct bPose *pose);
bool BKE_pose_channels_is_valid(const struct bPose *pose) ATTR_WARN_UNUSED_RESULT;
#endif
/**
* Checks for IK constraint, Spline IK, and also for Follow-Path constraint.
* can do more constraints flags later. pose should be entirely OK.
*/
void BKE_pose_update_constraint_flags(struct bPose *pose);
void BKE_pose_update_constraint_flags(struct bPose *pose) ATTR_NONNULL(1);
/**
* Tag constraint flags for update.
*/
void BKE_pose_tag_update_constraint_flags(struct bPose *pose);
void BKE_pose_tag_update_constraint_flags(struct bPose *pose) ATTR_NONNULL(1);
/**
* Return the name of structure pointed by `pose->ikparam`.
*/
const char *BKE_pose_ikparam_get_name(struct bPose *pose);
const char *BKE_pose_ikparam_get_name(struct bPose *pose) ATTR_WARN_UNUSED_RESULT;
/**
* Allocate and initialize `pose->ikparam` according to `pose->iksolver`.
*/
void BKE_pose_ikparam_init(struct bPose *pose);
void BKE_pose_ikparam_init(struct bPose *pose) ATTR_NONNULL(1);
/**
* Initialize a #bItasc structure with default value.
@ -336,17 +344,18 @@ bool BKE_pose_channel_in_IK_chain(struct Object *ob, struct bPoseChannel *pchan)
/**
* Adds a new bone-group (name may be NULL).
*/
struct bActionGroup *BKE_pose_add_group(struct bPose *pose, const char *name);
struct bActionGroup *BKE_pose_add_group(struct bPose *pose, const char *name) ATTR_NONNULL(1);
/**
* Remove the given bone-group (expects 'virtual' index (+1 one, used by active_group etc.))
* index might be invalid ( < 1), in which case it will be find from grp.
*/
void BKE_pose_remove_group(struct bPose *pose, struct bActionGroup *grp, int index);
void BKE_pose_remove_group(struct bPose *pose, struct bActionGroup *grp, int index)
ATTR_NONNULL(1);
/**
* Remove the indexed bone-group (expects 'virtual' index (+1 one, used by active_group etc.)).
*/
void BKE_pose_remove_group_index(struct bPose *pose, int index);
void BKE_pose_remove_group_index(struct bPose *pose, int index) ATTR_NONNULL(1);
/* Assorted Evaluation ----------------- */
@ -359,10 +368,10 @@ void what_does_obaction(struct Object *ob,
struct bPose *pose,
struct bAction *act,
char groupname[],
const struct AnimationEvalContext *anim_eval_context);
const struct AnimationEvalContext *anim_eval_context) ATTR_NONNULL(1, 2);
void BKE_pose_copy_pchan_result(struct bPoseChannel *pchanto,
const struct bPoseChannel *pchanfrom);
void BKE_pose_copy_pchan_result(struct bPoseChannel *pchanto, const struct bPoseChannel *pchanfrom)
ATTR_NONNULL(1, 2);
/**
* Both poses should be in sync.
*/
@ -375,16 +384,19 @@ void BKE_pose_rest(struct bPose *pose, bool selected_bones_only);
/**
* Tag pose for recalculation. Also tag all related data to be recalculated.
*/
void BKE_pose_tag_recalc(struct Main *bmain, struct bPose *pose);
void BKE_pose_tag_recalc(struct Main *bmain, struct bPose *pose) ATTR_NONNULL(1, 2);
void BKE_pose_blend_write(struct BlendWriter *writer, struct bPose *pose, struct bArmature *arm);
void BKE_pose_blend_read_data(struct BlendDataReader *reader, struct bPose *pose);
void BKE_pose_blend_read_lib(struct BlendLibReader *reader, struct Object *ob, struct bPose *pose);
void BKE_pose_blend_read_expand(struct BlendExpander *expander, struct bPose *pose);
void BKE_pose_blend_write(struct BlendWriter *writer, struct bPose *pose, struct bArmature *arm)
ATTR_NONNULL(1, 2, 3);
void BKE_pose_blend_read_data(struct BlendDataReader *reader, struct bPose *pose) ATTR_NONNULL(1);
void BKE_pose_blend_read_lib(struct BlendLibReader *reader, struct Object *ob, struct bPose *pose)
ATTR_NONNULL(1, 2);
void BKE_pose_blend_read_expand(struct BlendExpander *expander, struct bPose *pose)
ATTR_NONNULL(1);
/* action_mirror.c */
void BKE_action_flip_with_pose(struct bAction *act, struct Object *ob_arm);
void BKE_action_flip_with_pose(struct bAction *act, struct Object *ob_arm) ATTR_NONNULL(1, 2);
#ifdef __cplusplus
};

View File

@ -115,7 +115,7 @@ const char *BKE_id_attributes_default_color_name(const struct ID *id);
void BKE_id_attributes_active_color_set(struct ID *id, const char *name);
void BKE_id_attributes_default_color_set(struct ID *id, const char *name);
struct CustomDataLayer *BKE_id_attributes_color_find(const struct ID *id, const char *name);
const struct CustomDataLayer *BKE_id_attributes_color_find(const struct ID *id, const char *name);
bool BKE_id_attribute_calc_unique_name(struct ID *id, const char *name, char *outname);

View File

@ -27,7 +27,7 @@ extern "C" {
/* Blender file format version. */
#define BLENDER_FILE_VERSION BLENDER_VERSION
#define BLENDER_FILE_SUBVERSION 9
#define BLENDER_FILE_SUBVERSION 10
/* 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

View File

@ -78,4 +78,29 @@ class SimulationZoneComputeContext : public ComputeContext {
void print_current_in_line(std::ostream &stream) const override;
};
class RepeatZoneComputeContext : public ComputeContext {
private:
static constexpr const char *s_static_type = "REPEAT_ZONE";
int32_t output_node_id_;
int iteration_;
public:
RepeatZoneComputeContext(const ComputeContext *parent, int32_t output_node_id, int iteration);
RepeatZoneComputeContext(const ComputeContext *parent, const bNode &node, int iteration);
int32_t output_node_id() const
{
return output_node_id_;
}
int iteration() const
{
return iteration_;
}
private:
void print_current_in_line(std::ostream &stream) const override;
};
} // namespace blender::bke

View File

@ -85,7 +85,8 @@ class Drawing : public ::GreasePencilDrawing {
MutableSpan<float> radii_for_write();
/**
* Opacities for the points. Used by the render engine as an alpha value so they are expected to
* Opacity array for the points.
* Used by the render engine as an alpha value so they are expected to
* be between 0 and 1 inclusive.
*/
VArray<float> opacities() const;

View File

@ -277,7 +277,6 @@ extern IDTypeInfo IDType_ID_LP;
extern IDTypeInfo IDType_ID_CV;
extern IDTypeInfo IDType_ID_PT;
extern IDTypeInfo IDType_ID_VO;
extern IDTypeInfo IDType_ID_SIM;
extern IDTypeInfo IDType_ID_GP;
/** Empty shell mostly, but needed for read code. */

View File

@ -530,7 +530,7 @@ void BKE_lib_override_library_main_update(struct Main *bmain);
bool BKE_lib_override_library_id_is_user_deletable(struct Main *bmain, struct ID *id);
/**
* Debuging helper to show content of given liboverride data.
* Debugging helper to show content of given liboverride data.
*/
void BKE_lib_override_debug_print(struct IDOverrideLibrary *override, const char *intro_txt);

View File

@ -225,7 +225,6 @@ typedef struct Main {
ListBase hair_curves;
ListBase pointclouds;
ListBase volumes;
ListBase simulations;
/**
* Must be generated, used and freed by same code - never assume this is valid data unless you

View File

@ -880,7 +880,6 @@ struct NodeTreeIterStore {
struct Light *light;
struct World *world;
struct FreestyleLineStyle *linestyle;
struct Simulation *simulation;
};
void BKE_node_tree_iter_init(struct NodeTreeIterStore *ntreeiter, struct Main *bmain);
@ -1362,6 +1361,10 @@ void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree, struct Scene *scene, i
#define GEO_NODE_INPUT_SIGNED_DISTANCE 2102
#define GEO_NODE_SAMPLE_VOLUME 2103
#define GEO_NODE_MESH_TOPOLOGY_CORNERS_OF_EDGE 2104
/* Leaving out two indices to avoid crashes with files that were created during the development of
* the repeat zone. */
#define GEO_NODE_REPEAT_INPUT 2107
#define GEO_NODE_REPEAT_OUTPUT 2108
/** \} */

View File

@ -259,8 +259,6 @@ class bNodeRuntime : NonCopyable, NonMovable {
short preview_xsize, preview_ysize = 0;
/** Entire bound-box (world-space). */
rctf totr{};
/** Optional preview area. */
rctf prvr{};
/** Used at runtime when going through the tree. Initialize before use. */
short tmp_flag = 0;

View File

@ -12,6 +12,7 @@
#include "BLI_compiler_compat.h"
#ifdef __cplusplus
# include "BLI_array.hh"
# include "BLI_math_vector_types.hh"
# include "BLI_offset_indices.hh"
#endif
#include "BLI_utildefines.h"
@ -594,7 +595,7 @@ typedef struct SculptSession {
struct Depsgraph *depsgraph;
/* These are always assigned to base mesh data when using PBVH_FACES and PBVH_GRIDS. */
float (*vert_positions)[3];
blender::MutableSpan<blender::float3> vert_positions;
blender::OffsetIndices<int> polys;
blender::Span<int> corner_verts;

View File

@ -12,6 +12,7 @@
#include "BLI_bitmap.h"
#include "BLI_compiler_compat.h"
#include "BLI_ghash.h"
#include "BLI_math_vector_types.hh"
#include "BLI_offset_indices.hh"
#include "BLI_vector.hh"
@ -498,8 +499,8 @@ struct PBVHVertexIter {
int gridsize;
/* mesh */
float (*vert_positions)[3];
float (*vert_normals)[3];
blender::MutableSpan<blender::float3> vert_positions;
blender::MutableSpan<blender::float3> vert_normals;
const bool *hide_vert;
int totvert;
const int *vert_indices;
@ -558,7 +559,7 @@ void pbvh_vertex_iter_init(PBVH *pbvh, PBVHNode *node, PBVHVertexIter *vi, int m
} \
} \
} \
else if (vi.vert_positions) { \
else if (!vi.vert_positions.is_empty()) { \
vi.visible = !(vi.hide_vert && vi.hide_vert[vi.vert_indices[vi.gx]]); \
if (mode == PBVH_ITER_UNIQUE && !vi.visible) { \
continue; \
@ -682,7 +683,7 @@ const bool *BKE_pbvh_get_poly_hide(const PBVH *pbvh);
PBVHColorBufferNode *BKE_pbvh_node_color_buffer_get(PBVHNode *node);
void BKE_pbvh_node_color_buffer_free(PBVH *pbvh);
bool BKE_pbvh_get_color_layer(const Mesh *me, CustomDataLayer **r_layer, eAttrDomain *r_attr);
bool BKE_pbvh_get_color_layer(Mesh *me, CustomDataLayer **r_layer, eAttrDomain *r_domain);
/* Swaps colors at each element in indices (of domain pbvh->vcol_domain)
* with values in colors. */
@ -709,7 +710,7 @@ bool BKE_pbvh_is_drawing(const PBVH *pbvh);
/* Do not call in PBVH_GRIDS mode */
void BKE_pbvh_node_num_loops(PBVH *pbvh, PBVHNode *node, int *r_totloop);
void BKE_pbvh_update_active_vcol(PBVH *pbvh, const Mesh *mesh);
void BKE_pbvh_update_active_vcol(PBVH *pbvh, Mesh *mesh);
void BKE_pbvh_vertex_color_set(PBVH *pbvh, PBVHVertRef vertex, const float color[4]);
void BKE_pbvh_vertex_color_get(const PBVH *pbvh, PBVHVertRef vertex, float r_color[4]);

View File

@ -1,26 +0,0 @@
/* SPDX-FileCopyrightText: 2023 Blender Foundation
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
struct Depsgraph;
struct Main;
struct Scene;
struct Simulation;
void *BKE_simulation_add(struct Main *bmain, const char *name);
void BKE_simulation_data_update(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Simulation *simulation);
void BKE_simulation_reset_scene(Scene *scene);
#ifdef __cplusplus
}
#endif

View File

@ -197,4 +197,10 @@ class ModifierSimulationCache {
void reset();
};
/**
* Reset all simulation caches in the scene, for use when some fundamental change made them
* impossible to reuse.
*/
void scene_simulation_states_reset(Scene &scene);
} // namespace blender::bke::sim

View File

@ -53,6 +53,7 @@ ModifierViewerPathElem *BKE_viewer_path_elem_new_modifier(void);
GroupNodeViewerPathElem *BKE_viewer_path_elem_new_group_node(void);
SimulationZoneViewerPathElem *BKE_viewer_path_elem_new_simulation_zone(void);
ViewerNodeViewerPathElem *BKE_viewer_path_elem_new_viewer_node(void);
RepeatZoneViewerPathElem *BKE_viewer_path_elem_new_repeat_zone(void);
ViewerPathElem *BKE_viewer_path_elem_copy(const ViewerPathElem *src);
bool BKE_viewer_path_elem_equal(const ViewerPathElem *a, const ViewerPathElem *b);
void BKE_viewer_path_elem_free(ViewerPathElem *elem);

View File

@ -3,7 +3,7 @@
# SPDX-License-Identifier: GPL-2.0-or-later
set(INC
.
PUBLIC .
../asset_system
../blenfont
../blenloader
@ -264,7 +264,6 @@ set(SRC
intern/screen.c
intern/shader_fx.c
intern/shrinkwrap.cc
intern/simulation.cc
intern/simulation_state.cc
intern/simulation_state_serialize.cc
intern/softbody.c
@ -471,7 +470,6 @@ set(SRC
BKE_sequencer_offscreen.h
BKE_shader_fx.h
BKE_shrinkwrap.h
BKE_simulation.h
BKE_simulation_state.hh
BKE_simulation_state_serialize.hh
BKE_softbody.h
@ -814,6 +812,7 @@ endif()
# endif()
blender_add_lib(bf_blenkernel "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
add_library(bf::blenkernel ALIAS bf_blenkernel)
# RNA_prototypes.h
add_dependencies(bf_blenkernel bf_rna)

View File

@ -1489,7 +1489,7 @@ void BKE_action_frame_range_get(const bAction *act, float *r_start, float *r_end
*r_end = act->frame_end;
}
else {
BKE_action_frame_range_calc(act, r_start, r_end, false);
BKE_action_frame_range_calc(act, false, r_start, r_end);
}
/* Ensure that action is at least 1 frame long (for NLA strips to have a valid length). */
@ -1839,12 +1839,9 @@ void BKE_pose_check_uuids_unique_and_report(const bPose *pose)
void BKE_pose_blend_write(BlendWriter *writer, bPose *pose, bArmature *arm)
{
/* Write each channel */
if (pose == NULL) {
return;
}
BLI_assert(arm != NULL);
#ifndef __GNUC__
BLI_assert(pose != NULL && arm != NULL);
#endif
/* Write channels */
LISTBASE_FOREACH (bPoseChannel *, chan, &pose->chanbase) {

View File

@ -1313,9 +1313,6 @@ void BKE_animdata_main_cb(Main *bmain, ID_AnimData_Edit_Callback func, void *use
/* volumes */
ANIMDATA_IDS_CB(bmain->volumes.first);
/* simulations */
ANIMDATA_IDS_CB(bmain->simulations.first);
}
void BKE_animdata_fix_paths_rename_all(ID *ref_id,
@ -1443,9 +1440,6 @@ void BKE_animdata_fix_paths_rename_all_ex(Main *bmain,
/* volumes */
RENAMEFIX_ANIM_IDS(bmain->volumes.first);
/* simulations */
RENAMEFIX_ANIM_IDS(bmain->simulations.first);
/* scenes */
RENAMEFIX_ANIM_NODETREE_IDS(bmain->scenes.first, Scene);
}

View File

@ -4103,9 +4103,6 @@ void BKE_animsys_evaluate_all_animation(Main *main, Depsgraph *depsgraph, float
/* volumes */
EVAL_ANIM_IDS(main->volumes.first, ADT_RECALC_ANIM);
/* simulations */
EVAL_ANIM_IDS(main->simulations.first, ADT_RECALC_ANIM);
/* objects */
/* ADT_RECALC_ANIM doesn't need to be supplied here, since object AnimData gets
* this tagged by Depsgraph on frame-change. This optimization means that objects

View File

@ -868,26 +868,10 @@ void BKE_id_attributes_default_color_set(ID *id, const char *name)
}
}
CustomDataLayer *BKE_id_attributes_color_find(const ID *id, const char *name)
const CustomDataLayer *BKE_id_attributes_color_find(const ID *id, const char *name)
{
if (CustomDataLayer *layer = BKE_id_attribute_find(id, name, CD_PROP_COLOR, ATTR_DOMAIN_POINT)) {
return layer;
}
if (CustomDataLayer *layer = BKE_id_attribute_find(id, name, CD_PROP_COLOR, ATTR_DOMAIN_CORNER))
{
return layer;
}
if (CustomDataLayer *layer = BKE_id_attribute_find(
id, name, CD_PROP_BYTE_COLOR, ATTR_DOMAIN_POINT))
{
return layer;
}
if (CustomDataLayer *layer = BKE_id_attribute_find(
id, name, CD_PROP_BYTE_COLOR, ATTR_DOMAIN_CORNER))
{
return layer;
}
return nullptr;
return BKE_id_attribute_search(
const_cast<ID *>(id), name, CD_MASK_COLOR_ALL, ATTR_DOMAIN_MASK_COLOR);
}
const char *BKE_uv_map_vert_select_name_get(const char *uv_map_name, char *buffer)

View File

@ -88,4 +88,33 @@ void SimulationZoneComputeContext::print_current_in_line(std::ostream &stream) c
stream << "Simulation Zone ID: " << output_node_id_;
}
RepeatZoneComputeContext::RepeatZoneComputeContext(const ComputeContext *parent,
const int32_t output_node_id,
const int iteration)
: ComputeContext(s_static_type, parent), output_node_id_(output_node_id), iteration_(iteration)
{
/* Mix static type and node id into a single buffer so that only a single call to #mix_in is
* necessary. */
const int type_size = strlen(s_static_type);
const int buffer_size = type_size + 1 + sizeof(int32_t) + sizeof(int);
DynamicStackBuffer<64, 8> buffer_owner(buffer_size, 8);
char *buffer = static_cast<char *>(buffer_owner.buffer());
memcpy(buffer, s_static_type, type_size + 1);
memcpy(buffer + type_size + 1, &output_node_id_, sizeof(int32_t));
memcpy(buffer + type_size + 1 + sizeof(int32_t), &iteration_, sizeof(int));
hash_.mix_in(buffer, buffer_size);
}
RepeatZoneComputeContext::RepeatZoneComputeContext(const ComputeContext *parent,
const bNode &node,
const int iteration)
: RepeatZoneComputeContext(parent, node.identifier, iteration)
{
}
void RepeatZoneComputeContext::print_current_in_line(std::ostream &stream) const
{
stream << "Repeat Zone ID: " << output_node_id_;
}
} // namespace blender::bke

View File

@ -56,6 +56,7 @@ static void grease_pencil_init_data(ID *id)
new (&grease_pencil->root_group) greasepencil::LayerGroup();
grease_pencil->active_layer = nullptr;
grease_pencil->flag |= GREASE_PENCIL_ANIM_CHANNEL_EXPANDED;
}
static void grease_pencil_copy_data(Main * /*bmain*/,

View File

@ -95,7 +95,6 @@ static void id_type_init(void)
INIT_TYPE(ID_CV);
INIT_TYPE(ID_PT);
INIT_TYPE(ID_VO);
INIT_TYPE(ID_SIM);
INIT_TYPE(ID_GP);
/* Special naughty boy... */
@ -248,7 +247,6 @@ uint64_t BKE_idtype_idcode_to_idfilter(const short idcode)
CASE_IDFILTER(PT);
CASE_IDFILTER(SCE);
CASE_IDFILTER(SCR);
CASE_IDFILTER(SIM);
CASE_IDFILTER(SO);
CASE_IDFILTER(SPK);
CASE_IDFILTER(TE);
@ -307,7 +305,6 @@ short BKE_idtype_idcode_from_idfilter(const uint64_t idfilter)
CASE_IDFILTER(PT);
CASE_IDFILTER(SCE);
CASE_IDFILTER(SCR);
CASE_IDFILTER(SIM);
CASE_IDFILTER(SO);
CASE_IDFILTER(SPK);
CASE_IDFILTER(TE);
@ -364,7 +361,6 @@ int BKE_idtype_idcode_to_index(const short idcode)
CASE_IDINDEX(LP);
CASE_IDINDEX(SCE);
CASE_IDINDEX(SCR);
CASE_IDINDEX(SIM);
CASE_IDINDEX(SPK);
CASE_IDINDEX(SO);
CASE_IDINDEX(TE);
@ -424,7 +420,6 @@ short BKE_idtype_idcode_from_index(const int index)
CASE_IDCODE(LP);
CASE_IDCODE(SCE);
CASE_IDCODE(SCR);
CASE_IDCODE(SIM);
CASE_IDCODE(SPK);
CASE_IDCODE(SO);
CASE_IDCODE(TE);

View File

@ -49,7 +49,6 @@
#include "DNA_packedFile_types.h"
#include "DNA_scene_types.h"
#include "DNA_sequence_types.h"
#include "DNA_simulation_types.h"
#include "DNA_world_types.h"
#include "BLI_blenlib.h"
@ -2881,11 +2880,6 @@ static void image_walk_id_all_users(
}
break;
}
case ID_SIM: {
Simulation *simulation = (Simulation *)id;
image_walk_ntree_all_users(simulation->nodetree, &simulation->id, customdata, callback);
break;
}
default:
break;
}

View File

@ -49,6 +49,7 @@
#include "BLI_linklist.h"
#include "BLI_listbase.h"
#include "BLI_memarena.h"
#include "BLI_set.hh"
#include "BLI_string.h"
#include "BLI_task.h"
#include "BLI_utildefines.h"
@ -276,9 +277,12 @@ static ID *lib_override_library_create_from(Main *bmain,
LIB_ID_COPY_DEFAULT | LIB_ID_COPY_NO_LIB_OVERRIDE |
lib_id_copy_flags);
/* Incase we could not get an override ID with the exact same name as its linked reference, ensure we at least get a uniquely named override ID over the whole current Main data, to reduce potential name collisions with other reference IDs.
/* In case we could not get an override ID with the exact same name as its linked reference,
* ensure we at least get a uniquely named override ID over the whole current Main data, to
* reduce potential name collisions with other reference IDs.
*
* While in normal cases this would not be an issue, when files start to get heavily broken and not sound, such conflicts can become a source of problems. */
* While in normal cases this would not be an issue, when files start to get heavily broken and
* not sound, such conflicts can become a source of problems. */
if (!STREQ(local_id->name + 2, reference_id->name + 2)) {
BLI_strncpy(local_id->name + 2, reference_id->name + 2, MAX_ID_NAME - 2);
BKE_main_namemap_get_name(bmain, local_id, local_id->name + 2, true);
@ -1614,8 +1618,14 @@ static ID *lib_override_root_find(Main *bmain, ID *id, const int curr_level, int
return best_root_id_candidate;
}
static void lib_override_root_hierarchy_set(Main *bmain, ID *id_root, ID *id, ID *id_from)
static void lib_override_root_hierarchy_set(
Main *bmain, ID *id_root, ID *id, ID *id_from, blender::Set<ID *> &processed_ids)
{
if (processed_ids.contains(id)) {
/* This ID has already been checked as having a valid hierarchy root, do not attempt to replace
* it with another one just because it is also used by another liboverride hierarchy. */
return;
}
if (ID_IS_OVERRIDE_LIBRARY_REAL(id)) {
if (id->override_library->hierarchy_root == id_root) {
/* Already set, nothing else to do here, sub-hierarchy is also assumed to be properly set
@ -1685,6 +1695,15 @@ static void lib_override_root_hierarchy_set(Main *bmain, ID *id_root, ID *id, ID
}
}
CLOG_INFO(&LOG,
3,
"Modifying library override hierarchy of ID '%s'.\n"
"\tFrom old root '%s' to new root '%s'.",
id->name,
id->override_library->hierarchy_root ? id->override_library->hierarchy_root->name :
"<NONE>",
id_root->name);
id->override_library->hierarchy_root = id_root;
}
@ -1709,7 +1728,7 @@ static void lib_override_root_hierarchy_set(Main *bmain, ID *id_root, ID *id, ID
}
/* Recursively process the sub-hierarchy. */
lib_override_root_hierarchy_set(bmain, id_root, to_id, id);
lib_override_root_hierarchy_set(bmain, id_root, to_id, id, processed_ids);
}
}
@ -1718,9 +1737,11 @@ void BKE_lib_override_library_main_hierarchy_root_ensure(Main *bmain)
ID *id;
BKE_main_relations_create(bmain, 0);
blender::Set<ID *> processed_ids;
FOREACH_MAIN_ID_BEGIN (bmain, id) {
if (!ID_IS_OVERRIDE_LIBRARY_REAL(id)) {
processed_ids.add(id);
continue;
}
if (id->override_library->hierarchy_root != nullptr) {
@ -1738,6 +1759,8 @@ void BKE_lib_override_library_main_hierarchy_root_ensure(Main *bmain)
id->override_library->hierarchy_root = nullptr;
}
else {
/* This ID is considered as having a valid hierarchy root. */
processed_ids.add(id);
continue;
}
}
@ -1748,16 +1771,20 @@ void BKE_lib_override_library_main_hierarchy_root_ensure(Main *bmain)
ID *id_root = lib_override_root_find(bmain, id, best_level, &best_level);
if (!ELEM(id_root->override_library->hierarchy_root, id_root, nullptr)) {
/* FIXME This is probably never actually reached with current code? Check above for non-null
* hierarchy root pointer either skip the rest of the loop, or reset it to nullptr. */
CLOG_WARN(&LOG,
"Potential inconsistency in library override hierarchy of ID '%s', detected as "
"part of the hierarchy of '%s', which has a different root '%s'",
"Potential inconsistency in library override hierarchy of ID '%s' (current root "
"%s), detected as part of the hierarchy of '%s' (current root '%s')",
id->name,
id->override_library->hierarchy_root->name,
id_root->name,
id_root->override_library->hierarchy_root->name);
processed_ids.add(id);
continue;
}
lib_override_root_hierarchy_set(bmain, id_root, id, nullptr);
lib_override_root_hierarchy_set(bmain, id_root, id, nullptr, processed_ids);
BLI_assert(id->override_library->hierarchy_root != nullptr);
}
@ -2413,7 +2440,10 @@ static bool lib_override_library_resync(Main *bmain,
do_delete = false;
id_fake_user_set(id);
id->flag |= LIB_LIB_OVERRIDE_RESYNC_LEFTOVER;
CLOG_INFO(&LOG_RESYNC, 2, "Old override %s is being kept around as it was user-edited", id->name);
CLOG_INFO(&LOG_RESYNC,
2,
"Old override %s is being kept around as it was user-edited",
id->name);
}
#else
else {
@ -4859,7 +4889,8 @@ ID *BKE_lib_override_library_operations_store_start(Main *bmain,
RNA_id_pointer_create(storage_id, &rnaptr_storage);
if (!RNA_struct_override_store(
bmain, &rnaptr_final, &rnaptr_reference, &rnaptr_storage, local->override_library)) {
bmain, &rnaptr_final, &rnaptr_reference, &rnaptr_storage, local->override_library))
{
BKE_id_free_ex(override_storage, storage_id, LIB_ID_FREE_NO_UI_USER, true);
storage_id = nullptr;
}

View File

@ -475,8 +475,6 @@ uint64_t BKE_library_id_can_use_filter_id(const ID *owner_id, const bool include
return FILTER_ID_MA;
case ID_VO:
return FILTER_ID_MA;
case ID_SIM:
return FILTER_ID_OB | FILTER_ID_IM;
case ID_WM:
return FILTER_ID_SCE | FILTER_ID_WS;
case ID_IM:

View File

@ -597,8 +597,6 @@ ListBase *which_libbase(Main *bmain, short type)
return &(bmain->pointclouds);
case ID_VO:
return &(bmain->volumes);
case ID_SIM:
return &(bmain->simulations);
}
return NULL;
}
@ -664,7 +662,6 @@ int set_listbasepointers(Main *bmain, ListBase *lb[/*INDEX_ID_MAX*/])
lb[INDEX_ID_WS] = &(bmain->workspaces); /* before wm, so it's freed after it! */
lb[INDEX_ID_WM] = &(bmain->wm);
lb[INDEX_ID_MSK] = &(bmain->masks);
lb[INDEX_ID_SIM] = &(bmain->simulations);
lb[INDEX_ID_NULL] = NULL;

View File

@ -2046,7 +2046,7 @@ void BKE_mesh_legacy_convert_polys_to_offsets(Mesh *mesh)
}
});
CustomData_free(&old_poly_data, mesh->totloop);
CustomData_free(&old_poly_data, mesh->totpoly);
}
CustomData_free_layers(&mesh->pdata, CD_MPOLY, mesh->totpoly);

View File

@ -1188,11 +1188,11 @@ static void loop_split_generator(LoopSplitTaskDataCommon *common_data,
#if 0
printf("Checking loop %d / edge %u / vert %u (sharp edge: %d, skiploop: %d)",
ml_curr_index,
corner_edges[ml_curr_index],
corner_verts[ml_curr_index],
IS_EDGE_SHARP(edge_to_loops[corner_edges[ml_curr_index]]),
skip_loops[ml_curr_index]);
ml_curr_index,
corner_edges[ml_curr_index],
corner_verts[ml_curr_index],
IS_EDGE_SHARP(edge_to_loops[corner_edges[ml_curr_index]]),
skip_loops[ml_curr_index]);
#endif
/* A smooth edge, we have to check for cyclic smooth fan case.

View File

@ -174,6 +174,9 @@ const float (*BKE_mesh_wrapper_vert_coords(const Mesh *mesh))[3]
{
switch (mesh->runtime->wrapper_type) {
case ME_WRAPPER_TYPE_BMESH:
if (mesh->runtime->edit_data->vertexCos.is_empty()) {
return nullptr;
}
return reinterpret_cast<const float(*)[3]>(mesh->runtime->edit_data->vertexCos.data());
case ME_WRAPPER_TYPE_MDATA:
case ME_WRAPPER_TYPE_SUBD:
@ -187,6 +190,9 @@ const float (*BKE_mesh_wrapper_poly_normals(Mesh *mesh))[3]
switch (mesh->runtime->wrapper_type) {
case ME_WRAPPER_TYPE_BMESH:
BKE_editmesh_cache_ensure_poly_normals(mesh->edit_mesh, mesh->runtime->edit_data);
if (mesh->runtime->edit_data->polyNos.is_empty()) {
return nullptr;
}
return reinterpret_cast<const float(*)[3]>(mesh->runtime->edit_data->polyNos.data());
case ME_WRAPPER_TYPE_MDATA:
case ME_WRAPPER_TYPE_SUBD:

View File

@ -28,7 +28,6 @@
#include "DNA_modifier_types.h"
#include "DNA_node_types.h"
#include "DNA_scene_types.h"
#include "DNA_simulation_types.h"
#include "DNA_texture_types.h"
#include "DNA_world_types.h"
@ -676,6 +675,14 @@ void ntreeBlendWrite(BlendWriter *writer, bNodeTree *ntree)
BLO_write_string(writer, item.name);
}
}
if (node->type == GEO_NODE_REPEAT_OUTPUT) {
const NodeGeometryRepeatOutput &storage = *static_cast<const NodeGeometryRepeatOutput *>(
node->storage);
BLO_write_struct_array(writer, NodeRepeatItem, storage.items_num, storage.items);
for (const NodeRepeatItem &item : Span(storage.items, storage.items_num)) {
BLO_write_string(writer, item.name);
}
}
}
LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {
@ -872,6 +879,15 @@ void ntreeBlendReadData(BlendDataReader *reader, ID *owner_id, bNodeTree *ntree)
}
break;
}
case GEO_NODE_REPEAT_OUTPUT: {
NodeGeometryRepeatOutput &storage = *static_cast<NodeGeometryRepeatOutput *>(
node->storage);
BLO_read_data_address(reader, &storage.items);
for (const NodeRepeatItem &item : Span(storage.items, storage.items_num)) {
BLO_read_data_address(reader, &item.name);
}
break;
}
default:
break;
@ -3594,8 +3610,6 @@ bNodeTree **BKE_ntree_ptr_from_id(ID *id)
return &reinterpret_cast<Scene *>(id)->nodetree;
case ID_LS:
return &reinterpret_cast<FreestyleLineStyle *>(id)->nodetree;
case ID_SIM:
return &reinterpret_cast<Simulation *>(id)->nodetree;
default:
return nullptr;
}
@ -4726,7 +4740,6 @@ void BKE_node_tree_iter_init(NodeTreeIterStore *ntreeiter, Main *bmain)
ntreeiter->light = (Light *)bmain->lights.first;
ntreeiter->world = (World *)bmain->worlds.first;
ntreeiter->linestyle = (FreestyleLineStyle *)bmain->linestyles.first;
ntreeiter->simulation = (Simulation *)bmain->simulations.first;
}
bool BKE_node_tree_iter_step(NodeTreeIterStore *ntreeiter, bNodeTree **r_nodetree, ID **r_id)
{
@ -4766,11 +4779,6 @@ bool BKE_node_tree_iter_step(NodeTreeIterStore *ntreeiter, bNodeTree **r_nodetre
*r_id = &ntreeiter->linestyle->id;
ntreeiter->linestyle = reinterpret_cast<FreestyleLineStyle *>(ntreeiter->linestyle->id.next);
}
else if (ntreeiter->simulation) {
*r_nodetree = reinterpret_cast<bNodeTree *>(ntreeiter->simulation->nodetree);
*r_id = &ntreeiter->simulation->id;
ntreeiter->simulation = reinterpret_cast<Simulation *>(ntreeiter->simulation->id.next);
}
else {
return false;
}

View File

@ -294,6 +294,17 @@ static Vector<const bNode *> get_implicit_origin_nodes(const bNodeTree &ntree, b
}
}
}
if (node.type == GEO_NODE_REPEAT_OUTPUT) {
for (const bNode *repeat_input_node :
ntree.runtime->nodes_by_type.lookup(nodeTypeFind("GeometryNodeRepeatInput")))
{
const auto &storage = *static_cast<const NodeGeometryRepeatInput *>(
repeat_input_node->storage);
if (storage.output_node_id == node.identifier) {
origin_nodes.append(repeat_input_node);
}
}
}
return origin_nodes;
}
@ -306,6 +317,12 @@ static Vector<const bNode *> get_implicit_target_nodes(const bNodeTree &ntree, b
target_nodes.append(sim_output_node);
}
}
if (node.type == GEO_NODE_REPEAT_INPUT) {
const auto &storage = *static_cast<const NodeGeometryRepeatInput *>(node.storage);
if (const bNode *repeat_output_node = ntree.node_by_id(storage.output_node_id)) {
target_nodes.append(repeat_output_node);
}
}
return target_nodes;
}

View File

@ -99,6 +99,48 @@ static const aal::RelationsInNode &get_relations_in_node(const bNode &node, Reso
}
return relations;
}
if (ELEM(node.type, GEO_NODE_REPEAT_INPUT, GEO_NODE_REPEAT_OUTPUT)) {
aal::RelationsInNode &relations = scope.construct<aal::RelationsInNode>();
/* TODO: Add a smaller set of relations. This requires changing the inferencing algorithm to
* make it aware of loops. */
for (const bNodeSocket *socket : node.output_sockets()) {
if (socket->type == SOCK_GEOMETRY) {
for (const bNodeSocket *other_output : node.output_sockets()) {
if (socket_is_field(*other_output)) {
relations.available_relations.append({other_output->index(), socket->index()});
}
}
for (const bNodeSocket *input_socket : node.input_sockets()) {
if (input_socket->type == SOCK_GEOMETRY) {
relations.propagate_relations.append({input_socket->index(), socket->index()});
}
}
}
else if (socket_is_field(*socket)) {
/* Reference relations are not added for the output node, because then nodes after the
* repeat zone would have to know about the individual field sources within the repeat
* zone. This is not necessary, because the field outputs of a repeat zone already serve as
* field sources and anonymous attributes are extracted from them. */
if (node.type == GEO_NODE_REPEAT_INPUT) {
for (const bNodeSocket *input_socket : node.input_sockets()) {
if (socket_is_field(*input_socket)) {
relations.reference_relations.append({input_socket->index(), socket->index()});
}
}
}
}
}
for (const bNodeSocket *socket : node.input_sockets()) {
if (socket->type == SOCK_GEOMETRY) {
for (const bNodeSocket *other_input : node.input_sockets()) {
if (socket_is_field(*other_input)) {
relations.eval_relations.append({other_input->index(), socket->index()});
}
}
}
}
return relations;
}
if (const NodeDeclaration *node_decl = node.declaration()) {
if (const aal::RelationsInNode *relations = node_decl->anonymous_attribute_relations()) {
return *relations;

View File

@ -319,6 +319,22 @@ static eFieldStateSyncResult simulation_nodes_field_state_sync(
return res;
}
static eFieldStateSyncResult repeat_field_state_sync(
const bNode &input_node,
const bNode &output_node,
const MutableSpan<SocketFieldState> field_state_by_socket_id)
{
eFieldStateSyncResult res = eFieldStateSyncResult::NONE;
for (const int i : output_node.output_sockets().index_range()) {
const bNodeSocket &input_socket = input_node.output_socket(i);
const bNodeSocket &output_socket = output_node.output_socket(i);
SocketFieldState &input_state = field_state_by_socket_id[input_socket.index_in_tree()];
SocketFieldState &output_state = field_state_by_socket_id[output_socket.index_in_tree()];
res |= sync_field_states(input_state, output_state);
}
return res;
}
static bool propagate_special_data_requirements(
const bNodeTree &tree,
const bNode &node,
@ -328,29 +344,59 @@ static bool propagate_special_data_requirements(
bool need_update = false;
/* Sync field state between simulation nodes and schedule another pass if necessary. */
if (node.type == GEO_NODE_SIMULATION_INPUT) {
const NodeGeometrySimulationInput &data = *static_cast<const NodeGeometrySimulationInput *>(
node.storage);
if (const bNode *output_node = tree.node_by_id(data.output_node_id)) {
const eFieldStateSyncResult sync_result = simulation_nodes_field_state_sync(
node, *output_node, field_state_by_socket_id);
if (bool(sync_result & eFieldStateSyncResult::CHANGED_B)) {
need_update = true;
}
}
}
else if (node.type == GEO_NODE_SIMULATION_OUTPUT) {
for (const bNode *input_node : tree.nodes_by_type("GeometryNodeSimulationInput")) {
/* Sync field state between zone nodes and schedule another pass if necessary. */
switch (node.type) {
case GEO_NODE_SIMULATION_INPUT: {
const NodeGeometrySimulationInput &data = *static_cast<const NodeGeometrySimulationInput *>(
input_node->storage);
if (node.identifier == data.output_node_id) {
node.storage);
if (const bNode *output_node = tree.node_by_id(data.output_node_id)) {
const eFieldStateSyncResult sync_result = simulation_nodes_field_state_sync(
*input_node, node, field_state_by_socket_id);
if (bool(sync_result & eFieldStateSyncResult::CHANGED_A)) {
node, *output_node, field_state_by_socket_id);
if (bool(sync_result & eFieldStateSyncResult::CHANGED_B)) {
need_update = true;
}
}
break;
}
case GEO_NODE_SIMULATION_OUTPUT: {
for (const bNode *input_node : tree.nodes_by_type("GeometryNodeSimulationInput")) {
const NodeGeometrySimulationInput &data =
*static_cast<const NodeGeometrySimulationInput *>(input_node->storage);
if (node.identifier == data.output_node_id) {
const eFieldStateSyncResult sync_result = simulation_nodes_field_state_sync(
*input_node, node, field_state_by_socket_id);
if (bool(sync_result & eFieldStateSyncResult::CHANGED_A)) {
need_update = true;
}
}
}
break;
}
case GEO_NODE_REPEAT_INPUT: {
const NodeGeometryRepeatInput &data = *static_cast<const NodeGeometryRepeatInput *>(
node.storage);
if (const bNode *output_node = tree.node_by_id(data.output_node_id)) {
const eFieldStateSyncResult sync_result = repeat_field_state_sync(
node, *output_node, field_state_by_socket_id);
if (bool(sync_result & eFieldStateSyncResult::CHANGED_B)) {
need_update = true;
}
}
break;
}
case GEO_NODE_REPEAT_OUTPUT: {
for (const bNode *input_node : tree.nodes_by_type("GeometryNodeRepeatInput")) {
const NodeGeometryRepeatInput &data = *static_cast<const NodeGeometryRepeatInput *>(
input_node->storage);
if (node.identifier == data.output_node_id) {
const eFieldStateSyncResult sync_result = repeat_field_state_sync(
*input_node, node, field_state_by_socket_id);
if (bool(sync_result & eFieldStateSyncResult::CHANGED_A)) {
need_update = true;
}
}
}
break;
}
}
@ -365,8 +411,8 @@ static void propagate_data_requirements_from_right_to_left(
const Span<const bNode *> toposort_result = tree.toposort_right_to_left();
while (true) {
/* Node updates may require several passes due to cyclic dependencies caused by simulation
* input/output nodes. */
/* Node updates may require several passes due to cyclic dependencies caused by simulation or
* repeat input/output nodes. */
bool need_update = false;
for (const bNode *node : toposort_result) {

View File

@ -588,6 +588,15 @@ class NodeTreeMainUpdater {
}
}
}
if (node.type == GEO_NODE_REPEAT_INPUT) {
const NodeGeometryRepeatInput *data = static_cast<const NodeGeometryRepeatInput *>(
node.storage);
if (const bNode *output_node = ntree.node_by_id(data->output_node_id)) {
if (output_node->runtime->changed_flag & NTREE_CHANGED_NODE_PROPERTY) {
return true;
}
}
}
return false;
}

View File

@ -33,7 +33,10 @@ static Vector<std::unique_ptr<bNodeTreeZone>> find_zone_nodes(
Map<const bNode *, bNodeTreeZone *> &r_zone_by_inout_node)
{
Vector<std::unique_ptr<bNodeTreeZone>> zones;
for (const bNode *node : tree.nodes_by_type("GeometryNodeSimulationOutput")) {
Vector<const bNode *> zone_output_nodes;
zone_output_nodes.extend(tree.nodes_by_type("GeometryNodeSimulationOutput"));
zone_output_nodes.extend(tree.nodes_by_type("GeometryNodeRepeatOutput"));
for (const bNode *node : zone_output_nodes) {
auto zone = std::make_unique<bNodeTreeZone>();
zone->owner = &owner;
zone->index = zones.size();
@ -50,6 +53,15 @@ static Vector<std::unique_ptr<bNodeTreeZone>> find_zone_nodes(
}
}
}
for (const bNode *node : tree.nodes_by_type("GeometryNodeRepeatInput")) {
const auto &storage = *static_cast<NodeGeometryRepeatInput *>(node->storage);
if (const bNode *repeat_output_node = tree.node_by_id(storage.output_node_id)) {
if (bNodeTreeZone *zone = r_zone_by_inout_node.lookup_default(repeat_output_node, nullptr)) {
zone->input_node = node;
r_zone_by_inout_node.add(node, zone);
}
}
}
return zones;
}
@ -227,13 +239,13 @@ static std::unique_ptr<bNodeTreeZones> discover_tree_zones(const bNodeTree &tree
depend_on_output_flags |= depend_on_output_flag_array[from_node_i];
}
}
if (node->type == GEO_NODE_SIMULATION_INPUT) {
if (ELEM(node->type, GEO_NODE_SIMULATION_INPUT, GEO_NODE_REPEAT_INPUT)) {
if (const bNodeTreeZone *zone = zone_by_inout_node.lookup_default(node, nullptr)) {
/* Now entering a zone, so set the corresponding bit. */
depend_on_input_flags[zone->index].set();
}
}
else if (node->type == GEO_NODE_SIMULATION_OUTPUT) {
else if (ELEM(node->type, GEO_NODE_SIMULATION_OUTPUT, GEO_NODE_REPEAT_OUTPUT)) {
if (const bNodeTreeZone *zone = zone_by_inout_node.lookup_default(node, nullptr)) {
/* The output is implicitly linked to the input, so also propagate the bits from there. */
if (const bNode *zone_input_node = zone->input_node) {

View File

@ -577,7 +577,9 @@ static void object_blend_write(BlendWriter *writer, ID *id, const void *id_addre
arm = (bArmature *)ob->data;
}
BKE_pose_blend_write(writer, ob->pose, arm);
if (ob->pose) {
BKE_pose_blend_write(writer, ob->pose, arm);
}
BKE_constraint_blend_write(writer, &ob->constraints);
animviz_motionpath_blend_write(writer, ob->mpath);

View File

@ -1737,7 +1737,7 @@ static void sculpt_update_object(
/* These are assigned to the base mesh in Multires. This is needed because Face Sets operators
* and tools use the Face Sets data from the base mesh when Multires is active. */
ss->vert_positions = BKE_mesh_vert_positions_for_write(me);
ss->vert_positions = me->vert_positions_for_write();
ss->polys = me->polys();
ss->corner_verts = me->corner_verts();
}
@ -1745,7 +1745,7 @@ static void sculpt_update_object(
ss->totvert = me->totvert;
ss->totpoly = me->totpoly;
ss->totfaces = me->totpoly;
ss->vert_positions = BKE_mesh_vert_positions_for_write(me);
ss->vert_positions = me->vert_positions_for_write();
ss->polys = me->polys();
ss->corner_verts = me->corner_verts();
ss->multires.active = false;
@ -1756,7 +1756,6 @@ static void sculpt_update_object(
CustomDataLayer *layer;
eAttrDomain domain;
if (BKE_pbvh_get_color_layer(me, &layer, &domain)) {
if (layer->type == CD_PROP_COLOR) {
ss->vcol = static_cast<MPropCol *>(layer->data);

View File

@ -699,7 +699,6 @@ static void pbvh_draw_args_init(PBVH *pbvh, PBVH_GPU_Args *args, PBVHNode *node)
memset((void *)args, 0, sizeof(*args));
args->pbvh_type = pbvh->header.type;
args->mesh_verts_num = pbvh->totvert;
args->mesh_grids_num = pbvh->totgrid;
args->node = node;
@ -857,7 +856,7 @@ void BKE_pbvh_update_mesh_pointers(PBVH *pbvh, Mesh *mesh)
if (!pbvh->deformed) {
/* Deformed positions not matching the original mesh are owned directly by the PBVH, and are
* set separately by #BKE_pbvh_vert_coords_apply. */
pbvh->vert_positions = BKE_mesh_vert_positions_for_write(mesh);
pbvh->vert_positions = mesh->vert_positions_for_write();
}
pbvh->hide_poly = static_cast<bool *>(CustomData_get_layer_named_for_write(
@ -869,7 +868,7 @@ void BKE_pbvh_update_mesh_pointers(PBVH *pbvh, Mesh *mesh)
mesh->vert_normals();
mesh->poly_normals();
pbvh->vert_normals = BKE_mesh_vert_normals_for_write(mesh);
pbvh->vert_normals = mesh->runtime->vert_normals;
pbvh->poly_normals = mesh->runtime->poly_normals;
pbvh->vdata = &mesh->vdata;
@ -1095,14 +1094,6 @@ void BKE_pbvh_free(PBVH *pbvh)
}
}
if (pbvh->deformed) {
if (pbvh->vert_positions) {
/* if pbvh was deformed, new memory was allocated for verts/faces -- free it */
MEM_freeN((void *)pbvh->vert_positions);
}
}
if (pbvh->looptri) {
MEM_freeN((void *)pbvh->looptri);
}
@ -1119,7 +1110,7 @@ void BKE_pbvh_free(PBVH *pbvh)
pbvh_pixels_free(pbvh);
MEM_freeN(pbvh);
MEM_delete(pbvh);
}
static void pbvh_iter_begin(PBVHIter *iter,
@ -1387,8 +1378,7 @@ static void pbvh_faces_update_normals(PBVH *pbvh, Span<PBVHNode *> nodes)
{
using namespace blender;
using namespace blender::bke;
const Span<float3> positions(reinterpret_cast<const float3 *>(pbvh->vert_positions),
pbvh->totvert);
const Span<float3> positions = pbvh->vert_positions;
const OffsetIndices polys = pbvh->polys;
const Span<int> corner_verts(pbvh->corner_verts, pbvh->mesh->totloop);
@ -1407,7 +1397,7 @@ static void pbvh_faces_update_normals(PBVH *pbvh, Span<PBVHNode *> nodes)
return;
}
MutableSpan<float3> vert_normals(reinterpret_cast<float3 *>(pbvh->vert_normals), pbvh->totvert);
MutableSpan<float3> vert_normals = pbvh->vert_normals;
MutableSpan<float3> poly_normals = pbvh->poly_normals;
VectorSet<int> verts_to_update;
@ -1565,28 +1555,12 @@ static void pbvh_update_BB_redraw(PBVH *pbvh, Span<PBVHNode *> nodes, int flag)
BLI_task_parallel_range(0, nodes.size(), &data, pbvh_update_BB_redraw_task_cb, &settings);
}
bool BKE_pbvh_get_color_layer(const Mesh *me, CustomDataLayer **r_layer, eAttrDomain *r_attr)
bool BKE_pbvh_get_color_layer(Mesh *me, CustomDataLayer **r_layer, eAttrDomain *r_domain)
{
CustomDataLayer *layer = BKE_id_attributes_color_find(&me->id, me->active_color_attribute);
if (!layer || !ELEM(layer->type, CD_PROP_COLOR, CD_PROP_BYTE_COLOR)) {
*r_layer = nullptr;
*r_attr = ATTR_DOMAIN_POINT;
return false;
}
eAttrDomain domain = BKE_id_attribute_domain(&me->id, layer);
if (!ELEM(domain, ATTR_DOMAIN_POINT, ATTR_DOMAIN_CORNER)) {
*r_layer = nullptr;
*r_attr = ATTR_DOMAIN_POINT;
return false;
}
*r_layer = layer;
*r_attr = domain;
return true;
*r_layer = BKE_id_attribute_search(
&me->id, me->active_color_attribute, CD_MASK_COLOR_ALL, ATTR_DOMAIN_MASK_COLOR);
*r_domain = *r_layer ? BKE_id_attribute_domain(&me->id, *r_layer) : ATTR_DOMAIN_POINT;
return *r_layer != nullptr;
}
static void pbvh_update_draw_buffer_cb(void *__restrict userdata,
@ -2470,7 +2444,7 @@ static bool pbvh_faces_node_raycast(PBVH *pbvh,
int *r_active_face_index,
float *r_face_normal)
{
const float(*positions)[3] = pbvh->vert_positions;
const Span<float3> positions = pbvh->vert_positions;
const int *corner_verts = pbvh->corner_verts;
const int *looptris = node->prim_indices;
int looptris_num = node->totprim;
@ -2819,7 +2793,7 @@ static bool pbvh_faces_node_nearest_to_ray(PBVH *pbvh,
float *depth,
float *dist_sq)
{
const float(*positions)[3] = pbvh->vert_positions;
const Span<float3> positions = pbvh->vert_positions;
const int *corner_verts = pbvh->corner_verts;
const int *looptris = node->prim_indices;
int i, looptris_num = node->totprim;
@ -3182,10 +3156,10 @@ float (*BKE_pbvh_vert_coords_alloc(PBVH *pbvh))[3]
{
float(*vertCos)[3] = nullptr;
if (pbvh->vert_positions) {
if (!pbvh->vert_positions.is_empty()) {
vertCos = static_cast<float(*)[3]>(
MEM_malloc_arrayN(pbvh->totvert, sizeof(float[3]), __func__));
memcpy(vertCos, pbvh->vert_positions, sizeof(float[3]) * pbvh->totvert);
memcpy(vertCos, pbvh->vert_positions.data(), sizeof(float[3]) * pbvh->totvert);
}
return vertCos;
@ -3199,12 +3173,13 @@ void BKE_pbvh_vert_coords_apply(PBVH *pbvh, const float (*vertCos)[3], const int
}
if (!pbvh->deformed) {
if (pbvh->vert_positions) {
if (!pbvh->vert_positions.is_empty()) {
/* if pbvh is not already deformed, verts/faces points to the */
/* original data and applying new coords to this arrays would lead to */
/* unneeded deformation -- duplicate verts/faces to avoid this */
pbvh->vert_positions_deformed = blender::Array<float3>(pbvh->vert_positions.as_span());
pbvh->vert_positions = pbvh->vert_positions_deformed;
pbvh->vert_positions = static_cast<float(*)[3]>(MEM_dupallocN(pbvh->vert_positions));
/* No need to dupalloc pbvh->looptri, this one is 'totally owned' by pbvh,
* it's never some mesh data. */
@ -3212,8 +3187,8 @@ void BKE_pbvh_vert_coords_apply(PBVH *pbvh, const float (*vertCos)[3], const int
}
}
if (pbvh->vert_positions) {
float(*positions)[3] = pbvh->vert_positions;
if (!pbvh->vert_positions.is_empty()) {
MutableSpan<float3> positions = pbvh->vert_positions;
/* copy new verts coords */
for (int a = 0; a < pbvh->totvert; a++) {
/* no need for float comparison here (memory is exactly equal or not) */
@ -3301,7 +3276,7 @@ void pbvh_vertex_iter_init(PBVH *pbvh, PBVHNode *node, PBVHVertexIter *vi, int m
vi->grid = nullptr;
vi->no = nullptr;
vi->fno = nullptr;
vi->vert_positions = nullptr;
vi->vert_positions = {};
vi->vertex.i = 0LL;
BKE_pbvh_node_get_grids(pbvh, node, &grid_indices, &totgrid, nullptr, &gridsize, &grids);
@ -3322,7 +3297,7 @@ void pbvh_vertex_iter_init(PBVH *pbvh, PBVHNode *node, PBVHVertexIter *vi, int m
}
vi->vert_indices = vert_indices;
vi->vert_positions = pbvh->vert_positions;
vi->is_mesh = pbvh->vert_positions != nullptr;
vi->is_mesh = !pbvh->vert_positions.is_empty();
if (pbvh->header.type == PBVH_BMESH) {
BLI_gsetIterator_init(&vi->bm_unique_verts, node->bm_unique_verts);
@ -3402,13 +3377,13 @@ void BKE_pbvh_parallel_range_settings(TaskParallelSettings *settings,
float (*BKE_pbvh_get_vert_positions(const PBVH *pbvh))[3]
{
BLI_assert(pbvh->header.type == PBVH_FACES);
return pbvh->vert_positions;
return reinterpret_cast<float(*)[3]>(pbvh->vert_positions.data());
}
const float (*BKE_pbvh_get_vert_normals(const PBVH *pbvh))[3]
{
BLI_assert(pbvh->header.type == PBVH_FACES);
return pbvh->vert_normals;
return reinterpret_cast<const float(*)[3]>(pbvh->vert_normals.data());
}
const bool *BKE_pbvh_get_vert_hide(const PBVH *pbvh)
@ -3484,7 +3459,7 @@ void BKE_pbvh_node_num_loops(PBVH *pbvh, PBVHNode *node, int *r_totloop)
}
}
void BKE_pbvh_update_active_vcol(PBVH *pbvh, const Mesh *mesh)
void BKE_pbvh_update_active_vcol(PBVH *pbvh, Mesh *mesh)
{
BKE_pbvh_get_color_layer(mesh, &pbvh->color_layer, &pbvh->color_domain);
}

View File

@ -2198,13 +2198,15 @@ static void pbvh_bmesh_print(PBVH *pbvh)
BMIter iter;
BMFace *f;
BM_ITER_MESH (f, &iter, pbvh->header.bm, BM_FACES_OF_MESH) {
fprintf(stderr, " %d -> %d\n", BM_elem_index_get(f), pbvh_bmesh_node_index_from_face(pbvh, f));
fprintf(
stderr, " %d -> %d\n", BM_elem_index_get(f), pbvh_bmesh_node_index_from_face(pbvh, f));
}
fprintf(stderr, "bm_vert_to_node:\n");
BMVert *v;
BM_ITER_MESH (v, &iter, pbvh->header.bm, BM_FACES_OF_MESH) {
fprintf(stderr, " %d -> %d\n", BM_elem_index_get(v), pbvh_bmesh_node_index_from_vert(pbvh, v));
fprintf(
stderr, " %d -> %d\n", BM_elem_index_get(v), pbvh_bmesh_node_index_from_vert(pbvh, v));
}
for (int n = 0; n < pbvh->totnode; n++) {

View File

@ -157,10 +157,12 @@ struct PBVH {
Mesh *mesh;
/* NOTE: Normals are not `const` because they can be updated for drawing by sculpt code. */
float (*vert_normals)[3];
blender::MutableSpan<blender::float3> vert_normals;
blender::MutableSpan<blender::float3> poly_normals;
bool *hide_vert;
float (*vert_positions)[3];
blender::MutableSpan<blender::float3> vert_positions;
/** Local vertex positions owned by the PVBH when not sculpting base mesh positions directly. */
blender::Array<blender::float3> vert_positions_deformed;
blender::OffsetIndices<int> polys;
bool *hide_poly;
/** Only valid for polygon meshes. */

View File

@ -670,11 +670,10 @@ static bool update_pixels(PBVH *pbvh, Mesh *mesh, Image *image, ImageUser *image
const AttributeAccessor attributes = mesh->attributes();
const VArraySpan uv_map = *attributes.lookup<float2>(active_uv_name, ATTR_DOMAIN_CORNER);
uv_islands::MeshData mesh_data(
{pbvh->looptri, pbvh->totprim},
{pbvh->corner_verts, mesh->totloop},
uv_map,
{static_cast<blender::float3 *>(static_cast<void *>(pbvh->vert_positions)), pbvh->totvert});
uv_islands::MeshData mesh_data({pbvh->looptri, pbvh->totprim},
{pbvh->corner_verts, mesh->totloop},
uv_map,
pbvh->vert_positions);
uv_islands::UVIslands islands(mesh_data);
uv_islands::UVIslandsMask uv_masks;

View File

@ -26,7 +26,6 @@
#include "DNA_particle_types.h"
#include "DNA_rigidbody_types.h"
#include "DNA_scene_types.h"
#include "DNA_simulation_types.h"
#include "BLI_blenlib.h"
#include "BLI_endian_switch.h"

View File

@ -1,205 +0,0 @@
/* SPDX-FileCopyrightText: 2023 Blender Foundation
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup bke
*/
#include <iostream>
#include "MEM_guardedalloc.h"
#include "DNA_ID.h"
#include "DNA_defaults.h"
#include "DNA_modifier_types.h"
#include "DNA_scene_types.h"
#include "DNA_simulation_types.h"
#include "BLI_compiler_compat.h"
#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_math_vector_types.hh"
#include "BLI_rand.h"
#include "BLI_span.hh"
#include "BLI_string.h"
#include "BLI_utildefines.h"
#include "BKE_anim_data.h"
#include "BKE_animsys.h"
#include "BKE_collection.h"
#include "BKE_customdata.h"
#include "BKE_idtype.h"
#include "BKE_lib_id.h"
#include "BKE_lib_query.h"
#include "BKE_lib_remap.h"
#include "BKE_main.h"
#include "BKE_modifier.h"
#include "BKE_node.hh"
#include "BKE_pointcache.h"
#include "BKE_simulation.h"
#include "BKE_simulation_state.hh"
#include "NOD_geometry.hh"
#include "BLI_map.hh"
#include "BLT_translation.h"
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_query.h"
#include "MOD_nodes.hh"
#include "BLO_read_write.h"
static void simulation_init_data(ID *id)
{
Simulation *simulation = (Simulation *)id;
BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(simulation, id));
MEMCPY_STRUCT_AFTER(simulation, DNA_struct_default_get(Simulation), id);
blender::bke::ntreeAddTreeEmbedded(nullptr, id, "Geometry Nodetree", ntreeType_Geometry->idname);
}
static void simulation_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int flag)
{
Simulation *simulation_dst = (Simulation *)id_dst;
const Simulation *simulation_src = (const Simulation *)id_src;
/* We always need allocation of our private ID data. */
const int flag_private_id_data = flag & ~LIB_ID_CREATE_NO_ALLOCATE;
if (simulation_src->nodetree) {
BKE_id_copy_ex(bmain,
(ID *)simulation_src->nodetree,
(ID **)&simulation_dst->nodetree,
flag_private_id_data);
simulation_dst->nodetree->owner_id = &simulation_dst->id;
}
}
static void simulation_free_data(ID *id)
{
Simulation *simulation = (Simulation *)id;
BKE_animdata_free(&simulation->id, false);
if (simulation->nodetree) {
ntreeFreeEmbeddedTree(simulation->nodetree);
MEM_freeN(simulation->nodetree);
simulation->nodetree = nullptr;
}
}
static void simulation_foreach_id(ID *id, LibraryForeachIDData *data)
{
Simulation *simulation = (Simulation *)id;
if (simulation->nodetree) {
/* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */
BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(
data, BKE_library_foreach_ID_embedded(data, (ID **)&simulation->nodetree));
}
}
static void simulation_blend_write(BlendWriter *writer, ID *id, const void *id_address)
{
Simulation *simulation = (Simulation *)id;
BLO_write_id_struct(writer, Simulation, id_address, &simulation->id);
BKE_id_blend_write(writer, &simulation->id);
if (simulation->adt) {
BKE_animdata_blend_write(writer, simulation->adt);
}
/* nodetree is integral part of simulation, no libdata */
if (simulation->nodetree) {
BLO_Write_IDBuffer *temp_embedded_id_buffer = BLO_write_allocate_id_buffer();
BLO_write_init_id_buffer_from_id(
temp_embedded_id_buffer, &simulation->nodetree->id, BLO_write_is_undo(writer));
BLO_write_struct_at_address(writer,
bNodeTree,
simulation->nodetree,
BLO_write_get_id_buffer_temp_id(temp_embedded_id_buffer));
ntreeBlendWrite(
writer,
reinterpret_cast<bNodeTree *>(BLO_write_get_id_buffer_temp_id(temp_embedded_id_buffer)));
BLO_write_destroy_id_buffer(&temp_embedded_id_buffer);
}
}
static void simulation_blend_read_data(BlendDataReader *reader, ID *id)
{
Simulation *simulation = (Simulation *)id;
BLO_read_data_address(reader, &simulation->adt);
BKE_animdata_blend_read_data(reader, simulation->adt);
}
static void simulation_blend_read_lib(BlendLibReader *reader, ID *id)
{
Simulation *simulation = (Simulation *)id;
UNUSED_VARS(simulation, reader);
}
static void simulation_blend_read_expand(BlendExpander *expander, ID *id)
{
Simulation *simulation = (Simulation *)id;
UNUSED_VARS(simulation, expander);
}
IDTypeInfo IDType_ID_SIM = {
/*id_code*/ ID_SIM,
/*id_filter*/ FILTER_ID_SIM,
/*main_listbase_index*/ INDEX_ID_SIM,
/*struct_size*/ sizeof(Simulation),
/*name*/ "Simulation",
/*name_plural*/ "simulations",
/*translation_context*/ BLT_I18NCONTEXT_ID_SIMULATION,
/*flags*/ IDTYPE_FLAGS_APPEND_IS_REUSABLE,
/*asset_type_info*/ nullptr,
/*init_data*/ simulation_init_data,
/*copy_data*/ simulation_copy_data,
/*free_data*/ simulation_free_data,
/*make_local*/ nullptr,
/*foreach_id*/ simulation_foreach_id,
/*foreach_cache*/ nullptr,
/*foreach_path*/ nullptr,
/*owner_pointer_get*/ nullptr,
/*blend_write*/ simulation_blend_write,
/*blend_read_data*/ simulation_blend_read_data,
/*blend_read_lib*/ simulation_blend_read_lib,
/*blend_read_expand*/ simulation_blend_read_expand,
/*blend_read_undo_preserve*/ nullptr,
/*lib_override_apply_post*/ nullptr,
};
void *BKE_simulation_add(Main *bmain, const char *name)
{
Simulation *simulation = (Simulation *)BKE_id_new(bmain, ID_SIM, name);
return simulation;
}
void BKE_simulation_data_update(Depsgraph * /*depsgraph*/,
Scene * /*scene*/,
Simulation * /*simulation*/)
{
}
void BKE_simulation_reset_scene(Scene *scene)
{
FOREACH_SCENE_OBJECT_BEGIN (scene, ob) {
LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) {
if (md->type != eModifierType_Nodes) {
continue;
}
NodesModifierData *nmd = (NodesModifierData *)md;
nmd->runtime->simulation_cache.reset();
}
}
FOREACH_SCENE_OBJECT_END;
}

View File

@ -2,12 +2,12 @@
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "BKE_collection.h"
#include "BKE_curves.hh"
#include "BKE_simulation_state.hh"
#include "BKE_simulation_state_serialize.hh"
#include "DNA_curves_types.h"
#include "DNA_mesh_types.h"
#include "DNA_modifier_types.h"
#include "DNA_node_types.h"
#include "DNA_pointcloud_types.h"
@ -17,6 +17,8 @@
#include "BLI_path_util.h"
#include "BLI_string_utils.h"
#include "MOD_nodes.hh"
namespace blender::bke::sim {
GeometrySimulationStateItem::GeometrySimulationStateItem(GeometrySet geometry)
@ -251,4 +253,18 @@ void ModifierSimulationCache::reset()
this->cache_state = CacheState::Valid;
}
void scene_simulation_states_reset(Scene &scene)
{
FOREACH_SCENE_OBJECT_BEGIN (&scene, ob) {
LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) {
if (md->type != eModifierType_Nodes) {
continue;
}
NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md);
nmd->runtime->simulation_cache->reset();
}
}
FOREACH_SCENE_OBJECT_END;
}
} // namespace blender::bke::sim

View File

@ -231,7 +231,7 @@ void BKE_vfont_builtin_register(const void *mem, int size)
builtin_font_size = size;
}
static PackedFile *get_builtin_packedfile(void)
static PackedFile *get_builtin_packedfile()
{
if (!builtin_font_data) {
CLOG_ERROR(&LOG, "Internal error, builtin font not loaded");
@ -410,7 +410,7 @@ static VFont *which_vfont(Curve *cu, CharInfo *info)
}
}
VFont *BKE_vfont_builtin_get(void)
VFont *BKE_vfont_builtin_get()
{
LISTBASE_FOREACH (VFont *, vfont, &G_MAIN->fonts) {
if (BKE_vfont_is_builtin(vfont)) {
@ -2053,7 +2053,7 @@ static struct {
size_t len_utf8;
} g_vfont_clipboard = {nullptr};
void BKE_vfont_clipboard_free(void)
void BKE_vfont_clipboard_free()
{
MEM_SAFE_FREE(g_vfont_clipboard.text_buffer);
MEM_SAFE_FREE(g_vfont_clipboard.info_buffer);

View File

@ -88,6 +88,11 @@ void BKE_viewer_path_blend_write(BlendWriter *writer, const ViewerPath *viewer_p
BLO_write_struct(writer, ViewerNodeViewerPathElem, typed_elem);
break;
}
case VIEWER_PATH_ELEM_TYPE_REPEAT_ZONE: {
const auto *typed_elem = reinterpret_cast<RepeatZoneViewerPathElem *>(elem);
BLO_write_struct(writer, RepeatZoneViewerPathElem, typed_elem);
break;
}
}
BLO_write_string(writer, elem->ui_name);
}
@ -102,6 +107,7 @@ void BKE_viewer_path_blend_read_data(BlendDataReader *reader, ViewerPath *viewer
case VIEWER_PATH_ELEM_TYPE_GROUP_NODE:
case VIEWER_PATH_ELEM_TYPE_SIMULATION_ZONE:
case VIEWER_PATH_ELEM_TYPE_VIEWER_NODE:
case VIEWER_PATH_ELEM_TYPE_REPEAT_ZONE:
case VIEWER_PATH_ELEM_TYPE_ID: {
break;
}
@ -126,7 +132,8 @@ void BKE_viewer_path_blend_read_lib(BlendLibReader *reader, ID *self_id, ViewerP
case VIEWER_PATH_ELEM_TYPE_MODIFIER:
case VIEWER_PATH_ELEM_TYPE_GROUP_NODE:
case VIEWER_PATH_ELEM_TYPE_SIMULATION_ZONE:
case VIEWER_PATH_ELEM_TYPE_VIEWER_NODE: {
case VIEWER_PATH_ELEM_TYPE_VIEWER_NODE:
case VIEWER_PATH_ELEM_TYPE_REPEAT_ZONE: {
break;
}
}
@ -145,7 +152,8 @@ void BKE_viewer_path_foreach_id(LibraryForeachIDData *data, ViewerPath *viewer_p
case VIEWER_PATH_ELEM_TYPE_MODIFIER:
case VIEWER_PATH_ELEM_TYPE_GROUP_NODE:
case VIEWER_PATH_ELEM_TYPE_SIMULATION_ZONE:
case VIEWER_PATH_ELEM_TYPE_VIEWER_NODE: {
case VIEWER_PATH_ELEM_TYPE_VIEWER_NODE:
case VIEWER_PATH_ELEM_TYPE_REPEAT_ZONE: {
break;
}
}
@ -164,7 +172,8 @@ void BKE_viewer_path_id_remap(ViewerPath *viewer_path, const IDRemapper *mapping
case VIEWER_PATH_ELEM_TYPE_MODIFIER:
case VIEWER_PATH_ELEM_TYPE_GROUP_NODE:
case VIEWER_PATH_ELEM_TYPE_SIMULATION_ZONE:
case VIEWER_PATH_ELEM_TYPE_VIEWER_NODE: {
case VIEWER_PATH_ELEM_TYPE_VIEWER_NODE:
case VIEWER_PATH_ELEM_TYPE_REPEAT_ZONE: {
break;
}
}
@ -196,6 +205,9 @@ ViewerPathElem *BKE_viewer_path_elem_new(const ViewerPathElemType type)
case VIEWER_PATH_ELEM_TYPE_VIEWER_NODE: {
return &make_elem<ViewerNodeViewerPathElem>(type)->base;
}
case VIEWER_PATH_ELEM_TYPE_REPEAT_ZONE: {
return &make_elem<RepeatZoneViewerPathElem>(type)->base;
}
}
BLI_assert_unreachable();
return nullptr;
@ -230,6 +242,12 @@ ViewerNodeViewerPathElem *BKE_viewer_path_elem_new_viewer_node()
BKE_viewer_path_elem_new(VIEWER_PATH_ELEM_TYPE_VIEWER_NODE));
}
RepeatZoneViewerPathElem *BKE_viewer_path_elem_new_repeat_zone()
{
return reinterpret_cast<RepeatZoneViewerPathElem *>(
BKE_viewer_path_elem_new(VIEWER_PATH_ELEM_TYPE_REPEAT_ZONE));
}
ViewerPathElem *BKE_viewer_path_elem_copy(const ViewerPathElem *src)
{
ViewerPathElem *dst = BKE_viewer_path_elem_new(ViewerPathElemType(src->type));
@ -269,6 +287,13 @@ ViewerPathElem *BKE_viewer_path_elem_copy(const ViewerPathElem *src)
new_elem->node_id = old_elem->node_id;
break;
}
case VIEWER_PATH_ELEM_TYPE_REPEAT_ZONE: {
const auto *old_elem = reinterpret_cast<const RepeatZoneViewerPathElem *>(src);
auto *new_elem = reinterpret_cast<RepeatZoneViewerPathElem *>(dst);
new_elem->repeat_output_node_id = old_elem->repeat_output_node_id;
new_elem->iteration = old_elem->iteration;
break;
}
}
return dst;
}
@ -304,6 +329,12 @@ bool BKE_viewer_path_elem_equal(const ViewerPathElem *a, const ViewerPathElem *b
const auto *b_elem = reinterpret_cast<const ViewerNodeViewerPathElem *>(b);
return a_elem->node_id == b_elem->node_id;
}
case VIEWER_PATH_ELEM_TYPE_REPEAT_ZONE: {
const auto *a_elem = reinterpret_cast<const RepeatZoneViewerPathElem *>(a);
const auto *b_elem = reinterpret_cast<const RepeatZoneViewerPathElem *>(b);
return a_elem->repeat_output_node_id == b_elem->repeat_output_node_id &&
a_elem->iteration == b_elem->iteration;
}
}
return false;
}
@ -314,7 +345,8 @@ void BKE_viewer_path_elem_free(ViewerPathElem *elem)
case VIEWER_PATH_ELEM_TYPE_ID:
case VIEWER_PATH_ELEM_TYPE_GROUP_NODE:
case VIEWER_PATH_ELEM_TYPE_SIMULATION_ZONE:
case VIEWER_PATH_ELEM_TYPE_VIEWER_NODE: {
case VIEWER_PATH_ELEM_TYPE_VIEWER_NODE:
case VIEWER_PATH_ELEM_TYPE_REPEAT_ZONE: {
break;
}
case VIEWER_PATH_ELEM_TYPE_MODIFIER: {

View File

@ -87,6 +87,17 @@ struct FloatTraits {
}
};
template<typename T> struct TraitsType {
using type = void;
};
template<> struct TraitsType<ColorPaint4f> {
using type = FloatTraits;
};
template<> struct TraitsType<ColorPaint4b> {
using type = ByteTraits;
};
template<typename T> using Traits = typename TraitsType<T>::type;
static float get_luminance(ColorPaint4f c)
{
return IMB_colormanagement_get_luminance(&c.r);

View File

@ -50,12 +50,9 @@
* memory usage of the map.
* - The method names don't follow the std::unordered_map names in many cases. Searching for such
* names in this file will usually let you discover the new name.
* - There is a StdUnorderedMapWrapper class, that wraps std::unordered_map and gives it the same
* interface as blender::Map. This is useful for benchmarking.
*/
#include <optional>
#include <unordered_map>
#include "BLI_array.hh"
#include "BLI_hash.hh"
@ -1287,71 +1284,4 @@ template<typename Key,
using RawMap =
Map<Key, Value, InlineBufferCapacity, ProbingStrategy, Hash, IsEqual, Slot, RawAllocator>;
/**
* A wrapper for std::unordered_map with the API of blender::Map. This can be used for
* benchmarking.
*/
template<typename Key, typename Value> class StdUnorderedMapWrapper {
private:
using MapType = std::unordered_map<Key, Value, blender::DefaultHash<Key>>;
MapType map_;
public:
int64_t size() const
{
return int64_t(map_.size());
}
bool is_empty() const
{
return map_.empty();
}
void reserve(int64_t n)
{
map_.reserve(n);
}
template<typename ForwardKey, typename... ForwardValue>
void add_new(ForwardKey &&key, ForwardValue &&...value)
{
map_.insert({std::forward<ForwardKey>(key), Value(std::forward<ForwardValue>(value)...)});
}
template<typename ForwardKey, typename... ForwardValue>
bool add(ForwardKey &&key, ForwardValue &&...value)
{
return map_
.insert({std::forward<ForwardKey>(key), Value(std::forward<ForwardValue>(value)...)})
.second;
}
bool contains(const Key &key) const
{
return map_.find(key) != map_.end();
}
bool remove(const Key &key)
{
return bool(map_.erase(key));
}
Value &lookup(const Key &key)
{
return map_.find(key)->second;
}
const Value &lookup(const Key &key) const
{
return map_.find(key)->second;
}
void clear()
{
map_.clear();
}
void print_stats(StringRef /*name*/ = "") const {}
};
} // namespace blender

View File

@ -45,8 +45,6 @@
* memory usage of the set.
* - The method names don't follow the std::unordered_set names in many cases. Searching for such
* names in this file will usually let you discover the new name.
* - There is a #StdUnorderedSetWrapper class, that wraps std::unordered_set and gives it the same
* interface as blender::Set. This is useful for bench-marking.
*
* Possible Improvements:
* - Use a branch-less loop over slots in grow function (measured ~10% performance improvement when
@ -57,8 +55,6 @@
* to make a nice interface for this functionality.
*/
#include <unordered_set>
#include "BLI_array.hh"
#include "BLI_hash.hh"
#include "BLI_hash_tables.hh"
@ -889,87 +885,6 @@ class Set {
}
};
/**
* A wrapper for std::unordered_set with the API of blender::Set. This can be used for
* benchmarking.
*/
template<typename Key> class StdUnorderedSetWrapper {
private:
using SetType = std::unordered_set<Key, blender::DefaultHash<Key>>;
SetType set_;
public:
int64_t size() const
{
return int64_t(set_.size());
}
bool is_empty() const
{
return set_.empty();
}
void reserve(int64_t n)
{
set_.reserve(n);
}
void add_new(const Key &key)
{
set_.insert(key);
}
void add_new(Key &&key)
{
set_.insert(std::move(key));
}
bool add(const Key &key)
{
return set_.insert(key).second;
}
bool add(Key &&key)
{
return set_.insert(std::move(key)).second;
}
void add_multiple(Span<Key> keys)
{
for (const Key &key : keys) {
set_.insert(key);
}
}
bool contains(const Key &key) const
{
return set_.find(key) != set_.end();
}
bool remove(const Key &key)
{
return bool(set_.erase(key));
}
void remove_contained(const Key &key)
{
return set_.erase(key);
}
void clear()
{
set_.clear();
}
typename SetType::iterator begin() const
{
return set_.begin();
}
typename SetType::iterator end() const
{
return set_.end();
}
};
/**
* Same as a normal Set, but does not use Blender's guarded allocator. This is useful when
* allocating memory with static storage duration.

Some files were not shown because too many files have changed in this diff Show More