Fix #100718: NLA Hold Forward Inconsistency #109182
|
@ -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
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -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]);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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
|
||||
|
@ -1992,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
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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"
|
||||
|
@ -1617,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
|
||||
|
@ -1688,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;
|
||||
}
|
||||
|
||||
|
@ -1712,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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1721,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) {
|
||||
|
@ -1741,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;
|
||||
}
|
||||
}
|
||||
|
@ -1751,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);
|
||||
}
|
||||
|
|
|
@ -398,6 +398,8 @@ void DeferredLayer::begin_sync()
|
|||
gbuffer_single_sided_ps_ = &gbuffer_ps_.sub("SingleSided");
|
||||
gbuffer_single_sided_ps_->state_set(state | DRW_STATE_CULL_BACK);
|
||||
}
|
||||
|
||||
closure_bits_ = CLOSURE_NONE;
|
||||
}
|
||||
|
||||
void DeferredLayer::end_sync()
|
||||
|
|
|
@ -162,7 +162,7 @@ class DeferredLayer {
|
|||
PassSimple eval_light_ps_ = {"EvalLights"};
|
||||
|
||||
/* Closures bits from the materials in this pass. */
|
||||
eClosureBits closure_bits_;
|
||||
eClosureBits closure_bits_ = CLOSURE_NONE;
|
||||
|
||||
/**
|
||||
* Accumulation textures for all stages of lighting evaluation (Light, SSR, SSSS, SSGI ...).
|
||||
|
|
|
@ -81,7 +81,7 @@ void Sampling::end_sync()
|
|||
sample_ = viewport_sample_;
|
||||
}
|
||||
else if (interactive_mode_) {
|
||||
int interactive_sample_count = min_ii(interactive_sample_max_, sample_count_);
|
||||
int interactive_sample_count = interactive_sample_max_;
|
||||
|
||||
if (viewport_sample_ < interactive_sample_count) {
|
||||
/* Loop over the same starting samples. */
|
||||
|
@ -98,12 +98,13 @@ void Sampling::end_sync()
|
|||
void Sampling::step()
|
||||
{
|
||||
{
|
||||
uint64_t sample_filter = sample_ % interactive_sample_aa_;
|
||||
/* TODO(fclem) we could use some persistent states to speedup the computation. */
|
||||
double2 r, offset = {0, 0};
|
||||
/* Using 2,3 primes as per UE4 Temporal AA presentation.
|
||||
* http://advances.realtimerendering.com/s2014/epic/TemporalAA.pptx (slide 14) */
|
||||
uint2 primes = {2, 3};
|
||||
BLI_halton_2d(primes, offset, sample_ + 1, r);
|
||||
BLI_halton_2d(primes, offset, sample_filter + 1, r);
|
||||
/* WORKAROUND: We offset the distribution to make the first sample (0,0). This way, we are
|
||||
* assured that at least one of the samples inside the TAA rotation will match the one from the
|
||||
* draw manager. This makes sure overlays are correctly composited in static scene. */
|
||||
|
|
|
@ -31,7 +31,8 @@ class Sampling {
|
|||
/* High number of sample for viewport infinite rendering. */
|
||||
static constexpr uint64_t infinite_sample_count_ = 0xFFFFFFu;
|
||||
/* During interactive rendering, loop over the first few samples. */
|
||||
static constexpr uint64_t interactive_sample_max_ = 8;
|
||||
static constexpr uint64_t interactive_sample_aa_ = 8;
|
||||
static constexpr uint64_t interactive_sample_max_ = interactive_sample_aa_;
|
||||
|
||||
/** 0 based current sample. Might not increase sequentially in viewport. */
|
||||
uint64_t sample_ = 0;
|
||||
|
|
|
@ -966,6 +966,7 @@ BLI_STATIC_ASSERT_ALIGN(HiZData, 16)
|
|||
* \{ */
|
||||
|
||||
enum eClosureBits : uint32_t {
|
||||
CLOSURE_NONE = 0u,
|
||||
/** NOTE: These are used as stencil bits. So we are limited to 8bits. */
|
||||
CLOSURE_DIFFUSE = (1u << 0u),
|
||||
CLOSURE_SSS = (1u << 1u),
|
||||
|
|
|
@ -766,7 +766,15 @@ static int similar_edge_select_exec(bContext *C, wmOperator *op)
|
|||
case SIMEDGE_CREASE: {
|
||||
has_custom_data_layer = CustomData_has_layer_named(
|
||||
&bm->edata, CD_PROP_FLOAT, "crease_edge");
|
||||
ATTR_FALLTHROUGH;
|
||||
if (!has_custom_data_layer) {
|
||||
/* Proceed only if we have to select all the edges that have custom data value of 0.0f.
|
||||
* In this case we will just select all the edges.
|
||||
* Otherwise continue the for loop. */
|
||||
if (!ED_select_similar_compare_float_tree(tree_1d, 0.0f, thresh, eSimilarCmp(compare))) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SIMEDGE_BEVEL: {
|
||||
has_custom_data_layer = CustomData_has_layer_named(
|
||||
|
@ -779,6 +787,7 @@ static int similar_edge_select_exec(bContext *C, wmOperator *op)
|
|||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -162,7 +162,7 @@ typedef struct RenderEngine {
|
|||
void *update_render_passes_data;
|
||||
|
||||
/* GPU context. */
|
||||
void *wm_blender_gpu_context; /* WindowManager GPU context -> GHOSTContext. */
|
||||
void *system_gpu_context; /* WindowManager GPU context -> GHOSTContext. */
|
||||
ThreadMutex blender_gpu_context_mutex;
|
||||
bool use_drw_render_context;
|
||||
struct GPUContext *blender_gpu_context;
|
||||
|
|
|
@ -1287,17 +1287,17 @@ bool RE_engine_gpu_context_create(RenderEngine *engine)
|
|||
BLI_assert(BLI_thread_is_main());
|
||||
|
||||
const bool drw_state = DRW_gpu_context_release();
|
||||
engine->wm_blender_gpu_context = WM_system_gpu_context_create();
|
||||
engine->system_gpu_context = WM_system_gpu_context_create();
|
||||
|
||||
if (engine->wm_blender_gpu_context) {
|
||||
if (engine->system_gpu_context) {
|
||||
/* Activate new GPU Context for GPUContext creation. */
|
||||
WM_system_gpu_context_activate(engine->wm_blender_gpu_context);
|
||||
WM_system_gpu_context_activate(engine->system_gpu_context);
|
||||
/* Requires GPUContext for usage of GPU Module for displaying results. */
|
||||
engine->blender_gpu_context = GPU_context_create(nullptr, engine->wm_blender_gpu_context);
|
||||
engine->blender_gpu_context = GPU_context_create(nullptr, engine->system_gpu_context);
|
||||
GPU_context_active_set(nullptr);
|
||||
/* Deactivate newly created GPU Context, as it is not needed until
|
||||
* `RE_engine_gpu_context_enable` is called. */
|
||||
WM_system_gpu_context_release(engine->wm_blender_gpu_context);
|
||||
WM_system_gpu_context_release(engine->system_gpu_context);
|
||||
}
|
||||
else {
|
||||
engine->blender_gpu_context = nullptr;
|
||||
|
@ -1305,18 +1305,18 @@ bool RE_engine_gpu_context_create(RenderEngine *engine)
|
|||
|
||||
DRW_gpu_context_activate(drw_state);
|
||||
|
||||
return engine->wm_blender_gpu_context != nullptr;
|
||||
return engine->system_gpu_context != nullptr;
|
||||
}
|
||||
|
||||
void RE_engine_gpu_context_destroy(RenderEngine *engine)
|
||||
{
|
||||
if (!engine->wm_blender_gpu_context) {
|
||||
if (!engine->system_gpu_context) {
|
||||
return;
|
||||
}
|
||||
|
||||
const bool drw_state = DRW_gpu_context_release();
|
||||
|
||||
WM_system_gpu_context_activate(engine->wm_blender_gpu_context);
|
||||
WM_system_gpu_context_activate(engine->system_gpu_context);
|
||||
if (engine->blender_gpu_context) {
|
||||
GPUContext *restore_context = GPU_context_active_get();
|
||||
GPU_context_active_set(engine->blender_gpu_context);
|
||||
|
@ -1326,7 +1326,8 @@ void RE_engine_gpu_context_destroy(RenderEngine *engine)
|
|||
}
|
||||
engine->blender_gpu_context = nullptr;
|
||||
}
|
||||
WM_system_gpu_context_dispose(engine->wm_blender_gpu_context);
|
||||
WM_system_gpu_context_dispose(engine->system_gpu_context);
|
||||
engine->system_gpu_context = nullptr;
|
||||
|
||||
DRW_gpu_context_activate(drw_state);
|
||||
}
|
||||
|
@ -1338,14 +1339,14 @@ bool RE_engine_gpu_context_enable(RenderEngine *engine)
|
|||
DRW_render_context_enable(engine->re);
|
||||
return true;
|
||||
}
|
||||
if (engine->wm_blender_gpu_context) {
|
||||
if (engine->system_gpu_context) {
|
||||
BLI_mutex_lock(&engine->blender_gpu_context_mutex);
|
||||
/* If a previous GPU/GPUContext was active (DST.blender_gpu_context), we should later
|
||||
* restore this when disabling the RenderEngine context. */
|
||||
engine->gpu_restore_context = DRW_gpu_context_release();
|
||||
|
||||
/* Activate RenderEngine System and Blender GPU Context. */
|
||||
WM_system_gpu_context_activate(engine->wm_blender_gpu_context);
|
||||
WM_system_gpu_context_activate(engine->system_gpu_context);
|
||||
if (engine->blender_gpu_context) {
|
||||
GPU_context_active_set(engine->blender_gpu_context);
|
||||
GPU_render_begin();
|
||||
|
@ -1361,12 +1362,12 @@ void RE_engine_gpu_context_disable(RenderEngine *engine)
|
|||
DRW_render_context_disable(engine->re);
|
||||
}
|
||||
else {
|
||||
if (engine->wm_blender_gpu_context) {
|
||||
if (engine->system_gpu_context) {
|
||||
if (engine->blender_gpu_context) {
|
||||
GPU_render_end();
|
||||
GPU_context_active_set(nullptr);
|
||||
}
|
||||
WM_system_gpu_context_release(engine->wm_blender_gpu_context);
|
||||
WM_system_gpu_context_release(engine->system_gpu_context);
|
||||
/* Restore DRW state context if previously active. */
|
||||
DRW_gpu_context_activate(engine->gpu_restore_context);
|
||||
BLI_mutex_unlock(&engine->blender_gpu_context_mutex);
|
||||
|
@ -1380,7 +1381,7 @@ void RE_engine_gpu_context_lock(RenderEngine *engine)
|
|||
/* Locking already handled by the draw manager. */
|
||||
}
|
||||
else {
|
||||
if (engine->wm_blender_gpu_context) {
|
||||
if (engine->system_gpu_context) {
|
||||
BLI_mutex_lock(&engine->blender_gpu_context_mutex);
|
||||
}
|
||||
}
|
||||
|
@ -1392,7 +1393,7 @@ void RE_engine_gpu_context_unlock(RenderEngine *engine)
|
|||
/* Locking already handled by the draw manager. */
|
||||
}
|
||||
else {
|
||||
if (engine->wm_blender_gpu_context) {
|
||||
if (engine->system_gpu_context) {
|
||||
BLI_mutex_unlock(&engine->blender_gpu_context_mutex);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1267,24 +1267,8 @@ static bool ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_pt
|
|||
break;
|
||||
}
|
||||
case GHOST_kEventWindowActivate: {
|
||||
|
||||
#ifdef WIN32
|
||||
/* NOTE(@ideasman42): Alt-Tab on Windows-10 (22H2) can deactivate the window,
|
||||
* then (in rare cases - approx 1 in 20) immediately call `WM_ACTIVATE` on the window
|
||||
* (which isn't active) and doesn't receive modifier release events.
|
||||
* This looks like a bug in MS-Windows, searching online other apps
|
||||
* have run into similar issues although it's not clear exactly which.
|
||||
*
|
||||
* - Therefor activation must always clear modifiers
|
||||
* or Alt-Tab can occasionally get stuck, see: #105381.
|
||||
* - Unfortunately modifiers that are held before
|
||||
* the window is active are ignored, see: #40059.
|
||||
*/
|
||||
wm_window_update_eventstate_modifiers_clear(wm, win);
|
||||
#else
|
||||
/* Ensure the event state matches modifiers (window was inactive). */
|
||||
wm_window_update_eventstate_modifiers(wm, win);
|
||||
#endif
|
||||
|
||||
/* Entering window, update mouse position (without sending an event). */
|
||||
wm_window_update_eventstate(win);
|
||||
|
|
Loading…
Reference in New Issue